blob: 22e22aa076490f6eb8af64b76a918664f2854b99 [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
Janos Follath4ec0fb52024-03-08 17:22:40 +000040
41
42/*
43 * Conditionally select an MPI sign in constant time.
44 * (MPI sign is the field s in mbedtls_mpi. It is unsigned short and only 1 and -1 are valid
45 * values.)
46 */
47static inline unsigned short mbedtls_ct_mpi_sign_if(mbedtls_ct_condition_t cond,
48 unsigned short sign1, unsigned short sign2)
49{
50 return (unsigned short) mbedtls_ct_uint_if(cond, sign1 + 1, sign2 + 1) - 1;
51}
52
Dave Rodgman7d4f0192023-05-09 14:01:05 +010053/*
54 * Compare signed values in constant time
55 */
56int mbedtls_mpi_lt_mpi_ct(const mbedtls_mpi *X,
57 const mbedtls_mpi *Y,
58 unsigned *ret)
59{
Dave Rodgman1f39f032023-08-01 09:19:16 +010060 mbedtls_ct_condition_t different_sign, X_is_negative, Y_is_negative, result;
Dave Rodgman7d4f0192023-05-09 14:01:05 +010061
Dave Rodgman7d4f0192023-05-09 14:01:05 +010062 if (X->n != Y->n) {
63 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
64 }
65
66 /*
Dave Rodgmanb69239c2023-08-09 14:53:18 +010067 * Set N_is_negative to MBEDTLS_CT_FALSE if N >= 0, MBEDTLS_CT_TRUE if N < 0.
Dave Rodgman7d4f0192023-05-09 14:01:05 +010068 * We know that N->s == 1 if N >= 0 and N->s == -1 if N < 0.
69 */
Dave Rodgman1a7a5622023-05-17 13:47:56 +010070 X_is_negative = mbedtls_ct_bool((X->s & 2) >> 1);
71 Y_is_negative = mbedtls_ct_bool((Y->s & 2) >> 1);
Dave Rodgman7d4f0192023-05-09 14:01:05 +010072
73 /*
74 * If the signs are different, then the positive operand is the bigger.
75 * That is if X is negative (X_is_negative == 1), then X < Y is true and it
76 * is false if X is positive (X_is_negative == 0).
77 */
Dave Rodgman1cfc43c2023-09-19 16:18:59 +010078 different_sign = mbedtls_ct_bool_ne(X_is_negative, Y_is_negative); // true if different sign
Dave Rodgman1f39f032023-08-01 09:19:16 +010079 result = mbedtls_ct_bool_and(different_sign, X_is_negative);
Dave Rodgman7d4f0192023-05-09 14:01:05 +010080
Dave Rodgman32d72602023-07-31 12:28:05 +010081 /*
82 * Assuming signs are the same, compare X and Y. We switch the comparison
Dave Rodgman1a7a5622023-05-17 13:47:56 +010083 * order if they are negative so that we get the right result, regardles of
84 * sign.
Dave Rodgman7d4f0192023-05-09 14:01:05 +010085 */
Dave Rodgman7d4f0192023-05-09 14:01:05 +010086
Dave Rodgman32d72602023-07-31 12:28:05 +010087 /* This array is used to conditionally swap the pointers in const time */
Dave Rodgman1a7a5622023-05-17 13:47:56 +010088 void * const p[2] = { X->p, Y->p };
Dave Rodgman98ddc012023-08-10 12:11:31 +010089 size_t i = mbedtls_ct_size_if_else_0(X_is_negative, 1);
Dave Rodgman2c764842023-05-18 13:28:21 +010090 mbedtls_ct_condition_t lt = mbedtls_mpi_core_lt_ct(p[i], p[i ^ 1], X->n);
Dave Rodgman7d4f0192023-05-09 14:01:05 +010091
Dave Rodgman32d72602023-07-31 12:28:05 +010092 /*
Dave Rodgman1f39f032023-08-01 09:19:16 +010093 * Store in result iff the signs are the same (i.e., iff different_sign == false). If
Dave Rodgman32d72602023-07-31 12:28:05 +010094 * the signs differ, result has already been set, so we don't change it.
95 */
Dave Rodgman1f39f032023-08-01 09:19:16 +010096 result = mbedtls_ct_bool_or(result,
97 mbedtls_ct_bool_and(mbedtls_ct_bool_not(different_sign), lt));
Dave Rodgman1a7a5622023-05-17 13:47:56 +010098
Dave Rodgman98ddc012023-08-10 12:11:31 +010099 *ret = mbedtls_ct_uint_if_else_0(result, 1);
Dave Rodgman7d4f0192023-05-09 14:01:05 +0100100
101 return 0;
102}
103
104/*
105 * Conditionally assign X = Y, without leaking information
106 * about whether the assignment was made or not.
107 * (Leaking information about the respective sizes of X and Y is ok however.)
108 */
Dave Rodgman0a487172023-09-15 11:52:06 +0100109#if defined(_MSC_VER) && defined(MBEDTLS_PLATFORM_IS_WINDOWS_ON_ARM64) && \
110 (_MSC_FULL_VER < 193131103)
Dave Rodgman7d4f0192023-05-09 14:01:05 +0100111/*
112 * MSVC miscompiles this function if it's inlined prior to Visual Studio 2022 version 17.1. See:
113 * https://developercommunity.visualstudio.com/t/c-compiler-miscompiles-part-of-mbedtls-library-on/1646989
114 */
115__declspec(noinline)
116#endif
117int mbedtls_mpi_safe_cond_assign(mbedtls_mpi *X,
118 const mbedtls_mpi *Y,
119 unsigned char assign)
120{
121 int ret = 0;
Dave Rodgman7d4f0192023-05-09 14:01:05 +0100122
Dave Rodgman7d4f0192023-05-09 14:01:05 +0100123 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, Y->n));
124
Dave Rodgman7e9af052023-09-28 17:08:16 +0100125 {
126 mbedtls_ct_condition_t do_assign = mbedtls_ct_bool(assign);
Dave Rodgman589ccb82023-05-17 13:55:01 +0100127
Janos Follath4ec0fb52024-03-08 17:22:40 +0000128 X->s = mbedtls_ct_mpi_sign_if(do_assign, Y->s, X->s);
Dave Rodgman7d4f0192023-05-09 14:01:05 +0100129
Dave Rodgman7e9af052023-09-28 17:08:16 +0100130 mbedtls_mpi_core_cond_assign(X->p, Y->p, Y->n, do_assign);
Dave Rodgman7d4f0192023-05-09 14:01:05 +0100131
Dave Rodgman7e9af052023-09-28 17:08:16 +0100132 mbedtls_ct_condition_t do_not_assign = mbedtls_ct_bool_not(do_assign);
133 for (size_t i = Y->n; i < X->n; i++) {
134 X->p[i] = mbedtls_ct_mpi_uint_if_else_0(do_not_assign, X->p[i]);
135 }
Dave Rodgman7d4f0192023-05-09 14:01:05 +0100136 }
137
138cleanup:
139 return ret;
140}
141
142/*
143 * Conditionally swap X and Y, without leaking information
144 * about whether the swap was made or not.
145 * Here it is not ok to simply swap the pointers, which would lead to
146 * different memory access patterns when X and Y are used afterwards.
147 */
148int mbedtls_mpi_safe_cond_swap(mbedtls_mpi *X,
149 mbedtls_mpi *Y,
150 unsigned char swap)
151{
152 int ret = 0;
153 int s;
Dave Rodgman7d4f0192023-05-09 14:01:05 +0100154
155 if (X == Y) {
156 return 0;
157 }
158
Dave Rodgmancd2e38b2023-05-17 13:31:55 +0100159 mbedtls_ct_condition_t do_swap = mbedtls_ct_bool(swap);
160
Dave Rodgman7d4f0192023-05-09 14:01:05 +0100161 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, Y->n));
162 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(Y, X->n));
163
164 s = X->s;
Janos Follath4ec0fb52024-03-08 17:22:40 +0000165 X->s = mbedtls_ct_mpi_sign_if(do_swap, Y->s, X->s);
166 Y->s = mbedtls_ct_mpi_sign_if(do_swap, s, Y->s);
Dave Rodgman7d4f0192023-05-09 14:01:05 +0100167
Dave Rodgmancd2e38b2023-05-17 13:31:55 +0100168 mbedtls_mpi_core_cond_swap(X->p, Y->p, X->n, do_swap);
Dave Rodgman7d4f0192023-05-09 14:01:05 +0100169
170cleanup:
171 return ret;
172}
173
Andres Amaya Garcia1f6301b2018-04-17 09:51:09 -0500174/* Implementation that should never be optimized out by the compiler */
Tom Cosgrovebc345e82023-07-25 15:17:39 +0100175#define mbedtls_mpi_zeroize_and_free(v, n) mbedtls_zeroize_and_free(v, ciL * (n))
Andres Amaya Garcia1f6301b2018-04-17 09:51:09 -0500176
Paul Bakker5121ce52009-01-03 21:22:43 +0000177/*
Paul Bakker6c591fa2011-05-05 11:49:20 +0000178 * Initialize one MPI
Paul Bakker5121ce52009-01-03 21:22:43 +0000179 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100180void mbedtls_mpi_init(mbedtls_mpi *X)
Paul Bakker5121ce52009-01-03 21:22:43 +0000181{
Paul Bakker6c591fa2011-05-05 11:49:20 +0000182 X->s = 1;
183 X->n = 0;
184 X->p = NULL;
Paul Bakker5121ce52009-01-03 21:22:43 +0000185}
186
187/*
Paul Bakker6c591fa2011-05-05 11:49:20 +0000188 * Unallocate one MPI
Paul Bakker5121ce52009-01-03 21:22:43 +0000189 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100190void mbedtls_mpi_free(mbedtls_mpi *X)
Paul Bakker5121ce52009-01-03 21:22:43 +0000191{
Gilles Peskine449bd832023-01-11 14:50:10 +0100192 if (X == NULL) {
Paul Bakker6c591fa2011-05-05 11:49:20 +0000193 return;
Gilles Peskine449bd832023-01-11 14:50:10 +0100194 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000195
Gilles Peskine449bd832023-01-11 14:50:10 +0100196 if (X->p != NULL) {
Tom Cosgrove46259f62023-07-18 16:44:14 +0100197 mbedtls_mpi_zeroize_and_free(X->p, X->n);
Paul Bakker5121ce52009-01-03 21:22:43 +0000198 }
199
Paul Bakker6c591fa2011-05-05 11:49:20 +0000200 X->s = 1;
201 X->n = 0;
202 X->p = NULL;
Paul Bakker5121ce52009-01-03 21:22:43 +0000203}
204
205/*
206 * Enlarge to the specified number of limbs
207 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100208int mbedtls_mpi_grow(mbedtls_mpi *X, size_t nblimbs)
Paul Bakker5121ce52009-01-03 21:22:43 +0000209{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200210 mbedtls_mpi_uint *p;
Paul Bakker5121ce52009-01-03 21:22:43 +0000211
Gilles Peskine449bd832023-01-11 14:50:10 +0100212 if (nblimbs > MBEDTLS_MPI_MAX_LIMBS) {
213 return MBEDTLS_ERR_MPI_ALLOC_FAILED;
214 }
Paul Bakkerf9688572011-05-05 10:00:45 +0000215
Gilles Peskine449bd832023-01-11 14:50:10 +0100216 if (X->n < nblimbs) {
217 if ((p = (mbedtls_mpi_uint *) mbedtls_calloc(nblimbs, ciL)) == NULL) {
218 return MBEDTLS_ERR_MPI_ALLOC_FAILED;
219 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000220
Gilles Peskine449bd832023-01-11 14:50:10 +0100221 if (X->p != NULL) {
222 memcpy(p, X->p, X->n * ciL);
Tom Cosgrove46259f62023-07-18 16:44:14 +0100223 mbedtls_mpi_zeroize_and_free(X->p, X->n);
Paul Bakker5121ce52009-01-03 21:22:43 +0000224 }
225
Gilles Peskine053022f2023-06-29 19:26:48 +0200226 /* nblimbs fits in n because we ensure that MBEDTLS_MPI_MAX_LIMBS
227 * fits, and we've checked that nblimbs <= MBEDTLS_MPI_MAX_LIMBS. */
228 X->n = (unsigned short) nblimbs;
Paul Bakker5121ce52009-01-03 21:22:43 +0000229 X->p = p;
230 }
231
Gilles Peskine449bd832023-01-11 14:50:10 +0100232 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000233}
234
235/*
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100236 * Resize down as much as possible,
237 * while keeping at least the specified number of limbs
238 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100239int mbedtls_mpi_shrink(mbedtls_mpi *X, size_t nblimbs)
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100240{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200241 mbedtls_mpi_uint *p;
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100242 size_t i;
Hanno Becker73d7d792018-12-11 10:35:51 +0000243
Gilles Peskine449bd832023-01-11 14:50:10 +0100244 if (nblimbs > MBEDTLS_MPI_MAX_LIMBS) {
245 return MBEDTLS_ERR_MPI_ALLOC_FAILED;
246 }
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100247
Gilles Peskinee2f563e2020-01-20 21:17:43 +0100248 /* Actually resize up if there are currently fewer than nblimbs limbs. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100249 if (X->n <= nblimbs) {
250 return mbedtls_mpi_grow(X, nblimbs);
251 }
Gilles Peskine322752b2020-01-21 13:59:51 +0100252 /* After this point, then X->n > nblimbs and in particular X->n > 0. */
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100253
Gilles Peskine449bd832023-01-11 14:50:10 +0100254 for (i = X->n - 1; i > 0; i--) {
255 if (X->p[i] != 0) {
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100256 break;
Gilles Peskine449bd832023-01-11 14:50:10 +0100257 }
258 }
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100259 i++;
260
Gilles Peskine449bd832023-01-11 14:50:10 +0100261 if (i < nblimbs) {
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100262 i = nblimbs;
Gilles Peskine449bd832023-01-11 14:50:10 +0100263 }
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100264
Gilles Peskine449bd832023-01-11 14:50:10 +0100265 if ((p = (mbedtls_mpi_uint *) mbedtls_calloc(i, ciL)) == NULL) {
266 return MBEDTLS_ERR_MPI_ALLOC_FAILED;
267 }
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100268
Gilles Peskine449bd832023-01-11 14:50:10 +0100269 if (X->p != NULL) {
270 memcpy(p, X->p, i * ciL);
Tom Cosgrove46259f62023-07-18 16:44:14 +0100271 mbedtls_mpi_zeroize_and_free(X->p, X->n);
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100272 }
273
Gilles Peskine053022f2023-06-29 19:26:48 +0200274 /* i fits in n because we ensure that MBEDTLS_MPI_MAX_LIMBS
275 * fits, and we've checked that i <= nblimbs <= MBEDTLS_MPI_MAX_LIMBS. */
276 X->n = (unsigned short) i;
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100277 X->p = p;
278
Gilles Peskine449bd832023-01-11 14:50:10 +0100279 return 0;
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100280}
281
Gilles Peskineed32b572021-06-02 22:17:52 +0200282/* Resize X to have exactly n limbs and set it to 0. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100283static int mbedtls_mpi_resize_clear(mbedtls_mpi *X, size_t limbs)
Gilles Peskineed32b572021-06-02 22:17:52 +0200284{
Gilles Peskine449bd832023-01-11 14:50:10 +0100285 if (limbs == 0) {
286 mbedtls_mpi_free(X);
287 return 0;
288 } else if (X->n == limbs) {
289 memset(X->p, 0, limbs * ciL);
Gilles Peskineed32b572021-06-02 22:17:52 +0200290 X->s = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +0100291 return 0;
292 } else {
293 mbedtls_mpi_free(X);
294 return mbedtls_mpi_grow(X, limbs);
Gilles Peskineed32b572021-06-02 22:17:52 +0200295 }
296}
297
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100298/*
Gilles Peskine3da1a8f2021-06-08 23:17:42 +0200299 * Copy the contents of Y into X.
300 *
301 * This function is not constant-time. Leading zeros in Y may be removed.
302 *
303 * Ensure that X does not shrink. This is not guaranteed by the public API,
Janos Follathc9faea02024-02-19 10:49:18 +0000304 * but some code in the bignum module might still rely on this property.
Paul Bakker5121ce52009-01-03 21:22:43 +0000305 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100306int mbedtls_mpi_copy(mbedtls_mpi *X, const mbedtls_mpi *Y)
Paul Bakker5121ce52009-01-03 21:22:43 +0000307{
Gilles Peskine4e4be7c2018-03-21 16:29:03 +0100308 int ret = 0;
Paul Bakker23986e52011-04-24 08:57:21 +0000309 size_t i;
Paul Bakker5121ce52009-01-03 21:22:43 +0000310
Gilles Peskine449bd832023-01-11 14:50:10 +0100311 if (X == Y) {
312 return 0;
Manuel Pégourié-Gonnardf4999932013-08-12 17:02:59 +0200313 }
314
Gilles Peskine449bd832023-01-11 14:50:10 +0100315 if (Y->n == 0) {
316 if (X->n != 0) {
317 X->s = 1;
318 memset(X->p, 0, X->n * ciL);
319 }
320 return 0;
321 }
322
323 for (i = Y->n - 1; i > 0; i--) {
324 if (Y->p[i] != 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +0000325 break;
Gilles Peskine449bd832023-01-11 14:50:10 +0100326 }
327 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000328 i++;
329
330 X->s = Y->s;
331
Gilles Peskine449bd832023-01-11 14:50:10 +0100332 if (X->n < i) {
333 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, i));
334 } else {
335 memset(X->p + i, 0, (X->n - i) * ciL);
Gilles Peskine4e4be7c2018-03-21 16:29:03 +0100336 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000337
Gilles Peskine449bd832023-01-11 14:50:10 +0100338 memcpy(X->p, Y->p, i * ciL);
Paul Bakker5121ce52009-01-03 21:22:43 +0000339
340cleanup:
341
Gilles Peskine449bd832023-01-11 14:50:10 +0100342 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000343}
344
345/*
346 * Swap the contents of X and Y
347 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100348void mbedtls_mpi_swap(mbedtls_mpi *X, mbedtls_mpi *Y)
Paul Bakker5121ce52009-01-03 21:22:43 +0000349{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200350 mbedtls_mpi T;
Paul Bakker5121ce52009-01-03 21:22:43 +0000351
Gilles Peskine449bd832023-01-11 14:50:10 +0100352 memcpy(&T, X, sizeof(mbedtls_mpi));
353 memcpy(X, Y, sizeof(mbedtls_mpi));
354 memcpy(Y, &T, sizeof(mbedtls_mpi));
Paul Bakker5121ce52009-01-03 21:22:43 +0000355}
356
Gilles Peskine449bd832023-01-11 14:50:10 +0100357static inline mbedtls_mpi_uint mpi_sint_abs(mbedtls_mpi_sint z)
Gilles Peskineef7f4e42022-11-15 23:25:27 +0100358{
Gilles Peskine449bd832023-01-11 14:50:10 +0100359 if (z >= 0) {
360 return z;
361 }
Gilles Peskineef7f4e42022-11-15 23:25:27 +0100362 /* Take care to handle the most negative value (-2^(biL-1)) correctly.
363 * A naive -z would have undefined behavior.
364 * Write this in a way that makes popular compilers happy (GCC, Clang,
365 * MSVC). */
Gilles Peskine449bd832023-01-11 14:50:10 +0100366 return (mbedtls_mpi_uint) 0 - (mbedtls_mpi_uint) z;
Gilles Peskineef7f4e42022-11-15 23:25:27 +0100367}
368
Dave Rodgmanf3df1052023-08-09 18:55:41 +0100369/* Convert x to a sign, i.e. to 1, if x is positive, or -1, if x is negative.
370 * This looks awkward but generates smaller code than (x < 0 ? -1 : 1) */
Dave Rodgman73d85912023-09-28 17:00:50 +0100371#define TO_SIGN(x) ((mbedtls_mpi_sint) (((mbedtls_mpi_uint) x) >> (biL - 1)) * -2 + 1)
Dave Rodgmanf3df1052023-08-09 18:55:41 +0100372
Paul Bakker5121ce52009-01-03 21:22:43 +0000373/*
374 * Set value from integer
375 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100376int mbedtls_mpi_lset(mbedtls_mpi *X, mbedtls_mpi_sint z)
Paul Bakker5121ce52009-01-03 21:22:43 +0000377{
Janos Follath24eed8d2019-11-22 13:21:35 +0000378 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker5121ce52009-01-03 21:22:43 +0000379
Gilles Peskine449bd832023-01-11 14:50:10 +0100380 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, 1));
381 memset(X->p, 0, X->n * ciL);
Paul Bakker5121ce52009-01-03 21:22:43 +0000382
Gilles Peskine449bd832023-01-11 14:50:10 +0100383 X->p[0] = mpi_sint_abs(z);
Dave Rodgmanf3df1052023-08-09 18:55:41 +0100384 X->s = TO_SIGN(z);
Paul Bakker5121ce52009-01-03 21:22:43 +0000385
386cleanup:
387
Gilles Peskine449bd832023-01-11 14:50:10 +0100388 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000389}
390
391/*
Paul Bakker2f5947e2011-05-18 15:47:11 +0000392 * Get a specific bit
393 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100394int mbedtls_mpi_get_bit(const mbedtls_mpi *X, size_t pos)
Paul Bakker2f5947e2011-05-18 15:47:11 +0000395{
Gilles Peskine449bd832023-01-11 14:50:10 +0100396 if (X->n * biL <= pos) {
397 return 0;
398 }
Paul Bakker2f5947e2011-05-18 15:47:11 +0000399
Gilles Peskine449bd832023-01-11 14:50:10 +0100400 return (X->p[pos / biL] >> (pos % biL)) & 0x01;
Paul Bakker2f5947e2011-05-18 15:47:11 +0000401}
402
403/*
404 * Set a bit to a specific value of 0 or 1
405 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100406int mbedtls_mpi_set_bit(mbedtls_mpi *X, size_t pos, unsigned char val)
Paul Bakker2f5947e2011-05-18 15:47:11 +0000407{
408 int ret = 0;
409 size_t off = pos / biL;
410 size_t idx = pos % biL;
411
Gilles Peskine449bd832023-01-11 14:50:10 +0100412 if (val != 0 && val != 1) {
413 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
Paul Bakker2f5947e2011-05-18 15:47:11 +0000414 }
415
Gilles Peskine449bd832023-01-11 14:50:10 +0100416 if (X->n * biL <= pos) {
417 if (val == 0) {
418 return 0;
419 }
420
421 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, off + 1));
422 }
423
424 X->p[off] &= ~((mbedtls_mpi_uint) 0x01 << idx);
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200425 X->p[off] |= (mbedtls_mpi_uint) val << idx;
Paul Bakker2f5947e2011-05-18 15:47:11 +0000426
427cleanup:
Paul Bakker9af723c2014-05-01 13:03:14 +0200428
Gilles Peskine449bd832023-01-11 14:50:10 +0100429 return ret;
Paul Bakker2f5947e2011-05-18 15:47:11 +0000430}
431
432/*
Manuel Pégourié-Gonnardc0696c22015-06-18 16:47:17 +0200433 * Return the number of less significant zero-bits
Paul Bakker5121ce52009-01-03 21:22:43 +0000434 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100435size_t mbedtls_mpi_lsb(const mbedtls_mpi *X)
Paul Bakker5121ce52009-01-03 21:22:43 +0000436{
Dave Rodgmanfa703e32023-08-09 18:56:07 +0100437 size_t i;
Paul Bakker5121ce52009-01-03 21:22:43 +0000438
Dave Rodgmanfa703e32023-08-09 18:56:07 +0100439#if defined(__has_builtin)
440#if (MBEDTLS_MPI_UINT_MAX == UINT_MAX) && __has_builtin(__builtin_ctz)
441 #define mbedtls_mpi_uint_ctz __builtin_ctz
442#elif (MBEDTLS_MPI_UINT_MAX == ULONG_MAX) && __has_builtin(__builtin_ctzl)
443 #define mbedtls_mpi_uint_ctz __builtin_ctzl
444#elif (MBEDTLS_MPI_UINT_MAX == ULLONG_MAX) && __has_builtin(__builtin_ctzll)
445 #define mbedtls_mpi_uint_ctz __builtin_ctzll
446#endif
447#endif
448
449#if defined(mbedtls_mpi_uint_ctz)
Gilles Peskine449bd832023-01-11 14:50:10 +0100450 for (i = 0; i < X->n; i++) {
Dave Rodgman960eca92023-08-09 20:43:18 +0100451 if (X->p[i] != 0) {
452 return i * biL + mbedtls_mpi_uint_ctz(X->p[i]);
453 }
Dave Rodgmanfa703e32023-08-09 18:56:07 +0100454 }
455#else
456 size_t count = 0;
457 for (i = 0; i < X->n; i++) {
458 for (size_t j = 0; j < biL; j++, count++) {
Gilles Peskine449bd832023-01-11 14:50:10 +0100459 if (((X->p[i] >> j) & 1) != 0) {
460 return count;
461 }
462 }
463 }
Dave Rodgmanfa703e32023-08-09 18:56:07 +0100464#endif
Paul Bakker5121ce52009-01-03 21:22:43 +0000465
Gilles Peskine449bd832023-01-11 14:50:10 +0100466 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000467}
468
469/*
Manuel Pégourié-Gonnardc0696c22015-06-18 16:47:17 +0200470 * Return the number of bits
Paul Bakker5121ce52009-01-03 21:22:43 +0000471 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100472size_t mbedtls_mpi_bitlen(const mbedtls_mpi *X)
Paul Bakker5121ce52009-01-03 21:22:43 +0000473{
Gilles Peskine449bd832023-01-11 14:50:10 +0100474 return mbedtls_mpi_core_bitlen(X->p, X->n);
Paul Bakker5121ce52009-01-03 21:22:43 +0000475}
476
477/*
478 * Return the total size in bytes
479 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100480size_t mbedtls_mpi_size(const mbedtls_mpi *X)
Paul Bakker5121ce52009-01-03 21:22:43 +0000481{
Gilles Peskine449bd832023-01-11 14:50:10 +0100482 return (mbedtls_mpi_bitlen(X) + 7) >> 3;
Paul Bakker5121ce52009-01-03 21:22:43 +0000483}
484
485/*
486 * Convert an ASCII character to digit value
487 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100488static int mpi_get_digit(mbedtls_mpi_uint *d, int radix, char c)
Paul Bakker5121ce52009-01-03 21:22:43 +0000489{
490 *d = 255;
491
Gilles Peskine449bd832023-01-11 14:50:10 +0100492 if (c >= 0x30 && c <= 0x39) {
493 *d = c - 0x30;
494 }
495 if (c >= 0x41 && c <= 0x46) {
496 *d = c - 0x37;
497 }
498 if (c >= 0x61 && c <= 0x66) {
499 *d = c - 0x57;
500 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000501
Gilles Peskine449bd832023-01-11 14:50:10 +0100502 if (*d >= (mbedtls_mpi_uint) radix) {
503 return MBEDTLS_ERR_MPI_INVALID_CHARACTER;
504 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000505
Gilles Peskine449bd832023-01-11 14:50:10 +0100506 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000507}
508
509/*
510 * Import from an ASCII string
511 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100512int mbedtls_mpi_read_string(mbedtls_mpi *X, int radix, const char *s)
Paul Bakker5121ce52009-01-03 21:22:43 +0000513{
Janos Follath24eed8d2019-11-22 13:21:35 +0000514 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker23986e52011-04-24 08:57:21 +0000515 size_t i, j, slen, n;
Gilles Peskine80f56732021-04-03 18:26:13 +0200516 int sign = 1;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200517 mbedtls_mpi_uint d;
518 mbedtls_mpi T;
Paul Bakker5121ce52009-01-03 21:22:43 +0000519
Gilles Peskine449bd832023-01-11 14:50:10 +0100520 if (radix < 2 || radix > 16) {
521 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
Gilles Peskine7cba8592021-06-08 18:32:34 +0200522 }
523
Gilles Peskine449bd832023-01-11 14:50:10 +0100524 mbedtls_mpi_init(&T);
525
526 if (s[0] == 0) {
527 mbedtls_mpi_free(X);
528 return 0;
529 }
530
531 if (s[0] == '-') {
Gilles Peskine80f56732021-04-03 18:26:13 +0200532 ++s;
533 sign = -1;
534 }
535
Gilles Peskine449bd832023-01-11 14:50:10 +0100536 slen = strlen(s);
Paul Bakkerff60ee62010-03-16 21:09:09 +0000537
Gilles Peskine449bd832023-01-11 14:50:10 +0100538 if (radix == 16) {
Dave Rodgman68ef1d62023-05-18 20:49:03 +0100539 if (slen > SIZE_MAX >> 2) {
Gilles Peskine449bd832023-01-11 14:50:10 +0100540 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
Paul Bakker5121ce52009-01-03 21:22:43 +0000541 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000542
Gilles Peskine449bd832023-01-11 14:50:10 +0100543 n = BITS_TO_LIMBS(slen << 2);
544
545 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, n));
546 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(X, 0));
547
548 for (i = slen, j = 0; i > 0; i--, j++) {
549 MBEDTLS_MPI_CHK(mpi_get_digit(&d, radix, s[i - 1]));
550 X->p[j / (2 * ciL)] |= d << ((j % (2 * ciL)) << 2);
551 }
552 } else {
553 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(X, 0));
554
555 for (i = 0; i < slen; i++) {
556 MBEDTLS_MPI_CHK(mpi_get_digit(&d, radix, s[i]));
557 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_int(&T, X, radix));
558 MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(X, &T, d));
Paul Bakker5121ce52009-01-03 21:22:43 +0000559 }
560 }
561
Gilles Peskine449bd832023-01-11 14:50:10 +0100562 if (sign < 0 && mbedtls_mpi_bitlen(X) != 0) {
Gilles Peskine80f56732021-04-03 18:26:13 +0200563 X->s = -1;
Gilles Peskine449bd832023-01-11 14:50:10 +0100564 }
Gilles Peskine80f56732021-04-03 18:26:13 +0200565
Paul Bakker5121ce52009-01-03 21:22:43 +0000566cleanup:
567
Gilles Peskine449bd832023-01-11 14:50:10 +0100568 mbedtls_mpi_free(&T);
Paul Bakker5121ce52009-01-03 21:22:43 +0000569
Gilles Peskine449bd832023-01-11 14:50:10 +0100570 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000571}
572
573/*
Ron Eldora16fa292018-11-20 14:07:01 +0200574 * Helper to write the digits high-order first.
Paul Bakker5121ce52009-01-03 21:22:43 +0000575 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100576static int mpi_write_hlp(mbedtls_mpi *X, int radix,
577 char **p, const size_t buflen)
Paul Bakker5121ce52009-01-03 21:22:43 +0000578{
Janos Follath24eed8d2019-11-22 13:21:35 +0000579 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200580 mbedtls_mpi_uint r;
Ron Eldora16fa292018-11-20 14:07:01 +0200581 size_t length = 0;
582 char *p_end = *p + buflen;
Paul Bakker5121ce52009-01-03 21:22:43 +0000583
Gilles Peskine449bd832023-01-11 14:50:10 +0100584 do {
585 if (length >= buflen) {
586 return MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL;
Ron Eldora16fa292018-11-20 14:07:01 +0200587 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000588
Gilles Peskine449bd832023-01-11 14:50:10 +0100589 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_int(&r, X, radix));
590 MBEDTLS_MPI_CHK(mbedtls_mpi_div_int(X, NULL, X, radix));
Ron Eldora16fa292018-11-20 14:07:01 +0200591 /*
592 * Write the residue in the current position, as an ASCII character.
593 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100594 if (r < 0xA) {
595 *(--p_end) = (char) ('0' + r);
596 } else {
597 *(--p_end) = (char) ('A' + (r - 0xA));
598 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000599
Ron Eldora16fa292018-11-20 14:07:01 +0200600 length++;
Gilles Peskine449bd832023-01-11 14:50:10 +0100601 } while (mbedtls_mpi_cmp_int(X, 0) != 0);
Paul Bakker5121ce52009-01-03 21:22:43 +0000602
Gilles Peskine449bd832023-01-11 14:50:10 +0100603 memmove(*p, p_end, length);
Ron Eldora16fa292018-11-20 14:07:01 +0200604 *p += length;
Paul Bakker5121ce52009-01-03 21:22:43 +0000605
606cleanup:
607
Gilles Peskine449bd832023-01-11 14:50:10 +0100608 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000609}
610
611/*
612 * Export into an ASCII string
613 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100614int mbedtls_mpi_write_string(const mbedtls_mpi *X, int radix,
615 char *buf, size_t buflen, size_t *olen)
Paul Bakker5121ce52009-01-03 21:22:43 +0000616{
Paul Bakker23986e52011-04-24 08:57:21 +0000617 int ret = 0;
618 size_t n;
Paul Bakker5121ce52009-01-03 21:22:43 +0000619 char *p;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200620 mbedtls_mpi T;
Paul Bakker5121ce52009-01-03 21:22:43 +0000621
Gilles Peskine449bd832023-01-11 14:50:10 +0100622 if (radix < 2 || radix > 16) {
623 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
624 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000625
Gilles Peskine449bd832023-01-11 14:50:10 +0100626 n = mbedtls_mpi_bitlen(X); /* Number of bits necessary to present `n`. */
627 if (radix >= 4) {
628 n >>= 1; /* Number of 4-adic digits necessary to present
Hanno Becker23cfea02019-02-04 09:45:07 +0000629 * `n`. If radix > 4, this might be a strict
630 * overapproximation of the number of
631 * radix-adic digits needed to present `n`. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100632 }
633 if (radix >= 16) {
634 n >>= 1; /* Number of hexadecimal digits necessary to
Hanno Becker23cfea02019-02-04 09:45:07 +0000635 * present `n`. */
636
Gilles Peskine449bd832023-01-11 14:50:10 +0100637 }
Janos Follath80470622019-03-06 13:43:02 +0000638 n += 1; /* Terminating null byte */
Hanno Becker23cfea02019-02-04 09:45:07 +0000639 n += 1; /* Compensate for the divisions above, which round down `n`
640 * in case it's not even. */
641 n += 1; /* Potential '-'-sign. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100642 n += (n & 1); /* Make n even to have enough space for hexadecimal writing,
Hanno Becker23cfea02019-02-04 09:45:07 +0000643 * which always uses an even number of hex-digits. */
Paul Bakker5121ce52009-01-03 21:22:43 +0000644
Gilles Peskine449bd832023-01-11 14:50:10 +0100645 if (buflen < n) {
Manuel Pégourié-Gonnardf79b4252015-06-02 15:41:48 +0100646 *olen = n;
Gilles Peskine449bd832023-01-11 14:50:10 +0100647 return MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL;
Paul Bakker5121ce52009-01-03 21:22:43 +0000648 }
649
Manuel Pégourié-Gonnardf79b4252015-06-02 15:41:48 +0100650 p = buf;
Gilles Peskine449bd832023-01-11 14:50:10 +0100651 mbedtls_mpi_init(&T);
Paul Bakker5121ce52009-01-03 21:22:43 +0000652
Gilles Peskine449bd832023-01-11 14:50:10 +0100653 if (X->s == -1) {
Paul Bakker5121ce52009-01-03 21:22:43 +0000654 *p++ = '-';
Hanno Beckerc983c812019-02-01 16:41:30 +0000655 buflen--;
656 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000657
Gilles Peskine449bd832023-01-11 14:50:10 +0100658 if (radix == 16) {
Paul Bakker23986e52011-04-24 08:57:21 +0000659 int c;
660 size_t i, j, k;
Paul Bakker5121ce52009-01-03 21:22:43 +0000661
Gilles Peskine449bd832023-01-11 14:50:10 +0100662 for (i = X->n, k = 0; i > 0; i--) {
663 for (j = ciL; j > 0; j--) {
664 c = (X->p[i - 1] >> ((j - 1) << 3)) & 0xFF;
Paul Bakker5121ce52009-01-03 21:22:43 +0000665
Gilles Peskine449bd832023-01-11 14:50:10 +0100666 if (c == 0 && k == 0 && (i + j) != 2) {
Paul Bakker5121ce52009-01-03 21:22:43 +0000667 continue;
Gilles Peskine449bd832023-01-11 14:50:10 +0100668 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000669
Paul Bakker98fe5ea2012-10-24 11:17:48 +0000670 *(p++) = "0123456789ABCDEF" [c / 16];
Paul Bakkerd2c167e2012-10-30 07:49:19 +0000671 *(p++) = "0123456789ABCDEF" [c % 16];
Paul Bakker5121ce52009-01-03 21:22:43 +0000672 k = 1;
673 }
674 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100675 } else {
676 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&T, X));
Paul Bakkerce40a6d2009-06-23 19:46:08 +0000677
Gilles Peskine449bd832023-01-11 14:50:10 +0100678 if (T.s == -1) {
Paul Bakkerce40a6d2009-06-23 19:46:08 +0000679 T.s = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +0100680 }
Paul Bakkerce40a6d2009-06-23 19:46:08 +0000681
Gilles Peskine449bd832023-01-11 14:50:10 +0100682 MBEDTLS_MPI_CHK(mpi_write_hlp(&T, radix, &p, buflen));
Paul Bakker5121ce52009-01-03 21:22:43 +0000683 }
684
685 *p++ = '\0';
Dave Rodgmane4a6f5a2023-11-04 12:20:09 +0000686 *olen = (size_t) (p - buf);
Paul Bakker5121ce52009-01-03 21:22:43 +0000687
688cleanup:
689
Gilles Peskine449bd832023-01-11 14:50:10 +0100690 mbedtls_mpi_free(&T);
Paul Bakker5121ce52009-01-03 21:22:43 +0000691
Gilles Peskine449bd832023-01-11 14:50:10 +0100692 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000693}
694
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200695#if defined(MBEDTLS_FS_IO)
Paul Bakker5121ce52009-01-03 21:22:43 +0000696/*
697 * Read X from an opened file
698 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100699int mbedtls_mpi_read_file(mbedtls_mpi *X, int radix, FILE *fin)
Paul Bakker5121ce52009-01-03 21:22:43 +0000700{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200701 mbedtls_mpi_uint d;
Paul Bakker23986e52011-04-24 08:57:21 +0000702 size_t slen;
Paul Bakker5121ce52009-01-03 21:22:43 +0000703 char *p;
Paul Bakkerfe3256e2011-11-25 12:11:43 +0000704 /*
Paul Bakkercb37aa52011-11-30 16:00:20 +0000705 * Buffer should have space for (short) label and decimal formatted MPI,
706 * newline characters and '\0'
Paul Bakkerfe3256e2011-11-25 12:11:43 +0000707 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100708 char s[MBEDTLS_MPI_RW_BUFFER_SIZE];
Paul Bakker5121ce52009-01-03 21:22:43 +0000709
Gilles Peskine449bd832023-01-11 14:50:10 +0100710 if (radix < 2 || radix > 16) {
711 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
712 }
Hanno Becker73d7d792018-12-11 10:35:51 +0000713
Gilles Peskine449bd832023-01-11 14:50:10 +0100714 memset(s, 0, sizeof(s));
715 if (fgets(s, sizeof(s) - 1, fin) == NULL) {
716 return MBEDTLS_ERR_MPI_FILE_IO_ERROR;
717 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000718
Gilles Peskine449bd832023-01-11 14:50:10 +0100719 slen = strlen(s);
720 if (slen == sizeof(s) - 2) {
721 return MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL;
722 }
Paul Bakkercb37aa52011-11-30 16:00:20 +0000723
Gilles Peskine449bd832023-01-11 14:50:10 +0100724 if (slen > 0 && s[slen - 1] == '\n') {
725 slen--; s[slen] = '\0';
726 }
727 if (slen > 0 && s[slen - 1] == '\r') {
728 slen--; s[slen] = '\0';
729 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000730
731 p = s + slen;
Gilles Peskine449bd832023-01-11 14:50:10 +0100732 while (p-- > s) {
733 if (mpi_get_digit(&d, radix, *p) != 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +0000734 break;
Gilles Peskine449bd832023-01-11 14:50:10 +0100735 }
736 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000737
Gilles Peskine449bd832023-01-11 14:50:10 +0100738 return mbedtls_mpi_read_string(X, radix, p + 1);
Paul Bakker5121ce52009-01-03 21:22:43 +0000739}
740
741/*
742 * Write X into an opened file (or stdout if fout == NULL)
743 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100744int mbedtls_mpi_write_file(const char *p, const mbedtls_mpi *X, int radix, FILE *fout)
Paul Bakker5121ce52009-01-03 21:22:43 +0000745{
Janos Follath24eed8d2019-11-22 13:21:35 +0000746 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker23986e52011-04-24 08:57:21 +0000747 size_t n, slen, plen;
Paul Bakkerfe3256e2011-11-25 12:11:43 +0000748 /*
Paul Bakker5531c6d2012-09-26 19:20:46 +0000749 * Buffer should have space for (short) label and decimal formatted MPI,
750 * newline characters and '\0'
Paul Bakkerfe3256e2011-11-25 12:11:43 +0000751 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100752 char s[MBEDTLS_MPI_RW_BUFFER_SIZE];
Hanno Becker73d7d792018-12-11 10:35:51 +0000753
Gilles Peskine449bd832023-01-11 14:50:10 +0100754 if (radix < 2 || radix > 16) {
755 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
756 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000757
Gilles Peskine449bd832023-01-11 14:50:10 +0100758 memset(s, 0, sizeof(s));
Paul Bakker5121ce52009-01-03 21:22:43 +0000759
Gilles Peskine449bd832023-01-11 14:50:10 +0100760 MBEDTLS_MPI_CHK(mbedtls_mpi_write_string(X, radix, s, sizeof(s) - 2, &n));
Paul Bakker5121ce52009-01-03 21:22:43 +0000761
Gilles Peskine449bd832023-01-11 14:50:10 +0100762 if (p == NULL) {
763 p = "";
764 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000765
Gilles Peskine449bd832023-01-11 14:50:10 +0100766 plen = strlen(p);
767 slen = strlen(s);
Paul Bakker5121ce52009-01-03 21:22:43 +0000768 s[slen++] = '\r';
769 s[slen++] = '\n';
770
Gilles Peskine449bd832023-01-11 14:50:10 +0100771 if (fout != NULL) {
772 if (fwrite(p, 1, plen, fout) != plen ||
773 fwrite(s, 1, slen, fout) != slen) {
774 return MBEDTLS_ERR_MPI_FILE_IO_ERROR;
775 }
776 } else {
777 mbedtls_printf("%s%s", p, s);
Paul Bakker5121ce52009-01-03 21:22:43 +0000778 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000779
780cleanup:
781
Gilles Peskine449bd832023-01-11 14:50:10 +0100782 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000783}
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200784#endif /* MBEDTLS_FS_IO */
Paul Bakker5121ce52009-01-03 21:22:43 +0000785
786/*
Janos Follatha778a942019-02-13 10:28:28 +0000787 * Import X from unsigned binary data, little endian
Przemyslaw Stekiel76960a72022-02-21 13:42:09 +0100788 *
789 * This function is guaranteed to return an MPI with exactly the necessary
790 * number of limbs (in particular, it does not skip 0s in the input).
Janos Follatha778a942019-02-13 10:28:28 +0000791 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100792int mbedtls_mpi_read_binary_le(mbedtls_mpi *X,
793 const unsigned char *buf, size_t buflen)
Janos Follatha778a942019-02-13 10:28:28 +0000794{
Janos Follath24eed8d2019-11-22 13:21:35 +0000795 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Gilles Peskine449bd832023-01-11 14:50:10 +0100796 const size_t limbs = CHARS_TO_LIMBS(buflen);
Janos Follatha778a942019-02-13 10:28:28 +0000797
798 /* Ensure that target MPI has exactly the necessary number of limbs */
Gilles Peskine449bd832023-01-11 14:50:10 +0100799 MBEDTLS_MPI_CHK(mbedtls_mpi_resize_clear(X, limbs));
Janos Follatha778a942019-02-13 10:28:28 +0000800
Gilles Peskine449bd832023-01-11 14:50:10 +0100801 MBEDTLS_MPI_CHK(mbedtls_mpi_core_read_le(X->p, X->n, buf, buflen));
Janos Follatha778a942019-02-13 10:28:28 +0000802
803cleanup:
804
Janos Follath171a7ef2019-02-15 16:17:45 +0000805 /*
806 * This function is also used to import keys. However, wiping the buffers
807 * upon failure is not necessary because failure only can happen before any
808 * input is copied.
809 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100810 return ret;
Janos Follatha778a942019-02-13 10:28:28 +0000811}
812
813/*
Paul Bakker5121ce52009-01-03 21:22:43 +0000814 * Import X from unsigned binary data, big endian
Przemyslaw Stekiel76960a72022-02-21 13:42:09 +0100815 *
816 * This function is guaranteed to return an MPI with exactly the necessary
817 * number of limbs (in particular, it does not skip 0s in the input).
Paul Bakker5121ce52009-01-03 21:22:43 +0000818 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100819int mbedtls_mpi_read_binary(mbedtls_mpi *X, const unsigned char *buf, size_t buflen)
Paul Bakker5121ce52009-01-03 21:22:43 +0000820{
Janos Follath24eed8d2019-11-22 13:21:35 +0000821 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Gilles Peskine449bd832023-01-11 14:50:10 +0100822 const size_t limbs = CHARS_TO_LIMBS(buflen);
Hanno Becker73d7d792018-12-11 10:35:51 +0000823
Hanno Becker073c1992017-10-17 15:17:27 +0100824 /* Ensure that target MPI has exactly the necessary number of limbs */
Gilles Peskine449bd832023-01-11 14:50:10 +0100825 MBEDTLS_MPI_CHK(mbedtls_mpi_resize_clear(X, limbs));
Paul Bakker5121ce52009-01-03 21:22:43 +0000826
Gilles Peskine449bd832023-01-11 14:50:10 +0100827 MBEDTLS_MPI_CHK(mbedtls_mpi_core_read_be(X->p, X->n, buf, buflen));
Paul Bakker5121ce52009-01-03 21:22:43 +0000828
829cleanup:
830
Janos Follath171a7ef2019-02-15 16:17:45 +0000831 /*
832 * This function is also used to import keys. However, wiping the buffers
833 * upon failure is not necessary because failure only can happen before any
834 * input is copied.
835 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100836 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000837}
838
839/*
Janos Follathe344d0f2019-02-19 16:17:40 +0000840 * Export X into unsigned binary data, little endian
841 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100842int mbedtls_mpi_write_binary_le(const mbedtls_mpi *X,
843 unsigned char *buf, size_t buflen)
Janos Follathe344d0f2019-02-19 16:17:40 +0000844{
Gilles Peskine449bd832023-01-11 14:50:10 +0100845 return mbedtls_mpi_core_write_le(X->p, X->n, buf, buflen);
Janos Follathe344d0f2019-02-19 16:17:40 +0000846}
847
848/*
Paul Bakker5121ce52009-01-03 21:22:43 +0000849 * Export X into unsigned binary data, big endian
850 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100851int mbedtls_mpi_write_binary(const mbedtls_mpi *X,
852 unsigned char *buf, size_t buflen)
Paul Bakker5121ce52009-01-03 21:22:43 +0000853{
Gilles Peskine449bd832023-01-11 14:50:10 +0100854 return mbedtls_mpi_core_write_be(X->p, X->n, buf, buflen);
Paul Bakker5121ce52009-01-03 21:22:43 +0000855}
856
857/*
858 * Left-shift: X <<= count
859 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100860int mbedtls_mpi_shift_l(mbedtls_mpi *X, size_t count)
Paul Bakker5121ce52009-01-03 21:22:43 +0000861{
Janos Follath24eed8d2019-11-22 13:21:35 +0000862 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Minos Galanakis0144b352023-05-02 14:02:32 +0100863 size_t i;
Paul Bakker5121ce52009-01-03 21:22:43 +0000864
Gilles Peskine449bd832023-01-11 14:50:10 +0100865 i = mbedtls_mpi_bitlen(X) + count;
Paul Bakker5121ce52009-01-03 21:22:43 +0000866
Gilles Peskine449bd832023-01-11 14:50:10 +0100867 if (X->n * biL < i) {
868 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, BITS_TO_LIMBS(i)));
869 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000870
871 ret = 0;
872
Minos Galanakis0144b352023-05-02 14:02:32 +0100873 mbedtls_mpi_core_shift_l(X->p, X->n, count);
Paul Bakker5121ce52009-01-03 21:22:43 +0000874cleanup:
875
Gilles Peskine449bd832023-01-11 14:50:10 +0100876 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000877}
878
879/*
880 * Right-shift: X >>= count
881 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100882int mbedtls_mpi_shift_r(mbedtls_mpi *X, size_t count)
Paul Bakker5121ce52009-01-03 21:22:43 +0000883{
Gilles Peskine449bd832023-01-11 14:50:10 +0100884 if (X->n != 0) {
885 mbedtls_mpi_core_shift_r(X->p, X->n, count);
886 }
887 return 0;
Gilles Peskine66414202022-09-21 15:36:16 +0200888}
889
Paul Bakker5121ce52009-01-03 21:22:43 +0000890/*
891 * Compare unsigned values
892 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100893int mbedtls_mpi_cmp_abs(const mbedtls_mpi *X, const mbedtls_mpi *Y)
Paul Bakker5121ce52009-01-03 21:22:43 +0000894{
Paul Bakker23986e52011-04-24 08:57:21 +0000895 size_t i, j;
Paul Bakker5121ce52009-01-03 21:22:43 +0000896
Gilles Peskine449bd832023-01-11 14:50:10 +0100897 for (i = X->n; i > 0; i--) {
898 if (X->p[i - 1] != 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +0000899 break;
Gilles Peskine449bd832023-01-11 14:50:10 +0100900 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000901 }
902
Gilles Peskine449bd832023-01-11 14:50:10 +0100903 for (j = Y->n; j > 0; j--) {
904 if (Y->p[j - 1] != 0) {
905 break;
906 }
907 }
908
Dave Rodgmanebcd7852023-08-09 18:56:42 +0100909 /* If i == j == 0, i.e. abs(X) == abs(Y),
910 * we end up returning 0 at the end of the function. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100911
912 if (i > j) {
913 return 1;
914 }
915 if (j > i) {
916 return -1;
917 }
918
919 for (; i > 0; i--) {
920 if (X->p[i - 1] > Y->p[i - 1]) {
921 return 1;
922 }
923 if (X->p[i - 1] < Y->p[i - 1]) {
924 return -1;
925 }
926 }
927
928 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000929}
930
931/*
932 * Compare signed values
933 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100934int mbedtls_mpi_cmp_mpi(const mbedtls_mpi *X, const mbedtls_mpi *Y)
Paul Bakker5121ce52009-01-03 21:22:43 +0000935{
Paul Bakker23986e52011-04-24 08:57:21 +0000936 size_t i, j;
Paul Bakker5121ce52009-01-03 21:22:43 +0000937
Gilles Peskine449bd832023-01-11 14:50:10 +0100938 for (i = X->n; i > 0; i--) {
939 if (X->p[i - 1] != 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +0000940 break;
Gilles Peskine449bd832023-01-11 14:50:10 +0100941 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000942 }
943
Gilles Peskine449bd832023-01-11 14:50:10 +0100944 for (j = Y->n; j > 0; j--) {
945 if (Y->p[j - 1] != 0) {
946 break;
947 }
948 }
949
950 if (i == 0 && j == 0) {
951 return 0;
952 }
953
954 if (i > j) {
955 return X->s;
956 }
957 if (j > i) {
958 return -Y->s;
959 }
960
961 if (X->s > 0 && Y->s < 0) {
962 return 1;
963 }
964 if (Y->s > 0 && X->s < 0) {
965 return -1;
966 }
967
968 for (; i > 0; i--) {
969 if (X->p[i - 1] > Y->p[i - 1]) {
970 return X->s;
971 }
972 if (X->p[i - 1] < Y->p[i - 1]) {
973 return -X->s;
974 }
975 }
976
977 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000978}
979
Janos Follathee6abce2019-09-05 14:47:19 +0100980/*
Paul Bakker5121ce52009-01-03 21:22:43 +0000981 * Compare signed values
982 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100983int mbedtls_mpi_cmp_int(const mbedtls_mpi *X, mbedtls_mpi_sint z)
Paul Bakker5121ce52009-01-03 21:22:43 +0000984{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200985 mbedtls_mpi Y;
986 mbedtls_mpi_uint p[1];
Paul Bakker5121ce52009-01-03 21:22:43 +0000987
Gilles Peskine449bd832023-01-11 14:50:10 +0100988 *p = mpi_sint_abs(z);
Dave Rodgmanf3df1052023-08-09 18:55:41 +0100989 Y.s = TO_SIGN(z);
Paul Bakker5121ce52009-01-03 21:22:43 +0000990 Y.n = 1;
991 Y.p = p;
992
Gilles Peskine449bd832023-01-11 14:50:10 +0100993 return mbedtls_mpi_cmp_mpi(X, &Y);
Paul Bakker5121ce52009-01-03 21:22:43 +0000994}
995
996/*
997 * Unsigned addition: X = |A| + |B| (HAC 14.7)
998 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100999int mbedtls_mpi_add_abs(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B)
Paul Bakker5121ce52009-01-03 21:22:43 +00001000{
Janos Follath24eed8d2019-11-22 13:21:35 +00001001 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Tom Cosgroveaf7d44b2022-08-24 14:05:26 +01001002 size_t j;
Agathiyan Bragadeeshc99840a2023-07-12 11:15:46 +01001003 mbedtls_mpi_uint *p;
1004 mbedtls_mpi_uint c;
Paul Bakker5121ce52009-01-03 21:22:43 +00001005
Gilles Peskine449bd832023-01-11 14:50:10 +01001006 if (X == B) {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001007 const mbedtls_mpi *T = A; A = X; B = T;
Paul Bakker5121ce52009-01-03 21:22:43 +00001008 }
1009
Gilles Peskine449bd832023-01-11 14:50:10 +01001010 if (X != A) {
1011 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(X, A));
1012 }
Paul Bakker9af723c2014-05-01 13:03:14 +02001013
Paul Bakkerf7ca7b92009-06-20 10:31:06 +00001014 /*
Tom Cosgroveaf7d44b2022-08-24 14:05:26 +01001015 * X must always be positive as a result of unsigned additions.
Paul Bakkerf7ca7b92009-06-20 10:31:06 +00001016 */
1017 X->s = 1;
Paul Bakker5121ce52009-01-03 21:22:43 +00001018
Gilles Peskine449bd832023-01-11 14:50:10 +01001019 for (j = B->n; j > 0; j--) {
1020 if (B->p[j - 1] != 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00001021 break;
Gilles Peskine449bd832023-01-11 14:50:10 +01001022 }
1023 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001024
Gilles Peskinedb14a9d2022-11-15 22:59:00 +01001025 /* Exit early to avoid undefined behavior on NULL+0 when X->n == 0
1026 * and B is 0 (of any size). */
Gilles Peskine449bd832023-01-11 14:50:10 +01001027 if (j == 0) {
1028 return 0;
1029 }
Gilles Peskinedb14a9d2022-11-15 22:59:00 +01001030
Gilles Peskine449bd832023-01-11 14:50:10 +01001031 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, j));
Paul Bakker5121ce52009-01-03 21:22:43 +00001032
Tom Cosgroveaf7d44b2022-08-24 14:05:26 +01001033 /* j is the number of non-zero limbs of B. Add those to X. */
Paul Bakker5121ce52009-01-03 21:22:43 +00001034
Agathiyan Bragadeeshc99840a2023-07-12 11:15:46 +01001035 p = X->p;
Tom Cosgroveaf7d44b2022-08-24 14:05:26 +01001036
Agathiyan Bragadeeshc99840a2023-07-12 11:15:46 +01001037 c = mbedtls_mpi_core_add(p, p, B->p, j);
Tom Cosgroveaf7d44b2022-08-24 14:05:26 +01001038
1039 p += j;
1040
1041 /* Now propagate any carry */
Paul Bakker5121ce52009-01-03 21:22:43 +00001042
Gilles Peskine449bd832023-01-11 14:50:10 +01001043 while (c != 0) {
1044 if (j >= X->n) {
1045 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, j + 1));
Tom Cosgroveaf7d44b2022-08-24 14:05:26 +01001046 p = X->p + j;
Paul Bakker5121ce52009-01-03 21:22:43 +00001047 }
1048
Gilles Peskine449bd832023-01-11 14:50:10 +01001049 *p += c; c = (*p < c); j++; p++;
Paul Bakker5121ce52009-01-03 21:22:43 +00001050 }
1051
1052cleanup:
1053
Gilles Peskine449bd832023-01-11 14:50:10 +01001054 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001055}
1056
Paul Bakker5121ce52009-01-03 21:22:43 +00001057/*
Gilles Peskine0e5faf62020-06-08 22:50:35 +02001058 * Unsigned subtraction: X = |A| - |B| (HAC 14.9, 14.10)
Paul Bakker5121ce52009-01-03 21:22:43 +00001059 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001060int mbedtls_mpi_sub_abs(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B)
Paul Bakker5121ce52009-01-03 21:22:43 +00001061{
Janos Follath24eed8d2019-11-22 13:21:35 +00001062 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker23986e52011-04-24 08:57:21 +00001063 size_t n;
Gilles Peskine0e5faf62020-06-08 22:50:35 +02001064 mbedtls_mpi_uint carry;
Paul Bakker5121ce52009-01-03 21:22:43 +00001065
Gilles Peskine449bd832023-01-11 14:50:10 +01001066 for (n = B->n; n > 0; n--) {
1067 if (B->p[n - 1] != 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00001068 break;
Gilles Peskine449bd832023-01-11 14:50:10 +01001069 }
1070 }
1071 if (n > A->n) {
Gilles Peskinec8a91772021-01-27 22:30:43 +01001072 /* B >= (2^ciL)^n > A */
1073 ret = MBEDTLS_ERR_MPI_NEGATIVE_VALUE;
1074 goto cleanup;
1075 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001076
Gilles Peskine449bd832023-01-11 14:50:10 +01001077 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, A->n));
Gilles Peskine1acf7cb2020-07-23 01:03:22 +02001078
1079 /* Set the high limbs of X to match A. Don't touch the lower limbs
1080 * because X might be aliased to B, and we must not overwrite the
1081 * significant digits of B. */
Aaron M. Uckoaf67d2c2023-01-17 11:52:22 -05001082 if (A->n > n && A != X) {
Gilles Peskine449bd832023-01-11 14:50:10 +01001083 memcpy(X->p + n, A->p + n, (A->n - n) * ciL);
1084 }
1085 if (X->n > A->n) {
1086 memset(X->p + A->n, 0, (X->n - A->n) * ciL);
1087 }
Gilles Peskine1acf7cb2020-07-23 01:03:22 +02001088
Gilles Peskine449bd832023-01-11 14:50:10 +01001089 carry = mbedtls_mpi_core_sub(X->p, A->p, B->p, n);
1090 if (carry != 0) {
Tom Cosgrove452c99c2022-08-25 10:07:07 +01001091 /* Propagate the carry through the rest of X. */
Gilles Peskine449bd832023-01-11 14:50:10 +01001092 carry = mbedtls_mpi_core_sub_int(X->p + n, X->p + n, carry, X->n - n);
Tom Cosgrove452c99c2022-08-25 10:07:07 +01001093
1094 /* If we have further carry/borrow, the result is negative. */
Gilles Peskine449bd832023-01-11 14:50:10 +01001095 if (carry != 0) {
Gilles Peskine89b41302020-07-23 01:16:46 +02001096 ret = MBEDTLS_ERR_MPI_NEGATIVE_VALUE;
1097 goto cleanup;
1098 }
Gilles Peskinec097e9e2020-06-08 21:58:22 +02001099 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001100
Gilles Peskine1acf7cb2020-07-23 01:03:22 +02001101 /* X should always be positive as a result of unsigned subtractions. */
1102 X->s = 1;
1103
Paul Bakker5121ce52009-01-03 21:22:43 +00001104cleanup:
Gilles Peskine449bd832023-01-11 14:50:10 +01001105 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001106}
1107
Gilles Peskine72ee1e32022-11-09 21:34:09 +01001108/* Common function for signed addition and subtraction.
1109 * Calculate A + B * flip_B where flip_B is 1 or -1.
Paul Bakker5121ce52009-01-03 21:22:43 +00001110 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001111static int add_sub_mpi(mbedtls_mpi *X,
1112 const mbedtls_mpi *A, const mbedtls_mpi *B,
1113 int flip_B)
Paul Bakker5121ce52009-01-03 21:22:43 +00001114{
Hanno Becker73d7d792018-12-11 10:35:51 +00001115 int ret, s;
Paul Bakker5121ce52009-01-03 21:22:43 +00001116
Hanno Becker73d7d792018-12-11 10:35:51 +00001117 s = A->s;
Gilles Peskine449bd832023-01-11 14:50:10 +01001118 if (A->s * B->s * flip_B < 0) {
1119 int cmp = mbedtls_mpi_cmp_abs(A, B);
1120 if (cmp >= 0) {
1121 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_abs(X, A, B));
Gilles Peskine4a768dd2022-11-09 22:02:16 +01001122 /* If |A| = |B|, the result is 0 and we must set the sign bit
1123 * to +1 regardless of which of A or B was negative. Otherwise,
1124 * since |A| > |B|, the sign is the sign of A. */
1125 X->s = cmp == 0 ? 1 : s;
Gilles Peskine449bd832023-01-11 14:50:10 +01001126 } else {
1127 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_abs(X, B, A));
Gilles Peskine4a768dd2022-11-09 22:02:16 +01001128 /* Since |A| < |B|, the sign is the opposite of A. */
Paul Bakker5121ce52009-01-03 21:22:43 +00001129 X->s = -s;
1130 }
Gilles Peskine449bd832023-01-11 14:50:10 +01001131 } else {
1132 MBEDTLS_MPI_CHK(mbedtls_mpi_add_abs(X, A, B));
Paul Bakker5121ce52009-01-03 21:22:43 +00001133 X->s = s;
1134 }
1135
1136cleanup:
1137
Gilles Peskine449bd832023-01-11 14:50:10 +01001138 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001139}
1140
1141/*
Gilles Peskine72ee1e32022-11-09 21:34:09 +01001142 * Signed addition: X = A + B
1143 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001144int mbedtls_mpi_add_mpi(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B)
Gilles Peskine72ee1e32022-11-09 21:34:09 +01001145{
Gilles Peskine449bd832023-01-11 14:50:10 +01001146 return add_sub_mpi(X, A, B, 1);
Gilles Peskine72ee1e32022-11-09 21:34:09 +01001147}
1148
1149/*
Paul Bakker60b1d102013-10-29 10:02:51 +01001150 * Signed subtraction: X = A - B
Paul Bakker5121ce52009-01-03 21:22:43 +00001151 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001152int mbedtls_mpi_sub_mpi(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B)
Paul Bakker5121ce52009-01-03 21:22:43 +00001153{
Gilles Peskine449bd832023-01-11 14:50:10 +01001154 return add_sub_mpi(X, A, B, -1);
Paul Bakker5121ce52009-01-03 21:22:43 +00001155}
1156
1157/*
1158 * Signed addition: X = A + b
1159 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001160int mbedtls_mpi_add_int(mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b)
Paul Bakker5121ce52009-01-03 21:22:43 +00001161{
Yuto Takano36c8ddc2021-07-05 09:10:52 +01001162 mbedtls_mpi B;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001163 mbedtls_mpi_uint p[1];
Paul Bakker5121ce52009-01-03 21:22:43 +00001164
Gilles Peskine449bd832023-01-11 14:50:10 +01001165 p[0] = mpi_sint_abs(b);
Dave Rodgmanf3df1052023-08-09 18:55:41 +01001166 B.s = TO_SIGN(b);
Yuto Takano36c8ddc2021-07-05 09:10:52 +01001167 B.n = 1;
1168 B.p = p;
Paul Bakker5121ce52009-01-03 21:22:43 +00001169
Gilles Peskine449bd832023-01-11 14:50:10 +01001170 return mbedtls_mpi_add_mpi(X, A, &B);
Paul Bakker5121ce52009-01-03 21:22:43 +00001171}
1172
1173/*
Paul Bakker60b1d102013-10-29 10:02:51 +01001174 * Signed subtraction: X = A - b
Paul Bakker5121ce52009-01-03 21:22:43 +00001175 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001176int mbedtls_mpi_sub_int(mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b)
Paul Bakker5121ce52009-01-03 21:22:43 +00001177{
Yuto Takano36c8ddc2021-07-05 09:10:52 +01001178 mbedtls_mpi B;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001179 mbedtls_mpi_uint p[1];
Paul Bakker5121ce52009-01-03 21:22:43 +00001180
Gilles Peskine449bd832023-01-11 14:50:10 +01001181 p[0] = mpi_sint_abs(b);
Dave Rodgmanf3df1052023-08-09 18:55:41 +01001182 B.s = TO_SIGN(b);
Yuto Takano36c8ddc2021-07-05 09:10:52 +01001183 B.n = 1;
1184 B.p = p;
Paul Bakker5121ce52009-01-03 21:22:43 +00001185
Gilles Peskine449bd832023-01-11 14:50:10 +01001186 return mbedtls_mpi_sub_mpi(X, A, &B);
Paul Bakker5121ce52009-01-03 21:22:43 +00001187}
1188
Paul Bakker5121ce52009-01-03 21:22:43 +00001189/*
1190 * Baseline multiplication: X = A * B (HAC 14.12)
1191 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001192int mbedtls_mpi_mul_mpi(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B)
Paul Bakker5121ce52009-01-03 21:22:43 +00001193{
Janos Follath24eed8d2019-11-22 13:21:35 +00001194 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Hanno Becker1772e052022-04-13 06:51:40 +01001195 size_t i, j;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001196 mbedtls_mpi TA, TB;
Hanno Beckerda763de2022-04-13 06:50:02 +01001197 int result_is_zero = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +00001198
Tom Cosgrove6af26f32022-08-24 16:40:55 +01001199 mbedtls_mpi_init(&TA);
1200 mbedtls_mpi_init(&TB);
Paul Bakker5121ce52009-01-03 21:22:43 +00001201
Gilles Peskine449bd832023-01-11 14:50:10 +01001202 if (X == A) {
1203 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TA, A)); A = &TA;
1204 }
1205 if (X == B) {
1206 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TB, B)); B = &TB;
1207 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001208
Gilles Peskine449bd832023-01-11 14:50:10 +01001209 for (i = A->n; i > 0; i--) {
1210 if (A->p[i - 1] != 0) {
Hanno Beckerda763de2022-04-13 06:50:02 +01001211 break;
Gilles Peskine449bd832023-01-11 14:50:10 +01001212 }
1213 }
1214 if (i == 0) {
Hanno Beckerda763de2022-04-13 06:50:02 +01001215 result_is_zero = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +01001216 }
Hanno Beckerda763de2022-04-13 06:50:02 +01001217
Gilles Peskine449bd832023-01-11 14:50:10 +01001218 for (j = B->n; j > 0; j--) {
1219 if (B->p[j - 1] != 0) {
Hanno Beckerda763de2022-04-13 06:50:02 +01001220 break;
Gilles Peskine449bd832023-01-11 14:50:10 +01001221 }
1222 }
1223 if (j == 0) {
Hanno Beckerda763de2022-04-13 06:50:02 +01001224 result_is_zero = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +01001225 }
Hanno Beckerda763de2022-04-13 06:50:02 +01001226
Gilles Peskine449bd832023-01-11 14:50:10 +01001227 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, i + j));
1228 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(X, 0));
Paul Bakker5121ce52009-01-03 21:22:43 +00001229
Tom Cosgrove6af26f32022-08-24 16:40:55 +01001230 mbedtls_mpi_core_mul(X->p, A->p, i, B->p, j);
Paul Bakker5121ce52009-01-03 21:22:43 +00001231
Hanno Beckerda763de2022-04-13 06:50:02 +01001232 /* If the result is 0, we don't shortcut the operation, which reduces
1233 * but does not eliminate side channels leaking the zero-ness. We do
1234 * need to take care to set the sign bit properly since the library does
1235 * not fully support an MPI object with a value of 0 and s == -1. */
Gilles Peskine449bd832023-01-11 14:50:10 +01001236 if (result_is_zero) {
Hanno Beckerda763de2022-04-13 06:50:02 +01001237 X->s = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +01001238 } else {
Hanno Beckerda763de2022-04-13 06:50:02 +01001239 X->s = A->s * B->s;
Gilles Peskine449bd832023-01-11 14:50:10 +01001240 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001241
1242cleanup:
1243
Gilles Peskine449bd832023-01-11 14:50:10 +01001244 mbedtls_mpi_free(&TB); mbedtls_mpi_free(&TA);
Paul Bakker5121ce52009-01-03 21:22:43 +00001245
Gilles Peskine449bd832023-01-11 14:50:10 +01001246 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001247}
1248
1249/*
1250 * Baseline multiplication: X = A * b
1251 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001252int mbedtls_mpi_mul_int(mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_uint b)
Paul Bakker5121ce52009-01-03 21:22:43 +00001253{
Hanno Becker35771312022-04-14 11:52:11 +01001254 size_t n = A->n;
Gilles Peskine449bd832023-01-11 14:50:10 +01001255 while (n > 0 && A->p[n - 1] == 0) {
Hanno Becker35771312022-04-14 11:52:11 +01001256 --n;
Gilles Peskine449bd832023-01-11 14:50:10 +01001257 }
Hanno Becker35771312022-04-14 11:52:11 +01001258
Hanno Becker74a11a32022-04-06 06:27:00 +01001259 /* The general method below doesn't work if b==0. */
Gilles Peskine449bd832023-01-11 14:50:10 +01001260 if (b == 0 || n == 0) {
1261 return mbedtls_mpi_lset(X, 0);
1262 }
Gilles Peskine8fd95c62020-07-23 21:58:50 +02001263
Hanno Beckeraef9cc42022-04-11 06:36:29 +01001264 /* Calculate A*b as A + A*(b-1) to take advantage of mbedtls_mpi_core_mla */
Gilles Peskine8fd95c62020-07-23 21:58:50 +02001265 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Gilles Peskinecd0dbf32020-07-24 00:09:04 +02001266 /* In general, A * b requires 1 limb more than b. If
1267 * A->p[n - 1] * b / b == A->p[n - 1], then A * b fits in the same
1268 * number of limbs as A and the call to grow() is not required since
Gilles Peskinee1bba7c2021-03-10 23:44:10 +01001269 * copy() will take care of the growth if needed. However, experimentally,
1270 * making the call to grow() unconditional causes slightly fewer
Gilles Peskinecd0dbf32020-07-24 00:09:04 +02001271 * calls to calloc() in ECP code, presumably because it reuses the
1272 * same mpi for a while and this way the mpi is more likely to directly
Hanno Becker9137b9c2022-04-12 10:51:54 +01001273 * grow to its final size.
1274 *
1275 * Note that calculating A*b as 0 + A*b doesn't work as-is because
1276 * A,X can be the same. */
Gilles Peskine449bd832023-01-11 14:50:10 +01001277 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, n + 1));
1278 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(X, A));
1279 mbedtls_mpi_core_mla(X->p, X->n, A->p, n, b - 1);
Gilles Peskine8fd95c62020-07-23 21:58:50 +02001280
1281cleanup:
Gilles Peskine449bd832023-01-11 14:50:10 +01001282 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001283}
1284
1285/*
Simon Butcherf5ba0452015-12-27 23:01:55 +00001286 * Unsigned integer divide - double mbedtls_mpi_uint dividend, u1/u0, and
1287 * mbedtls_mpi_uint divisor, d
Simon Butcher15b15d12015-11-26 19:35:03 +00001288 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001289static mbedtls_mpi_uint mbedtls_int_div_int(mbedtls_mpi_uint u1,
1290 mbedtls_mpi_uint u0,
1291 mbedtls_mpi_uint d,
1292 mbedtls_mpi_uint *r)
Simon Butcher15b15d12015-11-26 19:35:03 +00001293{
Manuel Pégourié-Gonnard16308882015-12-01 10:27:00 +01001294#if defined(MBEDTLS_HAVE_UDBL)
1295 mbedtls_t_udbl dividend, quotient;
Simon Butcherf5ba0452015-12-27 23:01:55 +00001296#else
Simon Butcher9803d072016-01-03 00:24:34 +00001297 const mbedtls_mpi_uint radix = (mbedtls_mpi_uint) 1 << biH;
Gilles Peskine449bd832023-01-11 14:50:10 +01001298 const mbedtls_mpi_uint uint_halfword_mask = ((mbedtls_mpi_uint) 1 << biH) - 1;
Simon Butcherf5ba0452015-12-27 23:01:55 +00001299 mbedtls_mpi_uint d0, d1, q0, q1, rAX, r0, quotient;
1300 mbedtls_mpi_uint u0_msw, u0_lsw;
Simon Butcher9803d072016-01-03 00:24:34 +00001301 size_t s;
Manuel Pégourié-Gonnard16308882015-12-01 10:27:00 +01001302#endif
1303
Simon Butcher15b15d12015-11-26 19:35:03 +00001304 /*
1305 * Check for overflow
1306 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001307 if (0 == d || u1 >= d) {
1308 if (r != NULL) {
1309 *r = ~(mbedtls_mpi_uint) 0u;
1310 }
Simon Butcher15b15d12015-11-26 19:35:03 +00001311
Gilles Peskine449bd832023-01-11 14:50:10 +01001312 return ~(mbedtls_mpi_uint) 0u;
Simon Butcher15b15d12015-11-26 19:35:03 +00001313 }
1314
1315#if defined(MBEDTLS_HAVE_UDBL)
Simon Butcher15b15d12015-11-26 19:35:03 +00001316 dividend = (mbedtls_t_udbl) u1 << biL;
1317 dividend |= (mbedtls_t_udbl) u0;
1318 quotient = dividend / d;
Gilles Peskine449bd832023-01-11 14:50:10 +01001319 if (quotient > ((mbedtls_t_udbl) 1 << biL) - 1) {
1320 quotient = ((mbedtls_t_udbl) 1 << biL) - 1;
1321 }
Simon Butcher15b15d12015-11-26 19:35:03 +00001322
Gilles Peskine449bd832023-01-11 14:50:10 +01001323 if (r != NULL) {
1324 *r = (mbedtls_mpi_uint) (dividend - (quotient * d));
1325 }
Simon Butcher15b15d12015-11-26 19:35:03 +00001326
1327 return (mbedtls_mpi_uint) quotient;
1328#else
Simon Butcher15b15d12015-11-26 19:35:03 +00001329
1330 /*
1331 * Algorithm D, Section 4.3.1 - The Art of Computer Programming
1332 * Vol. 2 - Seminumerical Algorithms, Knuth
1333 */
1334
1335 /*
1336 * Normalize the divisor, d, and dividend, u0, u1
1337 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001338 s = mbedtls_mpi_core_clz(d);
Simon Butcher15b15d12015-11-26 19:35:03 +00001339 d = d << s;
1340
1341 u1 = u1 << s;
Gilles Peskine449bd832023-01-11 14:50:10 +01001342 u1 |= (u0 >> (biL - s)) & (-(mbedtls_mpi_sint) s >> (biL - 1));
Simon Butcher15b15d12015-11-26 19:35:03 +00001343 u0 = u0 << s;
1344
1345 d1 = d >> biH;
Simon Butcher9803d072016-01-03 00:24:34 +00001346 d0 = d & uint_halfword_mask;
Simon Butcher15b15d12015-11-26 19:35:03 +00001347
1348 u0_msw = u0 >> biH;
Simon Butcher9803d072016-01-03 00:24:34 +00001349 u0_lsw = u0 & uint_halfword_mask;
Simon Butcher15b15d12015-11-26 19:35:03 +00001350
1351 /*
1352 * Find the first quotient and remainder
1353 */
1354 q1 = u1 / d1;
1355 r0 = u1 - d1 * q1;
1356
Gilles Peskine449bd832023-01-11 14:50:10 +01001357 while (q1 >= radix || (q1 * d0 > radix * r0 + u0_msw)) {
Simon Butcher15b15d12015-11-26 19:35:03 +00001358 q1 -= 1;
1359 r0 += d1;
1360
Gilles Peskine449bd832023-01-11 14:50:10 +01001361 if (r0 >= radix) {
1362 break;
1363 }
Simon Butcher15b15d12015-11-26 19:35:03 +00001364 }
1365
Gilles Peskine449bd832023-01-11 14:50:10 +01001366 rAX = (u1 * radix) + (u0_msw - q1 * d);
Simon Butcher15b15d12015-11-26 19:35:03 +00001367 q0 = rAX / d1;
1368 r0 = rAX - q0 * d1;
1369
Gilles Peskine449bd832023-01-11 14:50:10 +01001370 while (q0 >= radix || (q0 * d0 > radix * r0 + u0_lsw)) {
Simon Butcher15b15d12015-11-26 19:35:03 +00001371 q0 -= 1;
1372 r0 += d1;
1373
Gilles Peskine449bd832023-01-11 14:50:10 +01001374 if (r0 >= radix) {
1375 break;
1376 }
Simon Butcher15b15d12015-11-26 19:35:03 +00001377 }
1378
Gilles Peskine449bd832023-01-11 14:50:10 +01001379 if (r != NULL) {
1380 *r = (rAX * radix + u0_lsw - q0 * d) >> s;
1381 }
Simon Butcher15b15d12015-11-26 19:35:03 +00001382
1383 quotient = q1 * radix + q0;
1384
1385 return quotient;
1386#endif
1387}
1388
1389/*
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001390 * Division by mbedtls_mpi: A = Q * B + R (HAC 14.20)
Paul Bakker5121ce52009-01-03 21:22:43 +00001391 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001392int mbedtls_mpi_div_mpi(mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A,
1393 const mbedtls_mpi *B)
Paul Bakker5121ce52009-01-03 21:22:43 +00001394{
Janos Follath24eed8d2019-11-22 13:21:35 +00001395 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker23986e52011-04-24 08:57:21 +00001396 size_t i, n, t, k;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001397 mbedtls_mpi X, Y, Z, T1, T2;
Alexander Kd19a1932019-11-01 18:20:42 +03001398 mbedtls_mpi_uint TP2[3];
Paul Bakker5121ce52009-01-03 21:22:43 +00001399
Gilles Peskine449bd832023-01-11 14:50:10 +01001400 if (mbedtls_mpi_cmp_int(B, 0) == 0) {
1401 return MBEDTLS_ERR_MPI_DIVISION_BY_ZERO;
1402 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001403
Gilles Peskine449bd832023-01-11 14:50:10 +01001404 mbedtls_mpi_init(&X); mbedtls_mpi_init(&Y); mbedtls_mpi_init(&Z);
1405 mbedtls_mpi_init(&T1);
Alexander Kd19a1932019-11-01 18:20:42 +03001406 /*
1407 * Avoid dynamic memory allocations for constant-size T2.
1408 *
1409 * T2 is used for comparison only and the 3 limbs are assigned explicitly,
1410 * so nobody increase the size of the MPI and we're safe to use an on-stack
1411 * buffer.
1412 */
Alexander K35d6d462019-10-31 14:46:45 +03001413 T2.s = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +01001414 T2.n = sizeof(TP2) / sizeof(*TP2);
Alexander Kd19a1932019-11-01 18:20:42 +03001415 T2.p = TP2;
Paul Bakker5121ce52009-01-03 21:22:43 +00001416
Gilles Peskine449bd832023-01-11 14:50:10 +01001417 if (mbedtls_mpi_cmp_abs(A, B) < 0) {
1418 if (Q != NULL) {
1419 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(Q, 0));
1420 }
1421 if (R != NULL) {
1422 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(R, A));
1423 }
1424 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +00001425 }
1426
Gilles Peskine449bd832023-01-11 14:50:10 +01001427 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&X, A));
1428 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&Y, B));
Paul Bakker5121ce52009-01-03 21:22:43 +00001429 X.s = Y.s = 1;
1430
Gilles Peskine449bd832023-01-11 14:50:10 +01001431 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(&Z, A->n + 2));
1432 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&Z, 0));
1433 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(&T1, A->n + 2));
Paul Bakker5121ce52009-01-03 21:22:43 +00001434
Gilles Peskine449bd832023-01-11 14:50:10 +01001435 k = mbedtls_mpi_bitlen(&Y) % biL;
1436 if (k < biL - 1) {
Paul Bakker5121ce52009-01-03 21:22:43 +00001437 k = biL - 1 - k;
Gilles Peskine449bd832023-01-11 14:50:10 +01001438 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&X, k));
1439 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&Y, k));
1440 } else {
1441 k = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +00001442 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001443
1444 n = X.n - 1;
1445 t = Y.n - 1;
Gilles Peskine449bd832023-01-11 14:50:10 +01001446 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&Y, biL * (n - t)));
Paul Bakker5121ce52009-01-03 21:22:43 +00001447
Gilles Peskine449bd832023-01-11 14:50:10 +01001448 while (mbedtls_mpi_cmp_mpi(&X, &Y) >= 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00001449 Z.p[n - t]++;
Gilles Peskine449bd832023-01-11 14:50:10 +01001450 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&X, &X, &Y));
Paul Bakker5121ce52009-01-03 21:22:43 +00001451 }
Gilles Peskine449bd832023-01-11 14:50:10 +01001452 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&Y, biL * (n - t)));
Paul Bakker5121ce52009-01-03 21:22:43 +00001453
Gilles Peskine449bd832023-01-11 14:50:10 +01001454 for (i = n; i > t; i--) {
1455 if (X.p[i] >= Y.p[t]) {
1456 Z.p[i - t - 1] = ~(mbedtls_mpi_uint) 0u;
1457 } else {
1458 Z.p[i - t - 1] = mbedtls_int_div_int(X.p[i], X.p[i - 1],
1459 Y.p[t], NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +00001460 }
1461
Gilles Peskine449bd832023-01-11 14:50:10 +01001462 T2.p[0] = (i < 2) ? 0 : X.p[i - 2];
1463 T2.p[1] = (i < 1) ? 0 : X.p[i - 1];
Alexander K35d6d462019-10-31 14:46:45 +03001464 T2.p[2] = X.p[i];
1465
Paul Bakker5121ce52009-01-03 21:22:43 +00001466 Z.p[i - t - 1]++;
Gilles Peskine449bd832023-01-11 14:50:10 +01001467 do {
Paul Bakker5121ce52009-01-03 21:22:43 +00001468 Z.p[i - t - 1]--;
1469
Gilles Peskine449bd832023-01-11 14:50:10 +01001470 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&T1, 0));
1471 T1.p[0] = (t < 1) ? 0 : Y.p[t - 1];
Paul Bakker5121ce52009-01-03 21:22:43 +00001472 T1.p[1] = Y.p[t];
Gilles Peskine449bd832023-01-11 14:50:10 +01001473 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_int(&T1, &T1, Z.p[i - t - 1]));
1474 } while (mbedtls_mpi_cmp_mpi(&T1, &T2) > 0);
Paul Bakker5121ce52009-01-03 21:22:43 +00001475
Gilles Peskine449bd832023-01-11 14:50:10 +01001476 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_int(&T1, &Y, Z.p[i - t - 1]));
1477 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&T1, biL * (i - t - 1)));
1478 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&X, &X, &T1));
Paul Bakker5121ce52009-01-03 21:22:43 +00001479
Gilles Peskine449bd832023-01-11 14:50:10 +01001480 if (mbedtls_mpi_cmp_int(&X, 0) < 0) {
1481 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&T1, &Y));
1482 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&T1, biL * (i - t - 1)));
1483 MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&X, &X, &T1));
Paul Bakker5121ce52009-01-03 21:22:43 +00001484 Z.p[i - t - 1]--;
1485 }
1486 }
1487
Gilles Peskine449bd832023-01-11 14:50:10 +01001488 if (Q != NULL) {
1489 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(Q, &Z));
Paul Bakker5121ce52009-01-03 21:22:43 +00001490 Q->s = A->s * B->s;
1491 }
1492
Gilles Peskine449bd832023-01-11 14:50:10 +01001493 if (R != NULL) {
1494 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&X, k));
Paul Bakkerf02c5642012-11-13 10:25:21 +00001495 X.s = A->s;
Gilles Peskine449bd832023-01-11 14:50:10 +01001496 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(R, &X));
Paul Bakker5121ce52009-01-03 21:22:43 +00001497
Gilles Peskine449bd832023-01-11 14:50:10 +01001498 if (mbedtls_mpi_cmp_int(R, 0) == 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00001499 R->s = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +01001500 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001501 }
1502
1503cleanup:
1504
Gilles Peskine449bd832023-01-11 14:50:10 +01001505 mbedtls_mpi_free(&X); mbedtls_mpi_free(&Y); mbedtls_mpi_free(&Z);
1506 mbedtls_mpi_free(&T1);
1507 mbedtls_platform_zeroize(TP2, sizeof(TP2));
Paul Bakker5121ce52009-01-03 21:22:43 +00001508
Gilles Peskine449bd832023-01-11 14:50:10 +01001509 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001510}
1511
1512/*
1513 * Division by int: A = Q * b + R
Paul Bakker5121ce52009-01-03 21:22:43 +00001514 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001515int mbedtls_mpi_div_int(mbedtls_mpi *Q, mbedtls_mpi *R,
1516 const mbedtls_mpi *A,
1517 mbedtls_mpi_sint b)
Paul Bakker5121ce52009-01-03 21:22:43 +00001518{
Yuto Takano36c8ddc2021-07-05 09:10:52 +01001519 mbedtls_mpi B;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001520 mbedtls_mpi_uint p[1];
Paul Bakker5121ce52009-01-03 21:22:43 +00001521
Gilles Peskine449bd832023-01-11 14:50:10 +01001522 p[0] = mpi_sint_abs(b);
Dave Rodgmanf3df1052023-08-09 18:55:41 +01001523 B.s = TO_SIGN(b);
Yuto Takano36c8ddc2021-07-05 09:10:52 +01001524 B.n = 1;
1525 B.p = p;
Paul Bakker5121ce52009-01-03 21:22:43 +00001526
Gilles Peskine449bd832023-01-11 14:50:10 +01001527 return mbedtls_mpi_div_mpi(Q, R, A, &B);
Paul Bakker5121ce52009-01-03 21:22:43 +00001528}
1529
1530/*
1531 * Modulo: R = A mod B
1532 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001533int mbedtls_mpi_mod_mpi(mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B)
Paul Bakker5121ce52009-01-03 21:22:43 +00001534{
Janos Follath24eed8d2019-11-22 13:21:35 +00001535 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker5121ce52009-01-03 21:22:43 +00001536
Gilles Peskine449bd832023-01-11 14:50:10 +01001537 if (mbedtls_mpi_cmp_int(B, 0) < 0) {
1538 return MBEDTLS_ERR_MPI_NEGATIVE_VALUE;
1539 }
Paul Bakkerce40a6d2009-06-23 19:46:08 +00001540
Gilles Peskine449bd832023-01-11 14:50:10 +01001541 MBEDTLS_MPI_CHK(mbedtls_mpi_div_mpi(NULL, R, A, B));
Paul Bakker5121ce52009-01-03 21:22:43 +00001542
Gilles Peskine449bd832023-01-11 14:50:10 +01001543 while (mbedtls_mpi_cmp_int(R, 0) < 0) {
1544 MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(R, R, B));
1545 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001546
Gilles Peskine449bd832023-01-11 14:50:10 +01001547 while (mbedtls_mpi_cmp_mpi(R, B) >= 0) {
1548 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(R, R, B));
1549 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001550
1551cleanup:
1552
Gilles Peskine449bd832023-01-11 14:50:10 +01001553 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001554}
1555
1556/*
1557 * Modulo: r = A mod b
1558 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001559int mbedtls_mpi_mod_int(mbedtls_mpi_uint *r, const mbedtls_mpi *A, mbedtls_mpi_sint b)
Paul Bakker5121ce52009-01-03 21:22:43 +00001560{
Paul Bakker23986e52011-04-24 08:57:21 +00001561 size_t i;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001562 mbedtls_mpi_uint x, y, z;
Paul Bakker5121ce52009-01-03 21:22:43 +00001563
Gilles Peskine449bd832023-01-11 14:50:10 +01001564 if (b == 0) {
1565 return MBEDTLS_ERR_MPI_DIVISION_BY_ZERO;
1566 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001567
Gilles Peskine449bd832023-01-11 14:50:10 +01001568 if (b < 0) {
1569 return MBEDTLS_ERR_MPI_NEGATIVE_VALUE;
1570 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001571
1572 /*
1573 * handle trivial cases
1574 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001575 if (b == 1 || A->n == 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00001576 *r = 0;
Gilles Peskine449bd832023-01-11 14:50:10 +01001577 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +00001578 }
1579
Gilles Peskine449bd832023-01-11 14:50:10 +01001580 if (b == 2) {
Paul Bakker5121ce52009-01-03 21:22:43 +00001581 *r = A->p[0] & 1;
Gilles Peskine449bd832023-01-11 14:50:10 +01001582 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +00001583 }
1584
1585 /*
1586 * general case
1587 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001588 for (i = A->n, y = 0; i > 0; i--) {
Paul Bakker23986e52011-04-24 08:57:21 +00001589 x = A->p[i - 1];
Gilles Peskine449bd832023-01-11 14:50:10 +01001590 y = (y << biH) | (x >> biH);
Paul Bakker5121ce52009-01-03 21:22:43 +00001591 z = y / b;
1592 y -= z * b;
1593
1594 x <<= biH;
Gilles Peskine449bd832023-01-11 14:50:10 +01001595 y = (y << biH) | (x >> biH);
Paul Bakker5121ce52009-01-03 21:22:43 +00001596 z = y / b;
1597 y -= z * b;
1598 }
1599
Paul Bakkerce40a6d2009-06-23 19:46:08 +00001600 /*
1601 * If A is negative, then the current y represents a negative value.
1602 * Flipping it to the positive side.
1603 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001604 if (A->s < 0 && y != 0) {
Paul Bakkerce40a6d2009-06-23 19:46:08 +00001605 y = b - y;
Gilles Peskine449bd832023-01-11 14:50:10 +01001606 }
Paul Bakkerce40a6d2009-06-23 19:46:08 +00001607
Paul Bakker5121ce52009-01-03 21:22:43 +00001608 *r = y;
1609
Gilles Peskine449bd832023-01-11 14:50:10 +01001610 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +00001611}
1612
Gilles Peskine449bd832023-01-11 14:50:10 +01001613int mbedtls_mpi_exp_mod(mbedtls_mpi *X, const mbedtls_mpi *A,
1614 const mbedtls_mpi *E, const mbedtls_mpi *N,
1615 mbedtls_mpi *prec_RR)
Paul Bakker5121ce52009-01-03 21:22:43 +00001616{
Janos Follath24eed8d2019-11-22 13:21:35 +00001617 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker5121ce52009-01-03 21:22:43 +00001618
Gilles Peskine449bd832023-01-11 14:50:10 +01001619 if (mbedtls_mpi_cmp_int(N, 0) <= 0 || (N->p[0] & 1) == 0) {
1620 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
1621 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001622
Gilles Peskine449bd832023-01-11 14:50:10 +01001623 if (mbedtls_mpi_cmp_int(E, 0) < 0) {
1624 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
1625 }
Paul Bakkerf6198c12012-05-16 08:02:29 +00001626
Gilles Peskine449bd832023-01-11 14:50:10 +01001627 if (mbedtls_mpi_bitlen(E) > MBEDTLS_MPI_MAX_BITS ||
1628 mbedtls_mpi_bitlen(N) > MBEDTLS_MPI_MAX_BITS) {
1629 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
1630 }
Chris Jones9246d042020-11-25 15:12:39 +00001631
Janos Follath583f0472024-02-19 11:16:44 +00001632 /*
1633 * Ensure that the exponent that we are passing to the core is not NULL.
1634 */
1635 if (E->n == 0) {
1636 ret = mbedtls_mpi_lset(X, 1);
1637 return ret;
1638 }
1639
Janos Follath424c2652024-02-21 09:26:36 +00001640 /*
1641 * Allocate working memory for mbedtls_mpi_core_exp_mod()
1642 */
1643 size_t T_limbs = mbedtls_mpi_core_exp_mod_working_limbs(N->n, E->n);
Janos Follath09025722024-02-21 11:50:25 +00001644 mbedtls_mpi_uint *T = (mbedtls_mpi_uint *) mbedtls_calloc(T_limbs, sizeof(mbedtls_mpi_uint));
Janos Follath424c2652024-02-21 09:26:36 +00001645 if (T == NULL) {
1646 return MBEDTLS_ERR_MPI_ALLOC_FAILED;
1647 }
1648
Janos Follath701ae1d2024-02-19 10:56:54 +00001649 mbedtls_mpi RR;
Janos Follath1ba40582024-02-13 12:36:13 +00001650 mbedtls_mpi_init(&RR);
Paul Bakker50546922012-05-19 08:40:49 +00001651
1652 /*
Paul Bakker5121ce52009-01-03 21:22:43 +00001653 * If 1st call, pre-compute R^2 mod N
1654 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001655 if (prec_RR == NULL || prec_RR->p == NULL) {
Janos Follath1ba40582024-02-13 12:36:13 +00001656 MBEDTLS_MPI_CHK(mbedtls_mpi_core_get_mont_r2_unsafe(&RR, N));
Paul Bakker5121ce52009-01-03 21:22:43 +00001657
Gilles Peskine449bd832023-01-11 14:50:10 +01001658 if (prec_RR != NULL) {
Janos Follath576087d2024-02-19 11:05:01 +00001659 *prec_RR = RR;
Gilles Peskine449bd832023-01-11 14:50:10 +01001660 }
1661 } else {
Janos Follath0512d172024-02-20 14:30:46 +00001662 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(prec_RR, N->n));
Janos Follath576087d2024-02-19 11:05:01 +00001663 RR = *prec_RR;
Paul Bakker5121ce52009-01-03 21:22:43 +00001664 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001665
1666 /*
Janos Follath1ba40582024-02-13 12:36:13 +00001667 * To preserve constness we need to make a copy of A. Using X for this to
1668 * save memory.
Paul Bakker5121ce52009-01-03 21:22:43 +00001669 */
Janos Follath1ba40582024-02-13 12:36:13 +00001670 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(X, A));
Paul Bakker5121ce52009-01-03 21:22:43 +00001671
1672 /*
Janos Follath1ba40582024-02-13 12:36:13 +00001673 * Compensate for negative A (and correct at the end).
Paul Bakker5121ce52009-01-03 21:22:43 +00001674 */
Janos Follath1ba40582024-02-13 12:36:13 +00001675 X->s = 1;
Paul Bakkerf6198c12012-05-16 08:02:29 +00001676
Janos Follath8e7d6a02022-10-04 13:27:40 +01001677 /*
Janos Follath467a5492024-02-19 11:27:38 +00001678 * Make sure that X is in a form that is safe for consumption by
1679 * the core functions.
1680 *
1681 * - The core functions will not touch the limbs of X above N->n. The
1682 * result will be correct if those limbs are 0, which the mod call
1683 * ensures.
1684 * - Also, X must have at least as many limbs as N for the calls to the
1685 * core functions.
Janos Follath8e7d6a02022-10-04 13:27:40 +01001686 */
Janos Follath1ba40582024-02-13 12:36:13 +00001687 if (mbedtls_mpi_cmp_mpi(X, N) >= 0) {
1688 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(X, X, N));
1689 }
1690 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, N->n));
1691
1692 /*
Janos Follath1ba40582024-02-13 12:36:13 +00001693 * Convert to and from Montgomery around mbedtls_mpi_core_exp_mod().
1694 */
1695 mbedtls_mpi_uint mm = mbedtls_mpi_core_montmul_init(N->p);
Janos Follath424c2652024-02-21 09:26:36 +00001696 mbedtls_mpi_core_to_mont_rep(X->p, X->p, N->p, N->n, mm, RR.p, T);
Janos Follath16ef4862024-03-08 17:25:57 +00001697 mbedtls_mpi_core_exp_mod(X->p, X->p, N->p, N->n, E->p, E->n, RR.p, T);
Janos Follath424c2652024-02-21 09:26:36 +00001698 mbedtls_mpi_core_from_mont_rep(X->p, X->p, N->p, N->n, mm, T);
Janos Follath1ba40582024-02-13 12:36:13 +00001699
1700 /*
1701 * Correct for negative A.
1702 */
Janos Follath583f0472024-02-19 11:16:44 +00001703 if (A->s == -1 && (E->p[0] & 1) != 0) {
Janos Follath86258f52024-02-21 11:25:41 +00001704 mbedtls_ct_condition_t is_x_non_zero = mbedtls_mpi_core_check_zero_ct(X->p, X->n);
Janos Follath4ec0fb52024-03-08 17:22:40 +00001705 X->s = mbedtls_ct_mpi_sign_if(is_x_non_zero, -1, 1);
Janos Follath86258f52024-02-21 11:25:41 +00001706
Janos Follath1ba40582024-02-13 12:36:13 +00001707 MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(X, N, X));
1708 }
Janos Follath8e7d6a02022-10-04 13:27:40 +01001709
Paul Bakker5121ce52009-01-03 21:22:43 +00001710cleanup:
1711
Janos Follath424c2652024-02-21 09:26:36 +00001712 mbedtls_mpi_zeroize_and_free(T, T_limbs);
Paul Bakker6c591fa2011-05-05 11:49:20 +00001713
Gilles Peskine449bd832023-01-11 14:50:10 +01001714 if (prec_RR == NULL || prec_RR->p == NULL) {
1715 mbedtls_mpi_free(&RR);
1716 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001717
Gilles Peskine449bd832023-01-11 14:50:10 +01001718 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001719}
1720
Paul Bakker5121ce52009-01-03 21:22:43 +00001721/*
1722 * Greatest common divisor: G = gcd(A, B) (HAC 14.54)
1723 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001724int mbedtls_mpi_gcd(mbedtls_mpi *G, const mbedtls_mpi *A, const mbedtls_mpi *B)
Paul Bakker5121ce52009-01-03 21:22:43 +00001725{
Janos Follath24eed8d2019-11-22 13:21:35 +00001726 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker23986e52011-04-24 08:57:21 +00001727 size_t lz, lzt;
Alexander Ke8ad49f2019-08-16 16:16:07 +03001728 mbedtls_mpi TA, TB;
Paul Bakker5121ce52009-01-03 21:22:43 +00001729
Gilles Peskine449bd832023-01-11 14:50:10 +01001730 mbedtls_mpi_init(&TA); mbedtls_mpi_init(&TB);
Paul Bakker5121ce52009-01-03 21:22:43 +00001731
Gilles Peskine449bd832023-01-11 14:50:10 +01001732 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TA, A));
1733 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TB, B));
Paul Bakker5121ce52009-01-03 21:22:43 +00001734
Gilles Peskine449bd832023-01-11 14:50:10 +01001735 lz = mbedtls_mpi_lsb(&TA);
1736 lzt = mbedtls_mpi_lsb(&TB);
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00001737
Gilles Peskine27253bc2021-06-09 13:26:43 +02001738 /* The loop below gives the correct result when A==0 but not when B==0.
1739 * So have a special case for B==0. Leverage the fact that we just
1740 * calculated the lsb and lsb(B)==0 iff B is odd or 0 to make the test
1741 * slightly more efficient than cmp_int(). */
Gilles Peskine449bd832023-01-11 14:50:10 +01001742 if (lzt == 0 && mbedtls_mpi_get_bit(&TB, 0) == 0) {
1743 ret = mbedtls_mpi_copy(G, A);
Gilles Peskine27253bc2021-06-09 13:26:43 +02001744 goto cleanup;
1745 }
1746
Gilles Peskine449bd832023-01-11 14:50:10 +01001747 if (lzt < lz) {
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00001748 lz = lzt;
Gilles Peskine449bd832023-01-11 14:50:10 +01001749 }
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00001750
Paul Bakker5121ce52009-01-03 21:22:43 +00001751 TA.s = TB.s = 1;
1752
Gilles Peskine2a63c5b2021-06-16 13:42:04 +02001753 /* We mostly follow the procedure described in HAC 14.54, but with some
1754 * minor differences:
1755 * - Sequences of multiplications or divisions by 2 are grouped into a
1756 * single shift operation.
Gilles Peskineb09c7ee2021-06-21 18:58:39 +02001757 * - The procedure in HAC assumes that 0 < TB <= TA.
1758 * - The condition TB <= TA is not actually necessary for correctness.
1759 * TA and TB have symmetric roles except for the loop termination
1760 * condition, and the shifts at the beginning of the loop body
1761 * remove any significance from the ordering of TA vs TB before
1762 * the shifts.
1763 * - If TA = 0, the loop goes through 0 iterations and the result is
1764 * correctly TB.
1765 * - The case TB = 0 was short-circuited above.
Gilles Peskine2a63c5b2021-06-16 13:42:04 +02001766 *
1767 * For the correctness proof below, decompose the original values of
1768 * A and B as
1769 * A = sa * 2^a * A' with A'=0 or A' odd, and sa = +-1
1770 * B = sb * 2^b * B' with B'=0 or B' odd, and sb = +-1
1771 * Then gcd(A, B) = 2^{min(a,b)} * gcd(A',B'),
1772 * and gcd(A',B') is odd or 0.
1773 *
1774 * At the beginning, we have TA = |A| and TB = |B| so gcd(A,B) = gcd(TA,TB).
1775 * The code maintains the following invariant:
1776 * gcd(A,B) = 2^k * gcd(TA,TB) for some k (I)
Gilles Peskine4df3f1f2021-06-15 22:09:39 +02001777 */
1778
Gilles Peskine2a63c5b2021-06-16 13:42:04 +02001779 /* Proof that the loop terminates:
1780 * At each iteration, either the right-shift by 1 is made on a nonzero
1781 * value and the nonnegative integer bitlen(TA) + bitlen(TB) decreases
1782 * by at least 1, or the right-shift by 1 is made on zero and then
1783 * TA becomes 0 which ends the loop (TB cannot be 0 if it is right-shifted
1784 * since in that case TB is calculated from TB-TA with the condition TB>TA).
1785 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001786 while (mbedtls_mpi_cmp_int(&TA, 0) != 0) {
Gilles Peskine2a63c5b2021-06-16 13:42:04 +02001787 /* Divisions by 2 preserve the invariant (I). */
Gilles Peskine449bd832023-01-11 14:50:10 +01001788 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TA, mbedtls_mpi_lsb(&TA)));
1789 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TB, mbedtls_mpi_lsb(&TB)));
Paul Bakker5121ce52009-01-03 21:22:43 +00001790
Gilles Peskine2a63c5b2021-06-16 13:42:04 +02001791 /* Set either TA or TB to |TA-TB|/2. Since TA and TB are both odd,
1792 * TA-TB is even so the division by 2 has an integer result.
1793 * Invariant (I) is preserved since any odd divisor of both TA and TB
1794 * also divides |TA-TB|/2, and any odd divisor of both TA and |TA-TB|/2
Shaun Case8b0ecbc2021-12-20 21:14:10 -08001795 * also divides TB, and any odd divisor of both TB and |TA-TB|/2 also
Gilles Peskine2a63c5b2021-06-16 13:42:04 +02001796 * divides TA.
1797 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001798 if (mbedtls_mpi_cmp_mpi(&TA, &TB) >= 0) {
1799 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_abs(&TA, &TA, &TB));
1800 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TA, 1));
1801 } else {
1802 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_abs(&TB, &TB, &TA));
1803 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TB, 1));
Paul Bakker5121ce52009-01-03 21:22:43 +00001804 }
Gilles Peskine2a63c5b2021-06-16 13:42:04 +02001805 /* Note that one of TA or TB is still odd. */
Paul Bakker5121ce52009-01-03 21:22:43 +00001806 }
1807
Gilles Peskine2a63c5b2021-06-16 13:42:04 +02001808 /* By invariant (I), gcd(A,B) = 2^k * gcd(TA,TB) for some k.
1809 * At the loop exit, TA = 0, so gcd(TA,TB) = TB.
1810 * - If there was at least one loop iteration, then one of TA or TB is odd,
1811 * and TA = 0, so TB is odd and gcd(TA,TB) = gcd(A',B'). In this case,
1812 * lz = min(a,b) so gcd(A,B) = 2^lz * TB.
1813 * - If there was no loop iteration, then A was 0, and gcd(A,B) = B.
Gilles Peskine4d3fd362021-06-21 11:40:38 +02001814 * 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 +02001815 */
1816
Gilles Peskine449bd832023-01-11 14:50:10 +01001817 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&TB, lz));
1818 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(G, &TB));
Paul Bakker5121ce52009-01-03 21:22:43 +00001819
1820cleanup:
1821
Gilles Peskine449bd832023-01-11 14:50:10 +01001822 mbedtls_mpi_free(&TA); mbedtls_mpi_free(&TB);
Paul Bakker5121ce52009-01-03 21:22:43 +00001823
Gilles Peskine449bd832023-01-11 14:50:10 +01001824 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001825}
1826
Paul Bakker33dc46b2014-04-30 16:11:39 +02001827/*
1828 * Fill X with size bytes of random.
Gilles Peskine22cdd0c2022-10-27 20:15:13 +02001829 * The bytes returned from the RNG are used in a specific order which
1830 * is suitable for deterministic ECDSA (see the specification of
1831 * mbedtls_mpi_random() and the implementation in mbedtls_mpi_fill_random()).
Paul Bakker33dc46b2014-04-30 16:11:39 +02001832 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001833int mbedtls_mpi_fill_random(mbedtls_mpi *X, size_t size,
1834 int (*f_rng)(void *, unsigned char *, size_t),
1835 void *p_rng)
Paul Bakker287781a2011-03-26 13:18:49 +00001836{
Janos Follath24eed8d2019-11-22 13:21:35 +00001837 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Gilles Peskine449bd832023-01-11 14:50:10 +01001838 const size_t limbs = CHARS_TO_LIMBS(size);
Hanno Beckerda1655a2017-10-18 14:21:44 +01001839
Hanno Beckerda1655a2017-10-18 14:21:44 +01001840 /* Ensure that target MPI has exactly the necessary number of limbs */
Gilles Peskine449bd832023-01-11 14:50:10 +01001841 MBEDTLS_MPI_CHK(mbedtls_mpi_resize_clear(X, limbs));
1842 if (size == 0) {
1843 return 0;
1844 }
Paul Bakker287781a2011-03-26 13:18:49 +00001845
Gilles Peskine449bd832023-01-11 14:50:10 +01001846 ret = mbedtls_mpi_core_fill_random(X->p, X->n, size, f_rng, p_rng);
Paul Bakker287781a2011-03-26 13:18:49 +00001847
1848cleanup:
Gilles Peskine449bd832023-01-11 14:50:10 +01001849 return ret;
Paul Bakker287781a2011-03-26 13:18:49 +00001850}
1851
Gilles Peskine449bd832023-01-11 14:50:10 +01001852int mbedtls_mpi_random(mbedtls_mpi *X,
1853 mbedtls_mpi_sint min,
1854 const mbedtls_mpi *N,
1855 int (*f_rng)(void *, unsigned char *, size_t),
1856 void *p_rng)
Gilles Peskine02ac93a2021-03-29 22:02:55 +02001857{
Gilles Peskine449bd832023-01-11 14:50:10 +01001858 if (min < 0) {
1859 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
1860 }
1861 if (mbedtls_mpi_cmp_int(N, min) <= 0) {
1862 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
1863 }
Gilles Peskine1e918f42021-03-29 22:14:51 +02001864
Gilles Peskine1a7df4e2021-04-01 15:57:18 +02001865 /* Ensure that target MPI has exactly the same number of limbs
1866 * as the upper bound, even if the upper bound has leading zeros.
Gilles Peskine6b7ce962022-12-15 15:04:33 +01001867 * This is necessary for mbedtls_mpi_core_random. */
Gilles Peskine449bd832023-01-11 14:50:10 +01001868 int ret = mbedtls_mpi_resize_clear(X, N->n);
1869 if (ret != 0) {
1870 return ret;
1871 }
Gilles Peskine1a7df4e2021-04-01 15:57:18 +02001872
Gilles Peskine449bd832023-01-11 14:50:10 +01001873 return mbedtls_mpi_core_random(X->p, min, N->p, X->n, f_rng, p_rng);
Gilles Peskine02ac93a2021-03-29 22:02:55 +02001874}
1875
Paul Bakker5121ce52009-01-03 21:22:43 +00001876/*
1877 * Modular inverse: X = A^-1 mod N (HAC 14.61 / 14.64)
1878 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001879int mbedtls_mpi_inv_mod(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *N)
Paul Bakker5121ce52009-01-03 21:22:43 +00001880{
Janos Follath24eed8d2019-11-22 13:21:35 +00001881 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001882 mbedtls_mpi G, TA, TU, U1, U2, TB, TV, V1, V2;
Paul Bakker5121ce52009-01-03 21:22:43 +00001883
Gilles Peskine449bd832023-01-11 14:50:10 +01001884 if (mbedtls_mpi_cmp_int(N, 1) <= 0) {
1885 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
1886 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001887
Gilles Peskine449bd832023-01-11 14:50:10 +01001888 mbedtls_mpi_init(&TA); mbedtls_mpi_init(&TU); mbedtls_mpi_init(&U1); mbedtls_mpi_init(&U2);
1889 mbedtls_mpi_init(&G); mbedtls_mpi_init(&TB); mbedtls_mpi_init(&TV);
1890 mbedtls_mpi_init(&V1); mbedtls_mpi_init(&V2);
Paul Bakker5121ce52009-01-03 21:22:43 +00001891
Gilles Peskine449bd832023-01-11 14:50:10 +01001892 MBEDTLS_MPI_CHK(mbedtls_mpi_gcd(&G, A, N));
Paul Bakker5121ce52009-01-03 21:22:43 +00001893
Gilles Peskine449bd832023-01-11 14:50:10 +01001894 if (mbedtls_mpi_cmp_int(&G, 1) != 0) {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001895 ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
Paul Bakker5121ce52009-01-03 21:22:43 +00001896 goto cleanup;
1897 }
1898
Gilles Peskine449bd832023-01-11 14:50:10 +01001899 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&TA, A, N));
1900 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TU, &TA));
1901 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TB, N));
1902 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TV, N));
Paul Bakker5121ce52009-01-03 21:22:43 +00001903
Gilles Peskine449bd832023-01-11 14:50:10 +01001904 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&U1, 1));
1905 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&U2, 0));
1906 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&V1, 0));
1907 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&V2, 1));
Paul Bakker5121ce52009-01-03 21:22:43 +00001908
Gilles Peskine449bd832023-01-11 14:50:10 +01001909 do {
1910 while ((TU.p[0] & 1) == 0) {
1911 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TU, 1));
Paul Bakker5121ce52009-01-03 21:22:43 +00001912
Gilles Peskine449bd832023-01-11 14:50:10 +01001913 if ((U1.p[0] & 1) != 0 || (U2.p[0] & 1) != 0) {
1914 MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&U1, &U1, &TB));
1915 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&U2, &U2, &TA));
Paul Bakker5121ce52009-01-03 21:22:43 +00001916 }
1917
Gilles Peskine449bd832023-01-11 14:50:10 +01001918 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&U1, 1));
1919 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&U2, 1));
Paul Bakker5121ce52009-01-03 21:22:43 +00001920 }
1921
Gilles Peskine449bd832023-01-11 14:50:10 +01001922 while ((TV.p[0] & 1) == 0) {
1923 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TV, 1));
Paul Bakker5121ce52009-01-03 21:22:43 +00001924
Gilles Peskine449bd832023-01-11 14:50:10 +01001925 if ((V1.p[0] & 1) != 0 || (V2.p[0] & 1) != 0) {
1926 MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&V1, &V1, &TB));
1927 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&V2, &V2, &TA));
Paul Bakker5121ce52009-01-03 21:22:43 +00001928 }
1929
Gilles Peskine449bd832023-01-11 14:50:10 +01001930 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&V1, 1));
1931 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&V2, 1));
Paul Bakker5121ce52009-01-03 21:22:43 +00001932 }
1933
Gilles Peskine449bd832023-01-11 14:50:10 +01001934 if (mbedtls_mpi_cmp_mpi(&TU, &TV) >= 0) {
1935 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&TU, &TU, &TV));
1936 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&U1, &U1, &V1));
1937 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&U2, &U2, &V2));
1938 } else {
1939 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&TV, &TV, &TU));
1940 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&V1, &V1, &U1));
1941 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&V2, &V2, &U2));
Paul Bakker5121ce52009-01-03 21:22:43 +00001942 }
Gilles Peskine449bd832023-01-11 14:50:10 +01001943 } while (mbedtls_mpi_cmp_int(&TU, 0) != 0);
1944
1945 while (mbedtls_mpi_cmp_int(&V1, 0) < 0) {
1946 MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&V1, &V1, N));
Paul Bakker5121ce52009-01-03 21:22:43 +00001947 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001948
Gilles Peskine449bd832023-01-11 14:50:10 +01001949 while (mbedtls_mpi_cmp_mpi(&V1, N) >= 0) {
1950 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&V1, &V1, N));
1951 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001952
Gilles Peskine449bd832023-01-11 14:50:10 +01001953 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(X, &V1));
Paul Bakker5121ce52009-01-03 21:22:43 +00001954
1955cleanup:
1956
Gilles Peskine449bd832023-01-11 14:50:10 +01001957 mbedtls_mpi_free(&TA); mbedtls_mpi_free(&TU); mbedtls_mpi_free(&U1); mbedtls_mpi_free(&U2);
1958 mbedtls_mpi_free(&G); mbedtls_mpi_free(&TB); mbedtls_mpi_free(&TV);
1959 mbedtls_mpi_free(&V1); mbedtls_mpi_free(&V2);
Paul Bakker5121ce52009-01-03 21:22:43 +00001960
Gilles Peskine449bd832023-01-11 14:50:10 +01001961 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001962}
1963
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001964#if defined(MBEDTLS_GENPRIME)
Paul Bakkerd9374b02012-11-02 11:02:58 +00001965
Gilles Peskineb2bc1712019-02-08 17:27:11 +01001966/* Gaps between primes, starting at 3. https://oeis.org/A001223 */
1967static const unsigned char small_prime_gaps[] = {
1968 2, 2, 4, 2, 4, 2, 4, 6,
1969 2, 6, 4, 2, 4, 6, 6, 2,
1970 6, 4, 2, 6, 4, 6, 8, 4,
1971 2, 4, 2, 4, 14, 4, 6, 2,
1972 10, 2, 6, 6, 4, 6, 6, 2,
1973 10, 2, 4, 2, 12, 12, 4, 2,
1974 4, 6, 2, 10, 6, 6, 6, 2,
1975 6, 4, 2, 10, 14, 4, 2, 4,
1976 14, 6, 10, 2, 4, 6, 8, 6,
1977 6, 4, 6, 8, 4, 8, 10, 2,
1978 10, 2, 6, 4, 6, 8, 4, 2,
1979 4, 12, 8, 4, 8, 4, 6, 12,
1980 2, 18, 6, 10, 6, 6, 2, 6,
1981 10, 6, 6, 2, 6, 6, 4, 2,
1982 12, 10, 2, 4, 6, 6, 2, 12,
1983 4, 6, 8, 10, 8, 10, 8, 6,
1984 6, 4, 8, 6, 4, 8, 4, 14,
1985 10, 12, 2, 10, 2, 4, 2, 10,
1986 14, 4, 2, 4, 14, 4, 2, 4,
1987 20, 4, 8, 10, 8, 4, 6, 6,
1988 14, 4, 6, 6, 8, 6, /*reaches 997*/
Gilles Peskine30b03782023-08-22 11:06:47 +02001989 0 /* the last entry is effectively unused */
Paul Bakker5121ce52009-01-03 21:22:43 +00001990};
1991
1992/*
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01001993 * Small divisors test (X must be positive)
1994 *
1995 * Return values:
1996 * 0: no small factor (possible prime, more tests needed)
1997 * 1: certain prime
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001998 * MBEDTLS_ERR_MPI_NOT_ACCEPTABLE: certain non-prime
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01001999 * other negative: error
Paul Bakker5121ce52009-01-03 21:22:43 +00002000 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002001static int mpi_check_small_factors(const mbedtls_mpi *X)
Paul Bakker5121ce52009-01-03 21:22:43 +00002002{
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002003 int ret = 0;
2004 size_t i;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002005 mbedtls_mpi_uint r;
Gilles Peskineb2bc1712019-02-08 17:27:11 +01002006 unsigned p = 3; /* The first odd prime */
Paul Bakker5121ce52009-01-03 21:22:43 +00002007
Gilles Peskine449bd832023-01-11 14:50:10 +01002008 if ((X->p[0] & 1) == 0) {
2009 return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2010 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002011
Gilles Peskineb2bc1712019-02-08 17:27:11 +01002012 for (i = 0; i < sizeof(small_prime_gaps); p += small_prime_gaps[i], i++) {
2013 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_int(&r, X, p));
Gilles Peskine449bd832023-01-11 14:50:10 +01002014 if (r == 0) {
Gilles Peskineb2bc1712019-02-08 17:27:11 +01002015 if (mbedtls_mpi_cmp_int(X, p) == 0) {
2016 return 1;
2017 } else {
2018 return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2019 }
Gilles Peskine449bd832023-01-11 14:50:10 +01002020 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002021 }
2022
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002023cleanup:
Gilles Peskine449bd832023-01-11 14:50:10 +01002024 return ret;
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002025}
2026
2027/*
2028 * Miller-Rabin pseudo-primality test (HAC 4.24)
2029 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002030static int mpi_miller_rabin(const mbedtls_mpi *X, size_t rounds,
2031 int (*f_rng)(void *, unsigned char *, size_t),
2032 void *p_rng)
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002033{
Pascal Junodb99183d2015-03-11 16:49:45 +01002034 int ret, count;
Janos Follathda31fa12018-09-03 14:45:23 +01002035 size_t i, j, k, s;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002036 mbedtls_mpi W, R, T, A, RR;
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002037
Gilles Peskine449bd832023-01-11 14:50:10 +01002038 mbedtls_mpi_init(&W); mbedtls_mpi_init(&R);
2039 mbedtls_mpi_init(&T); mbedtls_mpi_init(&A);
2040 mbedtls_mpi_init(&RR);
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002041
Paul Bakker5121ce52009-01-03 21:22:43 +00002042 /*
2043 * W = |X| - 1
2044 * R = W >> lsb( W )
2045 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002046 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(&W, X, 1));
2047 s = mbedtls_mpi_lsb(&W);
2048 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&R, &W));
2049 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&R, s));
Paul Bakker5121ce52009-01-03 21:22:43 +00002050
Gilles Peskine449bd832023-01-11 14:50:10 +01002051 for (i = 0; i < rounds; i++) {
Paul Bakker5121ce52009-01-03 21:22:43 +00002052 /*
2053 * pick a random A, 1 < A < |X| - 1
2054 */
Pascal Junodb99183d2015-03-11 16:49:45 +01002055 count = 0;
2056 do {
Gilles Peskine449bd832023-01-11 14:50:10 +01002057 MBEDTLS_MPI_CHK(mbedtls_mpi_fill_random(&A, X->n * ciL, f_rng, p_rng));
Pascal Junodb99183d2015-03-11 16:49:45 +01002058
Gilles Peskine449bd832023-01-11 14:50:10 +01002059 j = mbedtls_mpi_bitlen(&A);
2060 k = mbedtls_mpi_bitlen(&W);
Pascal Junodb99183d2015-03-11 16:49:45 +01002061 if (j > k) {
Gilles Peskine449bd832023-01-11 14:50:10 +01002062 A.p[A.n - 1] &= ((mbedtls_mpi_uint) 1 << (k - (A.n - 1) * biL - 1)) - 1;
Pascal Junodb99183d2015-03-11 16:49:45 +01002063 }
2064
2065 if (count++ > 30) {
Jens Wiklanderf08aa3e2019-01-17 13:30:57 +01002066 ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2067 goto cleanup;
Pascal Junodb99183d2015-03-11 16:49:45 +01002068 }
2069
Gilles Peskine449bd832023-01-11 14:50:10 +01002070 } while (mbedtls_mpi_cmp_mpi(&A, &W) >= 0 ||
2071 mbedtls_mpi_cmp_int(&A, 1) <= 0);
Paul Bakker5121ce52009-01-03 21:22:43 +00002072
2073 /*
2074 * A = A^R mod |X|
2075 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002076 MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&A, &A, &R, X, &RR));
Paul Bakker5121ce52009-01-03 21:22:43 +00002077
Gilles Peskine449bd832023-01-11 14:50:10 +01002078 if (mbedtls_mpi_cmp_mpi(&A, &W) == 0 ||
2079 mbedtls_mpi_cmp_int(&A, 1) == 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00002080 continue;
Gilles Peskine449bd832023-01-11 14:50:10 +01002081 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002082
2083 j = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +01002084 while (j < s && mbedtls_mpi_cmp_mpi(&A, &W) != 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00002085 /*
2086 * A = A * A mod |X|
2087 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002088 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&T, &A, &A));
2089 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&A, &T, X));
Paul Bakker5121ce52009-01-03 21:22:43 +00002090
Gilles Peskine449bd832023-01-11 14:50:10 +01002091 if (mbedtls_mpi_cmp_int(&A, 1) == 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00002092 break;
Gilles Peskine449bd832023-01-11 14:50:10 +01002093 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002094
2095 j++;
2096 }
2097
2098 /*
2099 * not prime if A != |X| - 1 or A == 1
2100 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002101 if (mbedtls_mpi_cmp_mpi(&A, &W) != 0 ||
2102 mbedtls_mpi_cmp_int(&A, 1) == 0) {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002103 ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
Paul Bakker5121ce52009-01-03 21:22:43 +00002104 break;
2105 }
2106 }
2107
2108cleanup:
Gilles Peskine449bd832023-01-11 14:50:10 +01002109 mbedtls_mpi_free(&W); mbedtls_mpi_free(&R);
2110 mbedtls_mpi_free(&T); mbedtls_mpi_free(&A);
2111 mbedtls_mpi_free(&RR);
Paul Bakker5121ce52009-01-03 21:22:43 +00002112
Gilles Peskine449bd832023-01-11 14:50:10 +01002113 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00002114}
2115
2116/*
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002117 * Pseudo-primality test: small factors, then Miller-Rabin
2118 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002119int mbedtls_mpi_is_prime_ext(const mbedtls_mpi *X, int rounds,
2120 int (*f_rng)(void *, unsigned char *, size_t),
2121 void *p_rng)
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002122{
Janos Follath24eed8d2019-11-22 13:21:35 +00002123 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002124 mbedtls_mpi XX;
Manuel Pégourié-Gonnard7f4ed672014-10-14 20:56:02 +02002125
2126 XX.s = 1;
2127 XX.n = X->n;
2128 XX.p = X->p;
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002129
Gilles Peskine449bd832023-01-11 14:50:10 +01002130 if (mbedtls_mpi_cmp_int(&XX, 0) == 0 ||
2131 mbedtls_mpi_cmp_int(&XX, 1) == 0) {
2132 return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002133 }
2134
Gilles Peskine449bd832023-01-11 14:50:10 +01002135 if (mbedtls_mpi_cmp_int(&XX, 2) == 0) {
2136 return 0;
2137 }
2138
2139 if ((ret = mpi_check_small_factors(&XX)) != 0) {
2140 if (ret == 1) {
2141 return 0;
2142 }
2143
2144 return ret;
2145 }
2146
2147 return mpi_miller_rabin(&XX, rounds, f_rng, p_rng);
Janos Follathf301d232018-08-14 13:34:01 +01002148}
2149
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002150/*
Paul Bakker5121ce52009-01-03 21:22:43 +00002151 * Prime number generation
Jethro Beekman66689272018-02-14 19:24:10 -08002152 *
Janos Follathf301d232018-08-14 13:34:01 +01002153 * To generate an RSA key in a way recommended by FIPS 186-4, both primes must
2154 * be either 1024 bits or 1536 bits long, and flags must contain
2155 * MBEDTLS_MPI_GEN_PRIME_FLAG_LOW_ERR.
Paul Bakker5121ce52009-01-03 21:22:43 +00002156 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002157int mbedtls_mpi_gen_prime(mbedtls_mpi *X, size_t nbits, int flags,
2158 int (*f_rng)(void *, unsigned char *, size_t),
2159 void *p_rng)
Paul Bakker5121ce52009-01-03 21:22:43 +00002160{
Jethro Beekman66689272018-02-14 19:24:10 -08002161#ifdef MBEDTLS_HAVE_INT64
2162// ceil(2^63.5)
2163#define CEIL_MAXUINT_DIV_SQRT2 0xb504f333f9de6485ULL
2164#else
2165// ceil(2^31.5)
2166#define CEIL_MAXUINT_DIV_SQRT2 0xb504f334U
2167#endif
2168 int ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
Paul Bakker23986e52011-04-24 08:57:21 +00002169 size_t k, n;
Janos Follathda31fa12018-09-03 14:45:23 +01002170 int rounds;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002171 mbedtls_mpi_uint r;
2172 mbedtls_mpi Y;
Paul Bakker5121ce52009-01-03 21:22:43 +00002173
Gilles Peskine449bd832023-01-11 14:50:10 +01002174 if (nbits < 3 || nbits > MBEDTLS_MPI_MAX_BITS) {
2175 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
2176 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002177
Gilles Peskine449bd832023-01-11 14:50:10 +01002178 mbedtls_mpi_init(&Y);
Paul Bakker5121ce52009-01-03 21:22:43 +00002179
Gilles Peskine449bd832023-01-11 14:50:10 +01002180 n = BITS_TO_LIMBS(nbits);
Paul Bakker5121ce52009-01-03 21:22:43 +00002181
Gilles Peskine449bd832023-01-11 14:50:10 +01002182 if ((flags & MBEDTLS_MPI_GEN_PRIME_FLAG_LOW_ERR) == 0) {
Janos Follathda31fa12018-09-03 14:45:23 +01002183 /*
2184 * 2^-80 error probability, number of rounds chosen per HAC, table 4.4
2185 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002186 rounds = ((nbits >= 1300) ? 2 : (nbits >= 850) ? 3 :
2187 (nbits >= 650) ? 4 : (nbits >= 350) ? 8 :
2188 (nbits >= 250) ? 12 : (nbits >= 150) ? 18 : 27);
2189 } else {
Janos Follathda31fa12018-09-03 14:45:23 +01002190 /*
2191 * 2^-100 error probability, number of rounds computed based on HAC,
2192 * fact 4.48
2193 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002194 rounds = ((nbits >= 1450) ? 4 : (nbits >= 1150) ? 5 :
2195 (nbits >= 1000) ? 6 : (nbits >= 850) ? 7 :
2196 (nbits >= 750) ? 8 : (nbits >= 500) ? 13 :
2197 (nbits >= 250) ? 28 : (nbits >= 150) ? 40 : 51);
Janos Follathda31fa12018-09-03 14:45:23 +01002198 }
2199
Gilles Peskine449bd832023-01-11 14:50:10 +01002200 while (1) {
2201 MBEDTLS_MPI_CHK(mbedtls_mpi_fill_random(X, n * ciL, f_rng, p_rng));
Jethro Beekman66689272018-02-14 19:24:10 -08002202 /* 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 +01002203 if (X->p[n-1] < CEIL_MAXUINT_DIV_SQRT2) {
2204 continue;
2205 }
Jethro Beekman66689272018-02-14 19:24:10 -08002206
2207 k = n * biL;
Gilles Peskine449bd832023-01-11 14:50:10 +01002208 if (k > nbits) {
2209 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(X, k - nbits));
2210 }
Jethro Beekman66689272018-02-14 19:24:10 -08002211 X->p[0] |= 1;
2212
Gilles Peskine449bd832023-01-11 14:50:10 +01002213 if ((flags & MBEDTLS_MPI_GEN_PRIME_FLAG_DH) == 0) {
2214 ret = mbedtls_mpi_is_prime_ext(X, rounds, f_rng, p_rng);
Jethro Beekman66689272018-02-14 19:24:10 -08002215
Gilles Peskine449bd832023-01-11 14:50:10 +01002216 if (ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE) {
Paul Bakker5121ce52009-01-03 21:22:43 +00002217 goto cleanup;
Gilles Peskine449bd832023-01-11 14:50:10 +01002218 }
2219 } else {
Manuel Pégourié-Gonnardddf76152013-11-22 19:58:22 +01002220 /*
Tom Cosgrovece7f18c2022-07-28 05:50:56 +01002221 * A necessary condition for Y and X = 2Y + 1 to be prime
Jethro Beekman66689272018-02-14 19:24:10 -08002222 * is X = 2 mod 3 (which is equivalent to Y = 2 mod 3).
2223 * Make sure it is satisfied, while keeping X = 3 mod 4
Manuel Pégourié-Gonnardddf76152013-11-22 19:58:22 +01002224 */
Jethro Beekman66689272018-02-14 19:24:10 -08002225
2226 X->p[0] |= 2;
2227
Gilles Peskine449bd832023-01-11 14:50:10 +01002228 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_int(&r, X, 3));
2229 if (r == 0) {
2230 MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(X, X, 8));
2231 } else if (r == 1) {
2232 MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(X, X, 4));
2233 }
Jethro Beekman66689272018-02-14 19:24:10 -08002234
2235 /* Set Y = (X-1) / 2, which is X / 2 because X is odd */
Gilles Peskine449bd832023-01-11 14:50:10 +01002236 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&Y, X));
2237 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&Y, 1));
Jethro Beekman66689272018-02-14 19:24:10 -08002238
Gilles Peskine449bd832023-01-11 14:50:10 +01002239 while (1) {
Jethro Beekman66689272018-02-14 19:24:10 -08002240 /*
2241 * First, check small factors for X and Y
2242 * before doing Miller-Rabin on any of them
2243 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002244 if ((ret = mpi_check_small_factors(X)) == 0 &&
2245 (ret = mpi_check_small_factors(&Y)) == 0 &&
2246 (ret = mpi_miller_rabin(X, rounds, f_rng, p_rng))
2247 == 0 &&
2248 (ret = mpi_miller_rabin(&Y, rounds, f_rng, p_rng))
2249 == 0) {
Jethro Beekman66689272018-02-14 19:24:10 -08002250 goto cleanup;
Gilles Peskine449bd832023-01-11 14:50:10 +01002251 }
Jethro Beekman66689272018-02-14 19:24:10 -08002252
Gilles Peskine449bd832023-01-11 14:50:10 +01002253 if (ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE) {
Jethro Beekman66689272018-02-14 19:24:10 -08002254 goto cleanup;
Gilles Peskine449bd832023-01-11 14:50:10 +01002255 }
Jethro Beekman66689272018-02-14 19:24:10 -08002256
2257 /*
2258 * Next candidates. We want to preserve Y = (X-1) / 2 and
2259 * Y = 1 mod 2 and Y = 2 mod 3 (eq X = 3 mod 4 and X = 2 mod 3)
2260 * so up Y by 6 and X by 12.
2261 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002262 MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(X, X, 12));
2263 MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(&Y, &Y, 6));
Paul Bakker5121ce52009-01-03 21:22:43 +00002264 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002265 }
2266 }
2267
2268cleanup:
2269
Gilles Peskine449bd832023-01-11 14:50:10 +01002270 mbedtls_mpi_free(&Y);
Paul Bakker5121ce52009-01-03 21:22:43 +00002271
Gilles Peskine449bd832023-01-11 14:50:10 +01002272 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00002273}
2274
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002275#endif /* MBEDTLS_GENPRIME */
Paul Bakker5121ce52009-01-03 21:22:43 +00002276
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002277#if defined(MBEDTLS_SELF_TEST)
Paul Bakker5121ce52009-01-03 21:22:43 +00002278
Paul Bakker23986e52011-04-24 08:57:21 +00002279#define GCD_PAIR_COUNT 3
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002280
2281static const int gcd_pairs[GCD_PAIR_COUNT][3] =
2282{
2283 { 693, 609, 21 },
2284 { 1764, 868, 28 },
2285 { 768454923, 542167814, 1 }
2286};
2287
Paul Bakker5121ce52009-01-03 21:22:43 +00002288/*
2289 * Checkup routine
2290 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002291int mbedtls_mpi_self_test(int verbose)
Paul Bakker5121ce52009-01-03 21:22:43 +00002292{
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002293 int ret, i;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002294 mbedtls_mpi A, E, N, X, Y, U, V;
Paul Bakker5121ce52009-01-03 21:22:43 +00002295
Gilles Peskine449bd832023-01-11 14:50:10 +01002296 mbedtls_mpi_init(&A); mbedtls_mpi_init(&E); mbedtls_mpi_init(&N); mbedtls_mpi_init(&X);
2297 mbedtls_mpi_init(&Y); mbedtls_mpi_init(&U); mbedtls_mpi_init(&V);
Paul Bakker5121ce52009-01-03 21:22:43 +00002298
Gilles Peskine449bd832023-01-11 14:50:10 +01002299 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&A, 16,
2300 "EFE021C2645FD1DC586E69184AF4A31E" \
2301 "D5F53E93B5F123FA41680867BA110131" \
2302 "944FE7952E2517337780CB0DB80E61AA" \
2303 "E7C8DDC6C5C6AADEB34EB38A2F40D5E6"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002304
Gilles Peskine449bd832023-01-11 14:50:10 +01002305 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&E, 16,
2306 "B2E7EFD37075B9F03FF989C7C5051C20" \
2307 "34D2A323810251127E7BF8625A4F49A5" \
2308 "F3E27F4DA8BD59C47D6DAABA4C8127BD" \
2309 "5B5C25763222FEFCCFC38B832366C29E"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002310
Gilles Peskine449bd832023-01-11 14:50:10 +01002311 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&N, 16,
2312 "0066A198186C18C10B2F5ED9B522752A" \
2313 "9830B69916E535C8F047518A889A43A5" \
2314 "94B6BED27A168D31D4A52F88925AA8F5"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002315
Gilles Peskine449bd832023-01-11 14:50:10 +01002316 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&X, &A, &N));
Paul Bakker5121ce52009-01-03 21:22:43 +00002317
Gilles Peskine449bd832023-01-11 14:50:10 +01002318 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&U, 16,
2319 "602AB7ECA597A3D6B56FF9829A5E8B85" \
2320 "9E857EA95A03512E2BAE7391688D264A" \
2321 "A5663B0341DB9CCFD2C4C5F421FEC814" \
2322 "8001B72E848A38CAE1C65F78E56ABDEF" \
2323 "E12D3C039B8A02D6BE593F0BBBDA56F1" \
2324 "ECF677152EF804370C1A305CAF3B5BF1" \
2325 "30879B56C61DE584A0F53A2447A51E"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002326
Gilles Peskine449bd832023-01-11 14:50:10 +01002327 if (verbose != 0) {
2328 mbedtls_printf(" MPI test #1 (mul_mpi): ");
2329 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002330
Gilles Peskine449bd832023-01-11 14:50:10 +01002331 if (mbedtls_mpi_cmp_mpi(&X, &U) != 0) {
2332 if (verbose != 0) {
2333 mbedtls_printf("failed\n");
2334 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002335
Manuel Pégourié-Gonnard9e987ed2014-01-20 10:03:15 +01002336 ret = 1;
2337 goto cleanup;
Paul Bakker5121ce52009-01-03 21:22:43 +00002338 }
2339
Gilles Peskine449bd832023-01-11 14:50:10 +01002340 if (verbose != 0) {
2341 mbedtls_printf("passed\n");
2342 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002343
Gilles Peskine449bd832023-01-11 14:50:10 +01002344 MBEDTLS_MPI_CHK(mbedtls_mpi_div_mpi(&X, &Y, &A, &N));
Paul Bakker5121ce52009-01-03 21:22:43 +00002345
Gilles Peskine449bd832023-01-11 14:50:10 +01002346 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&U, 16,
2347 "256567336059E52CAE22925474705F39A94"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002348
Gilles Peskine449bd832023-01-11 14:50:10 +01002349 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&V, 16,
2350 "6613F26162223DF488E9CD48CC132C7A" \
2351 "0AC93C701B001B092E4E5B9F73BCD27B" \
2352 "9EE50D0657C77F374E903CDFA4C642"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002353
Gilles Peskine449bd832023-01-11 14:50:10 +01002354 if (verbose != 0) {
2355 mbedtls_printf(" MPI test #2 (div_mpi): ");
2356 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002357
Gilles Peskine449bd832023-01-11 14:50:10 +01002358 if (mbedtls_mpi_cmp_mpi(&X, &U) != 0 ||
2359 mbedtls_mpi_cmp_mpi(&Y, &V) != 0) {
2360 if (verbose != 0) {
2361 mbedtls_printf("failed\n");
2362 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002363
Manuel Pégourié-Gonnard9e987ed2014-01-20 10:03:15 +01002364 ret = 1;
2365 goto cleanup;
Paul Bakker5121ce52009-01-03 21:22:43 +00002366 }
2367
Gilles Peskine449bd832023-01-11 14:50:10 +01002368 if (verbose != 0) {
2369 mbedtls_printf("passed\n");
2370 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002371
Gilles Peskine449bd832023-01-11 14:50:10 +01002372 MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&X, &A, &E, &N, NULL));
Paul Bakker5121ce52009-01-03 21:22:43 +00002373
Gilles Peskine449bd832023-01-11 14:50:10 +01002374 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&U, 16,
2375 "36E139AEA55215609D2816998ED020BB" \
2376 "BD96C37890F65171D948E9BC7CBAA4D9" \
2377 "325D24D6A3C12710F10A09FA08AB87"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002378
Gilles Peskine449bd832023-01-11 14:50:10 +01002379 if (verbose != 0) {
2380 mbedtls_printf(" MPI test #3 (exp_mod): ");
2381 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002382
Gilles Peskine449bd832023-01-11 14:50:10 +01002383 if (mbedtls_mpi_cmp_mpi(&X, &U) != 0) {
2384 if (verbose != 0) {
2385 mbedtls_printf("failed\n");
2386 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002387
Manuel Pégourié-Gonnard9e987ed2014-01-20 10:03:15 +01002388 ret = 1;
2389 goto cleanup;
Paul Bakker5121ce52009-01-03 21:22:43 +00002390 }
2391
Gilles Peskine449bd832023-01-11 14:50:10 +01002392 if (verbose != 0) {
2393 mbedtls_printf("passed\n");
2394 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002395
Gilles Peskine449bd832023-01-11 14:50:10 +01002396 MBEDTLS_MPI_CHK(mbedtls_mpi_inv_mod(&X, &A, &N));
Paul Bakker5121ce52009-01-03 21:22:43 +00002397
Gilles Peskine449bd832023-01-11 14:50:10 +01002398 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&U, 16,
2399 "003A0AAEDD7E784FC07D8F9EC6E3BFD5" \
2400 "C3DBA76456363A10869622EAC2DD84EC" \
2401 "C5B8A74DAC4D09E03B5E0BE779F2DF61"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002402
Gilles Peskine449bd832023-01-11 14:50:10 +01002403 if (verbose != 0) {
2404 mbedtls_printf(" MPI test #4 (inv_mod): ");
2405 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002406
Gilles Peskine449bd832023-01-11 14:50:10 +01002407 if (mbedtls_mpi_cmp_mpi(&X, &U) != 0) {
2408 if (verbose != 0) {
2409 mbedtls_printf("failed\n");
2410 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002411
Manuel Pégourié-Gonnard9e987ed2014-01-20 10:03:15 +01002412 ret = 1;
2413 goto cleanup;
Paul Bakker5121ce52009-01-03 21:22:43 +00002414 }
2415
Gilles Peskine449bd832023-01-11 14:50:10 +01002416 if (verbose != 0) {
2417 mbedtls_printf("passed\n");
2418 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002419
Gilles Peskine449bd832023-01-11 14:50:10 +01002420 if (verbose != 0) {
2421 mbedtls_printf(" MPI test #5 (simple gcd): ");
2422 }
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002423
Gilles Peskine449bd832023-01-11 14:50:10 +01002424 for (i = 0; i < GCD_PAIR_COUNT; i++) {
2425 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&X, gcd_pairs[i][0]));
2426 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&Y, gcd_pairs[i][1]));
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002427
Gilles Peskine449bd832023-01-11 14:50:10 +01002428 MBEDTLS_MPI_CHK(mbedtls_mpi_gcd(&A, &X, &Y));
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002429
Gilles Peskine449bd832023-01-11 14:50:10 +01002430 if (mbedtls_mpi_cmp_int(&A, gcd_pairs[i][2]) != 0) {
2431 if (verbose != 0) {
2432 mbedtls_printf("failed at %d\n", i);
2433 }
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002434
Manuel Pégourié-Gonnard9e987ed2014-01-20 10:03:15 +01002435 ret = 1;
2436 goto cleanup;
2437 }
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002438 }
2439
Gilles Peskine449bd832023-01-11 14:50:10 +01002440 if (verbose != 0) {
2441 mbedtls_printf("passed\n");
2442 }
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002443
Paul Bakker5121ce52009-01-03 21:22:43 +00002444cleanup:
2445
Gilles Peskine449bd832023-01-11 14:50:10 +01002446 if (ret != 0 && verbose != 0) {
2447 mbedtls_printf("Unexpected error, return code = %08X\n", (unsigned int) ret);
2448 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002449
Gilles Peskine449bd832023-01-11 14:50:10 +01002450 mbedtls_mpi_free(&A); mbedtls_mpi_free(&E); mbedtls_mpi_free(&N); mbedtls_mpi_free(&X);
2451 mbedtls_mpi_free(&Y); mbedtls_mpi_free(&U); mbedtls_mpi_free(&V);
Paul Bakker5121ce52009-01-03 21:22:43 +00002452
Gilles Peskine449bd832023-01-11 14:50:10 +01002453 if (verbose != 0) {
2454 mbedtls_printf("\n");
2455 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002456
Gilles Peskine449bd832023-01-11 14:50:10 +01002457 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00002458}
2459
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002460#endif /* MBEDTLS_SELF_TEST */
Paul Bakker5121ce52009-01-03 21:22:43 +00002461
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002462#endif /* MBEDTLS_BIGNUM_C */