blob: 7681982298ffcd24ece49fbe4a82d1b28de86207 [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
Dave Rodgman7d4f0192023-05-09 14:01:05 +010040/*
41 * Compare signed values in constant time
42 */
43int mbedtls_mpi_lt_mpi_ct(const mbedtls_mpi *X,
44 const mbedtls_mpi *Y,
45 unsigned *ret)
46{
Dave Rodgman1f39f032023-08-01 09:19:16 +010047 mbedtls_ct_condition_t different_sign, X_is_negative, Y_is_negative, result;
Dave Rodgman7d4f0192023-05-09 14:01:05 +010048
Dave Rodgman7d4f0192023-05-09 14:01:05 +010049 if (X->n != Y->n) {
50 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
51 }
52
53 /*
Dave Rodgmanb69239c2023-08-09 14:53:18 +010054 * Set N_is_negative to MBEDTLS_CT_FALSE if N >= 0, MBEDTLS_CT_TRUE if N < 0.
Dave Rodgman7d4f0192023-05-09 14:01:05 +010055 * We know that N->s == 1 if N >= 0 and N->s == -1 if N < 0.
56 */
Dave Rodgman1a7a5622023-05-17 13:47:56 +010057 X_is_negative = mbedtls_ct_bool((X->s & 2) >> 1);
58 Y_is_negative = mbedtls_ct_bool((Y->s & 2) >> 1);
Dave Rodgman7d4f0192023-05-09 14:01:05 +010059
60 /*
61 * If the signs are different, then the positive operand is the bigger.
62 * That is if X is negative (X_is_negative == 1), then X < Y is true and it
63 * is false if X is positive (X_is_negative == 0).
64 */
Dave Rodgman1cfc43c2023-09-19 16:18:59 +010065 different_sign = mbedtls_ct_bool_ne(X_is_negative, Y_is_negative); // true if different sign
Dave Rodgman1f39f032023-08-01 09:19:16 +010066 result = mbedtls_ct_bool_and(different_sign, X_is_negative);
Dave Rodgman7d4f0192023-05-09 14:01:05 +010067
Dave Rodgman32d72602023-07-31 12:28:05 +010068 /*
69 * Assuming signs are the same, compare X and Y. We switch the comparison
Dave Rodgman1a7a5622023-05-17 13:47:56 +010070 * order if they are negative so that we get the right result, regardles of
71 * sign.
Dave Rodgman7d4f0192023-05-09 14:01:05 +010072 */
Dave Rodgman7d4f0192023-05-09 14:01:05 +010073
Dave Rodgman32d72602023-07-31 12:28:05 +010074 /* This array is used to conditionally swap the pointers in const time */
Dave Rodgman1a7a5622023-05-17 13:47:56 +010075 void * const p[2] = { X->p, Y->p };
Dave Rodgman98ddc012023-08-10 12:11:31 +010076 size_t i = mbedtls_ct_size_if_else_0(X_is_negative, 1);
Dave Rodgman2c764842023-05-18 13:28:21 +010077 mbedtls_ct_condition_t lt = mbedtls_mpi_core_lt_ct(p[i], p[i ^ 1], X->n);
Dave Rodgman7d4f0192023-05-09 14:01:05 +010078
Dave Rodgman32d72602023-07-31 12:28:05 +010079 /*
Dave Rodgman1f39f032023-08-01 09:19:16 +010080 * Store in result iff the signs are the same (i.e., iff different_sign == false). If
Dave Rodgman32d72602023-07-31 12:28:05 +010081 * the signs differ, result has already been set, so we don't change it.
82 */
Dave Rodgman1f39f032023-08-01 09:19:16 +010083 result = mbedtls_ct_bool_or(result,
84 mbedtls_ct_bool_and(mbedtls_ct_bool_not(different_sign), lt));
Dave Rodgman1a7a5622023-05-17 13:47:56 +010085
Dave Rodgman98ddc012023-08-10 12:11:31 +010086 *ret = mbedtls_ct_uint_if_else_0(result, 1);
Dave Rodgman7d4f0192023-05-09 14:01:05 +010087
88 return 0;
89}
90
91/*
92 * Conditionally assign X = Y, without leaking information
93 * about whether the assignment was made or not.
94 * (Leaking information about the respective sizes of X and Y is ok however.)
95 */
Dave Rodgman0a487172023-09-15 11:52:06 +010096#if defined(_MSC_VER) && defined(MBEDTLS_PLATFORM_IS_WINDOWS_ON_ARM64) && \
97 (_MSC_FULL_VER < 193131103)
Dave Rodgman7d4f0192023-05-09 14:01:05 +010098/*
99 * MSVC miscompiles this function if it's inlined prior to Visual Studio 2022 version 17.1. See:
100 * https://developercommunity.visualstudio.com/t/c-compiler-miscompiles-part-of-mbedtls-library-on/1646989
101 */
102__declspec(noinline)
103#endif
104int mbedtls_mpi_safe_cond_assign(mbedtls_mpi *X,
105 const mbedtls_mpi *Y,
106 unsigned char assign)
107{
108 int ret = 0;
Dave Rodgman7d4f0192023-05-09 14:01:05 +0100109
Dave Rodgman7d4f0192023-05-09 14:01:05 +0100110 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, Y->n));
111
Dave Rodgman7e9af052023-09-28 17:08:16 +0100112 {
113 mbedtls_ct_condition_t do_assign = mbedtls_ct_bool(assign);
Dave Rodgman589ccb82023-05-17 13:55:01 +0100114
Dave Rodgman7e9af052023-09-28 17:08:16 +0100115 X->s = (int) mbedtls_ct_uint_if(do_assign, Y->s, X->s);
Dave Rodgman7d4f0192023-05-09 14:01:05 +0100116
Dave Rodgman7e9af052023-09-28 17:08:16 +0100117 mbedtls_mpi_core_cond_assign(X->p, Y->p, Y->n, do_assign);
Dave Rodgman7d4f0192023-05-09 14:01:05 +0100118
Dave Rodgman7e9af052023-09-28 17:08:16 +0100119 mbedtls_ct_condition_t do_not_assign = mbedtls_ct_bool_not(do_assign);
120 for (size_t i = Y->n; i < X->n; i++) {
121 X->p[i] = mbedtls_ct_mpi_uint_if_else_0(do_not_assign, X->p[i]);
122 }
Dave Rodgman7d4f0192023-05-09 14:01:05 +0100123 }
124
125cleanup:
126 return ret;
127}
128
129/*
130 * Conditionally swap X and Y, without leaking information
131 * about whether the swap was made or not.
132 * Here it is not ok to simply swap the pointers, which would lead to
133 * different memory access patterns when X and Y are used afterwards.
134 */
135int mbedtls_mpi_safe_cond_swap(mbedtls_mpi *X,
136 mbedtls_mpi *Y,
137 unsigned char swap)
138{
139 int ret = 0;
140 int s;
Dave Rodgman7d4f0192023-05-09 14:01:05 +0100141
142 if (X == Y) {
143 return 0;
144 }
145
Dave Rodgmancd2e38b2023-05-17 13:31:55 +0100146 mbedtls_ct_condition_t do_swap = mbedtls_ct_bool(swap);
147
Dave Rodgman7d4f0192023-05-09 14:01:05 +0100148 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, Y->n));
149 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(Y, X->n));
150
151 s = X->s;
Dave Rodgman2b4486a2023-05-17 15:51:59 +0100152 X->s = (int) mbedtls_ct_uint_if(do_swap, Y->s, X->s);
153 Y->s = (int) mbedtls_ct_uint_if(do_swap, s, Y->s);
Dave Rodgman7d4f0192023-05-09 14:01:05 +0100154
Dave Rodgmancd2e38b2023-05-17 13:31:55 +0100155 mbedtls_mpi_core_cond_swap(X->p, Y->p, X->n, do_swap);
Dave Rodgman7d4f0192023-05-09 14:01:05 +0100156
157cleanup:
158 return ret;
159}
160
Andres Amaya Garcia1f6301b2018-04-17 09:51:09 -0500161/* Implementation that should never be optimized out by the compiler */
Tom Cosgrovebc345e82023-07-25 15:17:39 +0100162#define mbedtls_mpi_zeroize_and_free(v, n) mbedtls_zeroize_and_free(v, ciL * (n))
Andres Amaya Garcia1f6301b2018-04-17 09:51:09 -0500163
Paul Bakker5121ce52009-01-03 21:22:43 +0000164/*
Paul Bakker6c591fa2011-05-05 11:49:20 +0000165 * Initialize one MPI
Paul Bakker5121ce52009-01-03 21:22:43 +0000166 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100167void mbedtls_mpi_init(mbedtls_mpi *X)
Paul Bakker5121ce52009-01-03 21:22:43 +0000168{
Paul Bakker6c591fa2011-05-05 11:49:20 +0000169 X->s = 1;
170 X->n = 0;
171 X->p = NULL;
Paul Bakker5121ce52009-01-03 21:22:43 +0000172}
173
174/*
Paul Bakker6c591fa2011-05-05 11:49:20 +0000175 * Unallocate one MPI
Paul Bakker5121ce52009-01-03 21:22:43 +0000176 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100177void mbedtls_mpi_free(mbedtls_mpi *X)
Paul Bakker5121ce52009-01-03 21:22:43 +0000178{
Gilles Peskine449bd832023-01-11 14:50:10 +0100179 if (X == NULL) {
Paul Bakker6c591fa2011-05-05 11:49:20 +0000180 return;
Gilles Peskine449bd832023-01-11 14:50:10 +0100181 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000182
Gilles Peskine449bd832023-01-11 14:50:10 +0100183 if (X->p != NULL) {
Tom Cosgrove46259f62023-07-18 16:44:14 +0100184 mbedtls_mpi_zeroize_and_free(X->p, X->n);
Paul Bakker5121ce52009-01-03 21:22:43 +0000185 }
186
Paul Bakker6c591fa2011-05-05 11:49:20 +0000187 X->s = 1;
188 X->n = 0;
189 X->p = NULL;
Paul Bakker5121ce52009-01-03 21:22:43 +0000190}
191
192/*
193 * Enlarge to the specified number of limbs
194 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100195int mbedtls_mpi_grow(mbedtls_mpi *X, size_t nblimbs)
Paul Bakker5121ce52009-01-03 21:22:43 +0000196{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200197 mbedtls_mpi_uint *p;
Paul Bakker5121ce52009-01-03 21:22:43 +0000198
Gilles Peskine449bd832023-01-11 14:50:10 +0100199 if (nblimbs > MBEDTLS_MPI_MAX_LIMBS) {
200 return MBEDTLS_ERR_MPI_ALLOC_FAILED;
201 }
Paul Bakkerf9688572011-05-05 10:00:45 +0000202
Gilles Peskine449bd832023-01-11 14:50:10 +0100203 if (X->n < nblimbs) {
204 if ((p = (mbedtls_mpi_uint *) mbedtls_calloc(nblimbs, ciL)) == NULL) {
205 return MBEDTLS_ERR_MPI_ALLOC_FAILED;
206 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000207
Gilles Peskine449bd832023-01-11 14:50:10 +0100208 if (X->p != NULL) {
209 memcpy(p, X->p, X->n * ciL);
Tom Cosgrove46259f62023-07-18 16:44:14 +0100210 mbedtls_mpi_zeroize_and_free(X->p, X->n);
Paul Bakker5121ce52009-01-03 21:22:43 +0000211 }
212
Gilles Peskine053022f2023-06-29 19:26:48 +0200213 /* nblimbs fits in n because we ensure that MBEDTLS_MPI_MAX_LIMBS
214 * fits, and we've checked that nblimbs <= MBEDTLS_MPI_MAX_LIMBS. */
215 X->n = (unsigned short) nblimbs;
Paul Bakker5121ce52009-01-03 21:22:43 +0000216 X->p = p;
217 }
218
Gilles Peskine449bd832023-01-11 14:50:10 +0100219 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000220}
221
222/*
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100223 * Resize down as much as possible,
224 * while keeping at least the specified number of limbs
225 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100226int mbedtls_mpi_shrink(mbedtls_mpi *X, size_t nblimbs)
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100227{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200228 mbedtls_mpi_uint *p;
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100229 size_t i;
Hanno Becker73d7d792018-12-11 10:35:51 +0000230
Gilles Peskine449bd832023-01-11 14:50:10 +0100231 if (nblimbs > MBEDTLS_MPI_MAX_LIMBS) {
232 return MBEDTLS_ERR_MPI_ALLOC_FAILED;
233 }
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100234
Gilles Peskinee2f563e2020-01-20 21:17:43 +0100235 /* Actually resize up if there are currently fewer than nblimbs limbs. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100236 if (X->n <= nblimbs) {
237 return mbedtls_mpi_grow(X, nblimbs);
238 }
Gilles Peskine322752b2020-01-21 13:59:51 +0100239 /* After this point, then X->n > nblimbs and in particular X->n > 0. */
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100240
Gilles Peskine449bd832023-01-11 14:50:10 +0100241 for (i = X->n - 1; i > 0; i--) {
242 if (X->p[i] != 0) {
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100243 break;
Gilles Peskine449bd832023-01-11 14:50:10 +0100244 }
245 }
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100246 i++;
247
Gilles Peskine449bd832023-01-11 14:50:10 +0100248 if (i < nblimbs) {
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100249 i = nblimbs;
Gilles Peskine449bd832023-01-11 14:50:10 +0100250 }
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100251
Gilles Peskine449bd832023-01-11 14:50:10 +0100252 if ((p = (mbedtls_mpi_uint *) mbedtls_calloc(i, ciL)) == NULL) {
253 return MBEDTLS_ERR_MPI_ALLOC_FAILED;
254 }
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100255
Gilles Peskine449bd832023-01-11 14:50:10 +0100256 if (X->p != NULL) {
257 memcpy(p, X->p, i * ciL);
Tom Cosgrove46259f62023-07-18 16:44:14 +0100258 mbedtls_mpi_zeroize_and_free(X->p, X->n);
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100259 }
260
Gilles Peskine053022f2023-06-29 19:26:48 +0200261 /* i fits in n because we ensure that MBEDTLS_MPI_MAX_LIMBS
262 * fits, and we've checked that i <= nblimbs <= MBEDTLS_MPI_MAX_LIMBS. */
263 X->n = (unsigned short) i;
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100264 X->p = p;
265
Gilles Peskine449bd832023-01-11 14:50:10 +0100266 return 0;
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100267}
268
Gilles Peskineed32b572021-06-02 22:17:52 +0200269/* Resize X to have exactly n limbs and set it to 0. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100270static int mbedtls_mpi_resize_clear(mbedtls_mpi *X, size_t limbs)
Gilles Peskineed32b572021-06-02 22:17:52 +0200271{
Gilles Peskine449bd832023-01-11 14:50:10 +0100272 if (limbs == 0) {
273 mbedtls_mpi_free(X);
274 return 0;
275 } else if (X->n == limbs) {
276 memset(X->p, 0, limbs * ciL);
Gilles Peskineed32b572021-06-02 22:17:52 +0200277 X->s = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +0100278 return 0;
279 } else {
280 mbedtls_mpi_free(X);
281 return mbedtls_mpi_grow(X, limbs);
Gilles Peskineed32b572021-06-02 22:17:52 +0200282 }
283}
284
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100285/*
Gilles Peskine3da1a8f2021-06-08 23:17:42 +0200286 * Copy the contents of Y into X.
287 *
288 * This function is not constant-time. Leading zeros in Y may be removed.
289 *
290 * Ensure that X does not shrink. This is not guaranteed by the public API,
Janos Follathc9faea02024-02-19 10:49:18 +0000291 * but some code in the bignum module might still rely on this property.
Paul Bakker5121ce52009-01-03 21:22:43 +0000292 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100293int mbedtls_mpi_copy(mbedtls_mpi *X, const mbedtls_mpi *Y)
Paul Bakker5121ce52009-01-03 21:22:43 +0000294{
Gilles Peskine4e4be7c2018-03-21 16:29:03 +0100295 int ret = 0;
Paul Bakker23986e52011-04-24 08:57:21 +0000296 size_t i;
Paul Bakker5121ce52009-01-03 21:22:43 +0000297
Gilles Peskine449bd832023-01-11 14:50:10 +0100298 if (X == Y) {
299 return 0;
Manuel Pégourié-Gonnardf4999932013-08-12 17:02:59 +0200300 }
301
Gilles Peskine449bd832023-01-11 14:50:10 +0100302 if (Y->n == 0) {
303 if (X->n != 0) {
304 X->s = 1;
305 memset(X->p, 0, X->n * ciL);
306 }
307 return 0;
308 }
309
310 for (i = Y->n - 1; i > 0; i--) {
311 if (Y->p[i] != 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +0000312 break;
Gilles Peskine449bd832023-01-11 14:50:10 +0100313 }
314 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000315 i++;
316
317 X->s = Y->s;
318
Gilles Peskine449bd832023-01-11 14:50:10 +0100319 if (X->n < i) {
320 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, i));
321 } else {
322 memset(X->p + i, 0, (X->n - i) * ciL);
Gilles Peskine4e4be7c2018-03-21 16:29:03 +0100323 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000324
Gilles Peskine449bd832023-01-11 14:50:10 +0100325 memcpy(X->p, Y->p, i * ciL);
Paul Bakker5121ce52009-01-03 21:22:43 +0000326
327cleanup:
328
Gilles Peskine449bd832023-01-11 14:50:10 +0100329 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000330}
331
332/*
333 * Swap the contents of X and Y
334 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100335void mbedtls_mpi_swap(mbedtls_mpi *X, mbedtls_mpi *Y)
Paul Bakker5121ce52009-01-03 21:22:43 +0000336{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200337 mbedtls_mpi T;
Paul Bakker5121ce52009-01-03 21:22:43 +0000338
Gilles Peskine449bd832023-01-11 14:50:10 +0100339 memcpy(&T, X, sizeof(mbedtls_mpi));
340 memcpy(X, Y, sizeof(mbedtls_mpi));
341 memcpy(Y, &T, sizeof(mbedtls_mpi));
Paul Bakker5121ce52009-01-03 21:22:43 +0000342}
343
Gilles Peskine449bd832023-01-11 14:50:10 +0100344static inline mbedtls_mpi_uint mpi_sint_abs(mbedtls_mpi_sint z)
Gilles Peskineef7f4e42022-11-15 23:25:27 +0100345{
Gilles Peskine449bd832023-01-11 14:50:10 +0100346 if (z >= 0) {
347 return z;
348 }
Gilles Peskineef7f4e42022-11-15 23:25:27 +0100349 /* Take care to handle the most negative value (-2^(biL-1)) correctly.
350 * A naive -z would have undefined behavior.
351 * Write this in a way that makes popular compilers happy (GCC, Clang,
352 * MSVC). */
Gilles Peskine449bd832023-01-11 14:50:10 +0100353 return (mbedtls_mpi_uint) 0 - (mbedtls_mpi_uint) z;
Gilles Peskineef7f4e42022-11-15 23:25:27 +0100354}
355
Dave Rodgmanf3df1052023-08-09 18:55:41 +0100356/* Convert x to a sign, i.e. to 1, if x is positive, or -1, if x is negative.
357 * This looks awkward but generates smaller code than (x < 0 ? -1 : 1) */
Dave Rodgman73d85912023-09-28 17:00:50 +0100358#define TO_SIGN(x) ((mbedtls_mpi_sint) (((mbedtls_mpi_uint) x) >> (biL - 1)) * -2 + 1)
Dave Rodgmanf3df1052023-08-09 18:55:41 +0100359
Paul Bakker5121ce52009-01-03 21:22:43 +0000360/*
361 * Set value from integer
362 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100363int mbedtls_mpi_lset(mbedtls_mpi *X, mbedtls_mpi_sint z)
Paul Bakker5121ce52009-01-03 21:22:43 +0000364{
Janos Follath24eed8d2019-11-22 13:21:35 +0000365 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker5121ce52009-01-03 21:22:43 +0000366
Gilles Peskine449bd832023-01-11 14:50:10 +0100367 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, 1));
368 memset(X->p, 0, X->n * ciL);
Paul Bakker5121ce52009-01-03 21:22:43 +0000369
Gilles Peskine449bd832023-01-11 14:50:10 +0100370 X->p[0] = mpi_sint_abs(z);
Dave Rodgmanf3df1052023-08-09 18:55:41 +0100371 X->s = TO_SIGN(z);
Paul Bakker5121ce52009-01-03 21:22:43 +0000372
373cleanup:
374
Gilles Peskine449bd832023-01-11 14:50:10 +0100375 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000376}
377
378/*
Paul Bakker2f5947e2011-05-18 15:47:11 +0000379 * Get a specific bit
380 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100381int mbedtls_mpi_get_bit(const mbedtls_mpi *X, size_t pos)
Paul Bakker2f5947e2011-05-18 15:47:11 +0000382{
Gilles Peskine449bd832023-01-11 14:50:10 +0100383 if (X->n * biL <= pos) {
384 return 0;
385 }
Paul Bakker2f5947e2011-05-18 15:47:11 +0000386
Gilles Peskine449bd832023-01-11 14:50:10 +0100387 return (X->p[pos / biL] >> (pos % biL)) & 0x01;
Paul Bakker2f5947e2011-05-18 15:47:11 +0000388}
389
390/*
391 * Set a bit to a specific value of 0 or 1
392 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100393int mbedtls_mpi_set_bit(mbedtls_mpi *X, size_t pos, unsigned char val)
Paul Bakker2f5947e2011-05-18 15:47:11 +0000394{
395 int ret = 0;
396 size_t off = pos / biL;
397 size_t idx = pos % biL;
398
Gilles Peskine449bd832023-01-11 14:50:10 +0100399 if (val != 0 && val != 1) {
400 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
Paul Bakker2f5947e2011-05-18 15:47:11 +0000401 }
402
Gilles Peskine449bd832023-01-11 14:50:10 +0100403 if (X->n * biL <= pos) {
404 if (val == 0) {
405 return 0;
406 }
407
408 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, off + 1));
409 }
410
411 X->p[off] &= ~((mbedtls_mpi_uint) 0x01 << idx);
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200412 X->p[off] |= (mbedtls_mpi_uint) val << idx;
Paul Bakker2f5947e2011-05-18 15:47:11 +0000413
414cleanup:
Paul Bakker9af723c2014-05-01 13:03:14 +0200415
Gilles Peskine449bd832023-01-11 14:50:10 +0100416 return ret;
Paul Bakker2f5947e2011-05-18 15:47:11 +0000417}
418
419/*
Manuel Pégourié-Gonnardc0696c22015-06-18 16:47:17 +0200420 * Return the number of less significant zero-bits
Paul Bakker5121ce52009-01-03 21:22:43 +0000421 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100422size_t mbedtls_mpi_lsb(const mbedtls_mpi *X)
Paul Bakker5121ce52009-01-03 21:22:43 +0000423{
Dave Rodgmanfa703e32023-08-09 18:56:07 +0100424 size_t i;
Paul Bakker5121ce52009-01-03 21:22:43 +0000425
Dave Rodgmanfa703e32023-08-09 18:56:07 +0100426#if defined(__has_builtin)
427#if (MBEDTLS_MPI_UINT_MAX == UINT_MAX) && __has_builtin(__builtin_ctz)
428 #define mbedtls_mpi_uint_ctz __builtin_ctz
429#elif (MBEDTLS_MPI_UINT_MAX == ULONG_MAX) && __has_builtin(__builtin_ctzl)
430 #define mbedtls_mpi_uint_ctz __builtin_ctzl
431#elif (MBEDTLS_MPI_UINT_MAX == ULLONG_MAX) && __has_builtin(__builtin_ctzll)
432 #define mbedtls_mpi_uint_ctz __builtin_ctzll
433#endif
434#endif
435
436#if defined(mbedtls_mpi_uint_ctz)
Gilles Peskine449bd832023-01-11 14:50:10 +0100437 for (i = 0; i < X->n; i++) {
Dave Rodgman960eca92023-08-09 20:43:18 +0100438 if (X->p[i] != 0) {
439 return i * biL + mbedtls_mpi_uint_ctz(X->p[i]);
440 }
Dave Rodgmanfa703e32023-08-09 18:56:07 +0100441 }
442#else
443 size_t count = 0;
444 for (i = 0; i < X->n; i++) {
445 for (size_t j = 0; j < biL; j++, count++) {
Gilles Peskine449bd832023-01-11 14:50:10 +0100446 if (((X->p[i] >> j) & 1) != 0) {
447 return count;
448 }
449 }
450 }
Dave Rodgmanfa703e32023-08-09 18:56:07 +0100451#endif
Paul Bakker5121ce52009-01-03 21:22:43 +0000452
Gilles Peskine449bd832023-01-11 14:50:10 +0100453 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000454}
455
456/*
Manuel Pégourié-Gonnardc0696c22015-06-18 16:47:17 +0200457 * Return the number of bits
Paul Bakker5121ce52009-01-03 21:22:43 +0000458 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100459size_t mbedtls_mpi_bitlen(const mbedtls_mpi *X)
Paul Bakker5121ce52009-01-03 21:22:43 +0000460{
Gilles Peskine449bd832023-01-11 14:50:10 +0100461 return mbedtls_mpi_core_bitlen(X->p, X->n);
Paul Bakker5121ce52009-01-03 21:22:43 +0000462}
463
464/*
465 * Return the total size in bytes
466 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100467size_t mbedtls_mpi_size(const mbedtls_mpi *X)
Paul Bakker5121ce52009-01-03 21:22:43 +0000468{
Gilles Peskine449bd832023-01-11 14:50:10 +0100469 return (mbedtls_mpi_bitlen(X) + 7) >> 3;
Paul Bakker5121ce52009-01-03 21:22:43 +0000470}
471
472/*
473 * Convert an ASCII character to digit value
474 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100475static int mpi_get_digit(mbedtls_mpi_uint *d, int radix, char c)
Paul Bakker5121ce52009-01-03 21:22:43 +0000476{
477 *d = 255;
478
Gilles Peskine449bd832023-01-11 14:50:10 +0100479 if (c >= 0x30 && c <= 0x39) {
480 *d = c - 0x30;
481 }
482 if (c >= 0x41 && c <= 0x46) {
483 *d = c - 0x37;
484 }
485 if (c >= 0x61 && c <= 0x66) {
486 *d = c - 0x57;
487 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000488
Gilles Peskine449bd832023-01-11 14:50:10 +0100489 if (*d >= (mbedtls_mpi_uint) radix) {
490 return MBEDTLS_ERR_MPI_INVALID_CHARACTER;
491 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000492
Gilles Peskine449bd832023-01-11 14:50:10 +0100493 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000494}
495
496/*
497 * Import from an ASCII string
498 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100499int mbedtls_mpi_read_string(mbedtls_mpi *X, int radix, const char *s)
Paul Bakker5121ce52009-01-03 21:22:43 +0000500{
Janos Follath24eed8d2019-11-22 13:21:35 +0000501 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker23986e52011-04-24 08:57:21 +0000502 size_t i, j, slen, n;
Gilles Peskine80f56732021-04-03 18:26:13 +0200503 int sign = 1;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200504 mbedtls_mpi_uint d;
505 mbedtls_mpi T;
Paul Bakker5121ce52009-01-03 21:22:43 +0000506
Gilles Peskine449bd832023-01-11 14:50:10 +0100507 if (radix < 2 || radix > 16) {
508 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
Gilles Peskine7cba8592021-06-08 18:32:34 +0200509 }
510
Gilles Peskine449bd832023-01-11 14:50:10 +0100511 mbedtls_mpi_init(&T);
512
513 if (s[0] == 0) {
514 mbedtls_mpi_free(X);
515 return 0;
516 }
517
518 if (s[0] == '-') {
Gilles Peskine80f56732021-04-03 18:26:13 +0200519 ++s;
520 sign = -1;
521 }
522
Gilles Peskine449bd832023-01-11 14:50:10 +0100523 slen = strlen(s);
Paul Bakkerff60ee62010-03-16 21:09:09 +0000524
Gilles Peskine449bd832023-01-11 14:50:10 +0100525 if (radix == 16) {
Dave Rodgman68ef1d62023-05-18 20:49:03 +0100526 if (slen > SIZE_MAX >> 2) {
Gilles Peskine449bd832023-01-11 14:50:10 +0100527 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
Paul Bakker5121ce52009-01-03 21:22:43 +0000528 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000529
Gilles Peskine449bd832023-01-11 14:50:10 +0100530 n = BITS_TO_LIMBS(slen << 2);
531
532 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, n));
533 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(X, 0));
534
535 for (i = slen, j = 0; i > 0; i--, j++) {
536 MBEDTLS_MPI_CHK(mpi_get_digit(&d, radix, s[i - 1]));
537 X->p[j / (2 * ciL)] |= d << ((j % (2 * ciL)) << 2);
538 }
539 } else {
540 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(X, 0));
541
542 for (i = 0; i < slen; i++) {
543 MBEDTLS_MPI_CHK(mpi_get_digit(&d, radix, s[i]));
544 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_int(&T, X, radix));
545 MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(X, &T, d));
Paul Bakker5121ce52009-01-03 21:22:43 +0000546 }
547 }
548
Gilles Peskine449bd832023-01-11 14:50:10 +0100549 if (sign < 0 && mbedtls_mpi_bitlen(X) != 0) {
Gilles Peskine80f56732021-04-03 18:26:13 +0200550 X->s = -1;
Gilles Peskine449bd832023-01-11 14:50:10 +0100551 }
Gilles Peskine80f56732021-04-03 18:26:13 +0200552
Paul Bakker5121ce52009-01-03 21:22:43 +0000553cleanup:
554
Gilles Peskine449bd832023-01-11 14:50:10 +0100555 mbedtls_mpi_free(&T);
Paul Bakker5121ce52009-01-03 21:22:43 +0000556
Gilles Peskine449bd832023-01-11 14:50:10 +0100557 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000558}
559
560/*
Ron Eldora16fa292018-11-20 14:07:01 +0200561 * Helper to write the digits high-order first.
Paul Bakker5121ce52009-01-03 21:22:43 +0000562 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100563static int mpi_write_hlp(mbedtls_mpi *X, int radix,
564 char **p, const size_t buflen)
Paul Bakker5121ce52009-01-03 21:22:43 +0000565{
Janos Follath24eed8d2019-11-22 13:21:35 +0000566 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200567 mbedtls_mpi_uint r;
Ron Eldora16fa292018-11-20 14:07:01 +0200568 size_t length = 0;
569 char *p_end = *p + buflen;
Paul Bakker5121ce52009-01-03 21:22:43 +0000570
Gilles Peskine449bd832023-01-11 14:50:10 +0100571 do {
572 if (length >= buflen) {
573 return MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL;
Ron Eldora16fa292018-11-20 14:07:01 +0200574 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000575
Gilles Peskine449bd832023-01-11 14:50:10 +0100576 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_int(&r, X, radix));
577 MBEDTLS_MPI_CHK(mbedtls_mpi_div_int(X, NULL, X, radix));
Ron Eldora16fa292018-11-20 14:07:01 +0200578 /*
579 * Write the residue in the current position, as an ASCII character.
580 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100581 if (r < 0xA) {
582 *(--p_end) = (char) ('0' + r);
583 } else {
584 *(--p_end) = (char) ('A' + (r - 0xA));
585 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000586
Ron Eldora16fa292018-11-20 14:07:01 +0200587 length++;
Gilles Peskine449bd832023-01-11 14:50:10 +0100588 } while (mbedtls_mpi_cmp_int(X, 0) != 0);
Paul Bakker5121ce52009-01-03 21:22:43 +0000589
Gilles Peskine449bd832023-01-11 14:50:10 +0100590 memmove(*p, p_end, length);
Ron Eldora16fa292018-11-20 14:07:01 +0200591 *p += length;
Paul Bakker5121ce52009-01-03 21:22:43 +0000592
593cleanup:
594
Gilles Peskine449bd832023-01-11 14:50:10 +0100595 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000596}
597
598/*
599 * Export into an ASCII string
600 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100601int mbedtls_mpi_write_string(const mbedtls_mpi *X, int radix,
602 char *buf, size_t buflen, size_t *olen)
Paul Bakker5121ce52009-01-03 21:22:43 +0000603{
Paul Bakker23986e52011-04-24 08:57:21 +0000604 int ret = 0;
605 size_t n;
Paul Bakker5121ce52009-01-03 21:22:43 +0000606 char *p;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200607 mbedtls_mpi T;
Paul Bakker5121ce52009-01-03 21:22:43 +0000608
Gilles Peskine449bd832023-01-11 14:50:10 +0100609 if (radix < 2 || radix > 16) {
610 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
611 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000612
Gilles Peskine449bd832023-01-11 14:50:10 +0100613 n = mbedtls_mpi_bitlen(X); /* Number of bits necessary to present `n`. */
614 if (radix >= 4) {
615 n >>= 1; /* Number of 4-adic digits necessary to present
Hanno Becker23cfea02019-02-04 09:45:07 +0000616 * `n`. If radix > 4, this might be a strict
617 * overapproximation of the number of
618 * radix-adic digits needed to present `n`. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100619 }
620 if (radix >= 16) {
621 n >>= 1; /* Number of hexadecimal digits necessary to
Hanno Becker23cfea02019-02-04 09:45:07 +0000622 * present `n`. */
623
Gilles Peskine449bd832023-01-11 14:50:10 +0100624 }
Janos Follath80470622019-03-06 13:43:02 +0000625 n += 1; /* Terminating null byte */
Hanno Becker23cfea02019-02-04 09:45:07 +0000626 n += 1; /* Compensate for the divisions above, which round down `n`
627 * in case it's not even. */
628 n += 1; /* Potential '-'-sign. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100629 n += (n & 1); /* Make n even to have enough space for hexadecimal writing,
Hanno Becker23cfea02019-02-04 09:45:07 +0000630 * which always uses an even number of hex-digits. */
Paul Bakker5121ce52009-01-03 21:22:43 +0000631
Gilles Peskine449bd832023-01-11 14:50:10 +0100632 if (buflen < n) {
Manuel Pégourié-Gonnardf79b4252015-06-02 15:41:48 +0100633 *olen = n;
Gilles Peskine449bd832023-01-11 14:50:10 +0100634 return MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL;
Paul Bakker5121ce52009-01-03 21:22:43 +0000635 }
636
Manuel Pégourié-Gonnardf79b4252015-06-02 15:41:48 +0100637 p = buf;
Gilles Peskine449bd832023-01-11 14:50:10 +0100638 mbedtls_mpi_init(&T);
Paul Bakker5121ce52009-01-03 21:22:43 +0000639
Gilles Peskine449bd832023-01-11 14:50:10 +0100640 if (X->s == -1) {
Paul Bakker5121ce52009-01-03 21:22:43 +0000641 *p++ = '-';
Hanno Beckerc983c812019-02-01 16:41:30 +0000642 buflen--;
643 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000644
Gilles Peskine449bd832023-01-11 14:50:10 +0100645 if (radix == 16) {
Paul Bakker23986e52011-04-24 08:57:21 +0000646 int c;
647 size_t i, j, k;
Paul Bakker5121ce52009-01-03 21:22:43 +0000648
Gilles Peskine449bd832023-01-11 14:50:10 +0100649 for (i = X->n, k = 0; i > 0; i--) {
650 for (j = ciL; j > 0; j--) {
651 c = (X->p[i - 1] >> ((j - 1) << 3)) & 0xFF;
Paul Bakker5121ce52009-01-03 21:22:43 +0000652
Gilles Peskine449bd832023-01-11 14:50:10 +0100653 if (c == 0 && k == 0 && (i + j) != 2) {
Paul Bakker5121ce52009-01-03 21:22:43 +0000654 continue;
Gilles Peskine449bd832023-01-11 14:50:10 +0100655 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000656
Paul Bakker98fe5ea2012-10-24 11:17:48 +0000657 *(p++) = "0123456789ABCDEF" [c / 16];
Paul Bakkerd2c167e2012-10-30 07:49:19 +0000658 *(p++) = "0123456789ABCDEF" [c % 16];
Paul Bakker5121ce52009-01-03 21:22:43 +0000659 k = 1;
660 }
661 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100662 } else {
663 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&T, X));
Paul Bakkerce40a6d2009-06-23 19:46:08 +0000664
Gilles Peskine449bd832023-01-11 14:50:10 +0100665 if (T.s == -1) {
Paul Bakkerce40a6d2009-06-23 19:46:08 +0000666 T.s = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +0100667 }
Paul Bakkerce40a6d2009-06-23 19:46:08 +0000668
Gilles Peskine449bd832023-01-11 14:50:10 +0100669 MBEDTLS_MPI_CHK(mpi_write_hlp(&T, radix, &p, buflen));
Paul Bakker5121ce52009-01-03 21:22:43 +0000670 }
671
672 *p++ = '\0';
Dave Rodgmane4a6f5a2023-11-04 12:20:09 +0000673 *olen = (size_t) (p - buf);
Paul Bakker5121ce52009-01-03 21:22:43 +0000674
675cleanup:
676
Gilles Peskine449bd832023-01-11 14:50:10 +0100677 mbedtls_mpi_free(&T);
Paul Bakker5121ce52009-01-03 21:22:43 +0000678
Gilles Peskine449bd832023-01-11 14:50:10 +0100679 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000680}
681
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200682#if defined(MBEDTLS_FS_IO)
Paul Bakker5121ce52009-01-03 21:22:43 +0000683/*
684 * Read X from an opened file
685 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100686int mbedtls_mpi_read_file(mbedtls_mpi *X, int radix, FILE *fin)
Paul Bakker5121ce52009-01-03 21:22:43 +0000687{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200688 mbedtls_mpi_uint d;
Paul Bakker23986e52011-04-24 08:57:21 +0000689 size_t slen;
Paul Bakker5121ce52009-01-03 21:22:43 +0000690 char *p;
Paul Bakkerfe3256e2011-11-25 12:11:43 +0000691 /*
Paul Bakkercb37aa52011-11-30 16:00:20 +0000692 * Buffer should have space for (short) label and decimal formatted MPI,
693 * newline characters and '\0'
Paul Bakkerfe3256e2011-11-25 12:11:43 +0000694 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100695 char s[MBEDTLS_MPI_RW_BUFFER_SIZE];
Paul Bakker5121ce52009-01-03 21:22:43 +0000696
Gilles Peskine449bd832023-01-11 14:50:10 +0100697 if (radix < 2 || radix > 16) {
698 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
699 }
Hanno Becker73d7d792018-12-11 10:35:51 +0000700
Gilles Peskine449bd832023-01-11 14:50:10 +0100701 memset(s, 0, sizeof(s));
702 if (fgets(s, sizeof(s) - 1, fin) == NULL) {
703 return MBEDTLS_ERR_MPI_FILE_IO_ERROR;
704 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000705
Gilles Peskine449bd832023-01-11 14:50:10 +0100706 slen = strlen(s);
707 if (slen == sizeof(s) - 2) {
708 return MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL;
709 }
Paul Bakkercb37aa52011-11-30 16:00:20 +0000710
Gilles Peskine449bd832023-01-11 14:50:10 +0100711 if (slen > 0 && s[slen - 1] == '\n') {
712 slen--; s[slen] = '\0';
713 }
714 if (slen > 0 && s[slen - 1] == '\r') {
715 slen--; s[slen] = '\0';
716 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000717
718 p = s + slen;
Gilles Peskine449bd832023-01-11 14:50:10 +0100719 while (p-- > s) {
720 if (mpi_get_digit(&d, radix, *p) != 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +0000721 break;
Gilles Peskine449bd832023-01-11 14:50:10 +0100722 }
723 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000724
Gilles Peskine449bd832023-01-11 14:50:10 +0100725 return mbedtls_mpi_read_string(X, radix, p + 1);
Paul Bakker5121ce52009-01-03 21:22:43 +0000726}
727
728/*
729 * Write X into an opened file (or stdout if fout == NULL)
730 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100731int mbedtls_mpi_write_file(const char *p, const mbedtls_mpi *X, int radix, FILE *fout)
Paul Bakker5121ce52009-01-03 21:22:43 +0000732{
Janos Follath24eed8d2019-11-22 13:21:35 +0000733 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker23986e52011-04-24 08:57:21 +0000734 size_t n, slen, plen;
Paul Bakkerfe3256e2011-11-25 12:11:43 +0000735 /*
Paul Bakker5531c6d2012-09-26 19:20:46 +0000736 * Buffer should have space for (short) label and decimal formatted MPI,
737 * newline characters and '\0'
Paul Bakkerfe3256e2011-11-25 12:11:43 +0000738 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100739 char s[MBEDTLS_MPI_RW_BUFFER_SIZE];
Hanno Becker73d7d792018-12-11 10:35:51 +0000740
Gilles Peskine449bd832023-01-11 14:50:10 +0100741 if (radix < 2 || radix > 16) {
742 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
743 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000744
Gilles Peskine449bd832023-01-11 14:50:10 +0100745 memset(s, 0, sizeof(s));
Paul Bakker5121ce52009-01-03 21:22:43 +0000746
Gilles Peskine449bd832023-01-11 14:50:10 +0100747 MBEDTLS_MPI_CHK(mbedtls_mpi_write_string(X, radix, s, sizeof(s) - 2, &n));
Paul Bakker5121ce52009-01-03 21:22:43 +0000748
Gilles Peskine449bd832023-01-11 14:50:10 +0100749 if (p == NULL) {
750 p = "";
751 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000752
Gilles Peskine449bd832023-01-11 14:50:10 +0100753 plen = strlen(p);
754 slen = strlen(s);
Paul Bakker5121ce52009-01-03 21:22:43 +0000755 s[slen++] = '\r';
756 s[slen++] = '\n';
757
Gilles Peskine449bd832023-01-11 14:50:10 +0100758 if (fout != NULL) {
759 if (fwrite(p, 1, plen, fout) != plen ||
760 fwrite(s, 1, slen, fout) != slen) {
761 return MBEDTLS_ERR_MPI_FILE_IO_ERROR;
762 }
763 } else {
764 mbedtls_printf("%s%s", p, s);
Paul Bakker5121ce52009-01-03 21:22:43 +0000765 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000766
767cleanup:
768
Gilles Peskine449bd832023-01-11 14:50:10 +0100769 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000770}
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200771#endif /* MBEDTLS_FS_IO */
Paul Bakker5121ce52009-01-03 21:22:43 +0000772
773/*
Janos Follatha778a942019-02-13 10:28:28 +0000774 * Import X from unsigned binary data, little endian
Przemyslaw Stekiel76960a72022-02-21 13:42:09 +0100775 *
776 * This function is guaranteed to return an MPI with exactly the necessary
777 * number of limbs (in particular, it does not skip 0s in the input).
Janos Follatha778a942019-02-13 10:28:28 +0000778 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100779int mbedtls_mpi_read_binary_le(mbedtls_mpi *X,
780 const unsigned char *buf, size_t buflen)
Janos Follatha778a942019-02-13 10:28:28 +0000781{
Janos Follath24eed8d2019-11-22 13:21:35 +0000782 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Gilles Peskine449bd832023-01-11 14:50:10 +0100783 const size_t limbs = CHARS_TO_LIMBS(buflen);
Janos Follatha778a942019-02-13 10:28:28 +0000784
785 /* Ensure that target MPI has exactly the necessary number of limbs */
Gilles Peskine449bd832023-01-11 14:50:10 +0100786 MBEDTLS_MPI_CHK(mbedtls_mpi_resize_clear(X, limbs));
Janos Follatha778a942019-02-13 10:28:28 +0000787
Gilles Peskine449bd832023-01-11 14:50:10 +0100788 MBEDTLS_MPI_CHK(mbedtls_mpi_core_read_le(X->p, X->n, buf, buflen));
Janos Follatha778a942019-02-13 10:28:28 +0000789
790cleanup:
791
Janos Follath171a7ef2019-02-15 16:17:45 +0000792 /*
793 * This function is also used to import keys. However, wiping the buffers
794 * upon failure is not necessary because failure only can happen before any
795 * input is copied.
796 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100797 return ret;
Janos Follatha778a942019-02-13 10:28:28 +0000798}
799
800/*
Paul Bakker5121ce52009-01-03 21:22:43 +0000801 * Import X from unsigned binary data, big endian
Przemyslaw Stekiel76960a72022-02-21 13:42:09 +0100802 *
803 * This function is guaranteed to return an MPI with exactly the necessary
804 * number of limbs (in particular, it does not skip 0s in the input).
Paul Bakker5121ce52009-01-03 21:22:43 +0000805 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100806int mbedtls_mpi_read_binary(mbedtls_mpi *X, const unsigned char *buf, size_t buflen)
Paul Bakker5121ce52009-01-03 21:22:43 +0000807{
Janos Follath24eed8d2019-11-22 13:21:35 +0000808 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Gilles Peskine449bd832023-01-11 14:50:10 +0100809 const size_t limbs = CHARS_TO_LIMBS(buflen);
Hanno Becker73d7d792018-12-11 10:35:51 +0000810
Hanno Becker073c1992017-10-17 15:17:27 +0100811 /* Ensure that target MPI has exactly the necessary number of limbs */
Gilles Peskine449bd832023-01-11 14:50:10 +0100812 MBEDTLS_MPI_CHK(mbedtls_mpi_resize_clear(X, limbs));
Paul Bakker5121ce52009-01-03 21:22:43 +0000813
Gilles Peskine449bd832023-01-11 14:50:10 +0100814 MBEDTLS_MPI_CHK(mbedtls_mpi_core_read_be(X->p, X->n, buf, buflen));
Paul Bakker5121ce52009-01-03 21:22:43 +0000815
816cleanup:
817
Janos Follath171a7ef2019-02-15 16:17:45 +0000818 /*
819 * This function is also used to import keys. However, wiping the buffers
820 * upon failure is not necessary because failure only can happen before any
821 * input is copied.
822 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100823 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000824}
825
826/*
Janos Follathe344d0f2019-02-19 16:17:40 +0000827 * Export X into unsigned binary data, little endian
828 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100829int mbedtls_mpi_write_binary_le(const mbedtls_mpi *X,
830 unsigned char *buf, size_t buflen)
Janos Follathe344d0f2019-02-19 16:17:40 +0000831{
Gilles Peskine449bd832023-01-11 14:50:10 +0100832 return mbedtls_mpi_core_write_le(X->p, X->n, buf, buflen);
Janos Follathe344d0f2019-02-19 16:17:40 +0000833}
834
835/*
Paul Bakker5121ce52009-01-03 21:22:43 +0000836 * Export X into unsigned binary data, big endian
837 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100838int mbedtls_mpi_write_binary(const mbedtls_mpi *X,
839 unsigned char *buf, size_t buflen)
Paul Bakker5121ce52009-01-03 21:22:43 +0000840{
Gilles Peskine449bd832023-01-11 14:50:10 +0100841 return mbedtls_mpi_core_write_be(X->p, X->n, buf, buflen);
Paul Bakker5121ce52009-01-03 21:22:43 +0000842}
843
844/*
845 * Left-shift: X <<= count
846 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100847int mbedtls_mpi_shift_l(mbedtls_mpi *X, size_t count)
Paul Bakker5121ce52009-01-03 21:22:43 +0000848{
Janos Follath24eed8d2019-11-22 13:21:35 +0000849 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Minos Galanakis0144b352023-05-02 14:02:32 +0100850 size_t i;
Paul Bakker5121ce52009-01-03 21:22:43 +0000851
Gilles Peskine449bd832023-01-11 14:50:10 +0100852 i = mbedtls_mpi_bitlen(X) + count;
Paul Bakker5121ce52009-01-03 21:22:43 +0000853
Gilles Peskine449bd832023-01-11 14:50:10 +0100854 if (X->n * biL < i) {
855 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, BITS_TO_LIMBS(i)));
856 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000857
858 ret = 0;
859
Minos Galanakis0144b352023-05-02 14:02:32 +0100860 mbedtls_mpi_core_shift_l(X->p, X->n, count);
Paul Bakker5121ce52009-01-03 21:22:43 +0000861cleanup:
862
Gilles Peskine449bd832023-01-11 14:50:10 +0100863 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000864}
865
866/*
867 * Right-shift: X >>= count
868 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100869int mbedtls_mpi_shift_r(mbedtls_mpi *X, size_t count)
Paul Bakker5121ce52009-01-03 21:22:43 +0000870{
Gilles Peskine449bd832023-01-11 14:50:10 +0100871 if (X->n != 0) {
872 mbedtls_mpi_core_shift_r(X->p, X->n, count);
873 }
874 return 0;
Gilles Peskine66414202022-09-21 15:36:16 +0200875}
876
Paul Bakker5121ce52009-01-03 21:22:43 +0000877/*
878 * Compare unsigned values
879 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100880int mbedtls_mpi_cmp_abs(const mbedtls_mpi *X, const mbedtls_mpi *Y)
Paul Bakker5121ce52009-01-03 21:22:43 +0000881{
Paul Bakker23986e52011-04-24 08:57:21 +0000882 size_t i, j;
Paul Bakker5121ce52009-01-03 21:22:43 +0000883
Gilles Peskine449bd832023-01-11 14:50:10 +0100884 for (i = X->n; i > 0; i--) {
885 if (X->p[i - 1] != 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +0000886 break;
Gilles Peskine449bd832023-01-11 14:50:10 +0100887 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000888 }
889
Gilles Peskine449bd832023-01-11 14:50:10 +0100890 for (j = Y->n; j > 0; j--) {
891 if (Y->p[j - 1] != 0) {
892 break;
893 }
894 }
895
Dave Rodgmanebcd7852023-08-09 18:56:42 +0100896 /* If i == j == 0, i.e. abs(X) == abs(Y),
897 * we end up returning 0 at the end of the function. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100898
899 if (i > j) {
900 return 1;
901 }
902 if (j > i) {
903 return -1;
904 }
905
906 for (; i > 0; i--) {
907 if (X->p[i - 1] > Y->p[i - 1]) {
908 return 1;
909 }
910 if (X->p[i - 1] < Y->p[i - 1]) {
911 return -1;
912 }
913 }
914
915 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000916}
917
918/*
919 * Compare signed values
920 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100921int mbedtls_mpi_cmp_mpi(const mbedtls_mpi *X, const mbedtls_mpi *Y)
Paul Bakker5121ce52009-01-03 21:22:43 +0000922{
Paul Bakker23986e52011-04-24 08:57:21 +0000923 size_t i, j;
Paul Bakker5121ce52009-01-03 21:22:43 +0000924
Gilles Peskine449bd832023-01-11 14:50:10 +0100925 for (i = X->n; i > 0; i--) {
926 if (X->p[i - 1] != 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +0000927 break;
Gilles Peskine449bd832023-01-11 14:50:10 +0100928 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000929 }
930
Gilles Peskine449bd832023-01-11 14:50:10 +0100931 for (j = Y->n; j > 0; j--) {
932 if (Y->p[j - 1] != 0) {
933 break;
934 }
935 }
936
937 if (i == 0 && j == 0) {
938 return 0;
939 }
940
941 if (i > j) {
942 return X->s;
943 }
944 if (j > i) {
945 return -Y->s;
946 }
947
948 if (X->s > 0 && Y->s < 0) {
949 return 1;
950 }
951 if (Y->s > 0 && X->s < 0) {
952 return -1;
953 }
954
955 for (; i > 0; i--) {
956 if (X->p[i - 1] > Y->p[i - 1]) {
957 return X->s;
958 }
959 if (X->p[i - 1] < Y->p[i - 1]) {
960 return -X->s;
961 }
962 }
963
964 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000965}
966
Janos Follathee6abce2019-09-05 14:47:19 +0100967/*
Paul Bakker5121ce52009-01-03 21:22:43 +0000968 * Compare signed values
969 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100970int mbedtls_mpi_cmp_int(const mbedtls_mpi *X, mbedtls_mpi_sint z)
Paul Bakker5121ce52009-01-03 21:22:43 +0000971{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200972 mbedtls_mpi Y;
973 mbedtls_mpi_uint p[1];
Paul Bakker5121ce52009-01-03 21:22:43 +0000974
Gilles Peskine449bd832023-01-11 14:50:10 +0100975 *p = mpi_sint_abs(z);
Dave Rodgmanf3df1052023-08-09 18:55:41 +0100976 Y.s = TO_SIGN(z);
Paul Bakker5121ce52009-01-03 21:22:43 +0000977 Y.n = 1;
978 Y.p = p;
979
Gilles Peskine449bd832023-01-11 14:50:10 +0100980 return mbedtls_mpi_cmp_mpi(X, &Y);
Paul Bakker5121ce52009-01-03 21:22:43 +0000981}
982
983/*
984 * Unsigned addition: X = |A| + |B| (HAC 14.7)
985 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100986int mbedtls_mpi_add_abs(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B)
Paul Bakker5121ce52009-01-03 21:22:43 +0000987{
Janos Follath24eed8d2019-11-22 13:21:35 +0000988 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Tom Cosgroveaf7d44b2022-08-24 14:05:26 +0100989 size_t j;
Agathiyan Bragadeeshc99840a2023-07-12 11:15:46 +0100990 mbedtls_mpi_uint *p;
991 mbedtls_mpi_uint c;
Paul Bakker5121ce52009-01-03 21:22:43 +0000992
Gilles Peskine449bd832023-01-11 14:50:10 +0100993 if (X == B) {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200994 const mbedtls_mpi *T = A; A = X; B = T;
Paul Bakker5121ce52009-01-03 21:22:43 +0000995 }
996
Gilles Peskine449bd832023-01-11 14:50:10 +0100997 if (X != A) {
998 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(X, A));
999 }
Paul Bakker9af723c2014-05-01 13:03:14 +02001000
Paul Bakkerf7ca7b92009-06-20 10:31:06 +00001001 /*
Tom Cosgroveaf7d44b2022-08-24 14:05:26 +01001002 * X must always be positive as a result of unsigned additions.
Paul Bakkerf7ca7b92009-06-20 10:31:06 +00001003 */
1004 X->s = 1;
Paul Bakker5121ce52009-01-03 21:22:43 +00001005
Gilles Peskine449bd832023-01-11 14:50:10 +01001006 for (j = B->n; j > 0; j--) {
1007 if (B->p[j - 1] != 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00001008 break;
Gilles Peskine449bd832023-01-11 14:50:10 +01001009 }
1010 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001011
Gilles Peskinedb14a9d2022-11-15 22:59:00 +01001012 /* Exit early to avoid undefined behavior on NULL+0 when X->n == 0
1013 * and B is 0 (of any size). */
Gilles Peskine449bd832023-01-11 14:50:10 +01001014 if (j == 0) {
1015 return 0;
1016 }
Gilles Peskinedb14a9d2022-11-15 22:59:00 +01001017
Gilles Peskine449bd832023-01-11 14:50:10 +01001018 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, j));
Paul Bakker5121ce52009-01-03 21:22:43 +00001019
Tom Cosgroveaf7d44b2022-08-24 14:05:26 +01001020 /* j is the number of non-zero limbs of B. Add those to X. */
Paul Bakker5121ce52009-01-03 21:22:43 +00001021
Agathiyan Bragadeeshc99840a2023-07-12 11:15:46 +01001022 p = X->p;
Tom Cosgroveaf7d44b2022-08-24 14:05:26 +01001023
Agathiyan Bragadeeshc99840a2023-07-12 11:15:46 +01001024 c = mbedtls_mpi_core_add(p, p, B->p, j);
Tom Cosgroveaf7d44b2022-08-24 14:05:26 +01001025
1026 p += j;
1027
1028 /* Now propagate any carry */
Paul Bakker5121ce52009-01-03 21:22:43 +00001029
Gilles Peskine449bd832023-01-11 14:50:10 +01001030 while (c != 0) {
1031 if (j >= X->n) {
1032 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, j + 1));
Tom Cosgroveaf7d44b2022-08-24 14:05:26 +01001033 p = X->p + j;
Paul Bakker5121ce52009-01-03 21:22:43 +00001034 }
1035
Gilles Peskine449bd832023-01-11 14:50:10 +01001036 *p += c; c = (*p < c); j++; p++;
Paul Bakker5121ce52009-01-03 21:22:43 +00001037 }
1038
1039cleanup:
1040
Gilles Peskine449bd832023-01-11 14:50:10 +01001041 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001042}
1043
Paul Bakker5121ce52009-01-03 21:22:43 +00001044/*
Gilles Peskine0e5faf62020-06-08 22:50:35 +02001045 * Unsigned subtraction: X = |A| - |B| (HAC 14.9, 14.10)
Paul Bakker5121ce52009-01-03 21:22:43 +00001046 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001047int mbedtls_mpi_sub_abs(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B)
Paul Bakker5121ce52009-01-03 21:22:43 +00001048{
Janos Follath24eed8d2019-11-22 13:21:35 +00001049 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker23986e52011-04-24 08:57:21 +00001050 size_t n;
Gilles Peskine0e5faf62020-06-08 22:50:35 +02001051 mbedtls_mpi_uint carry;
Paul Bakker5121ce52009-01-03 21:22:43 +00001052
Gilles Peskine449bd832023-01-11 14:50:10 +01001053 for (n = B->n; n > 0; n--) {
1054 if (B->p[n - 1] != 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00001055 break;
Gilles Peskine449bd832023-01-11 14:50:10 +01001056 }
1057 }
1058 if (n > A->n) {
Gilles Peskinec8a91772021-01-27 22:30:43 +01001059 /* B >= (2^ciL)^n > A */
1060 ret = MBEDTLS_ERR_MPI_NEGATIVE_VALUE;
1061 goto cleanup;
1062 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001063
Gilles Peskine449bd832023-01-11 14:50:10 +01001064 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, A->n));
Gilles Peskine1acf7cb2020-07-23 01:03:22 +02001065
1066 /* Set the high limbs of X to match A. Don't touch the lower limbs
1067 * because X might be aliased to B, and we must not overwrite the
1068 * significant digits of B. */
Aaron M. Uckoaf67d2c2023-01-17 11:52:22 -05001069 if (A->n > n && A != X) {
Gilles Peskine449bd832023-01-11 14:50:10 +01001070 memcpy(X->p + n, A->p + n, (A->n - n) * ciL);
1071 }
1072 if (X->n > A->n) {
1073 memset(X->p + A->n, 0, (X->n - A->n) * ciL);
1074 }
Gilles Peskine1acf7cb2020-07-23 01:03:22 +02001075
Gilles Peskine449bd832023-01-11 14:50:10 +01001076 carry = mbedtls_mpi_core_sub(X->p, A->p, B->p, n);
1077 if (carry != 0) {
Tom Cosgrove452c99c2022-08-25 10:07:07 +01001078 /* Propagate the carry through the rest of X. */
Gilles Peskine449bd832023-01-11 14:50:10 +01001079 carry = mbedtls_mpi_core_sub_int(X->p + n, X->p + n, carry, X->n - n);
Tom Cosgrove452c99c2022-08-25 10:07:07 +01001080
1081 /* If we have further carry/borrow, the result is negative. */
Gilles Peskine449bd832023-01-11 14:50:10 +01001082 if (carry != 0) {
Gilles Peskine89b41302020-07-23 01:16:46 +02001083 ret = MBEDTLS_ERR_MPI_NEGATIVE_VALUE;
1084 goto cleanup;
1085 }
Gilles Peskinec097e9e2020-06-08 21:58:22 +02001086 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001087
Gilles Peskine1acf7cb2020-07-23 01:03:22 +02001088 /* X should always be positive as a result of unsigned subtractions. */
1089 X->s = 1;
1090
Paul Bakker5121ce52009-01-03 21:22:43 +00001091cleanup:
Gilles Peskine449bd832023-01-11 14:50:10 +01001092 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001093}
1094
Gilles Peskine72ee1e32022-11-09 21:34:09 +01001095/* Common function for signed addition and subtraction.
1096 * Calculate A + B * flip_B where flip_B is 1 or -1.
Paul Bakker5121ce52009-01-03 21:22:43 +00001097 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001098static int add_sub_mpi(mbedtls_mpi *X,
1099 const mbedtls_mpi *A, const mbedtls_mpi *B,
1100 int flip_B)
Paul Bakker5121ce52009-01-03 21:22:43 +00001101{
Hanno Becker73d7d792018-12-11 10:35:51 +00001102 int ret, s;
Paul Bakker5121ce52009-01-03 21:22:43 +00001103
Hanno Becker73d7d792018-12-11 10:35:51 +00001104 s = A->s;
Gilles Peskine449bd832023-01-11 14:50:10 +01001105 if (A->s * B->s * flip_B < 0) {
1106 int cmp = mbedtls_mpi_cmp_abs(A, B);
1107 if (cmp >= 0) {
1108 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_abs(X, A, B));
Gilles Peskine4a768dd2022-11-09 22:02:16 +01001109 /* If |A| = |B|, the result is 0 and we must set the sign bit
1110 * to +1 regardless of which of A or B was negative. Otherwise,
1111 * since |A| > |B|, the sign is the sign of A. */
1112 X->s = cmp == 0 ? 1 : s;
Gilles Peskine449bd832023-01-11 14:50:10 +01001113 } else {
1114 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_abs(X, B, A));
Gilles Peskine4a768dd2022-11-09 22:02:16 +01001115 /* Since |A| < |B|, the sign is the opposite of A. */
Paul Bakker5121ce52009-01-03 21:22:43 +00001116 X->s = -s;
1117 }
Gilles Peskine449bd832023-01-11 14:50:10 +01001118 } else {
1119 MBEDTLS_MPI_CHK(mbedtls_mpi_add_abs(X, A, B));
Paul Bakker5121ce52009-01-03 21:22:43 +00001120 X->s = s;
1121 }
1122
1123cleanup:
1124
Gilles Peskine449bd832023-01-11 14:50:10 +01001125 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001126}
1127
1128/*
Gilles Peskine72ee1e32022-11-09 21:34:09 +01001129 * Signed addition: X = A + B
1130 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001131int mbedtls_mpi_add_mpi(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B)
Gilles Peskine72ee1e32022-11-09 21:34:09 +01001132{
Gilles Peskine449bd832023-01-11 14:50:10 +01001133 return add_sub_mpi(X, A, B, 1);
Gilles Peskine72ee1e32022-11-09 21:34:09 +01001134}
1135
1136/*
Paul Bakker60b1d102013-10-29 10:02:51 +01001137 * Signed subtraction: X = A - B
Paul Bakker5121ce52009-01-03 21:22:43 +00001138 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001139int mbedtls_mpi_sub_mpi(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B)
Paul Bakker5121ce52009-01-03 21:22:43 +00001140{
Gilles Peskine449bd832023-01-11 14:50:10 +01001141 return add_sub_mpi(X, A, B, -1);
Paul Bakker5121ce52009-01-03 21:22:43 +00001142}
1143
1144/*
1145 * Signed addition: X = A + b
1146 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001147int mbedtls_mpi_add_int(mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b)
Paul Bakker5121ce52009-01-03 21:22:43 +00001148{
Yuto Takano36c8ddc2021-07-05 09:10:52 +01001149 mbedtls_mpi B;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001150 mbedtls_mpi_uint p[1];
Paul Bakker5121ce52009-01-03 21:22:43 +00001151
Gilles Peskine449bd832023-01-11 14:50:10 +01001152 p[0] = mpi_sint_abs(b);
Dave Rodgmanf3df1052023-08-09 18:55:41 +01001153 B.s = TO_SIGN(b);
Yuto Takano36c8ddc2021-07-05 09:10:52 +01001154 B.n = 1;
1155 B.p = p;
Paul Bakker5121ce52009-01-03 21:22:43 +00001156
Gilles Peskine449bd832023-01-11 14:50:10 +01001157 return mbedtls_mpi_add_mpi(X, A, &B);
Paul Bakker5121ce52009-01-03 21:22:43 +00001158}
1159
1160/*
Paul Bakker60b1d102013-10-29 10:02:51 +01001161 * Signed subtraction: X = A - b
Paul Bakker5121ce52009-01-03 21:22:43 +00001162 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001163int mbedtls_mpi_sub_int(mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b)
Paul Bakker5121ce52009-01-03 21:22:43 +00001164{
Yuto Takano36c8ddc2021-07-05 09:10:52 +01001165 mbedtls_mpi B;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001166 mbedtls_mpi_uint p[1];
Paul Bakker5121ce52009-01-03 21:22:43 +00001167
Gilles Peskine449bd832023-01-11 14:50:10 +01001168 p[0] = mpi_sint_abs(b);
Dave Rodgmanf3df1052023-08-09 18:55:41 +01001169 B.s = TO_SIGN(b);
Yuto Takano36c8ddc2021-07-05 09:10:52 +01001170 B.n = 1;
1171 B.p = p;
Paul Bakker5121ce52009-01-03 21:22:43 +00001172
Gilles Peskine449bd832023-01-11 14:50:10 +01001173 return mbedtls_mpi_sub_mpi(X, A, &B);
Paul Bakker5121ce52009-01-03 21:22:43 +00001174}
1175
Paul Bakker5121ce52009-01-03 21:22:43 +00001176/*
1177 * Baseline multiplication: X = A * B (HAC 14.12)
1178 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001179int mbedtls_mpi_mul_mpi(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B)
Paul Bakker5121ce52009-01-03 21:22:43 +00001180{
Janos Follath24eed8d2019-11-22 13:21:35 +00001181 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Hanno Becker1772e052022-04-13 06:51:40 +01001182 size_t i, j;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001183 mbedtls_mpi TA, TB;
Hanno Beckerda763de2022-04-13 06:50:02 +01001184 int result_is_zero = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +00001185
Tom Cosgrove6af26f32022-08-24 16:40:55 +01001186 mbedtls_mpi_init(&TA);
1187 mbedtls_mpi_init(&TB);
Paul Bakker5121ce52009-01-03 21:22:43 +00001188
Gilles Peskine449bd832023-01-11 14:50:10 +01001189 if (X == A) {
1190 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TA, A)); A = &TA;
1191 }
1192 if (X == B) {
1193 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TB, B)); B = &TB;
1194 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001195
Gilles Peskine449bd832023-01-11 14:50:10 +01001196 for (i = A->n; i > 0; i--) {
1197 if (A->p[i - 1] != 0) {
Hanno Beckerda763de2022-04-13 06:50:02 +01001198 break;
Gilles Peskine449bd832023-01-11 14:50:10 +01001199 }
1200 }
1201 if (i == 0) {
Hanno Beckerda763de2022-04-13 06:50:02 +01001202 result_is_zero = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +01001203 }
Hanno Beckerda763de2022-04-13 06:50:02 +01001204
Gilles Peskine449bd832023-01-11 14:50:10 +01001205 for (j = B->n; j > 0; j--) {
1206 if (B->p[j - 1] != 0) {
Hanno Beckerda763de2022-04-13 06:50:02 +01001207 break;
Gilles Peskine449bd832023-01-11 14:50:10 +01001208 }
1209 }
1210 if (j == 0) {
Hanno Beckerda763de2022-04-13 06:50:02 +01001211 result_is_zero = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +01001212 }
Hanno Beckerda763de2022-04-13 06:50:02 +01001213
Gilles Peskine449bd832023-01-11 14:50:10 +01001214 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, i + j));
1215 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(X, 0));
Paul Bakker5121ce52009-01-03 21:22:43 +00001216
Tom Cosgrove6af26f32022-08-24 16:40:55 +01001217 mbedtls_mpi_core_mul(X->p, A->p, i, B->p, j);
Paul Bakker5121ce52009-01-03 21:22:43 +00001218
Hanno Beckerda763de2022-04-13 06:50:02 +01001219 /* If the result is 0, we don't shortcut the operation, which reduces
1220 * but does not eliminate side channels leaking the zero-ness. We do
1221 * need to take care to set the sign bit properly since the library does
1222 * not fully support an MPI object with a value of 0 and s == -1. */
Gilles Peskine449bd832023-01-11 14:50:10 +01001223 if (result_is_zero) {
Hanno Beckerda763de2022-04-13 06:50:02 +01001224 X->s = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +01001225 } else {
Hanno Beckerda763de2022-04-13 06:50:02 +01001226 X->s = A->s * B->s;
Gilles Peskine449bd832023-01-11 14:50:10 +01001227 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001228
1229cleanup:
1230
Gilles Peskine449bd832023-01-11 14:50:10 +01001231 mbedtls_mpi_free(&TB); mbedtls_mpi_free(&TA);
Paul Bakker5121ce52009-01-03 21:22:43 +00001232
Gilles Peskine449bd832023-01-11 14:50:10 +01001233 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001234}
1235
1236/*
1237 * Baseline multiplication: X = A * b
1238 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001239int mbedtls_mpi_mul_int(mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_uint b)
Paul Bakker5121ce52009-01-03 21:22:43 +00001240{
Hanno Becker35771312022-04-14 11:52:11 +01001241 size_t n = A->n;
Gilles Peskine449bd832023-01-11 14:50:10 +01001242 while (n > 0 && A->p[n - 1] == 0) {
Hanno Becker35771312022-04-14 11:52:11 +01001243 --n;
Gilles Peskine449bd832023-01-11 14:50:10 +01001244 }
Hanno Becker35771312022-04-14 11:52:11 +01001245
Hanno Becker74a11a32022-04-06 06:27:00 +01001246 /* The general method below doesn't work if b==0. */
Gilles Peskine449bd832023-01-11 14:50:10 +01001247 if (b == 0 || n == 0) {
1248 return mbedtls_mpi_lset(X, 0);
1249 }
Gilles Peskine8fd95c62020-07-23 21:58:50 +02001250
Hanno Beckeraef9cc42022-04-11 06:36:29 +01001251 /* Calculate A*b as A + A*(b-1) to take advantage of mbedtls_mpi_core_mla */
Gilles Peskine8fd95c62020-07-23 21:58:50 +02001252 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Gilles Peskinecd0dbf32020-07-24 00:09:04 +02001253 /* In general, A * b requires 1 limb more than b. If
1254 * A->p[n - 1] * b / b == A->p[n - 1], then A * b fits in the same
1255 * number of limbs as A and the call to grow() is not required since
Gilles Peskinee1bba7c2021-03-10 23:44:10 +01001256 * copy() will take care of the growth if needed. However, experimentally,
1257 * making the call to grow() unconditional causes slightly fewer
Gilles Peskinecd0dbf32020-07-24 00:09:04 +02001258 * calls to calloc() in ECP code, presumably because it reuses the
1259 * same mpi for a while and this way the mpi is more likely to directly
Hanno Becker9137b9c2022-04-12 10:51:54 +01001260 * grow to its final size.
1261 *
1262 * Note that calculating A*b as 0 + A*b doesn't work as-is because
1263 * A,X can be the same. */
Gilles Peskine449bd832023-01-11 14:50:10 +01001264 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, n + 1));
1265 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(X, A));
1266 mbedtls_mpi_core_mla(X->p, X->n, A->p, n, b - 1);
Gilles Peskine8fd95c62020-07-23 21:58:50 +02001267
1268cleanup:
Gilles Peskine449bd832023-01-11 14:50:10 +01001269 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001270}
1271
1272/*
Simon Butcherf5ba0452015-12-27 23:01:55 +00001273 * Unsigned integer divide - double mbedtls_mpi_uint dividend, u1/u0, and
1274 * mbedtls_mpi_uint divisor, d
Simon Butcher15b15d12015-11-26 19:35:03 +00001275 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001276static mbedtls_mpi_uint mbedtls_int_div_int(mbedtls_mpi_uint u1,
1277 mbedtls_mpi_uint u0,
1278 mbedtls_mpi_uint d,
1279 mbedtls_mpi_uint *r)
Simon Butcher15b15d12015-11-26 19:35:03 +00001280{
Manuel Pégourié-Gonnard16308882015-12-01 10:27:00 +01001281#if defined(MBEDTLS_HAVE_UDBL)
1282 mbedtls_t_udbl dividend, quotient;
Simon Butcherf5ba0452015-12-27 23:01:55 +00001283#else
Simon Butcher9803d072016-01-03 00:24:34 +00001284 const mbedtls_mpi_uint radix = (mbedtls_mpi_uint) 1 << biH;
Gilles Peskine449bd832023-01-11 14:50:10 +01001285 const mbedtls_mpi_uint uint_halfword_mask = ((mbedtls_mpi_uint) 1 << biH) - 1;
Simon Butcherf5ba0452015-12-27 23:01:55 +00001286 mbedtls_mpi_uint d0, d1, q0, q1, rAX, r0, quotient;
1287 mbedtls_mpi_uint u0_msw, u0_lsw;
Simon Butcher9803d072016-01-03 00:24:34 +00001288 size_t s;
Manuel Pégourié-Gonnard16308882015-12-01 10:27:00 +01001289#endif
1290
Simon Butcher15b15d12015-11-26 19:35:03 +00001291 /*
1292 * Check for overflow
1293 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001294 if (0 == d || u1 >= d) {
1295 if (r != NULL) {
1296 *r = ~(mbedtls_mpi_uint) 0u;
1297 }
Simon Butcher15b15d12015-11-26 19:35:03 +00001298
Gilles Peskine449bd832023-01-11 14:50:10 +01001299 return ~(mbedtls_mpi_uint) 0u;
Simon Butcher15b15d12015-11-26 19:35:03 +00001300 }
1301
1302#if defined(MBEDTLS_HAVE_UDBL)
Simon Butcher15b15d12015-11-26 19:35:03 +00001303 dividend = (mbedtls_t_udbl) u1 << biL;
1304 dividend |= (mbedtls_t_udbl) u0;
1305 quotient = dividend / d;
Gilles Peskine449bd832023-01-11 14:50:10 +01001306 if (quotient > ((mbedtls_t_udbl) 1 << biL) - 1) {
1307 quotient = ((mbedtls_t_udbl) 1 << biL) - 1;
1308 }
Simon Butcher15b15d12015-11-26 19:35:03 +00001309
Gilles Peskine449bd832023-01-11 14:50:10 +01001310 if (r != NULL) {
1311 *r = (mbedtls_mpi_uint) (dividend - (quotient * d));
1312 }
Simon Butcher15b15d12015-11-26 19:35:03 +00001313
1314 return (mbedtls_mpi_uint) quotient;
1315#else
Simon Butcher15b15d12015-11-26 19:35:03 +00001316
1317 /*
1318 * Algorithm D, Section 4.3.1 - The Art of Computer Programming
1319 * Vol. 2 - Seminumerical Algorithms, Knuth
1320 */
1321
1322 /*
1323 * Normalize the divisor, d, and dividend, u0, u1
1324 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001325 s = mbedtls_mpi_core_clz(d);
Simon Butcher15b15d12015-11-26 19:35:03 +00001326 d = d << s;
1327
1328 u1 = u1 << s;
Gilles Peskine449bd832023-01-11 14:50:10 +01001329 u1 |= (u0 >> (biL - s)) & (-(mbedtls_mpi_sint) s >> (biL - 1));
Simon Butcher15b15d12015-11-26 19:35:03 +00001330 u0 = u0 << s;
1331
1332 d1 = d >> biH;
Simon Butcher9803d072016-01-03 00:24:34 +00001333 d0 = d & uint_halfword_mask;
Simon Butcher15b15d12015-11-26 19:35:03 +00001334
1335 u0_msw = u0 >> biH;
Simon Butcher9803d072016-01-03 00:24:34 +00001336 u0_lsw = u0 & uint_halfword_mask;
Simon Butcher15b15d12015-11-26 19:35:03 +00001337
1338 /*
1339 * Find the first quotient and remainder
1340 */
1341 q1 = u1 / d1;
1342 r0 = u1 - d1 * q1;
1343
Gilles Peskine449bd832023-01-11 14:50:10 +01001344 while (q1 >= radix || (q1 * d0 > radix * r0 + u0_msw)) {
Simon Butcher15b15d12015-11-26 19:35:03 +00001345 q1 -= 1;
1346 r0 += d1;
1347
Gilles Peskine449bd832023-01-11 14:50:10 +01001348 if (r0 >= radix) {
1349 break;
1350 }
Simon Butcher15b15d12015-11-26 19:35:03 +00001351 }
1352
Gilles Peskine449bd832023-01-11 14:50:10 +01001353 rAX = (u1 * radix) + (u0_msw - q1 * d);
Simon Butcher15b15d12015-11-26 19:35:03 +00001354 q0 = rAX / d1;
1355 r0 = rAX - q0 * d1;
1356
Gilles Peskine449bd832023-01-11 14:50:10 +01001357 while (q0 >= radix || (q0 * d0 > radix * r0 + u0_lsw)) {
Simon Butcher15b15d12015-11-26 19:35:03 +00001358 q0 -= 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 if (r != NULL) {
1367 *r = (rAX * radix + u0_lsw - q0 * d) >> s;
1368 }
Simon Butcher15b15d12015-11-26 19:35:03 +00001369
1370 quotient = q1 * radix + q0;
1371
1372 return quotient;
1373#endif
1374}
1375
1376/*
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001377 * Division by mbedtls_mpi: A = Q * B + R (HAC 14.20)
Paul Bakker5121ce52009-01-03 21:22:43 +00001378 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001379int mbedtls_mpi_div_mpi(mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A,
1380 const mbedtls_mpi *B)
Paul Bakker5121ce52009-01-03 21:22:43 +00001381{
Janos Follath24eed8d2019-11-22 13:21:35 +00001382 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker23986e52011-04-24 08:57:21 +00001383 size_t i, n, t, k;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001384 mbedtls_mpi X, Y, Z, T1, T2;
Alexander Kd19a1932019-11-01 18:20:42 +03001385 mbedtls_mpi_uint TP2[3];
Paul Bakker5121ce52009-01-03 21:22:43 +00001386
Gilles Peskine449bd832023-01-11 14:50:10 +01001387 if (mbedtls_mpi_cmp_int(B, 0) == 0) {
1388 return MBEDTLS_ERR_MPI_DIVISION_BY_ZERO;
1389 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001390
Gilles Peskine449bd832023-01-11 14:50:10 +01001391 mbedtls_mpi_init(&X); mbedtls_mpi_init(&Y); mbedtls_mpi_init(&Z);
1392 mbedtls_mpi_init(&T1);
Alexander Kd19a1932019-11-01 18:20:42 +03001393 /*
1394 * Avoid dynamic memory allocations for constant-size T2.
1395 *
1396 * T2 is used for comparison only and the 3 limbs are assigned explicitly,
1397 * so nobody increase the size of the MPI and we're safe to use an on-stack
1398 * buffer.
1399 */
Alexander K35d6d462019-10-31 14:46:45 +03001400 T2.s = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +01001401 T2.n = sizeof(TP2) / sizeof(*TP2);
Alexander Kd19a1932019-11-01 18:20:42 +03001402 T2.p = TP2;
Paul Bakker5121ce52009-01-03 21:22:43 +00001403
Gilles Peskine449bd832023-01-11 14:50:10 +01001404 if (mbedtls_mpi_cmp_abs(A, B) < 0) {
1405 if (Q != NULL) {
1406 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(Q, 0));
1407 }
1408 if (R != NULL) {
1409 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(R, A));
1410 }
1411 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +00001412 }
1413
Gilles Peskine449bd832023-01-11 14:50:10 +01001414 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&X, A));
1415 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&Y, B));
Paul Bakker5121ce52009-01-03 21:22:43 +00001416 X.s = Y.s = 1;
1417
Gilles Peskine449bd832023-01-11 14:50:10 +01001418 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(&Z, A->n + 2));
1419 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&Z, 0));
1420 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(&T1, A->n + 2));
Paul Bakker5121ce52009-01-03 21:22:43 +00001421
Gilles Peskine449bd832023-01-11 14:50:10 +01001422 k = mbedtls_mpi_bitlen(&Y) % biL;
1423 if (k < biL - 1) {
Paul Bakker5121ce52009-01-03 21:22:43 +00001424 k = biL - 1 - k;
Gilles Peskine449bd832023-01-11 14:50:10 +01001425 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&X, k));
1426 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&Y, k));
1427 } else {
1428 k = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +00001429 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001430
1431 n = X.n - 1;
1432 t = Y.n - 1;
Gilles Peskine449bd832023-01-11 14:50:10 +01001433 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&Y, biL * (n - t)));
Paul Bakker5121ce52009-01-03 21:22:43 +00001434
Gilles Peskine449bd832023-01-11 14:50:10 +01001435 while (mbedtls_mpi_cmp_mpi(&X, &Y) >= 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00001436 Z.p[n - t]++;
Gilles Peskine449bd832023-01-11 14:50:10 +01001437 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&X, &X, &Y));
Paul Bakker5121ce52009-01-03 21:22:43 +00001438 }
Gilles Peskine449bd832023-01-11 14:50:10 +01001439 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&Y, biL * (n - t)));
Paul Bakker5121ce52009-01-03 21:22:43 +00001440
Gilles Peskine449bd832023-01-11 14:50:10 +01001441 for (i = n; i > t; i--) {
1442 if (X.p[i] >= Y.p[t]) {
1443 Z.p[i - t - 1] = ~(mbedtls_mpi_uint) 0u;
1444 } else {
1445 Z.p[i - t - 1] = mbedtls_int_div_int(X.p[i], X.p[i - 1],
1446 Y.p[t], NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +00001447 }
1448
Gilles Peskine449bd832023-01-11 14:50:10 +01001449 T2.p[0] = (i < 2) ? 0 : X.p[i - 2];
1450 T2.p[1] = (i < 1) ? 0 : X.p[i - 1];
Alexander K35d6d462019-10-31 14:46:45 +03001451 T2.p[2] = X.p[i];
1452
Paul Bakker5121ce52009-01-03 21:22:43 +00001453 Z.p[i - t - 1]++;
Gilles Peskine449bd832023-01-11 14:50:10 +01001454 do {
Paul Bakker5121ce52009-01-03 21:22:43 +00001455 Z.p[i - t - 1]--;
1456
Gilles Peskine449bd832023-01-11 14:50:10 +01001457 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&T1, 0));
1458 T1.p[0] = (t < 1) ? 0 : Y.p[t - 1];
Paul Bakker5121ce52009-01-03 21:22:43 +00001459 T1.p[1] = Y.p[t];
Gilles Peskine449bd832023-01-11 14:50:10 +01001460 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_int(&T1, &T1, Z.p[i - t - 1]));
1461 } while (mbedtls_mpi_cmp_mpi(&T1, &T2) > 0);
Paul Bakker5121ce52009-01-03 21:22:43 +00001462
Gilles Peskine449bd832023-01-11 14:50:10 +01001463 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_int(&T1, &Y, Z.p[i - t - 1]));
1464 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&T1, biL * (i - t - 1)));
1465 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&X, &X, &T1));
Paul Bakker5121ce52009-01-03 21:22:43 +00001466
Gilles Peskine449bd832023-01-11 14:50:10 +01001467 if (mbedtls_mpi_cmp_int(&X, 0) < 0) {
1468 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&T1, &Y));
1469 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&T1, biL * (i - t - 1)));
1470 MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&X, &X, &T1));
Paul Bakker5121ce52009-01-03 21:22:43 +00001471 Z.p[i - t - 1]--;
1472 }
1473 }
1474
Gilles Peskine449bd832023-01-11 14:50:10 +01001475 if (Q != NULL) {
1476 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(Q, &Z));
Paul Bakker5121ce52009-01-03 21:22:43 +00001477 Q->s = A->s * B->s;
1478 }
1479
Gilles Peskine449bd832023-01-11 14:50:10 +01001480 if (R != NULL) {
1481 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&X, k));
Paul Bakkerf02c5642012-11-13 10:25:21 +00001482 X.s = A->s;
Gilles Peskine449bd832023-01-11 14:50:10 +01001483 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(R, &X));
Paul Bakker5121ce52009-01-03 21:22:43 +00001484
Gilles Peskine449bd832023-01-11 14:50:10 +01001485 if (mbedtls_mpi_cmp_int(R, 0) == 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00001486 R->s = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +01001487 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001488 }
1489
1490cleanup:
1491
Gilles Peskine449bd832023-01-11 14:50:10 +01001492 mbedtls_mpi_free(&X); mbedtls_mpi_free(&Y); mbedtls_mpi_free(&Z);
1493 mbedtls_mpi_free(&T1);
1494 mbedtls_platform_zeroize(TP2, sizeof(TP2));
Paul Bakker5121ce52009-01-03 21:22:43 +00001495
Gilles Peskine449bd832023-01-11 14:50:10 +01001496 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001497}
1498
1499/*
1500 * Division by int: A = Q * b + R
Paul Bakker5121ce52009-01-03 21:22:43 +00001501 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001502int mbedtls_mpi_div_int(mbedtls_mpi *Q, mbedtls_mpi *R,
1503 const mbedtls_mpi *A,
1504 mbedtls_mpi_sint b)
Paul Bakker5121ce52009-01-03 21:22:43 +00001505{
Yuto Takano36c8ddc2021-07-05 09:10:52 +01001506 mbedtls_mpi B;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001507 mbedtls_mpi_uint p[1];
Paul Bakker5121ce52009-01-03 21:22:43 +00001508
Gilles Peskine449bd832023-01-11 14:50:10 +01001509 p[0] = mpi_sint_abs(b);
Dave Rodgmanf3df1052023-08-09 18:55:41 +01001510 B.s = TO_SIGN(b);
Yuto Takano36c8ddc2021-07-05 09:10:52 +01001511 B.n = 1;
1512 B.p = p;
Paul Bakker5121ce52009-01-03 21:22:43 +00001513
Gilles Peskine449bd832023-01-11 14:50:10 +01001514 return mbedtls_mpi_div_mpi(Q, R, A, &B);
Paul Bakker5121ce52009-01-03 21:22:43 +00001515}
1516
1517/*
1518 * Modulo: R = A mod B
1519 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001520int mbedtls_mpi_mod_mpi(mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B)
Paul Bakker5121ce52009-01-03 21:22:43 +00001521{
Janos Follath24eed8d2019-11-22 13:21:35 +00001522 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker5121ce52009-01-03 21:22:43 +00001523
Gilles Peskine449bd832023-01-11 14:50:10 +01001524 if (mbedtls_mpi_cmp_int(B, 0) < 0) {
1525 return MBEDTLS_ERR_MPI_NEGATIVE_VALUE;
1526 }
Paul Bakkerce40a6d2009-06-23 19:46:08 +00001527
Gilles Peskine449bd832023-01-11 14:50:10 +01001528 MBEDTLS_MPI_CHK(mbedtls_mpi_div_mpi(NULL, R, A, B));
Paul Bakker5121ce52009-01-03 21:22:43 +00001529
Gilles Peskine449bd832023-01-11 14:50:10 +01001530 while (mbedtls_mpi_cmp_int(R, 0) < 0) {
1531 MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(R, R, B));
1532 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001533
Gilles Peskine449bd832023-01-11 14:50:10 +01001534 while (mbedtls_mpi_cmp_mpi(R, B) >= 0) {
1535 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(R, R, B));
1536 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001537
1538cleanup:
1539
Gilles Peskine449bd832023-01-11 14:50:10 +01001540 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001541}
1542
1543/*
1544 * Modulo: r = A mod b
1545 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001546int mbedtls_mpi_mod_int(mbedtls_mpi_uint *r, const mbedtls_mpi *A, mbedtls_mpi_sint b)
Paul Bakker5121ce52009-01-03 21:22:43 +00001547{
Paul Bakker23986e52011-04-24 08:57:21 +00001548 size_t i;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001549 mbedtls_mpi_uint x, y, z;
Paul Bakker5121ce52009-01-03 21:22:43 +00001550
Gilles Peskine449bd832023-01-11 14:50:10 +01001551 if (b == 0) {
1552 return MBEDTLS_ERR_MPI_DIVISION_BY_ZERO;
1553 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001554
Gilles Peskine449bd832023-01-11 14:50:10 +01001555 if (b < 0) {
1556 return MBEDTLS_ERR_MPI_NEGATIVE_VALUE;
1557 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001558
1559 /*
1560 * handle trivial cases
1561 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001562 if (b == 1 || A->n == 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00001563 *r = 0;
Gilles Peskine449bd832023-01-11 14:50:10 +01001564 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +00001565 }
1566
Gilles Peskine449bd832023-01-11 14:50:10 +01001567 if (b == 2) {
Paul Bakker5121ce52009-01-03 21:22:43 +00001568 *r = A->p[0] & 1;
Gilles Peskine449bd832023-01-11 14:50:10 +01001569 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +00001570 }
1571
1572 /*
1573 * general case
1574 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001575 for (i = A->n, y = 0; i > 0; i--) {
Paul Bakker23986e52011-04-24 08:57:21 +00001576 x = A->p[i - 1];
Gilles Peskine449bd832023-01-11 14:50:10 +01001577 y = (y << biH) | (x >> biH);
Paul Bakker5121ce52009-01-03 21:22:43 +00001578 z = y / b;
1579 y -= z * b;
1580
1581 x <<= biH;
Gilles Peskine449bd832023-01-11 14:50:10 +01001582 y = (y << biH) | (x >> biH);
Paul Bakker5121ce52009-01-03 21:22:43 +00001583 z = y / b;
1584 y -= z * b;
1585 }
1586
Paul Bakkerce40a6d2009-06-23 19:46:08 +00001587 /*
1588 * If A is negative, then the current y represents a negative value.
1589 * Flipping it to the positive side.
1590 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001591 if (A->s < 0 && y != 0) {
Paul Bakkerce40a6d2009-06-23 19:46:08 +00001592 y = b - y;
Gilles Peskine449bd832023-01-11 14:50:10 +01001593 }
Paul Bakkerce40a6d2009-06-23 19:46:08 +00001594
Paul Bakker5121ce52009-01-03 21:22:43 +00001595 *r = y;
1596
Gilles Peskine449bd832023-01-11 14:50:10 +01001597 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +00001598}
1599
Gilles Peskine449bd832023-01-11 14:50:10 +01001600int mbedtls_mpi_exp_mod(mbedtls_mpi *X, const mbedtls_mpi *A,
1601 const mbedtls_mpi *E, const mbedtls_mpi *N,
1602 mbedtls_mpi *prec_RR)
Paul Bakker5121ce52009-01-03 21:22:43 +00001603{
Janos Follath24eed8d2019-11-22 13:21:35 +00001604 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker5121ce52009-01-03 21:22:43 +00001605
Gilles Peskine449bd832023-01-11 14:50:10 +01001606 if (mbedtls_mpi_cmp_int(N, 0) <= 0 || (N->p[0] & 1) == 0) {
1607 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
1608 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001609
Gilles Peskine449bd832023-01-11 14:50:10 +01001610 if (mbedtls_mpi_cmp_int(E, 0) < 0) {
1611 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
1612 }
Paul Bakkerf6198c12012-05-16 08:02:29 +00001613
Gilles Peskine449bd832023-01-11 14:50:10 +01001614 if (mbedtls_mpi_bitlen(E) > MBEDTLS_MPI_MAX_BITS ||
1615 mbedtls_mpi_bitlen(N) > MBEDTLS_MPI_MAX_BITS) {
1616 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
1617 }
Chris Jones9246d042020-11-25 15:12:39 +00001618
Janos Follath583f0472024-02-19 11:16:44 +00001619 /*
1620 * Ensure that the exponent that we are passing to the core is not NULL.
1621 */
1622 if (E->n == 0) {
1623 ret = mbedtls_mpi_lset(X, 1);
1624 return ret;
1625 }
1626
Janos Follath424c2652024-02-21 09:26:36 +00001627 /*
1628 * Allocate working memory for mbedtls_mpi_core_exp_mod()
1629 */
1630 size_t T_limbs = mbedtls_mpi_core_exp_mod_working_limbs(N->n, E->n);
1631 mbedtls_mpi_uint *T = (mbedtls_mpi_uint*) mbedtls_calloc(T_limbs, sizeof(mbedtls_mpi_uint));
1632 if (T == NULL) {
1633 return MBEDTLS_ERR_MPI_ALLOC_FAILED;
1634 }
1635
Janos Follath701ae1d2024-02-19 10:56:54 +00001636 mbedtls_mpi RR;
Janos Follath1ba40582024-02-13 12:36:13 +00001637 mbedtls_mpi_init(&RR);
Paul Bakker50546922012-05-19 08:40:49 +00001638
1639 /*
Paul Bakker5121ce52009-01-03 21:22:43 +00001640 * If 1st call, pre-compute R^2 mod N
1641 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001642 if (prec_RR == NULL || prec_RR->p == NULL) {
Janos Follath1ba40582024-02-13 12:36:13 +00001643 MBEDTLS_MPI_CHK(mbedtls_mpi_core_get_mont_r2_unsafe(&RR, N));
Paul Bakker5121ce52009-01-03 21:22:43 +00001644
Gilles Peskine449bd832023-01-11 14:50:10 +01001645 if (prec_RR != NULL) {
Janos Follath576087d2024-02-19 11:05:01 +00001646 *prec_RR = RR;
Gilles Peskine449bd832023-01-11 14:50:10 +01001647 }
1648 } else {
Janos Follath0512d172024-02-20 14:30:46 +00001649 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(prec_RR, N->n));
Janos Follath576087d2024-02-19 11:05:01 +00001650 RR = *prec_RR;
Paul Bakker5121ce52009-01-03 21:22:43 +00001651 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001652
1653 /*
Janos Follath1ba40582024-02-13 12:36:13 +00001654 * To preserve constness we need to make a copy of A. Using X for this to
1655 * save memory.
Paul Bakker5121ce52009-01-03 21:22:43 +00001656 */
Janos Follath1ba40582024-02-13 12:36:13 +00001657 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(X, A));
Paul Bakker5121ce52009-01-03 21:22:43 +00001658
1659 /*
Janos Follath1ba40582024-02-13 12:36:13 +00001660 * Compensate for negative A (and correct at the end).
Paul Bakker5121ce52009-01-03 21:22:43 +00001661 */
Janos Follath1ba40582024-02-13 12:36:13 +00001662 X->s = 1;
Paul Bakkerf6198c12012-05-16 08:02:29 +00001663
Janos Follath8e7d6a02022-10-04 13:27:40 +01001664 /*
Janos Follath467a5492024-02-19 11:27:38 +00001665 * Make sure that X is in a form that is safe for consumption by
1666 * the core functions.
1667 *
1668 * - The core functions will not touch the limbs of X above N->n. The
1669 * result will be correct if those limbs are 0, which the mod call
1670 * ensures.
1671 * - Also, X must have at least as many limbs as N for the calls to the
1672 * core functions.
Janos Follath8e7d6a02022-10-04 13:27:40 +01001673 */
Janos Follath1ba40582024-02-13 12:36:13 +00001674 if (mbedtls_mpi_cmp_mpi(X, N) >= 0) {
1675 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(X, X, N));
1676 }
1677 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, N->n));
1678
1679 /*
Janos Follath1ba40582024-02-13 12:36:13 +00001680 * Convert to and from Montgomery around mbedtls_mpi_core_exp_mod().
1681 */
1682 mbedtls_mpi_uint mm = mbedtls_mpi_core_montmul_init(N->p);
Janos Follath424c2652024-02-21 09:26:36 +00001683 mbedtls_mpi_core_to_mont_rep(X->p, X->p, N->p, N->n, mm, RR.p, T);
Janos Follath583f0472024-02-19 11:16:44 +00001684 mbedtls_mpi_core_exp_mod(X->p, X->p, N->p, N->n, E->p, E->n, RR.p,
Janos Follath424c2652024-02-21 09:26:36 +00001685 T);
1686 mbedtls_mpi_core_from_mont_rep(X->p, X->p, N->p, N->n, mm, T);
Janos Follath1ba40582024-02-13 12:36:13 +00001687
1688 /*
1689 * Correct for negative A.
1690 */
Janos Follath583f0472024-02-19 11:16:44 +00001691 if (A->s == -1 && (E->p[0] & 1) != 0) {
Janos Follath1ba40582024-02-13 12:36:13 +00001692 X->s = -1;
1693 MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(X, N, X));
1694 }
Janos Follath8e7d6a02022-10-04 13:27:40 +01001695
Paul Bakker5121ce52009-01-03 21:22:43 +00001696cleanup:
1697
Janos Follath424c2652024-02-21 09:26:36 +00001698 mbedtls_mpi_zeroize_and_free(T, T_limbs);
Paul Bakker6c591fa2011-05-05 11:49:20 +00001699
Gilles Peskine449bd832023-01-11 14:50:10 +01001700 if (prec_RR == NULL || prec_RR->p == NULL) {
1701 mbedtls_mpi_free(&RR);
1702 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001703
Gilles Peskine449bd832023-01-11 14:50:10 +01001704 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001705}
1706
Paul Bakker5121ce52009-01-03 21:22:43 +00001707/*
1708 * Greatest common divisor: G = gcd(A, B) (HAC 14.54)
1709 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001710int mbedtls_mpi_gcd(mbedtls_mpi *G, const mbedtls_mpi *A, const mbedtls_mpi *B)
Paul Bakker5121ce52009-01-03 21:22:43 +00001711{
Janos Follath24eed8d2019-11-22 13:21:35 +00001712 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker23986e52011-04-24 08:57:21 +00001713 size_t lz, lzt;
Alexander Ke8ad49f2019-08-16 16:16:07 +03001714 mbedtls_mpi TA, TB;
Paul Bakker5121ce52009-01-03 21:22:43 +00001715
Gilles Peskine449bd832023-01-11 14:50:10 +01001716 mbedtls_mpi_init(&TA); mbedtls_mpi_init(&TB);
Paul Bakker5121ce52009-01-03 21:22:43 +00001717
Gilles Peskine449bd832023-01-11 14:50:10 +01001718 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TA, A));
1719 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TB, B));
Paul Bakker5121ce52009-01-03 21:22:43 +00001720
Gilles Peskine449bd832023-01-11 14:50:10 +01001721 lz = mbedtls_mpi_lsb(&TA);
1722 lzt = mbedtls_mpi_lsb(&TB);
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00001723
Gilles Peskine27253bc2021-06-09 13:26:43 +02001724 /* The loop below gives the correct result when A==0 but not when B==0.
1725 * So have a special case for B==0. Leverage the fact that we just
1726 * calculated the lsb and lsb(B)==0 iff B is odd or 0 to make the test
1727 * slightly more efficient than cmp_int(). */
Gilles Peskine449bd832023-01-11 14:50:10 +01001728 if (lzt == 0 && mbedtls_mpi_get_bit(&TB, 0) == 0) {
1729 ret = mbedtls_mpi_copy(G, A);
Gilles Peskine27253bc2021-06-09 13:26:43 +02001730 goto cleanup;
1731 }
1732
Gilles Peskine449bd832023-01-11 14:50:10 +01001733 if (lzt < lz) {
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00001734 lz = lzt;
Gilles Peskine449bd832023-01-11 14:50:10 +01001735 }
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00001736
Paul Bakker5121ce52009-01-03 21:22:43 +00001737 TA.s = TB.s = 1;
1738
Gilles Peskine2a63c5b2021-06-16 13:42:04 +02001739 /* We mostly follow the procedure described in HAC 14.54, but with some
1740 * minor differences:
1741 * - Sequences of multiplications or divisions by 2 are grouped into a
1742 * single shift operation.
Gilles Peskineb09c7ee2021-06-21 18:58:39 +02001743 * - The procedure in HAC assumes that 0 < TB <= TA.
1744 * - The condition TB <= TA is not actually necessary for correctness.
1745 * TA and TB have symmetric roles except for the loop termination
1746 * condition, and the shifts at the beginning of the loop body
1747 * remove any significance from the ordering of TA vs TB before
1748 * the shifts.
1749 * - If TA = 0, the loop goes through 0 iterations and the result is
1750 * correctly TB.
1751 * - The case TB = 0 was short-circuited above.
Gilles Peskine2a63c5b2021-06-16 13:42:04 +02001752 *
1753 * For the correctness proof below, decompose the original values of
1754 * A and B as
1755 * A = sa * 2^a * A' with A'=0 or A' odd, and sa = +-1
1756 * B = sb * 2^b * B' with B'=0 or B' odd, and sb = +-1
1757 * Then gcd(A, B) = 2^{min(a,b)} * gcd(A',B'),
1758 * and gcd(A',B') is odd or 0.
1759 *
1760 * At the beginning, we have TA = |A| and TB = |B| so gcd(A,B) = gcd(TA,TB).
1761 * The code maintains the following invariant:
1762 * gcd(A,B) = 2^k * gcd(TA,TB) for some k (I)
Gilles Peskine4df3f1f2021-06-15 22:09:39 +02001763 */
1764
Gilles Peskine2a63c5b2021-06-16 13:42:04 +02001765 /* Proof that the loop terminates:
1766 * At each iteration, either the right-shift by 1 is made on a nonzero
1767 * value and the nonnegative integer bitlen(TA) + bitlen(TB) decreases
1768 * by at least 1, or the right-shift by 1 is made on zero and then
1769 * TA becomes 0 which ends the loop (TB cannot be 0 if it is right-shifted
1770 * since in that case TB is calculated from TB-TA with the condition TB>TA).
1771 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001772 while (mbedtls_mpi_cmp_int(&TA, 0) != 0) {
Gilles Peskine2a63c5b2021-06-16 13:42:04 +02001773 /* Divisions by 2 preserve the invariant (I). */
Gilles Peskine449bd832023-01-11 14:50:10 +01001774 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TA, mbedtls_mpi_lsb(&TA)));
1775 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TB, mbedtls_mpi_lsb(&TB)));
Paul Bakker5121ce52009-01-03 21:22:43 +00001776
Gilles Peskine2a63c5b2021-06-16 13:42:04 +02001777 /* Set either TA or TB to |TA-TB|/2. Since TA and TB are both odd,
1778 * TA-TB is even so the division by 2 has an integer result.
1779 * Invariant (I) is preserved since any odd divisor of both TA and TB
1780 * also divides |TA-TB|/2, and any odd divisor of both TA and |TA-TB|/2
Shaun Case8b0ecbc2021-12-20 21:14:10 -08001781 * also divides TB, and any odd divisor of both TB and |TA-TB|/2 also
Gilles Peskine2a63c5b2021-06-16 13:42:04 +02001782 * divides TA.
1783 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001784 if (mbedtls_mpi_cmp_mpi(&TA, &TB) >= 0) {
1785 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_abs(&TA, &TA, &TB));
1786 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TA, 1));
1787 } else {
1788 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_abs(&TB, &TB, &TA));
1789 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TB, 1));
Paul Bakker5121ce52009-01-03 21:22:43 +00001790 }
Gilles Peskine2a63c5b2021-06-16 13:42:04 +02001791 /* Note that one of TA or TB is still odd. */
Paul Bakker5121ce52009-01-03 21:22:43 +00001792 }
1793
Gilles Peskine2a63c5b2021-06-16 13:42:04 +02001794 /* By invariant (I), gcd(A,B) = 2^k * gcd(TA,TB) for some k.
1795 * At the loop exit, TA = 0, so gcd(TA,TB) = TB.
1796 * - If there was at least one loop iteration, then one of TA or TB is odd,
1797 * and TA = 0, so TB is odd and gcd(TA,TB) = gcd(A',B'). In this case,
1798 * lz = min(a,b) so gcd(A,B) = 2^lz * TB.
1799 * - If there was no loop iteration, then A was 0, and gcd(A,B) = B.
Gilles Peskine4d3fd362021-06-21 11:40:38 +02001800 * 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 +02001801 */
1802
Gilles Peskine449bd832023-01-11 14:50:10 +01001803 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&TB, lz));
1804 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(G, &TB));
Paul Bakker5121ce52009-01-03 21:22:43 +00001805
1806cleanup:
1807
Gilles Peskine449bd832023-01-11 14:50:10 +01001808 mbedtls_mpi_free(&TA); mbedtls_mpi_free(&TB);
Paul Bakker5121ce52009-01-03 21:22:43 +00001809
Gilles Peskine449bd832023-01-11 14:50:10 +01001810 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001811}
1812
Paul Bakker33dc46b2014-04-30 16:11:39 +02001813/*
1814 * Fill X with size bytes of random.
Gilles Peskine22cdd0c2022-10-27 20:15:13 +02001815 * The bytes returned from the RNG are used in a specific order which
1816 * is suitable for deterministic ECDSA (see the specification of
1817 * mbedtls_mpi_random() and the implementation in mbedtls_mpi_fill_random()).
Paul Bakker33dc46b2014-04-30 16:11:39 +02001818 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001819int mbedtls_mpi_fill_random(mbedtls_mpi *X, size_t size,
1820 int (*f_rng)(void *, unsigned char *, size_t),
1821 void *p_rng)
Paul Bakker287781a2011-03-26 13:18:49 +00001822{
Janos Follath24eed8d2019-11-22 13:21:35 +00001823 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Gilles Peskine449bd832023-01-11 14:50:10 +01001824 const size_t limbs = CHARS_TO_LIMBS(size);
Hanno Beckerda1655a2017-10-18 14:21:44 +01001825
Hanno Beckerda1655a2017-10-18 14:21:44 +01001826 /* Ensure that target MPI has exactly the necessary number of limbs */
Gilles Peskine449bd832023-01-11 14:50:10 +01001827 MBEDTLS_MPI_CHK(mbedtls_mpi_resize_clear(X, limbs));
1828 if (size == 0) {
1829 return 0;
1830 }
Paul Bakker287781a2011-03-26 13:18:49 +00001831
Gilles Peskine449bd832023-01-11 14:50:10 +01001832 ret = mbedtls_mpi_core_fill_random(X->p, X->n, size, f_rng, p_rng);
Paul Bakker287781a2011-03-26 13:18:49 +00001833
1834cleanup:
Gilles Peskine449bd832023-01-11 14:50:10 +01001835 return ret;
Paul Bakker287781a2011-03-26 13:18:49 +00001836}
1837
Gilles Peskine449bd832023-01-11 14:50:10 +01001838int mbedtls_mpi_random(mbedtls_mpi *X,
1839 mbedtls_mpi_sint min,
1840 const mbedtls_mpi *N,
1841 int (*f_rng)(void *, unsigned char *, size_t),
1842 void *p_rng)
Gilles Peskine02ac93a2021-03-29 22:02:55 +02001843{
Gilles Peskine449bd832023-01-11 14:50:10 +01001844 if (min < 0) {
1845 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
1846 }
1847 if (mbedtls_mpi_cmp_int(N, min) <= 0) {
1848 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
1849 }
Gilles Peskine1e918f42021-03-29 22:14:51 +02001850
Gilles Peskine1a7df4e2021-04-01 15:57:18 +02001851 /* Ensure that target MPI has exactly the same number of limbs
1852 * as the upper bound, even if the upper bound has leading zeros.
Gilles Peskine6b7ce962022-12-15 15:04:33 +01001853 * This is necessary for mbedtls_mpi_core_random. */
Gilles Peskine449bd832023-01-11 14:50:10 +01001854 int ret = mbedtls_mpi_resize_clear(X, N->n);
1855 if (ret != 0) {
1856 return ret;
1857 }
Gilles Peskine1a7df4e2021-04-01 15:57:18 +02001858
Gilles Peskine449bd832023-01-11 14:50:10 +01001859 return mbedtls_mpi_core_random(X->p, min, N->p, X->n, f_rng, p_rng);
Gilles Peskine02ac93a2021-03-29 22:02:55 +02001860}
1861
Paul Bakker5121ce52009-01-03 21:22:43 +00001862/*
1863 * Modular inverse: X = A^-1 mod N (HAC 14.61 / 14.64)
1864 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001865int mbedtls_mpi_inv_mod(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *N)
Paul Bakker5121ce52009-01-03 21:22:43 +00001866{
Janos Follath24eed8d2019-11-22 13:21:35 +00001867 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001868 mbedtls_mpi G, TA, TU, U1, U2, TB, TV, V1, V2;
Paul Bakker5121ce52009-01-03 21:22:43 +00001869
Gilles Peskine449bd832023-01-11 14:50:10 +01001870 if (mbedtls_mpi_cmp_int(N, 1) <= 0) {
1871 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
1872 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001873
Gilles Peskine449bd832023-01-11 14:50:10 +01001874 mbedtls_mpi_init(&TA); mbedtls_mpi_init(&TU); mbedtls_mpi_init(&U1); mbedtls_mpi_init(&U2);
1875 mbedtls_mpi_init(&G); mbedtls_mpi_init(&TB); mbedtls_mpi_init(&TV);
1876 mbedtls_mpi_init(&V1); mbedtls_mpi_init(&V2);
Paul Bakker5121ce52009-01-03 21:22:43 +00001877
Gilles Peskine449bd832023-01-11 14:50:10 +01001878 MBEDTLS_MPI_CHK(mbedtls_mpi_gcd(&G, A, N));
Paul Bakker5121ce52009-01-03 21:22:43 +00001879
Gilles Peskine449bd832023-01-11 14:50:10 +01001880 if (mbedtls_mpi_cmp_int(&G, 1) != 0) {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001881 ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
Paul Bakker5121ce52009-01-03 21:22:43 +00001882 goto cleanup;
1883 }
1884
Gilles Peskine449bd832023-01-11 14:50:10 +01001885 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&TA, A, N));
1886 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TU, &TA));
1887 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TB, N));
1888 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TV, N));
Paul Bakker5121ce52009-01-03 21:22:43 +00001889
Gilles Peskine449bd832023-01-11 14:50:10 +01001890 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&U1, 1));
1891 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&U2, 0));
1892 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&V1, 0));
1893 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&V2, 1));
Paul Bakker5121ce52009-01-03 21:22:43 +00001894
Gilles Peskine449bd832023-01-11 14:50:10 +01001895 do {
1896 while ((TU.p[0] & 1) == 0) {
1897 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TU, 1));
Paul Bakker5121ce52009-01-03 21:22:43 +00001898
Gilles Peskine449bd832023-01-11 14:50:10 +01001899 if ((U1.p[0] & 1) != 0 || (U2.p[0] & 1) != 0) {
1900 MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&U1, &U1, &TB));
1901 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&U2, &U2, &TA));
Paul Bakker5121ce52009-01-03 21:22:43 +00001902 }
1903
Gilles Peskine449bd832023-01-11 14:50:10 +01001904 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&U1, 1));
1905 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&U2, 1));
Paul Bakker5121ce52009-01-03 21:22:43 +00001906 }
1907
Gilles Peskine449bd832023-01-11 14:50:10 +01001908 while ((TV.p[0] & 1) == 0) {
1909 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TV, 1));
Paul Bakker5121ce52009-01-03 21:22:43 +00001910
Gilles Peskine449bd832023-01-11 14:50:10 +01001911 if ((V1.p[0] & 1) != 0 || (V2.p[0] & 1) != 0) {
1912 MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&V1, &V1, &TB));
1913 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&V2, &V2, &TA));
Paul Bakker5121ce52009-01-03 21:22:43 +00001914 }
1915
Gilles Peskine449bd832023-01-11 14:50:10 +01001916 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&V1, 1));
1917 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&V2, 1));
Paul Bakker5121ce52009-01-03 21:22:43 +00001918 }
1919
Gilles Peskine449bd832023-01-11 14:50:10 +01001920 if (mbedtls_mpi_cmp_mpi(&TU, &TV) >= 0) {
1921 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&TU, &TU, &TV));
1922 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&U1, &U1, &V1));
1923 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&U2, &U2, &V2));
1924 } else {
1925 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&TV, &TV, &TU));
1926 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&V1, &V1, &U1));
1927 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&V2, &V2, &U2));
Paul Bakker5121ce52009-01-03 21:22:43 +00001928 }
Gilles Peskine449bd832023-01-11 14:50:10 +01001929 } while (mbedtls_mpi_cmp_int(&TU, 0) != 0);
1930
1931 while (mbedtls_mpi_cmp_int(&V1, 0) < 0) {
1932 MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&V1, &V1, N));
Paul Bakker5121ce52009-01-03 21:22:43 +00001933 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001934
Gilles Peskine449bd832023-01-11 14:50:10 +01001935 while (mbedtls_mpi_cmp_mpi(&V1, N) >= 0) {
1936 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&V1, &V1, N));
1937 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001938
Gilles Peskine449bd832023-01-11 14:50:10 +01001939 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(X, &V1));
Paul Bakker5121ce52009-01-03 21:22:43 +00001940
1941cleanup:
1942
Gilles Peskine449bd832023-01-11 14:50:10 +01001943 mbedtls_mpi_free(&TA); mbedtls_mpi_free(&TU); mbedtls_mpi_free(&U1); mbedtls_mpi_free(&U2);
1944 mbedtls_mpi_free(&G); mbedtls_mpi_free(&TB); mbedtls_mpi_free(&TV);
1945 mbedtls_mpi_free(&V1); mbedtls_mpi_free(&V2);
Paul Bakker5121ce52009-01-03 21:22:43 +00001946
Gilles Peskine449bd832023-01-11 14:50:10 +01001947 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001948}
1949
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001950#if defined(MBEDTLS_GENPRIME)
Paul Bakkerd9374b02012-11-02 11:02:58 +00001951
Gilles Peskineb2bc1712019-02-08 17:27:11 +01001952/* Gaps between primes, starting at 3. https://oeis.org/A001223 */
1953static const unsigned char small_prime_gaps[] = {
1954 2, 2, 4, 2, 4, 2, 4, 6,
1955 2, 6, 4, 2, 4, 6, 6, 2,
1956 6, 4, 2, 6, 4, 6, 8, 4,
1957 2, 4, 2, 4, 14, 4, 6, 2,
1958 10, 2, 6, 6, 4, 6, 6, 2,
1959 10, 2, 4, 2, 12, 12, 4, 2,
1960 4, 6, 2, 10, 6, 6, 6, 2,
1961 6, 4, 2, 10, 14, 4, 2, 4,
1962 14, 6, 10, 2, 4, 6, 8, 6,
1963 6, 4, 6, 8, 4, 8, 10, 2,
1964 10, 2, 6, 4, 6, 8, 4, 2,
1965 4, 12, 8, 4, 8, 4, 6, 12,
1966 2, 18, 6, 10, 6, 6, 2, 6,
1967 10, 6, 6, 2, 6, 6, 4, 2,
1968 12, 10, 2, 4, 6, 6, 2, 12,
1969 4, 6, 8, 10, 8, 10, 8, 6,
1970 6, 4, 8, 6, 4, 8, 4, 14,
1971 10, 12, 2, 10, 2, 4, 2, 10,
1972 14, 4, 2, 4, 14, 4, 2, 4,
1973 20, 4, 8, 10, 8, 4, 6, 6,
1974 14, 4, 6, 6, 8, 6, /*reaches 997*/
Gilles Peskine30b03782023-08-22 11:06:47 +02001975 0 /* the last entry is effectively unused */
Paul Bakker5121ce52009-01-03 21:22:43 +00001976};
1977
1978/*
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01001979 * Small divisors test (X must be positive)
1980 *
1981 * Return values:
1982 * 0: no small factor (possible prime, more tests needed)
1983 * 1: certain prime
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001984 * MBEDTLS_ERR_MPI_NOT_ACCEPTABLE: certain non-prime
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01001985 * other negative: error
Paul Bakker5121ce52009-01-03 21:22:43 +00001986 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001987static int mpi_check_small_factors(const mbedtls_mpi *X)
Paul Bakker5121ce52009-01-03 21:22:43 +00001988{
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01001989 int ret = 0;
1990 size_t i;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001991 mbedtls_mpi_uint r;
Gilles Peskineb2bc1712019-02-08 17:27:11 +01001992 unsigned p = 3; /* The first odd prime */
Paul Bakker5121ce52009-01-03 21:22:43 +00001993
Gilles Peskine449bd832023-01-11 14:50:10 +01001994 if ((X->p[0] & 1) == 0) {
1995 return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
1996 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001997
Gilles Peskineb2bc1712019-02-08 17:27:11 +01001998 for (i = 0; i < sizeof(small_prime_gaps); p += small_prime_gaps[i], i++) {
1999 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_int(&r, X, p));
Gilles Peskine449bd832023-01-11 14:50:10 +01002000 if (r == 0) {
Gilles Peskineb2bc1712019-02-08 17:27:11 +01002001 if (mbedtls_mpi_cmp_int(X, p) == 0) {
2002 return 1;
2003 } else {
2004 return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2005 }
Gilles Peskine449bd832023-01-11 14:50:10 +01002006 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002007 }
2008
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002009cleanup:
Gilles Peskine449bd832023-01-11 14:50:10 +01002010 return ret;
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002011}
2012
2013/*
2014 * Miller-Rabin pseudo-primality test (HAC 4.24)
2015 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002016static int mpi_miller_rabin(const mbedtls_mpi *X, size_t rounds,
2017 int (*f_rng)(void *, unsigned char *, size_t),
2018 void *p_rng)
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002019{
Pascal Junodb99183d2015-03-11 16:49:45 +01002020 int ret, count;
Janos Follathda31fa12018-09-03 14:45:23 +01002021 size_t i, j, k, s;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002022 mbedtls_mpi W, R, T, A, RR;
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002023
Gilles Peskine449bd832023-01-11 14:50:10 +01002024 mbedtls_mpi_init(&W); mbedtls_mpi_init(&R);
2025 mbedtls_mpi_init(&T); mbedtls_mpi_init(&A);
2026 mbedtls_mpi_init(&RR);
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002027
Paul Bakker5121ce52009-01-03 21:22:43 +00002028 /*
2029 * W = |X| - 1
2030 * R = W >> lsb( W )
2031 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002032 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(&W, X, 1));
2033 s = mbedtls_mpi_lsb(&W);
2034 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&R, &W));
2035 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&R, s));
Paul Bakker5121ce52009-01-03 21:22:43 +00002036
Gilles Peskine449bd832023-01-11 14:50:10 +01002037 for (i = 0; i < rounds; i++) {
Paul Bakker5121ce52009-01-03 21:22:43 +00002038 /*
2039 * pick a random A, 1 < A < |X| - 1
2040 */
Pascal Junodb99183d2015-03-11 16:49:45 +01002041 count = 0;
2042 do {
Gilles Peskine449bd832023-01-11 14:50:10 +01002043 MBEDTLS_MPI_CHK(mbedtls_mpi_fill_random(&A, X->n * ciL, f_rng, p_rng));
Pascal Junodb99183d2015-03-11 16:49:45 +01002044
Gilles Peskine449bd832023-01-11 14:50:10 +01002045 j = mbedtls_mpi_bitlen(&A);
2046 k = mbedtls_mpi_bitlen(&W);
Pascal Junodb99183d2015-03-11 16:49:45 +01002047 if (j > k) {
Gilles Peskine449bd832023-01-11 14:50:10 +01002048 A.p[A.n - 1] &= ((mbedtls_mpi_uint) 1 << (k - (A.n - 1) * biL - 1)) - 1;
Pascal Junodb99183d2015-03-11 16:49:45 +01002049 }
2050
2051 if (count++ > 30) {
Jens Wiklanderf08aa3e2019-01-17 13:30:57 +01002052 ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2053 goto cleanup;
Pascal Junodb99183d2015-03-11 16:49:45 +01002054 }
2055
Gilles Peskine449bd832023-01-11 14:50:10 +01002056 } while (mbedtls_mpi_cmp_mpi(&A, &W) >= 0 ||
2057 mbedtls_mpi_cmp_int(&A, 1) <= 0);
Paul Bakker5121ce52009-01-03 21:22:43 +00002058
2059 /*
2060 * A = A^R mod |X|
2061 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002062 MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&A, &A, &R, X, &RR));
Paul Bakker5121ce52009-01-03 21:22:43 +00002063
Gilles Peskine449bd832023-01-11 14:50:10 +01002064 if (mbedtls_mpi_cmp_mpi(&A, &W) == 0 ||
2065 mbedtls_mpi_cmp_int(&A, 1) == 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00002066 continue;
Gilles Peskine449bd832023-01-11 14:50:10 +01002067 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002068
2069 j = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +01002070 while (j < s && mbedtls_mpi_cmp_mpi(&A, &W) != 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00002071 /*
2072 * A = A * A mod |X|
2073 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002074 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&T, &A, &A));
2075 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&A, &T, X));
Paul Bakker5121ce52009-01-03 21:22:43 +00002076
Gilles Peskine449bd832023-01-11 14:50:10 +01002077 if (mbedtls_mpi_cmp_int(&A, 1) == 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00002078 break;
Gilles Peskine449bd832023-01-11 14:50:10 +01002079 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002080
2081 j++;
2082 }
2083
2084 /*
2085 * not prime if A != |X| - 1 or A == 1
2086 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002087 if (mbedtls_mpi_cmp_mpi(&A, &W) != 0 ||
2088 mbedtls_mpi_cmp_int(&A, 1) == 0) {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002089 ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
Paul Bakker5121ce52009-01-03 21:22:43 +00002090 break;
2091 }
2092 }
2093
2094cleanup:
Gilles Peskine449bd832023-01-11 14:50:10 +01002095 mbedtls_mpi_free(&W); mbedtls_mpi_free(&R);
2096 mbedtls_mpi_free(&T); mbedtls_mpi_free(&A);
2097 mbedtls_mpi_free(&RR);
Paul Bakker5121ce52009-01-03 21:22:43 +00002098
Gilles Peskine449bd832023-01-11 14:50:10 +01002099 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00002100}
2101
2102/*
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002103 * Pseudo-primality test: small factors, then Miller-Rabin
2104 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002105int mbedtls_mpi_is_prime_ext(const mbedtls_mpi *X, int rounds,
2106 int (*f_rng)(void *, unsigned char *, size_t),
2107 void *p_rng)
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002108{
Janos Follath24eed8d2019-11-22 13:21:35 +00002109 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002110 mbedtls_mpi XX;
Manuel Pégourié-Gonnard7f4ed672014-10-14 20:56:02 +02002111
2112 XX.s = 1;
2113 XX.n = X->n;
2114 XX.p = X->p;
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002115
Gilles Peskine449bd832023-01-11 14:50:10 +01002116 if (mbedtls_mpi_cmp_int(&XX, 0) == 0 ||
2117 mbedtls_mpi_cmp_int(&XX, 1) == 0) {
2118 return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002119 }
2120
Gilles Peskine449bd832023-01-11 14:50:10 +01002121 if (mbedtls_mpi_cmp_int(&XX, 2) == 0) {
2122 return 0;
2123 }
2124
2125 if ((ret = mpi_check_small_factors(&XX)) != 0) {
2126 if (ret == 1) {
2127 return 0;
2128 }
2129
2130 return ret;
2131 }
2132
2133 return mpi_miller_rabin(&XX, rounds, f_rng, p_rng);
Janos Follathf301d232018-08-14 13:34:01 +01002134}
2135
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002136/*
Paul Bakker5121ce52009-01-03 21:22:43 +00002137 * Prime number generation
Jethro Beekman66689272018-02-14 19:24:10 -08002138 *
Janos Follathf301d232018-08-14 13:34:01 +01002139 * To generate an RSA key in a way recommended by FIPS 186-4, both primes must
2140 * be either 1024 bits or 1536 bits long, and flags must contain
2141 * MBEDTLS_MPI_GEN_PRIME_FLAG_LOW_ERR.
Paul Bakker5121ce52009-01-03 21:22:43 +00002142 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002143int mbedtls_mpi_gen_prime(mbedtls_mpi *X, size_t nbits, int flags,
2144 int (*f_rng)(void *, unsigned char *, size_t),
2145 void *p_rng)
Paul Bakker5121ce52009-01-03 21:22:43 +00002146{
Jethro Beekman66689272018-02-14 19:24:10 -08002147#ifdef MBEDTLS_HAVE_INT64
2148// ceil(2^63.5)
2149#define CEIL_MAXUINT_DIV_SQRT2 0xb504f333f9de6485ULL
2150#else
2151// ceil(2^31.5)
2152#define CEIL_MAXUINT_DIV_SQRT2 0xb504f334U
2153#endif
2154 int ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
Paul Bakker23986e52011-04-24 08:57:21 +00002155 size_t k, n;
Janos Follathda31fa12018-09-03 14:45:23 +01002156 int rounds;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002157 mbedtls_mpi_uint r;
2158 mbedtls_mpi Y;
Paul Bakker5121ce52009-01-03 21:22:43 +00002159
Gilles Peskine449bd832023-01-11 14:50:10 +01002160 if (nbits < 3 || nbits > MBEDTLS_MPI_MAX_BITS) {
2161 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
2162 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002163
Gilles Peskine449bd832023-01-11 14:50:10 +01002164 mbedtls_mpi_init(&Y);
Paul Bakker5121ce52009-01-03 21:22:43 +00002165
Gilles Peskine449bd832023-01-11 14:50:10 +01002166 n = BITS_TO_LIMBS(nbits);
Paul Bakker5121ce52009-01-03 21:22:43 +00002167
Gilles Peskine449bd832023-01-11 14:50:10 +01002168 if ((flags & MBEDTLS_MPI_GEN_PRIME_FLAG_LOW_ERR) == 0) {
Janos Follathda31fa12018-09-03 14:45:23 +01002169 /*
2170 * 2^-80 error probability, number of rounds chosen per HAC, table 4.4
2171 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002172 rounds = ((nbits >= 1300) ? 2 : (nbits >= 850) ? 3 :
2173 (nbits >= 650) ? 4 : (nbits >= 350) ? 8 :
2174 (nbits >= 250) ? 12 : (nbits >= 150) ? 18 : 27);
2175 } else {
Janos Follathda31fa12018-09-03 14:45:23 +01002176 /*
2177 * 2^-100 error probability, number of rounds computed based on HAC,
2178 * fact 4.48
2179 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002180 rounds = ((nbits >= 1450) ? 4 : (nbits >= 1150) ? 5 :
2181 (nbits >= 1000) ? 6 : (nbits >= 850) ? 7 :
2182 (nbits >= 750) ? 8 : (nbits >= 500) ? 13 :
2183 (nbits >= 250) ? 28 : (nbits >= 150) ? 40 : 51);
Janos Follathda31fa12018-09-03 14:45:23 +01002184 }
2185
Gilles Peskine449bd832023-01-11 14:50:10 +01002186 while (1) {
2187 MBEDTLS_MPI_CHK(mbedtls_mpi_fill_random(X, n * ciL, f_rng, p_rng));
Jethro Beekman66689272018-02-14 19:24:10 -08002188 /* 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 +01002189 if (X->p[n-1] < CEIL_MAXUINT_DIV_SQRT2) {
2190 continue;
2191 }
Jethro Beekman66689272018-02-14 19:24:10 -08002192
2193 k = n * biL;
Gilles Peskine449bd832023-01-11 14:50:10 +01002194 if (k > nbits) {
2195 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(X, k - nbits));
2196 }
Jethro Beekman66689272018-02-14 19:24:10 -08002197 X->p[0] |= 1;
2198
Gilles Peskine449bd832023-01-11 14:50:10 +01002199 if ((flags & MBEDTLS_MPI_GEN_PRIME_FLAG_DH) == 0) {
2200 ret = mbedtls_mpi_is_prime_ext(X, rounds, f_rng, p_rng);
Jethro Beekman66689272018-02-14 19:24:10 -08002201
Gilles Peskine449bd832023-01-11 14:50:10 +01002202 if (ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE) {
Paul Bakker5121ce52009-01-03 21:22:43 +00002203 goto cleanup;
Gilles Peskine449bd832023-01-11 14:50:10 +01002204 }
2205 } else {
Manuel Pégourié-Gonnardddf76152013-11-22 19:58:22 +01002206 /*
Tom Cosgrovece7f18c2022-07-28 05:50:56 +01002207 * A necessary condition for Y and X = 2Y + 1 to be prime
Jethro Beekman66689272018-02-14 19:24:10 -08002208 * is X = 2 mod 3 (which is equivalent to Y = 2 mod 3).
2209 * Make sure it is satisfied, while keeping X = 3 mod 4
Manuel Pégourié-Gonnardddf76152013-11-22 19:58:22 +01002210 */
Jethro Beekman66689272018-02-14 19:24:10 -08002211
2212 X->p[0] |= 2;
2213
Gilles Peskine449bd832023-01-11 14:50:10 +01002214 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_int(&r, X, 3));
2215 if (r == 0) {
2216 MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(X, X, 8));
2217 } else if (r == 1) {
2218 MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(X, X, 4));
2219 }
Jethro Beekman66689272018-02-14 19:24:10 -08002220
2221 /* Set Y = (X-1) / 2, which is X / 2 because X is odd */
Gilles Peskine449bd832023-01-11 14:50:10 +01002222 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&Y, X));
2223 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&Y, 1));
Jethro Beekman66689272018-02-14 19:24:10 -08002224
Gilles Peskine449bd832023-01-11 14:50:10 +01002225 while (1) {
Jethro Beekman66689272018-02-14 19:24:10 -08002226 /*
2227 * First, check small factors for X and Y
2228 * before doing Miller-Rabin on any of them
2229 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002230 if ((ret = mpi_check_small_factors(X)) == 0 &&
2231 (ret = mpi_check_small_factors(&Y)) == 0 &&
2232 (ret = mpi_miller_rabin(X, rounds, f_rng, p_rng))
2233 == 0 &&
2234 (ret = mpi_miller_rabin(&Y, rounds, f_rng, p_rng))
2235 == 0) {
Jethro Beekman66689272018-02-14 19:24:10 -08002236 goto cleanup;
Gilles Peskine449bd832023-01-11 14:50:10 +01002237 }
Jethro Beekman66689272018-02-14 19:24:10 -08002238
Gilles Peskine449bd832023-01-11 14:50:10 +01002239 if (ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE) {
Jethro Beekman66689272018-02-14 19:24:10 -08002240 goto cleanup;
Gilles Peskine449bd832023-01-11 14:50:10 +01002241 }
Jethro Beekman66689272018-02-14 19:24:10 -08002242
2243 /*
2244 * Next candidates. We want to preserve Y = (X-1) / 2 and
2245 * Y = 1 mod 2 and Y = 2 mod 3 (eq X = 3 mod 4 and X = 2 mod 3)
2246 * so up Y by 6 and X by 12.
2247 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002248 MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(X, X, 12));
2249 MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(&Y, &Y, 6));
Paul Bakker5121ce52009-01-03 21:22:43 +00002250 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002251 }
2252 }
2253
2254cleanup:
2255
Gilles Peskine449bd832023-01-11 14:50:10 +01002256 mbedtls_mpi_free(&Y);
Paul Bakker5121ce52009-01-03 21:22:43 +00002257
Gilles Peskine449bd832023-01-11 14:50:10 +01002258 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00002259}
2260
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002261#endif /* MBEDTLS_GENPRIME */
Paul Bakker5121ce52009-01-03 21:22:43 +00002262
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002263#if defined(MBEDTLS_SELF_TEST)
Paul Bakker5121ce52009-01-03 21:22:43 +00002264
Paul Bakker23986e52011-04-24 08:57:21 +00002265#define GCD_PAIR_COUNT 3
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002266
2267static const int gcd_pairs[GCD_PAIR_COUNT][3] =
2268{
2269 { 693, 609, 21 },
2270 { 1764, 868, 28 },
2271 { 768454923, 542167814, 1 }
2272};
2273
Paul Bakker5121ce52009-01-03 21:22:43 +00002274/*
2275 * Checkup routine
2276 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002277int mbedtls_mpi_self_test(int verbose)
Paul Bakker5121ce52009-01-03 21:22:43 +00002278{
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002279 int ret, i;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002280 mbedtls_mpi A, E, N, X, Y, U, V;
Paul Bakker5121ce52009-01-03 21:22:43 +00002281
Gilles Peskine449bd832023-01-11 14:50:10 +01002282 mbedtls_mpi_init(&A); mbedtls_mpi_init(&E); mbedtls_mpi_init(&N); mbedtls_mpi_init(&X);
2283 mbedtls_mpi_init(&Y); mbedtls_mpi_init(&U); mbedtls_mpi_init(&V);
Paul Bakker5121ce52009-01-03 21:22:43 +00002284
Gilles Peskine449bd832023-01-11 14:50:10 +01002285 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&A, 16,
2286 "EFE021C2645FD1DC586E69184AF4A31E" \
2287 "D5F53E93B5F123FA41680867BA110131" \
2288 "944FE7952E2517337780CB0DB80E61AA" \
2289 "E7C8DDC6C5C6AADEB34EB38A2F40D5E6"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002290
Gilles Peskine449bd832023-01-11 14:50:10 +01002291 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&E, 16,
2292 "B2E7EFD37075B9F03FF989C7C5051C20" \
2293 "34D2A323810251127E7BF8625A4F49A5" \
2294 "F3E27F4DA8BD59C47D6DAABA4C8127BD" \
2295 "5B5C25763222FEFCCFC38B832366C29E"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002296
Gilles Peskine449bd832023-01-11 14:50:10 +01002297 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&N, 16,
2298 "0066A198186C18C10B2F5ED9B522752A" \
2299 "9830B69916E535C8F047518A889A43A5" \
2300 "94B6BED27A168D31D4A52F88925AA8F5"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002301
Gilles Peskine449bd832023-01-11 14:50:10 +01002302 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&X, &A, &N));
Paul Bakker5121ce52009-01-03 21:22:43 +00002303
Gilles Peskine449bd832023-01-11 14:50:10 +01002304 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&U, 16,
2305 "602AB7ECA597A3D6B56FF9829A5E8B85" \
2306 "9E857EA95A03512E2BAE7391688D264A" \
2307 "A5663B0341DB9CCFD2C4C5F421FEC814" \
2308 "8001B72E848A38CAE1C65F78E56ABDEF" \
2309 "E12D3C039B8A02D6BE593F0BBBDA56F1" \
2310 "ECF677152EF804370C1A305CAF3B5BF1" \
2311 "30879B56C61DE584A0F53A2447A51E"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002312
Gilles Peskine449bd832023-01-11 14:50:10 +01002313 if (verbose != 0) {
2314 mbedtls_printf(" MPI test #1 (mul_mpi): ");
2315 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002316
Gilles Peskine449bd832023-01-11 14:50:10 +01002317 if (mbedtls_mpi_cmp_mpi(&X, &U) != 0) {
2318 if (verbose != 0) {
2319 mbedtls_printf("failed\n");
2320 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002321
Manuel Pégourié-Gonnard9e987ed2014-01-20 10:03:15 +01002322 ret = 1;
2323 goto cleanup;
Paul Bakker5121ce52009-01-03 21:22:43 +00002324 }
2325
Gilles Peskine449bd832023-01-11 14:50:10 +01002326 if (verbose != 0) {
2327 mbedtls_printf("passed\n");
2328 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002329
Gilles Peskine449bd832023-01-11 14:50:10 +01002330 MBEDTLS_MPI_CHK(mbedtls_mpi_div_mpi(&X, &Y, &A, &N));
Paul Bakker5121ce52009-01-03 21:22:43 +00002331
Gilles Peskine449bd832023-01-11 14:50:10 +01002332 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&U, 16,
2333 "256567336059E52CAE22925474705F39A94"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002334
Gilles Peskine449bd832023-01-11 14:50:10 +01002335 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&V, 16,
2336 "6613F26162223DF488E9CD48CC132C7A" \
2337 "0AC93C701B001B092E4E5B9F73BCD27B" \
2338 "9EE50D0657C77F374E903CDFA4C642"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002339
Gilles Peskine449bd832023-01-11 14:50:10 +01002340 if (verbose != 0) {
2341 mbedtls_printf(" MPI test #2 (div_mpi): ");
2342 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002343
Gilles Peskine449bd832023-01-11 14:50:10 +01002344 if (mbedtls_mpi_cmp_mpi(&X, &U) != 0 ||
2345 mbedtls_mpi_cmp_mpi(&Y, &V) != 0) {
2346 if (verbose != 0) {
2347 mbedtls_printf("failed\n");
2348 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002349
Manuel Pégourié-Gonnard9e987ed2014-01-20 10:03:15 +01002350 ret = 1;
2351 goto cleanup;
Paul Bakker5121ce52009-01-03 21:22:43 +00002352 }
2353
Gilles Peskine449bd832023-01-11 14:50:10 +01002354 if (verbose != 0) {
2355 mbedtls_printf("passed\n");
2356 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002357
Gilles Peskine449bd832023-01-11 14:50:10 +01002358 MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&X, &A, &E, &N, NULL));
Paul Bakker5121ce52009-01-03 21:22:43 +00002359
Gilles Peskine449bd832023-01-11 14:50:10 +01002360 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&U, 16,
2361 "36E139AEA55215609D2816998ED020BB" \
2362 "BD96C37890F65171D948E9BC7CBAA4D9" \
2363 "325D24D6A3C12710F10A09FA08AB87"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002364
Gilles Peskine449bd832023-01-11 14:50:10 +01002365 if (verbose != 0) {
2366 mbedtls_printf(" MPI test #3 (exp_mod): ");
2367 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002368
Gilles Peskine449bd832023-01-11 14:50:10 +01002369 if (mbedtls_mpi_cmp_mpi(&X, &U) != 0) {
2370 if (verbose != 0) {
2371 mbedtls_printf("failed\n");
2372 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002373
Manuel Pégourié-Gonnard9e987ed2014-01-20 10:03:15 +01002374 ret = 1;
2375 goto cleanup;
Paul Bakker5121ce52009-01-03 21:22:43 +00002376 }
2377
Gilles Peskine449bd832023-01-11 14:50:10 +01002378 if (verbose != 0) {
2379 mbedtls_printf("passed\n");
2380 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002381
Gilles Peskine449bd832023-01-11 14:50:10 +01002382 MBEDTLS_MPI_CHK(mbedtls_mpi_inv_mod(&X, &A, &N));
Paul Bakker5121ce52009-01-03 21:22:43 +00002383
Gilles Peskine449bd832023-01-11 14:50:10 +01002384 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&U, 16,
2385 "003A0AAEDD7E784FC07D8F9EC6E3BFD5" \
2386 "C3DBA76456363A10869622EAC2DD84EC" \
2387 "C5B8A74DAC4D09E03B5E0BE779F2DF61"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002388
Gilles Peskine449bd832023-01-11 14:50:10 +01002389 if (verbose != 0) {
2390 mbedtls_printf(" MPI test #4 (inv_mod): ");
2391 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002392
Gilles Peskine449bd832023-01-11 14:50:10 +01002393 if (mbedtls_mpi_cmp_mpi(&X, &U) != 0) {
2394 if (verbose != 0) {
2395 mbedtls_printf("failed\n");
2396 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002397
Manuel Pégourié-Gonnard9e987ed2014-01-20 10:03:15 +01002398 ret = 1;
2399 goto cleanup;
Paul Bakker5121ce52009-01-03 21:22:43 +00002400 }
2401
Gilles Peskine449bd832023-01-11 14:50:10 +01002402 if (verbose != 0) {
2403 mbedtls_printf("passed\n");
2404 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002405
Gilles Peskine449bd832023-01-11 14:50:10 +01002406 if (verbose != 0) {
2407 mbedtls_printf(" MPI test #5 (simple gcd): ");
2408 }
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002409
Gilles Peskine449bd832023-01-11 14:50:10 +01002410 for (i = 0; i < GCD_PAIR_COUNT; i++) {
2411 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&X, gcd_pairs[i][0]));
2412 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&Y, gcd_pairs[i][1]));
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002413
Gilles Peskine449bd832023-01-11 14:50:10 +01002414 MBEDTLS_MPI_CHK(mbedtls_mpi_gcd(&A, &X, &Y));
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002415
Gilles Peskine449bd832023-01-11 14:50:10 +01002416 if (mbedtls_mpi_cmp_int(&A, gcd_pairs[i][2]) != 0) {
2417 if (verbose != 0) {
2418 mbedtls_printf("failed at %d\n", i);
2419 }
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002420
Manuel Pégourié-Gonnard9e987ed2014-01-20 10:03:15 +01002421 ret = 1;
2422 goto cleanup;
2423 }
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002424 }
2425
Gilles Peskine449bd832023-01-11 14:50:10 +01002426 if (verbose != 0) {
2427 mbedtls_printf("passed\n");
2428 }
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002429
Paul Bakker5121ce52009-01-03 21:22:43 +00002430cleanup:
2431
Gilles Peskine449bd832023-01-11 14:50:10 +01002432 if (ret != 0 && verbose != 0) {
2433 mbedtls_printf("Unexpected error, return code = %08X\n", (unsigned int) ret);
2434 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002435
Gilles Peskine449bd832023-01-11 14:50:10 +01002436 mbedtls_mpi_free(&A); mbedtls_mpi_free(&E); mbedtls_mpi_free(&N); mbedtls_mpi_free(&X);
2437 mbedtls_mpi_free(&Y); mbedtls_mpi_free(&U); mbedtls_mpi_free(&V);
Paul Bakker5121ce52009-01-03 21:22:43 +00002438
Gilles Peskine449bd832023-01-11 14:50:10 +01002439 if (verbose != 0) {
2440 mbedtls_printf("\n");
2441 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002442
Gilles Peskine449bd832023-01-11 14:50:10 +01002443 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00002444}
2445
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002446#endif /* MBEDTLS_SELF_TEST */
Paul Bakker5121ce52009-01-03 21:22:43 +00002447
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002448#endif /* MBEDTLS_BIGNUM_C */