blob: f7ec35a9df658dac83b58e8ea278d49fb3c0ecdd [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"
Janos Follath5f316972024-08-22 14:53:13 +010030#include "bignum_internal.h"
Chris Jones4c5819c2021-03-03 17:45:34 +000031#include "bn_mul.h"
Andres Amaya Garcia1f6301b2018-04-17 09:51:09 -050032#include "mbedtls/platform_util.h"
Janos Follath24eed8d2019-11-22 13:21:35 +000033#include "mbedtls/error.h"
Gabor Mezei22c9a6f2021-10-20 12:09:35 +020034#include "constant_time_internal.h"
Paul Bakker5121ce52009-01-03 21:22:43 +000035
Dave Rodgman351c71b2021-12-06 17:50:53 +000036#include <limits.h>
Rich Evans00ab4702015-02-06 13:43:58 +000037#include <string.h>
38
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000039#include "mbedtls/platform.h"
Paul Bakker6e339b52013-07-03 13:37:05 +020040
Janos Follath4ec0fb52024-03-08 17:22:40 +000041
42
43/*
44 * Conditionally select an MPI sign in constant time.
45 * (MPI sign is the field s in mbedtls_mpi. It is unsigned short and only 1 and -1 are valid
46 * values.)
47 */
Janos Follathb888bc02024-03-11 09:29:53 +000048static inline signed short mbedtls_ct_mpi_sign_if(mbedtls_ct_condition_t cond,
49 signed short sign1, signed short sign2)
Janos Follath4ec0fb52024-03-08 17:22:40 +000050{
Janos Follathb888bc02024-03-11 09:29:53 +000051 return (signed short) mbedtls_ct_uint_if(cond, sign1 + 1, sign2 + 1) - 1;
Janos Follath4ec0fb52024-03-08 17:22:40 +000052}
53
Dave Rodgman7d4f0192023-05-09 14:01:05 +010054/*
55 * Compare signed values in constant time
56 */
57int mbedtls_mpi_lt_mpi_ct(const mbedtls_mpi *X,
58 const mbedtls_mpi *Y,
59 unsigned *ret)
60{
Dave Rodgman1f39f032023-08-01 09:19:16 +010061 mbedtls_ct_condition_t different_sign, X_is_negative, Y_is_negative, result;
Dave Rodgman7d4f0192023-05-09 14:01:05 +010062
Dave Rodgman7d4f0192023-05-09 14:01:05 +010063 if (X->n != Y->n) {
64 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
65 }
66
67 /*
Dave Rodgmanb69239c2023-08-09 14:53:18 +010068 * Set N_is_negative to MBEDTLS_CT_FALSE if N >= 0, MBEDTLS_CT_TRUE if N < 0.
Dave Rodgman7d4f0192023-05-09 14:01:05 +010069 * We know that N->s == 1 if N >= 0 and N->s == -1 if N < 0.
70 */
Dave Rodgman1a7a5622023-05-17 13:47:56 +010071 X_is_negative = mbedtls_ct_bool((X->s & 2) >> 1);
72 Y_is_negative = mbedtls_ct_bool((Y->s & 2) >> 1);
Dave Rodgman7d4f0192023-05-09 14:01:05 +010073
74 /*
75 * If the signs are different, then the positive operand is the bigger.
76 * That is if X is negative (X_is_negative == 1), then X < Y is true and it
77 * is false if X is positive (X_is_negative == 0).
78 */
Dave Rodgman1cfc43c2023-09-19 16:18:59 +010079 different_sign = mbedtls_ct_bool_ne(X_is_negative, Y_is_negative); // true if different sign
Dave Rodgman1f39f032023-08-01 09:19:16 +010080 result = mbedtls_ct_bool_and(different_sign, X_is_negative);
Dave Rodgman7d4f0192023-05-09 14:01:05 +010081
Dave Rodgman32d72602023-07-31 12:28:05 +010082 /*
83 * Assuming signs are the same, compare X and Y. We switch the comparison
Dave Rodgman1a7a5622023-05-17 13:47:56 +010084 * order if they are negative so that we get the right result, regardles of
85 * sign.
Dave Rodgman7d4f0192023-05-09 14:01:05 +010086 */
Dave Rodgman7d4f0192023-05-09 14:01:05 +010087
Dave Rodgman32d72602023-07-31 12:28:05 +010088 /* This array is used to conditionally swap the pointers in const time */
Dave Rodgman1a7a5622023-05-17 13:47:56 +010089 void * const p[2] = { X->p, Y->p };
Dave Rodgman98ddc012023-08-10 12:11:31 +010090 size_t i = mbedtls_ct_size_if_else_0(X_is_negative, 1);
Dave Rodgman2c764842023-05-18 13:28:21 +010091 mbedtls_ct_condition_t lt = mbedtls_mpi_core_lt_ct(p[i], p[i ^ 1], X->n);
Dave Rodgman7d4f0192023-05-09 14:01:05 +010092
Dave Rodgman32d72602023-07-31 12:28:05 +010093 /*
Dave Rodgman1f39f032023-08-01 09:19:16 +010094 * Store in result iff the signs are the same (i.e., iff different_sign == false). If
Dave Rodgman32d72602023-07-31 12:28:05 +010095 * the signs differ, result has already been set, so we don't change it.
96 */
Dave Rodgman1f39f032023-08-01 09:19:16 +010097 result = mbedtls_ct_bool_or(result,
98 mbedtls_ct_bool_and(mbedtls_ct_bool_not(different_sign), lt));
Dave Rodgman1a7a5622023-05-17 13:47:56 +010099
Dave Rodgman98ddc012023-08-10 12:11:31 +0100100 *ret = mbedtls_ct_uint_if_else_0(result, 1);
Dave Rodgman7d4f0192023-05-09 14:01:05 +0100101
102 return 0;
103}
104
105/*
106 * Conditionally assign X = Y, without leaking information
107 * about whether the assignment was made or not.
108 * (Leaking information about the respective sizes of X and Y is ok however.)
109 */
Dave Rodgman0a487172023-09-15 11:52:06 +0100110#if defined(_MSC_VER) && defined(MBEDTLS_PLATFORM_IS_WINDOWS_ON_ARM64) && \
111 (_MSC_FULL_VER < 193131103)
Dave Rodgman7d4f0192023-05-09 14:01:05 +0100112/*
113 * MSVC miscompiles this function if it's inlined prior to Visual Studio 2022 version 17.1. See:
114 * https://developercommunity.visualstudio.com/t/c-compiler-miscompiles-part-of-mbedtls-library-on/1646989
115 */
116__declspec(noinline)
117#endif
118int mbedtls_mpi_safe_cond_assign(mbedtls_mpi *X,
119 const mbedtls_mpi *Y,
120 unsigned char assign)
121{
122 int ret = 0;
Dave Rodgman7d4f0192023-05-09 14:01:05 +0100123
Dave Rodgman7d4f0192023-05-09 14:01:05 +0100124 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, Y->n));
125
Dave Rodgman7e9af052023-09-28 17:08:16 +0100126 {
127 mbedtls_ct_condition_t do_assign = mbedtls_ct_bool(assign);
Dave Rodgman589ccb82023-05-17 13:55:01 +0100128
Janos Follath4ec0fb52024-03-08 17:22:40 +0000129 X->s = mbedtls_ct_mpi_sign_if(do_assign, Y->s, X->s);
Dave Rodgman7d4f0192023-05-09 14:01:05 +0100130
Dave Rodgman7e9af052023-09-28 17:08:16 +0100131 mbedtls_mpi_core_cond_assign(X->p, Y->p, Y->n, do_assign);
Dave Rodgman7d4f0192023-05-09 14:01:05 +0100132
Dave Rodgman7e9af052023-09-28 17:08:16 +0100133 mbedtls_ct_condition_t do_not_assign = mbedtls_ct_bool_not(do_assign);
134 for (size_t i = Y->n; i < X->n; i++) {
135 X->p[i] = mbedtls_ct_mpi_uint_if_else_0(do_not_assign, X->p[i]);
136 }
Dave Rodgman7d4f0192023-05-09 14:01:05 +0100137 }
138
139cleanup:
140 return ret;
141}
142
143/*
144 * Conditionally swap X and Y, without leaking information
145 * about whether the swap was made or not.
146 * Here it is not ok to simply swap the pointers, which would lead to
147 * different memory access patterns when X and Y are used afterwards.
148 */
149int mbedtls_mpi_safe_cond_swap(mbedtls_mpi *X,
150 mbedtls_mpi *Y,
151 unsigned char swap)
152{
153 int ret = 0;
154 int s;
Dave Rodgman7d4f0192023-05-09 14:01:05 +0100155
156 if (X == Y) {
157 return 0;
158 }
159
Dave Rodgmancd2e38b2023-05-17 13:31:55 +0100160 mbedtls_ct_condition_t do_swap = mbedtls_ct_bool(swap);
161
Dave Rodgman7d4f0192023-05-09 14:01:05 +0100162 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, Y->n));
163 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(Y, X->n));
164
165 s = X->s;
Janos Follath4ec0fb52024-03-08 17:22:40 +0000166 X->s = mbedtls_ct_mpi_sign_if(do_swap, Y->s, X->s);
167 Y->s = mbedtls_ct_mpi_sign_if(do_swap, s, Y->s);
Dave Rodgman7d4f0192023-05-09 14:01:05 +0100168
Dave Rodgmancd2e38b2023-05-17 13:31:55 +0100169 mbedtls_mpi_core_cond_swap(X->p, Y->p, X->n, do_swap);
Dave Rodgman7d4f0192023-05-09 14:01:05 +0100170
171cleanup:
172 return ret;
173}
174
Andres Amaya Garcia1f6301b2018-04-17 09:51:09 -0500175/* Implementation that should never be optimized out by the compiler */
Tom Cosgrovebc345e82023-07-25 15:17:39 +0100176#define mbedtls_mpi_zeroize_and_free(v, n) mbedtls_zeroize_and_free(v, ciL * (n))
Andres Amaya Garcia1f6301b2018-04-17 09:51:09 -0500177
Paul Bakker5121ce52009-01-03 21:22:43 +0000178/*
Paul Bakker6c591fa2011-05-05 11:49:20 +0000179 * Initialize one MPI
Paul Bakker5121ce52009-01-03 21:22:43 +0000180 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100181void mbedtls_mpi_init(mbedtls_mpi *X)
Paul Bakker5121ce52009-01-03 21:22:43 +0000182{
Paul Bakker6c591fa2011-05-05 11:49:20 +0000183 X->s = 1;
184 X->n = 0;
185 X->p = NULL;
Paul Bakker5121ce52009-01-03 21:22:43 +0000186}
187
188/*
Paul Bakker6c591fa2011-05-05 11:49:20 +0000189 * Unallocate one MPI
Paul Bakker5121ce52009-01-03 21:22:43 +0000190 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100191void mbedtls_mpi_free(mbedtls_mpi *X)
Paul Bakker5121ce52009-01-03 21:22:43 +0000192{
Gilles Peskine449bd832023-01-11 14:50:10 +0100193 if (X == NULL) {
Paul Bakker6c591fa2011-05-05 11:49:20 +0000194 return;
Gilles Peskine449bd832023-01-11 14:50:10 +0100195 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000196
Gilles Peskine449bd832023-01-11 14:50:10 +0100197 if (X->p != NULL) {
Tom Cosgrove46259f62023-07-18 16:44:14 +0100198 mbedtls_mpi_zeroize_and_free(X->p, X->n);
Paul Bakker5121ce52009-01-03 21:22:43 +0000199 }
200
Paul Bakker6c591fa2011-05-05 11:49:20 +0000201 X->s = 1;
202 X->n = 0;
203 X->p = NULL;
Paul Bakker5121ce52009-01-03 21:22:43 +0000204}
205
206/*
207 * Enlarge to the specified number of limbs
208 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100209int mbedtls_mpi_grow(mbedtls_mpi *X, size_t nblimbs)
Paul Bakker5121ce52009-01-03 21:22:43 +0000210{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200211 mbedtls_mpi_uint *p;
Paul Bakker5121ce52009-01-03 21:22:43 +0000212
Gilles Peskine449bd832023-01-11 14:50:10 +0100213 if (nblimbs > MBEDTLS_MPI_MAX_LIMBS) {
214 return MBEDTLS_ERR_MPI_ALLOC_FAILED;
215 }
Paul Bakkerf9688572011-05-05 10:00:45 +0000216
Gilles Peskine449bd832023-01-11 14:50:10 +0100217 if (X->n < nblimbs) {
218 if ((p = (mbedtls_mpi_uint *) mbedtls_calloc(nblimbs, ciL)) == NULL) {
219 return MBEDTLS_ERR_MPI_ALLOC_FAILED;
220 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000221
Gilles Peskine449bd832023-01-11 14:50:10 +0100222 if (X->p != NULL) {
223 memcpy(p, X->p, X->n * ciL);
Tom Cosgrove46259f62023-07-18 16:44:14 +0100224 mbedtls_mpi_zeroize_and_free(X->p, X->n);
Paul Bakker5121ce52009-01-03 21:22:43 +0000225 }
226
Gilles Peskine053022f2023-06-29 19:26:48 +0200227 /* nblimbs fits in n because we ensure that MBEDTLS_MPI_MAX_LIMBS
228 * fits, and we've checked that nblimbs <= MBEDTLS_MPI_MAX_LIMBS. */
229 X->n = (unsigned short) nblimbs;
Paul Bakker5121ce52009-01-03 21:22:43 +0000230 X->p = p;
231 }
232
Gilles Peskine449bd832023-01-11 14:50:10 +0100233 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000234}
235
236/*
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100237 * Resize down as much as possible,
238 * while keeping at least the specified number of limbs
239 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100240int mbedtls_mpi_shrink(mbedtls_mpi *X, size_t nblimbs)
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100241{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200242 mbedtls_mpi_uint *p;
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100243 size_t i;
Hanno Becker73d7d792018-12-11 10:35:51 +0000244
Gilles Peskine449bd832023-01-11 14:50:10 +0100245 if (nblimbs > MBEDTLS_MPI_MAX_LIMBS) {
246 return MBEDTLS_ERR_MPI_ALLOC_FAILED;
247 }
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100248
Gilles Peskinee2f563e2020-01-20 21:17:43 +0100249 /* Actually resize up if there are currently fewer than nblimbs limbs. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100250 if (X->n <= nblimbs) {
251 return mbedtls_mpi_grow(X, nblimbs);
252 }
Gilles Peskine322752b2020-01-21 13:59:51 +0100253 /* After this point, then X->n > nblimbs and in particular X->n > 0. */
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100254
Gilles Peskine449bd832023-01-11 14:50:10 +0100255 for (i = X->n - 1; i > 0; i--) {
256 if (X->p[i] != 0) {
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100257 break;
Gilles Peskine449bd832023-01-11 14:50:10 +0100258 }
259 }
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100260 i++;
261
Gilles Peskine449bd832023-01-11 14:50:10 +0100262 if (i < nblimbs) {
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100263 i = nblimbs;
Gilles Peskine449bd832023-01-11 14:50:10 +0100264 }
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100265
Gilles Peskine449bd832023-01-11 14:50:10 +0100266 if ((p = (mbedtls_mpi_uint *) mbedtls_calloc(i, ciL)) == NULL) {
267 return MBEDTLS_ERR_MPI_ALLOC_FAILED;
268 }
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100269
Gilles Peskine449bd832023-01-11 14:50:10 +0100270 if (X->p != NULL) {
271 memcpy(p, X->p, i * ciL);
Tom Cosgrove46259f62023-07-18 16:44:14 +0100272 mbedtls_mpi_zeroize_and_free(X->p, X->n);
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100273 }
274
Gilles Peskine053022f2023-06-29 19:26:48 +0200275 /* i fits in n because we ensure that MBEDTLS_MPI_MAX_LIMBS
276 * fits, and we've checked that i <= nblimbs <= MBEDTLS_MPI_MAX_LIMBS. */
277 X->n = (unsigned short) i;
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100278 X->p = p;
279
Gilles Peskine449bd832023-01-11 14:50:10 +0100280 return 0;
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100281}
282
Gilles Peskineed32b572021-06-02 22:17:52 +0200283/* Resize X to have exactly n limbs and set it to 0. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100284static int mbedtls_mpi_resize_clear(mbedtls_mpi *X, size_t limbs)
Gilles Peskineed32b572021-06-02 22:17:52 +0200285{
Gilles Peskine449bd832023-01-11 14:50:10 +0100286 if (limbs == 0) {
287 mbedtls_mpi_free(X);
288 return 0;
289 } else if (X->n == limbs) {
290 memset(X->p, 0, limbs * ciL);
Gilles Peskineed32b572021-06-02 22:17:52 +0200291 X->s = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +0100292 return 0;
293 } else {
294 mbedtls_mpi_free(X);
295 return mbedtls_mpi_grow(X, limbs);
Gilles Peskineed32b572021-06-02 22:17:52 +0200296 }
297}
298
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100299/*
Gilles Peskine3da1a8f2021-06-08 23:17:42 +0200300 * Copy the contents of Y into X.
301 *
302 * This function is not constant-time. Leading zeros in Y may be removed.
303 *
304 * Ensure that X does not shrink. This is not guaranteed by the public API,
Janos Follathc9faea02024-02-19 10:49:18 +0000305 * but some code in the bignum module might still rely on this property.
Paul Bakker5121ce52009-01-03 21:22:43 +0000306 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100307int mbedtls_mpi_copy(mbedtls_mpi *X, const mbedtls_mpi *Y)
Paul Bakker5121ce52009-01-03 21:22:43 +0000308{
Gilles Peskine4e4be7c2018-03-21 16:29:03 +0100309 int ret = 0;
Paul Bakker23986e52011-04-24 08:57:21 +0000310 size_t i;
Paul Bakker5121ce52009-01-03 21:22:43 +0000311
Gilles Peskine449bd832023-01-11 14:50:10 +0100312 if (X == Y) {
313 return 0;
Manuel Pégourié-Gonnardf4999932013-08-12 17:02:59 +0200314 }
315
Gilles Peskine449bd832023-01-11 14:50:10 +0100316 if (Y->n == 0) {
317 if (X->n != 0) {
318 X->s = 1;
319 memset(X->p, 0, X->n * ciL);
320 }
321 return 0;
322 }
323
324 for (i = Y->n - 1; i > 0; i--) {
325 if (Y->p[i] != 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +0000326 break;
Gilles Peskine449bd832023-01-11 14:50:10 +0100327 }
328 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000329 i++;
330
331 X->s = Y->s;
332
Gilles Peskine449bd832023-01-11 14:50:10 +0100333 if (X->n < i) {
334 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, i));
335 } else {
336 memset(X->p + i, 0, (X->n - i) * ciL);
Gilles Peskine4e4be7c2018-03-21 16:29:03 +0100337 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000338
Gilles Peskine449bd832023-01-11 14:50:10 +0100339 memcpy(X->p, Y->p, i * ciL);
Paul Bakker5121ce52009-01-03 21:22:43 +0000340
341cleanup:
342
Gilles Peskine449bd832023-01-11 14:50:10 +0100343 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000344}
345
346/*
347 * Swap the contents of X and Y
348 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100349void mbedtls_mpi_swap(mbedtls_mpi *X, mbedtls_mpi *Y)
Paul Bakker5121ce52009-01-03 21:22:43 +0000350{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200351 mbedtls_mpi T;
Paul Bakker5121ce52009-01-03 21:22:43 +0000352
Gilles Peskine449bd832023-01-11 14:50:10 +0100353 memcpy(&T, X, sizeof(mbedtls_mpi));
354 memcpy(X, Y, sizeof(mbedtls_mpi));
355 memcpy(Y, &T, sizeof(mbedtls_mpi));
Paul Bakker5121ce52009-01-03 21:22:43 +0000356}
357
Gilles Peskine449bd832023-01-11 14:50:10 +0100358static inline mbedtls_mpi_uint mpi_sint_abs(mbedtls_mpi_sint z)
Gilles Peskineef7f4e42022-11-15 23:25:27 +0100359{
Gilles Peskine449bd832023-01-11 14:50:10 +0100360 if (z >= 0) {
361 return z;
362 }
Gilles Peskineef7f4e42022-11-15 23:25:27 +0100363 /* Take care to handle the most negative value (-2^(biL-1)) correctly.
364 * A naive -z would have undefined behavior.
365 * Write this in a way that makes popular compilers happy (GCC, Clang,
366 * MSVC). */
Gilles Peskine449bd832023-01-11 14:50:10 +0100367 return (mbedtls_mpi_uint) 0 - (mbedtls_mpi_uint) z;
Gilles Peskineef7f4e42022-11-15 23:25:27 +0100368}
369
Dave Rodgmanf3df1052023-08-09 18:55:41 +0100370/* Convert x to a sign, i.e. to 1, if x is positive, or -1, if x is negative.
371 * This looks awkward but generates smaller code than (x < 0 ? -1 : 1) */
Dave Rodgman73d85912023-09-28 17:00:50 +0100372#define TO_SIGN(x) ((mbedtls_mpi_sint) (((mbedtls_mpi_uint) x) >> (biL - 1)) * -2 + 1)
Dave Rodgmanf3df1052023-08-09 18:55:41 +0100373
Paul Bakker5121ce52009-01-03 21:22:43 +0000374/*
375 * Set value from integer
376 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100377int mbedtls_mpi_lset(mbedtls_mpi *X, mbedtls_mpi_sint z)
Paul Bakker5121ce52009-01-03 21:22:43 +0000378{
Janos Follath24eed8d2019-11-22 13:21:35 +0000379 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker5121ce52009-01-03 21:22:43 +0000380
Gilles Peskine449bd832023-01-11 14:50:10 +0100381 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, 1));
382 memset(X->p, 0, X->n * ciL);
Paul Bakker5121ce52009-01-03 21:22:43 +0000383
Gilles Peskine449bd832023-01-11 14:50:10 +0100384 X->p[0] = mpi_sint_abs(z);
Dave Rodgmanf3df1052023-08-09 18:55:41 +0100385 X->s = TO_SIGN(z);
Paul Bakker5121ce52009-01-03 21:22:43 +0000386
387cleanup:
388
Gilles Peskine449bd832023-01-11 14:50:10 +0100389 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000390}
391
392/*
Paul Bakker2f5947e2011-05-18 15:47:11 +0000393 * Get a specific bit
394 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100395int mbedtls_mpi_get_bit(const mbedtls_mpi *X, size_t pos)
Paul Bakker2f5947e2011-05-18 15:47:11 +0000396{
Gilles Peskine449bd832023-01-11 14:50:10 +0100397 if (X->n * biL <= pos) {
398 return 0;
399 }
Paul Bakker2f5947e2011-05-18 15:47:11 +0000400
Gilles Peskine449bd832023-01-11 14:50:10 +0100401 return (X->p[pos / biL] >> (pos % biL)) & 0x01;
Paul Bakker2f5947e2011-05-18 15:47:11 +0000402}
403
404/*
405 * Set a bit to a specific value of 0 or 1
406 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100407int mbedtls_mpi_set_bit(mbedtls_mpi *X, size_t pos, unsigned char val)
Paul Bakker2f5947e2011-05-18 15:47:11 +0000408{
409 int ret = 0;
410 size_t off = pos / biL;
411 size_t idx = pos % biL;
412
Gilles Peskine449bd832023-01-11 14:50:10 +0100413 if (val != 0 && val != 1) {
414 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
Paul Bakker2f5947e2011-05-18 15:47:11 +0000415 }
416
Gilles Peskine449bd832023-01-11 14:50:10 +0100417 if (X->n * biL <= pos) {
418 if (val == 0) {
419 return 0;
420 }
421
422 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, off + 1));
423 }
424
425 X->p[off] &= ~((mbedtls_mpi_uint) 0x01 << idx);
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200426 X->p[off] |= (mbedtls_mpi_uint) val << idx;
Paul Bakker2f5947e2011-05-18 15:47:11 +0000427
428cleanup:
Paul Bakker9af723c2014-05-01 13:03:14 +0200429
Gilles Peskine449bd832023-01-11 14:50:10 +0100430 return ret;
Paul Bakker2f5947e2011-05-18 15:47:11 +0000431}
432
Dave Rodgmanfa703e32023-08-09 18:56:07 +0100433#if defined(__has_builtin)
434#if (MBEDTLS_MPI_UINT_MAX == UINT_MAX) && __has_builtin(__builtin_ctz)
435 #define mbedtls_mpi_uint_ctz __builtin_ctz
436#elif (MBEDTLS_MPI_UINT_MAX == ULONG_MAX) && __has_builtin(__builtin_ctzl)
437 #define mbedtls_mpi_uint_ctz __builtin_ctzl
438#elif (MBEDTLS_MPI_UINT_MAX == ULLONG_MAX) && __has_builtin(__builtin_ctzll)
439 #define mbedtls_mpi_uint_ctz __builtin_ctzll
440#endif
441#endif
442
Manuel Pégourié-Gonnard65b80112025-07-10 21:26:42 +0200443#if !defined(mbedtls_mpi_uint_ctz)
444static size_t mbedtls_mpi_uint_ctz(mbedtls_mpi_uint x)
445{
446 size_t count = 0;
447 mbedtls_ct_condition_t done = MBEDTLS_CT_FALSE;
448
449 for (size_t i = 0; i < biL; i++) {
450 mbedtls_ct_condition_t non_zero = mbedtls_ct_bool((x >> i) & 1);
451 done = mbedtls_ct_bool_or(done, non_zero);
452 count = mbedtls_ct_size_if(done, count, i + 1);
453 }
454
455 return count;
456}
457#endif
458
459/*
460 * Return the number of less significant zero-bits
461 */
462size_t mbedtls_mpi_lsb(const mbedtls_mpi *X)
463{
464 size_t i;
465
Gilles Peskine449bd832023-01-11 14:50:10 +0100466 for (i = 0; i < X->n; i++) {
Dave Rodgman960eca92023-08-09 20:43:18 +0100467 if (X->p[i] != 0) {
468 return i * biL + mbedtls_mpi_uint_ctz(X->p[i]);
469 }
Dave Rodgmanfa703e32023-08-09 18:56:07 +0100470 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000471
Gilles Peskine449bd832023-01-11 14:50:10 +0100472 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000473}
474
475/*
Manuel Pégourié-Gonnardc0696c22015-06-18 16:47:17 +0200476 * Return the number of bits
Paul Bakker5121ce52009-01-03 21:22:43 +0000477 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100478size_t mbedtls_mpi_bitlen(const mbedtls_mpi *X)
Paul Bakker5121ce52009-01-03 21:22:43 +0000479{
Gilles Peskine449bd832023-01-11 14:50:10 +0100480 return mbedtls_mpi_core_bitlen(X->p, X->n);
Paul Bakker5121ce52009-01-03 21:22:43 +0000481}
482
483/*
484 * Return the total size in bytes
485 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100486size_t mbedtls_mpi_size(const mbedtls_mpi *X)
Paul Bakker5121ce52009-01-03 21:22:43 +0000487{
Gilles Peskine449bd832023-01-11 14:50:10 +0100488 return (mbedtls_mpi_bitlen(X) + 7) >> 3;
Paul Bakker5121ce52009-01-03 21:22:43 +0000489}
490
491/*
492 * Convert an ASCII character to digit value
493 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100494static int mpi_get_digit(mbedtls_mpi_uint *d, int radix, char c)
Paul Bakker5121ce52009-01-03 21:22:43 +0000495{
496 *d = 255;
497
Gilles Peskine449bd832023-01-11 14:50:10 +0100498 if (c >= 0x30 && c <= 0x39) {
499 *d = c - 0x30;
500 }
501 if (c >= 0x41 && c <= 0x46) {
502 *d = c - 0x37;
503 }
504 if (c >= 0x61 && c <= 0x66) {
505 *d = c - 0x57;
506 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000507
Gilles Peskine449bd832023-01-11 14:50:10 +0100508 if (*d >= (mbedtls_mpi_uint) radix) {
509 return MBEDTLS_ERR_MPI_INVALID_CHARACTER;
510 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000511
Gilles Peskine449bd832023-01-11 14:50:10 +0100512 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000513}
514
515/*
516 * Import from an ASCII string
517 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100518int mbedtls_mpi_read_string(mbedtls_mpi *X, int radix, const char *s)
Paul Bakker5121ce52009-01-03 21:22:43 +0000519{
Janos Follath24eed8d2019-11-22 13:21:35 +0000520 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker23986e52011-04-24 08:57:21 +0000521 size_t i, j, slen, n;
Gilles Peskine80f56732021-04-03 18:26:13 +0200522 int sign = 1;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200523 mbedtls_mpi_uint d;
524 mbedtls_mpi T;
Paul Bakker5121ce52009-01-03 21:22:43 +0000525
Gilles Peskine449bd832023-01-11 14:50:10 +0100526 if (radix < 2 || radix > 16) {
527 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
Gilles Peskine7cba8592021-06-08 18:32:34 +0200528 }
529
Gilles Peskine449bd832023-01-11 14:50:10 +0100530 mbedtls_mpi_init(&T);
531
532 if (s[0] == 0) {
533 mbedtls_mpi_free(X);
534 return 0;
535 }
536
537 if (s[0] == '-') {
Gilles Peskine80f56732021-04-03 18:26:13 +0200538 ++s;
539 sign = -1;
540 }
541
Gilles Peskine449bd832023-01-11 14:50:10 +0100542 slen = strlen(s);
Paul Bakkerff60ee62010-03-16 21:09:09 +0000543
Gilles Peskine449bd832023-01-11 14:50:10 +0100544 if (radix == 16) {
Dave Rodgman68ef1d62023-05-18 20:49:03 +0100545 if (slen > SIZE_MAX >> 2) {
Gilles Peskine449bd832023-01-11 14:50:10 +0100546 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
Paul Bakker5121ce52009-01-03 21:22:43 +0000547 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000548
Gilles Peskine449bd832023-01-11 14:50:10 +0100549 n = BITS_TO_LIMBS(slen << 2);
550
551 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, n));
552 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(X, 0));
553
554 for (i = slen, j = 0; i > 0; i--, j++) {
555 MBEDTLS_MPI_CHK(mpi_get_digit(&d, radix, s[i - 1]));
556 X->p[j / (2 * ciL)] |= d << ((j % (2 * ciL)) << 2);
557 }
558 } else {
559 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(X, 0));
560
561 for (i = 0; i < slen; i++) {
562 MBEDTLS_MPI_CHK(mpi_get_digit(&d, radix, s[i]));
563 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_int(&T, X, radix));
564 MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(X, &T, d));
Paul Bakker5121ce52009-01-03 21:22:43 +0000565 }
566 }
567
Gilles Peskine449bd832023-01-11 14:50:10 +0100568 if (sign < 0 && mbedtls_mpi_bitlen(X) != 0) {
Gilles Peskine80f56732021-04-03 18:26:13 +0200569 X->s = -1;
Gilles Peskine449bd832023-01-11 14:50:10 +0100570 }
Gilles Peskine80f56732021-04-03 18:26:13 +0200571
Paul Bakker5121ce52009-01-03 21:22:43 +0000572cleanup:
573
Gilles Peskine449bd832023-01-11 14:50:10 +0100574 mbedtls_mpi_free(&T);
Paul Bakker5121ce52009-01-03 21:22:43 +0000575
Gilles Peskine449bd832023-01-11 14:50:10 +0100576 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000577}
578
579/*
Ron Eldora16fa292018-11-20 14:07:01 +0200580 * Helper to write the digits high-order first.
Paul Bakker5121ce52009-01-03 21:22:43 +0000581 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100582static int mpi_write_hlp(mbedtls_mpi *X, int radix,
583 char **p, const size_t buflen)
Paul Bakker5121ce52009-01-03 21:22:43 +0000584{
Janos Follath24eed8d2019-11-22 13:21:35 +0000585 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200586 mbedtls_mpi_uint r;
Ron Eldora16fa292018-11-20 14:07:01 +0200587 size_t length = 0;
588 char *p_end = *p + buflen;
Paul Bakker5121ce52009-01-03 21:22:43 +0000589
Gilles Peskine449bd832023-01-11 14:50:10 +0100590 do {
591 if (length >= buflen) {
592 return MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL;
Ron Eldora16fa292018-11-20 14:07:01 +0200593 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000594
Gilles Peskine449bd832023-01-11 14:50:10 +0100595 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_int(&r, X, radix));
596 MBEDTLS_MPI_CHK(mbedtls_mpi_div_int(X, NULL, X, radix));
Ron Eldora16fa292018-11-20 14:07:01 +0200597 /*
598 * Write the residue in the current position, as an ASCII character.
599 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100600 if (r < 0xA) {
601 *(--p_end) = (char) ('0' + r);
602 } else {
603 *(--p_end) = (char) ('A' + (r - 0xA));
604 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000605
Ron Eldora16fa292018-11-20 14:07:01 +0200606 length++;
Gilles Peskine449bd832023-01-11 14:50:10 +0100607 } while (mbedtls_mpi_cmp_int(X, 0) != 0);
Paul Bakker5121ce52009-01-03 21:22:43 +0000608
Gilles Peskine449bd832023-01-11 14:50:10 +0100609 memmove(*p, p_end, length);
Ron Eldora16fa292018-11-20 14:07:01 +0200610 *p += length;
Paul Bakker5121ce52009-01-03 21:22:43 +0000611
612cleanup:
613
Gilles Peskine449bd832023-01-11 14:50:10 +0100614 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000615}
616
617/*
618 * Export into an ASCII string
619 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100620int mbedtls_mpi_write_string(const mbedtls_mpi *X, int radix,
621 char *buf, size_t buflen, size_t *olen)
Paul Bakker5121ce52009-01-03 21:22:43 +0000622{
Paul Bakker23986e52011-04-24 08:57:21 +0000623 int ret = 0;
624 size_t n;
Paul Bakker5121ce52009-01-03 21:22:43 +0000625 char *p;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200626 mbedtls_mpi T;
Paul Bakker5121ce52009-01-03 21:22:43 +0000627
Gilles Peskine449bd832023-01-11 14:50:10 +0100628 if (radix < 2 || radix > 16) {
629 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
630 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000631
Gilles Peskine449bd832023-01-11 14:50:10 +0100632 n = mbedtls_mpi_bitlen(X); /* Number of bits necessary to present `n`. */
633 if (radix >= 4) {
634 n >>= 1; /* Number of 4-adic digits necessary to present
Hanno Becker23cfea02019-02-04 09:45:07 +0000635 * `n`. If radix > 4, this might be a strict
636 * overapproximation of the number of
637 * radix-adic digits needed to present `n`. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100638 }
639 if (radix >= 16) {
640 n >>= 1; /* Number of hexadecimal digits necessary to
Hanno Becker23cfea02019-02-04 09:45:07 +0000641 * present `n`. */
642
Gilles Peskine449bd832023-01-11 14:50:10 +0100643 }
Janos Follath80470622019-03-06 13:43:02 +0000644 n += 1; /* Terminating null byte */
Hanno Becker23cfea02019-02-04 09:45:07 +0000645 n += 1; /* Compensate for the divisions above, which round down `n`
646 * in case it's not even. */
647 n += 1; /* Potential '-'-sign. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100648 n += (n & 1); /* Make n even to have enough space for hexadecimal writing,
Hanno Becker23cfea02019-02-04 09:45:07 +0000649 * which always uses an even number of hex-digits. */
Paul Bakker5121ce52009-01-03 21:22:43 +0000650
Gilles Peskine449bd832023-01-11 14:50:10 +0100651 if (buflen < n) {
Manuel Pégourié-Gonnardf79b4252015-06-02 15:41:48 +0100652 *olen = n;
Gilles Peskine449bd832023-01-11 14:50:10 +0100653 return MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL;
Paul Bakker5121ce52009-01-03 21:22:43 +0000654 }
655
Manuel Pégourié-Gonnardf79b4252015-06-02 15:41:48 +0100656 p = buf;
Gilles Peskine449bd832023-01-11 14:50:10 +0100657 mbedtls_mpi_init(&T);
Paul Bakker5121ce52009-01-03 21:22:43 +0000658
Gilles Peskine449bd832023-01-11 14:50:10 +0100659 if (X->s == -1) {
Paul Bakker5121ce52009-01-03 21:22:43 +0000660 *p++ = '-';
Hanno Beckerc983c812019-02-01 16:41:30 +0000661 buflen--;
662 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000663
Gilles Peskine449bd832023-01-11 14:50:10 +0100664 if (radix == 16) {
Paul Bakker23986e52011-04-24 08:57:21 +0000665 int c;
666 size_t i, j, k;
Paul Bakker5121ce52009-01-03 21:22:43 +0000667
Gilles Peskine449bd832023-01-11 14:50:10 +0100668 for (i = X->n, k = 0; i > 0; i--) {
669 for (j = ciL; j > 0; j--) {
670 c = (X->p[i - 1] >> ((j - 1) << 3)) & 0xFF;
Paul Bakker5121ce52009-01-03 21:22:43 +0000671
Gilles Peskine449bd832023-01-11 14:50:10 +0100672 if (c == 0 && k == 0 && (i + j) != 2) {
Paul Bakker5121ce52009-01-03 21:22:43 +0000673 continue;
Gilles Peskine449bd832023-01-11 14:50:10 +0100674 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000675
Paul Bakker98fe5ea2012-10-24 11:17:48 +0000676 *(p++) = "0123456789ABCDEF" [c / 16];
Paul Bakkerd2c167e2012-10-30 07:49:19 +0000677 *(p++) = "0123456789ABCDEF" [c % 16];
Paul Bakker5121ce52009-01-03 21:22:43 +0000678 k = 1;
679 }
680 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100681 } else {
682 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&T, X));
Paul Bakkerce40a6d2009-06-23 19:46:08 +0000683
Gilles Peskine449bd832023-01-11 14:50:10 +0100684 if (T.s == -1) {
Paul Bakkerce40a6d2009-06-23 19:46:08 +0000685 T.s = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +0100686 }
Paul Bakkerce40a6d2009-06-23 19:46:08 +0000687
Gilles Peskine449bd832023-01-11 14:50:10 +0100688 MBEDTLS_MPI_CHK(mpi_write_hlp(&T, radix, &p, buflen));
Paul Bakker5121ce52009-01-03 21:22:43 +0000689 }
690
691 *p++ = '\0';
Dave Rodgmane4a6f5a2023-11-04 12:20:09 +0000692 *olen = (size_t) (p - buf);
Paul Bakker5121ce52009-01-03 21:22:43 +0000693
694cleanup:
695
Gilles Peskine449bd832023-01-11 14:50:10 +0100696 mbedtls_mpi_free(&T);
Paul Bakker5121ce52009-01-03 21:22:43 +0000697
Gilles Peskine449bd832023-01-11 14:50:10 +0100698 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000699}
700
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200701#if defined(MBEDTLS_FS_IO)
Paul Bakker5121ce52009-01-03 21:22:43 +0000702/*
703 * Read X from an opened file
704 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100705int mbedtls_mpi_read_file(mbedtls_mpi *X, int radix, FILE *fin)
Paul Bakker5121ce52009-01-03 21:22:43 +0000706{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200707 mbedtls_mpi_uint d;
Paul Bakker23986e52011-04-24 08:57:21 +0000708 size_t slen;
Paul Bakker5121ce52009-01-03 21:22:43 +0000709 char *p;
Paul Bakkerfe3256e2011-11-25 12:11:43 +0000710 /*
Paul Bakkercb37aa52011-11-30 16:00:20 +0000711 * Buffer should have space for (short) label and decimal formatted MPI,
712 * newline characters and '\0'
Paul Bakkerfe3256e2011-11-25 12:11:43 +0000713 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100714 char s[MBEDTLS_MPI_RW_BUFFER_SIZE];
Paul Bakker5121ce52009-01-03 21:22:43 +0000715
Gilles Peskine449bd832023-01-11 14:50:10 +0100716 if (radix < 2 || radix > 16) {
717 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
718 }
Hanno Becker73d7d792018-12-11 10:35:51 +0000719
Gilles Peskine449bd832023-01-11 14:50:10 +0100720 memset(s, 0, sizeof(s));
721 if (fgets(s, sizeof(s) - 1, fin) == NULL) {
722 return MBEDTLS_ERR_MPI_FILE_IO_ERROR;
723 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000724
Gilles Peskine449bd832023-01-11 14:50:10 +0100725 slen = strlen(s);
726 if (slen == sizeof(s) - 2) {
727 return MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL;
728 }
Paul Bakkercb37aa52011-11-30 16:00:20 +0000729
Gilles Peskine449bd832023-01-11 14:50:10 +0100730 if (slen > 0 && s[slen - 1] == '\n') {
731 slen--; s[slen] = '\0';
732 }
733 if (slen > 0 && s[slen - 1] == '\r') {
734 slen--; s[slen] = '\0';
735 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000736
737 p = s + slen;
Gilles Peskine449bd832023-01-11 14:50:10 +0100738 while (p-- > s) {
739 if (mpi_get_digit(&d, radix, *p) != 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +0000740 break;
Gilles Peskine449bd832023-01-11 14:50:10 +0100741 }
742 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000743
Gilles Peskine449bd832023-01-11 14:50:10 +0100744 return mbedtls_mpi_read_string(X, radix, p + 1);
Paul Bakker5121ce52009-01-03 21:22:43 +0000745}
746
747/*
748 * Write X into an opened file (or stdout if fout == NULL)
749 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100750int mbedtls_mpi_write_file(const char *p, const mbedtls_mpi *X, int radix, FILE *fout)
Paul Bakker5121ce52009-01-03 21:22:43 +0000751{
Janos Follath24eed8d2019-11-22 13:21:35 +0000752 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker23986e52011-04-24 08:57:21 +0000753 size_t n, slen, plen;
Paul Bakkerfe3256e2011-11-25 12:11:43 +0000754 /*
Paul Bakker5531c6d2012-09-26 19:20:46 +0000755 * Buffer should have space for (short) label and decimal formatted MPI,
756 * newline characters and '\0'
Paul Bakkerfe3256e2011-11-25 12:11:43 +0000757 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100758 char s[MBEDTLS_MPI_RW_BUFFER_SIZE];
Hanno Becker73d7d792018-12-11 10:35:51 +0000759
Gilles Peskine449bd832023-01-11 14:50:10 +0100760 if (radix < 2 || radix > 16) {
761 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
762 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000763
Gilles Peskine449bd832023-01-11 14:50:10 +0100764 memset(s, 0, sizeof(s));
Paul Bakker5121ce52009-01-03 21:22:43 +0000765
Gilles Peskine449bd832023-01-11 14:50:10 +0100766 MBEDTLS_MPI_CHK(mbedtls_mpi_write_string(X, radix, s, sizeof(s) - 2, &n));
Paul Bakker5121ce52009-01-03 21:22:43 +0000767
Gilles Peskine449bd832023-01-11 14:50:10 +0100768 if (p == NULL) {
769 p = "";
770 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000771
Gilles Peskine449bd832023-01-11 14:50:10 +0100772 plen = strlen(p);
773 slen = strlen(s);
Paul Bakker5121ce52009-01-03 21:22:43 +0000774 s[slen++] = '\r';
775 s[slen++] = '\n';
776
Gilles Peskine449bd832023-01-11 14:50:10 +0100777 if (fout != NULL) {
778 if (fwrite(p, 1, plen, fout) != plen ||
779 fwrite(s, 1, slen, fout) != slen) {
780 return MBEDTLS_ERR_MPI_FILE_IO_ERROR;
781 }
782 } else {
783 mbedtls_printf("%s%s", p, s);
Paul Bakker5121ce52009-01-03 21:22:43 +0000784 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000785
786cleanup:
787
Gilles Peskine449bd832023-01-11 14:50:10 +0100788 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000789}
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200790#endif /* MBEDTLS_FS_IO */
Paul Bakker5121ce52009-01-03 21:22:43 +0000791
792/*
Janos Follatha778a942019-02-13 10:28:28 +0000793 * Import X from unsigned binary data, little endian
Przemyslaw Stekiel76960a72022-02-21 13:42:09 +0100794 *
795 * This function is guaranteed to return an MPI with exactly the necessary
796 * number of limbs (in particular, it does not skip 0s in the input).
Janos Follatha778a942019-02-13 10:28:28 +0000797 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100798int mbedtls_mpi_read_binary_le(mbedtls_mpi *X,
799 const unsigned char *buf, size_t buflen)
Janos Follatha778a942019-02-13 10:28:28 +0000800{
Janos Follath24eed8d2019-11-22 13:21:35 +0000801 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Gilles Peskine449bd832023-01-11 14:50:10 +0100802 const size_t limbs = CHARS_TO_LIMBS(buflen);
Janos Follatha778a942019-02-13 10:28:28 +0000803
804 /* Ensure that target MPI has exactly the necessary number of limbs */
Gilles Peskine449bd832023-01-11 14:50:10 +0100805 MBEDTLS_MPI_CHK(mbedtls_mpi_resize_clear(X, limbs));
Janos Follatha778a942019-02-13 10:28:28 +0000806
Gilles Peskine449bd832023-01-11 14:50:10 +0100807 MBEDTLS_MPI_CHK(mbedtls_mpi_core_read_le(X->p, X->n, buf, buflen));
Janos Follatha778a942019-02-13 10:28:28 +0000808
809cleanup:
810
Janos Follath171a7ef2019-02-15 16:17:45 +0000811 /*
812 * This function is also used to import keys. However, wiping the buffers
813 * upon failure is not necessary because failure only can happen before any
814 * input is copied.
815 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100816 return ret;
Janos Follatha778a942019-02-13 10:28:28 +0000817}
818
819/*
Paul Bakker5121ce52009-01-03 21:22:43 +0000820 * Import X from unsigned binary data, big endian
Przemyslaw Stekiel76960a72022-02-21 13:42:09 +0100821 *
822 * This function is guaranteed to return an MPI with exactly the necessary
823 * number of limbs (in particular, it does not skip 0s in the input).
Paul Bakker5121ce52009-01-03 21:22:43 +0000824 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100825int mbedtls_mpi_read_binary(mbedtls_mpi *X, const unsigned char *buf, size_t buflen)
Paul Bakker5121ce52009-01-03 21:22:43 +0000826{
Janos Follath24eed8d2019-11-22 13:21:35 +0000827 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Gilles Peskine449bd832023-01-11 14:50:10 +0100828 const size_t limbs = CHARS_TO_LIMBS(buflen);
Hanno Becker73d7d792018-12-11 10:35:51 +0000829
Hanno Becker073c1992017-10-17 15:17:27 +0100830 /* Ensure that target MPI has exactly the necessary number of limbs */
Gilles Peskine449bd832023-01-11 14:50:10 +0100831 MBEDTLS_MPI_CHK(mbedtls_mpi_resize_clear(X, limbs));
Paul Bakker5121ce52009-01-03 21:22:43 +0000832
Gilles Peskine449bd832023-01-11 14:50:10 +0100833 MBEDTLS_MPI_CHK(mbedtls_mpi_core_read_be(X->p, X->n, buf, buflen));
Paul Bakker5121ce52009-01-03 21:22:43 +0000834
835cleanup:
836
Janos Follath171a7ef2019-02-15 16:17:45 +0000837 /*
838 * This function is also used to import keys. However, wiping the buffers
839 * upon failure is not necessary because failure only can happen before any
840 * input is copied.
841 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100842 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000843}
844
845/*
Janos Follathe344d0f2019-02-19 16:17:40 +0000846 * Export X into unsigned binary data, little endian
847 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100848int mbedtls_mpi_write_binary_le(const mbedtls_mpi *X,
849 unsigned char *buf, size_t buflen)
Janos Follathe344d0f2019-02-19 16:17:40 +0000850{
Gilles Peskine449bd832023-01-11 14:50:10 +0100851 return mbedtls_mpi_core_write_le(X->p, X->n, buf, buflen);
Janos Follathe344d0f2019-02-19 16:17:40 +0000852}
853
854/*
Paul Bakker5121ce52009-01-03 21:22:43 +0000855 * Export X into unsigned binary data, big endian
856 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100857int mbedtls_mpi_write_binary(const mbedtls_mpi *X,
858 unsigned char *buf, size_t buflen)
Paul Bakker5121ce52009-01-03 21:22:43 +0000859{
Gilles Peskine449bd832023-01-11 14:50:10 +0100860 return mbedtls_mpi_core_write_be(X->p, X->n, buf, buflen);
Paul Bakker5121ce52009-01-03 21:22:43 +0000861}
862
863/*
864 * Left-shift: X <<= count
865 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100866int mbedtls_mpi_shift_l(mbedtls_mpi *X, size_t count)
Paul Bakker5121ce52009-01-03 21:22:43 +0000867{
Janos Follath24eed8d2019-11-22 13:21:35 +0000868 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Minos Galanakis0144b352023-05-02 14:02:32 +0100869 size_t i;
Paul Bakker5121ce52009-01-03 21:22:43 +0000870
Gilles Peskine449bd832023-01-11 14:50:10 +0100871 i = mbedtls_mpi_bitlen(X) + count;
Paul Bakker5121ce52009-01-03 21:22:43 +0000872
Gilles Peskine449bd832023-01-11 14:50:10 +0100873 if (X->n * biL < i) {
874 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, BITS_TO_LIMBS(i)));
875 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000876
877 ret = 0;
878
Minos Galanakis0144b352023-05-02 14:02:32 +0100879 mbedtls_mpi_core_shift_l(X->p, X->n, count);
Paul Bakker5121ce52009-01-03 21:22:43 +0000880cleanup:
881
Gilles Peskine449bd832023-01-11 14:50:10 +0100882 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000883}
884
885/*
886 * Right-shift: X >>= count
887 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100888int mbedtls_mpi_shift_r(mbedtls_mpi *X, size_t count)
Paul Bakker5121ce52009-01-03 21:22:43 +0000889{
Gilles Peskine449bd832023-01-11 14:50:10 +0100890 if (X->n != 0) {
891 mbedtls_mpi_core_shift_r(X->p, X->n, count);
892 }
893 return 0;
Gilles Peskine66414202022-09-21 15:36:16 +0200894}
895
Paul Bakker5121ce52009-01-03 21:22:43 +0000896/*
897 * Compare unsigned values
898 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100899int mbedtls_mpi_cmp_abs(const mbedtls_mpi *X, const mbedtls_mpi *Y)
Paul Bakker5121ce52009-01-03 21:22:43 +0000900{
Paul Bakker23986e52011-04-24 08:57:21 +0000901 size_t i, j;
Paul Bakker5121ce52009-01-03 21:22:43 +0000902
Gilles Peskine449bd832023-01-11 14:50:10 +0100903 for (i = X->n; i > 0; i--) {
904 if (X->p[i - 1] != 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +0000905 break;
Gilles Peskine449bd832023-01-11 14:50:10 +0100906 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000907 }
908
Gilles Peskine449bd832023-01-11 14:50:10 +0100909 for (j = Y->n; j > 0; j--) {
910 if (Y->p[j - 1] != 0) {
911 break;
912 }
913 }
914
Dave Rodgmanebcd7852023-08-09 18:56:42 +0100915 /* If i == j == 0, i.e. abs(X) == abs(Y),
916 * we end up returning 0 at the end of the function. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100917
918 if (i > j) {
919 return 1;
920 }
921 if (j > i) {
922 return -1;
923 }
924
925 for (; i > 0; i--) {
926 if (X->p[i - 1] > Y->p[i - 1]) {
927 return 1;
928 }
929 if (X->p[i - 1] < Y->p[i - 1]) {
930 return -1;
931 }
932 }
933
934 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000935}
936
937/*
938 * Compare signed values
939 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100940int mbedtls_mpi_cmp_mpi(const mbedtls_mpi *X, const mbedtls_mpi *Y)
Paul Bakker5121ce52009-01-03 21:22:43 +0000941{
Paul Bakker23986e52011-04-24 08:57:21 +0000942 size_t i, j;
Paul Bakker5121ce52009-01-03 21:22:43 +0000943
Gilles Peskine449bd832023-01-11 14:50:10 +0100944 for (i = X->n; i > 0; i--) {
945 if (X->p[i - 1] != 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +0000946 break;
Gilles Peskine449bd832023-01-11 14:50:10 +0100947 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000948 }
949
Gilles Peskine449bd832023-01-11 14:50:10 +0100950 for (j = Y->n; j > 0; j--) {
951 if (Y->p[j - 1] != 0) {
952 break;
953 }
954 }
955
956 if (i == 0 && j == 0) {
957 return 0;
958 }
959
960 if (i > j) {
961 return X->s;
962 }
963 if (j > i) {
964 return -Y->s;
965 }
966
967 if (X->s > 0 && Y->s < 0) {
968 return 1;
969 }
970 if (Y->s > 0 && X->s < 0) {
971 return -1;
972 }
973
974 for (; i > 0; i--) {
975 if (X->p[i - 1] > Y->p[i - 1]) {
976 return X->s;
977 }
978 if (X->p[i - 1] < Y->p[i - 1]) {
979 return -X->s;
980 }
981 }
982
983 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000984}
985
Janos Follathee6abce2019-09-05 14:47:19 +0100986/*
Paul Bakker5121ce52009-01-03 21:22:43 +0000987 * Compare signed values
988 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100989int mbedtls_mpi_cmp_int(const mbedtls_mpi *X, mbedtls_mpi_sint z)
Paul Bakker5121ce52009-01-03 21:22:43 +0000990{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200991 mbedtls_mpi Y;
992 mbedtls_mpi_uint p[1];
Paul Bakker5121ce52009-01-03 21:22:43 +0000993
Gilles Peskine449bd832023-01-11 14:50:10 +0100994 *p = mpi_sint_abs(z);
Dave Rodgmanf3df1052023-08-09 18:55:41 +0100995 Y.s = TO_SIGN(z);
Paul Bakker5121ce52009-01-03 21:22:43 +0000996 Y.n = 1;
997 Y.p = p;
998
Gilles Peskine449bd832023-01-11 14:50:10 +0100999 return mbedtls_mpi_cmp_mpi(X, &Y);
Paul Bakker5121ce52009-01-03 21:22:43 +00001000}
1001
1002/*
1003 * Unsigned addition: X = |A| + |B| (HAC 14.7)
1004 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001005int mbedtls_mpi_add_abs(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B)
Paul Bakker5121ce52009-01-03 21:22:43 +00001006{
Janos Follath24eed8d2019-11-22 13:21:35 +00001007 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Tom Cosgroveaf7d44b2022-08-24 14:05:26 +01001008 size_t j;
Agathiyan Bragadeeshc99840a2023-07-12 11:15:46 +01001009 mbedtls_mpi_uint *p;
1010 mbedtls_mpi_uint c;
Paul Bakker5121ce52009-01-03 21:22:43 +00001011
Gilles Peskine449bd832023-01-11 14:50:10 +01001012 if (X == B) {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001013 const mbedtls_mpi *T = A; A = X; B = T;
Paul Bakker5121ce52009-01-03 21:22:43 +00001014 }
1015
Gilles Peskine449bd832023-01-11 14:50:10 +01001016 if (X != A) {
1017 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(X, A));
1018 }
Paul Bakker9af723c2014-05-01 13:03:14 +02001019
Paul Bakkerf7ca7b92009-06-20 10:31:06 +00001020 /*
Tom Cosgroveaf7d44b2022-08-24 14:05:26 +01001021 * X must always be positive as a result of unsigned additions.
Paul Bakkerf7ca7b92009-06-20 10:31:06 +00001022 */
1023 X->s = 1;
Paul Bakker5121ce52009-01-03 21:22:43 +00001024
Gilles Peskine449bd832023-01-11 14:50:10 +01001025 for (j = B->n; j > 0; j--) {
1026 if (B->p[j - 1] != 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00001027 break;
Gilles Peskine449bd832023-01-11 14:50:10 +01001028 }
1029 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001030
Gilles Peskinedb14a9d2022-11-15 22:59:00 +01001031 /* Exit early to avoid undefined behavior on NULL+0 when X->n == 0
1032 * and B is 0 (of any size). */
Gilles Peskine449bd832023-01-11 14:50:10 +01001033 if (j == 0) {
1034 return 0;
1035 }
Gilles Peskinedb14a9d2022-11-15 22:59:00 +01001036
Gilles Peskine449bd832023-01-11 14:50:10 +01001037 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, j));
Paul Bakker5121ce52009-01-03 21:22:43 +00001038
Tom Cosgroveaf7d44b2022-08-24 14:05:26 +01001039 /* j is the number of non-zero limbs of B. Add those to X. */
Paul Bakker5121ce52009-01-03 21:22:43 +00001040
Agathiyan Bragadeeshc99840a2023-07-12 11:15:46 +01001041 p = X->p;
Tom Cosgroveaf7d44b2022-08-24 14:05:26 +01001042
Agathiyan Bragadeeshc99840a2023-07-12 11:15:46 +01001043 c = mbedtls_mpi_core_add(p, p, B->p, j);
Tom Cosgroveaf7d44b2022-08-24 14:05:26 +01001044
1045 p += j;
1046
1047 /* Now propagate any carry */
Paul Bakker5121ce52009-01-03 21:22:43 +00001048
Gilles Peskine449bd832023-01-11 14:50:10 +01001049 while (c != 0) {
1050 if (j >= X->n) {
1051 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, j + 1));
Tom Cosgroveaf7d44b2022-08-24 14:05:26 +01001052 p = X->p + j;
Paul Bakker5121ce52009-01-03 21:22:43 +00001053 }
1054
Gilles Peskine449bd832023-01-11 14:50:10 +01001055 *p += c; c = (*p < c); j++; p++;
Paul Bakker5121ce52009-01-03 21:22:43 +00001056 }
1057
1058cleanup:
1059
Gilles Peskine449bd832023-01-11 14:50:10 +01001060 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001061}
1062
Paul Bakker5121ce52009-01-03 21:22:43 +00001063/*
Gilles Peskine0e5faf62020-06-08 22:50:35 +02001064 * Unsigned subtraction: X = |A| - |B| (HAC 14.9, 14.10)
Paul Bakker5121ce52009-01-03 21:22:43 +00001065 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001066int mbedtls_mpi_sub_abs(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B)
Paul Bakker5121ce52009-01-03 21:22:43 +00001067{
Janos Follath24eed8d2019-11-22 13:21:35 +00001068 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker23986e52011-04-24 08:57:21 +00001069 size_t n;
Gilles Peskine0e5faf62020-06-08 22:50:35 +02001070 mbedtls_mpi_uint carry;
Paul Bakker5121ce52009-01-03 21:22:43 +00001071
Gilles Peskine449bd832023-01-11 14:50:10 +01001072 for (n = B->n; n > 0; n--) {
1073 if (B->p[n - 1] != 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00001074 break;
Gilles Peskine449bd832023-01-11 14:50:10 +01001075 }
1076 }
1077 if (n > A->n) {
Gilles Peskinec8a91772021-01-27 22:30:43 +01001078 /* B >= (2^ciL)^n > A */
1079 ret = MBEDTLS_ERR_MPI_NEGATIVE_VALUE;
1080 goto cleanup;
1081 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001082
Gilles Peskine449bd832023-01-11 14:50:10 +01001083 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, A->n));
Gilles Peskine1acf7cb2020-07-23 01:03:22 +02001084
1085 /* Set the high limbs of X to match A. Don't touch the lower limbs
1086 * because X might be aliased to B, and we must not overwrite the
1087 * significant digits of B. */
Aaron M. Uckoaf67d2c2023-01-17 11:52:22 -05001088 if (A->n > n && A != X) {
Gilles Peskine449bd832023-01-11 14:50:10 +01001089 memcpy(X->p + n, A->p + n, (A->n - n) * ciL);
1090 }
1091 if (X->n > A->n) {
1092 memset(X->p + A->n, 0, (X->n - A->n) * ciL);
1093 }
Gilles Peskine1acf7cb2020-07-23 01:03:22 +02001094
Gilles Peskine449bd832023-01-11 14:50:10 +01001095 carry = mbedtls_mpi_core_sub(X->p, A->p, B->p, n);
1096 if (carry != 0) {
Tom Cosgrove452c99c2022-08-25 10:07:07 +01001097 /* Propagate the carry through the rest of X. */
Gilles Peskine449bd832023-01-11 14:50:10 +01001098 carry = mbedtls_mpi_core_sub_int(X->p + n, X->p + n, carry, X->n - n);
Tom Cosgrove452c99c2022-08-25 10:07:07 +01001099
1100 /* If we have further carry/borrow, the result is negative. */
Gilles Peskine449bd832023-01-11 14:50:10 +01001101 if (carry != 0) {
Gilles Peskine89b41302020-07-23 01:16:46 +02001102 ret = MBEDTLS_ERR_MPI_NEGATIVE_VALUE;
1103 goto cleanup;
1104 }
Gilles Peskinec097e9e2020-06-08 21:58:22 +02001105 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001106
Gilles Peskine1acf7cb2020-07-23 01:03:22 +02001107 /* X should always be positive as a result of unsigned subtractions. */
1108 X->s = 1;
1109
Paul Bakker5121ce52009-01-03 21:22:43 +00001110cleanup:
Gilles Peskine449bd832023-01-11 14:50:10 +01001111 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001112}
1113
Gilles Peskine72ee1e32022-11-09 21:34:09 +01001114/* Common function for signed addition and subtraction.
1115 * Calculate A + B * flip_B where flip_B is 1 or -1.
Paul Bakker5121ce52009-01-03 21:22:43 +00001116 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001117static int add_sub_mpi(mbedtls_mpi *X,
1118 const mbedtls_mpi *A, const mbedtls_mpi *B,
1119 int flip_B)
Paul Bakker5121ce52009-01-03 21:22:43 +00001120{
Hanno Becker73d7d792018-12-11 10:35:51 +00001121 int ret, s;
Paul Bakker5121ce52009-01-03 21:22:43 +00001122
Hanno Becker73d7d792018-12-11 10:35:51 +00001123 s = A->s;
Gilles Peskine449bd832023-01-11 14:50:10 +01001124 if (A->s * B->s * flip_B < 0) {
1125 int cmp = mbedtls_mpi_cmp_abs(A, B);
1126 if (cmp >= 0) {
1127 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_abs(X, A, B));
Gilles Peskine4a768dd2022-11-09 22:02:16 +01001128 /* If |A| = |B|, the result is 0 and we must set the sign bit
1129 * to +1 regardless of which of A or B was negative. Otherwise,
1130 * since |A| > |B|, the sign is the sign of A. */
1131 X->s = cmp == 0 ? 1 : s;
Gilles Peskine449bd832023-01-11 14:50:10 +01001132 } else {
1133 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_abs(X, B, A));
Gilles Peskine4a768dd2022-11-09 22:02:16 +01001134 /* Since |A| < |B|, the sign is the opposite of A. */
Paul Bakker5121ce52009-01-03 21:22:43 +00001135 X->s = -s;
1136 }
Gilles Peskine449bd832023-01-11 14:50:10 +01001137 } else {
1138 MBEDTLS_MPI_CHK(mbedtls_mpi_add_abs(X, A, B));
Paul Bakker5121ce52009-01-03 21:22:43 +00001139 X->s = s;
1140 }
1141
1142cleanup:
1143
Gilles Peskine449bd832023-01-11 14:50:10 +01001144 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001145}
1146
1147/*
Gilles Peskine72ee1e32022-11-09 21:34:09 +01001148 * Signed addition: X = A + B
1149 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001150int mbedtls_mpi_add_mpi(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B)
Gilles Peskine72ee1e32022-11-09 21:34:09 +01001151{
Gilles Peskine449bd832023-01-11 14:50:10 +01001152 return add_sub_mpi(X, A, B, 1);
Gilles Peskine72ee1e32022-11-09 21:34:09 +01001153}
1154
1155/*
Paul Bakker60b1d102013-10-29 10:02:51 +01001156 * Signed subtraction: X = A - B
Paul Bakker5121ce52009-01-03 21:22:43 +00001157 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001158int mbedtls_mpi_sub_mpi(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B)
Paul Bakker5121ce52009-01-03 21:22:43 +00001159{
Gilles Peskine449bd832023-01-11 14:50:10 +01001160 return add_sub_mpi(X, A, B, -1);
Paul Bakker5121ce52009-01-03 21:22:43 +00001161}
1162
1163/*
1164 * Signed addition: X = A + b
1165 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001166int mbedtls_mpi_add_int(mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b)
Paul Bakker5121ce52009-01-03 21:22:43 +00001167{
Yuto Takano36c8ddc2021-07-05 09:10:52 +01001168 mbedtls_mpi B;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001169 mbedtls_mpi_uint p[1];
Paul Bakker5121ce52009-01-03 21:22:43 +00001170
Gilles Peskine449bd832023-01-11 14:50:10 +01001171 p[0] = mpi_sint_abs(b);
Dave Rodgmanf3df1052023-08-09 18:55:41 +01001172 B.s = TO_SIGN(b);
Yuto Takano36c8ddc2021-07-05 09:10:52 +01001173 B.n = 1;
1174 B.p = p;
Paul Bakker5121ce52009-01-03 21:22:43 +00001175
Gilles Peskine449bd832023-01-11 14:50:10 +01001176 return mbedtls_mpi_add_mpi(X, A, &B);
Paul Bakker5121ce52009-01-03 21:22:43 +00001177}
1178
1179/*
Paul Bakker60b1d102013-10-29 10:02:51 +01001180 * Signed subtraction: X = A - b
Paul Bakker5121ce52009-01-03 21:22:43 +00001181 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001182int mbedtls_mpi_sub_int(mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b)
Paul Bakker5121ce52009-01-03 21:22:43 +00001183{
Yuto Takano36c8ddc2021-07-05 09:10:52 +01001184 mbedtls_mpi B;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001185 mbedtls_mpi_uint p[1];
Paul Bakker5121ce52009-01-03 21:22:43 +00001186
Gilles Peskine449bd832023-01-11 14:50:10 +01001187 p[0] = mpi_sint_abs(b);
Dave Rodgmanf3df1052023-08-09 18:55:41 +01001188 B.s = TO_SIGN(b);
Yuto Takano36c8ddc2021-07-05 09:10:52 +01001189 B.n = 1;
1190 B.p = p;
Paul Bakker5121ce52009-01-03 21:22:43 +00001191
Gilles Peskine449bd832023-01-11 14:50:10 +01001192 return mbedtls_mpi_sub_mpi(X, A, &B);
Paul Bakker5121ce52009-01-03 21:22:43 +00001193}
1194
Paul Bakker5121ce52009-01-03 21:22:43 +00001195/*
1196 * Baseline multiplication: X = A * B (HAC 14.12)
1197 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001198int mbedtls_mpi_mul_mpi(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B)
Paul Bakker5121ce52009-01-03 21:22:43 +00001199{
Janos Follath24eed8d2019-11-22 13:21:35 +00001200 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Hanno Becker1772e052022-04-13 06:51:40 +01001201 size_t i, j;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001202 mbedtls_mpi TA, TB;
Hanno Beckerda763de2022-04-13 06:50:02 +01001203 int result_is_zero = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +00001204
Tom Cosgrove6af26f32022-08-24 16:40:55 +01001205 mbedtls_mpi_init(&TA);
1206 mbedtls_mpi_init(&TB);
Paul Bakker5121ce52009-01-03 21:22:43 +00001207
Gilles Peskine449bd832023-01-11 14:50:10 +01001208 if (X == A) {
1209 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TA, A)); A = &TA;
1210 }
1211 if (X == B) {
1212 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TB, B)); B = &TB;
1213 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001214
Gilles Peskine449bd832023-01-11 14:50:10 +01001215 for (i = A->n; i > 0; i--) {
1216 if (A->p[i - 1] != 0) {
Hanno Beckerda763de2022-04-13 06:50:02 +01001217 break;
Gilles Peskine449bd832023-01-11 14:50:10 +01001218 }
1219 }
1220 if (i == 0) {
Hanno Beckerda763de2022-04-13 06:50:02 +01001221 result_is_zero = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +01001222 }
Hanno Beckerda763de2022-04-13 06:50:02 +01001223
Gilles Peskine449bd832023-01-11 14:50:10 +01001224 for (j = B->n; j > 0; j--) {
1225 if (B->p[j - 1] != 0) {
Hanno Beckerda763de2022-04-13 06:50:02 +01001226 break;
Gilles Peskine449bd832023-01-11 14:50:10 +01001227 }
1228 }
1229 if (j == 0) {
Hanno Beckerda763de2022-04-13 06:50:02 +01001230 result_is_zero = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +01001231 }
Hanno Beckerda763de2022-04-13 06:50:02 +01001232
Gilles Peskine449bd832023-01-11 14:50:10 +01001233 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, i + j));
1234 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(X, 0));
Paul Bakker5121ce52009-01-03 21:22:43 +00001235
Tom Cosgrove6af26f32022-08-24 16:40:55 +01001236 mbedtls_mpi_core_mul(X->p, A->p, i, B->p, j);
Paul Bakker5121ce52009-01-03 21:22:43 +00001237
Hanno Beckerda763de2022-04-13 06:50:02 +01001238 /* If the result is 0, we don't shortcut the operation, which reduces
1239 * but does not eliminate side channels leaking the zero-ness. We do
1240 * need to take care to set the sign bit properly since the library does
1241 * not fully support an MPI object with a value of 0 and s == -1. */
Gilles Peskine449bd832023-01-11 14:50:10 +01001242 if (result_is_zero) {
Hanno Beckerda763de2022-04-13 06:50:02 +01001243 X->s = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +01001244 } else {
Hanno Beckerda763de2022-04-13 06:50:02 +01001245 X->s = A->s * B->s;
Gilles Peskine449bd832023-01-11 14:50:10 +01001246 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001247
1248cleanup:
1249
Gilles Peskine449bd832023-01-11 14:50:10 +01001250 mbedtls_mpi_free(&TB); mbedtls_mpi_free(&TA);
Paul Bakker5121ce52009-01-03 21:22:43 +00001251
Gilles Peskine449bd832023-01-11 14:50:10 +01001252 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001253}
1254
1255/*
1256 * Baseline multiplication: X = A * b
1257 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001258int mbedtls_mpi_mul_int(mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_uint b)
Paul Bakker5121ce52009-01-03 21:22:43 +00001259{
Hanno Becker35771312022-04-14 11:52:11 +01001260 size_t n = A->n;
Gilles Peskine449bd832023-01-11 14:50:10 +01001261 while (n > 0 && A->p[n - 1] == 0) {
Hanno Becker35771312022-04-14 11:52:11 +01001262 --n;
Gilles Peskine449bd832023-01-11 14:50:10 +01001263 }
Hanno Becker35771312022-04-14 11:52:11 +01001264
Hanno Becker74a11a32022-04-06 06:27:00 +01001265 /* The general method below doesn't work if b==0. */
Gilles Peskine449bd832023-01-11 14:50:10 +01001266 if (b == 0 || n == 0) {
1267 return mbedtls_mpi_lset(X, 0);
1268 }
Gilles Peskine8fd95c62020-07-23 21:58:50 +02001269
Hanno Beckeraef9cc42022-04-11 06:36:29 +01001270 /* Calculate A*b as A + A*(b-1) to take advantage of mbedtls_mpi_core_mla */
Gilles Peskine8fd95c62020-07-23 21:58:50 +02001271 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Gilles Peskinecd0dbf32020-07-24 00:09:04 +02001272 /* In general, A * b requires 1 limb more than b. If
1273 * A->p[n - 1] * b / b == A->p[n - 1], then A * b fits in the same
1274 * number of limbs as A and the call to grow() is not required since
Gilles Peskinee1bba7c2021-03-10 23:44:10 +01001275 * copy() will take care of the growth if needed. However, experimentally,
1276 * making the call to grow() unconditional causes slightly fewer
Gilles Peskinecd0dbf32020-07-24 00:09:04 +02001277 * calls to calloc() in ECP code, presumably because it reuses the
1278 * same mpi for a while and this way the mpi is more likely to directly
Hanno Becker9137b9c2022-04-12 10:51:54 +01001279 * grow to its final size.
1280 *
1281 * Note that calculating A*b as 0 + A*b doesn't work as-is because
1282 * A,X can be the same. */
Gilles Peskine449bd832023-01-11 14:50:10 +01001283 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, n + 1));
1284 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(X, A));
1285 mbedtls_mpi_core_mla(X->p, X->n, A->p, n, b - 1);
Gilles Peskine8fd95c62020-07-23 21:58:50 +02001286
1287cleanup:
Gilles Peskine449bd832023-01-11 14:50:10 +01001288 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001289}
1290
1291/*
Simon Butcherf5ba0452015-12-27 23:01:55 +00001292 * Unsigned integer divide - double mbedtls_mpi_uint dividend, u1/u0, and
1293 * mbedtls_mpi_uint divisor, d
Simon Butcher15b15d12015-11-26 19:35:03 +00001294 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001295static mbedtls_mpi_uint mbedtls_int_div_int(mbedtls_mpi_uint u1,
1296 mbedtls_mpi_uint u0,
1297 mbedtls_mpi_uint d,
1298 mbedtls_mpi_uint *r)
Simon Butcher15b15d12015-11-26 19:35:03 +00001299{
Manuel Pégourié-Gonnard16308882015-12-01 10:27:00 +01001300#if defined(MBEDTLS_HAVE_UDBL)
1301 mbedtls_t_udbl dividend, quotient;
Simon Butcherf5ba0452015-12-27 23:01:55 +00001302#else
Simon Butcher9803d072016-01-03 00:24:34 +00001303 const mbedtls_mpi_uint radix = (mbedtls_mpi_uint) 1 << biH;
Gilles Peskine449bd832023-01-11 14:50:10 +01001304 const mbedtls_mpi_uint uint_halfword_mask = ((mbedtls_mpi_uint) 1 << biH) - 1;
Simon Butcherf5ba0452015-12-27 23:01:55 +00001305 mbedtls_mpi_uint d0, d1, q0, q1, rAX, r0, quotient;
1306 mbedtls_mpi_uint u0_msw, u0_lsw;
Simon Butcher9803d072016-01-03 00:24:34 +00001307 size_t s;
Manuel Pégourié-Gonnard16308882015-12-01 10:27:00 +01001308#endif
1309
Simon Butcher15b15d12015-11-26 19:35:03 +00001310 /*
1311 * Check for overflow
1312 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001313 if (0 == d || u1 >= d) {
1314 if (r != NULL) {
1315 *r = ~(mbedtls_mpi_uint) 0u;
1316 }
Simon Butcher15b15d12015-11-26 19:35:03 +00001317
Gilles Peskine449bd832023-01-11 14:50:10 +01001318 return ~(mbedtls_mpi_uint) 0u;
Simon Butcher15b15d12015-11-26 19:35:03 +00001319 }
1320
1321#if defined(MBEDTLS_HAVE_UDBL)
Simon Butcher15b15d12015-11-26 19:35:03 +00001322 dividend = (mbedtls_t_udbl) u1 << biL;
1323 dividend |= (mbedtls_t_udbl) u0;
1324 quotient = dividend / d;
Gilles Peskine449bd832023-01-11 14:50:10 +01001325 if (quotient > ((mbedtls_t_udbl) 1 << biL) - 1) {
1326 quotient = ((mbedtls_t_udbl) 1 << biL) - 1;
1327 }
Simon Butcher15b15d12015-11-26 19:35:03 +00001328
Gilles Peskine449bd832023-01-11 14:50:10 +01001329 if (r != NULL) {
1330 *r = (mbedtls_mpi_uint) (dividend - (quotient * d));
1331 }
Simon Butcher15b15d12015-11-26 19:35:03 +00001332
1333 return (mbedtls_mpi_uint) quotient;
1334#else
Simon Butcher15b15d12015-11-26 19:35:03 +00001335
1336 /*
1337 * Algorithm D, Section 4.3.1 - The Art of Computer Programming
1338 * Vol. 2 - Seminumerical Algorithms, Knuth
1339 */
1340
1341 /*
1342 * Normalize the divisor, d, and dividend, u0, u1
1343 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001344 s = mbedtls_mpi_core_clz(d);
Simon Butcher15b15d12015-11-26 19:35:03 +00001345 d = d << s;
1346
1347 u1 = u1 << s;
Gilles Peskine449bd832023-01-11 14:50:10 +01001348 u1 |= (u0 >> (biL - s)) & (-(mbedtls_mpi_sint) s >> (biL - 1));
Simon Butcher15b15d12015-11-26 19:35:03 +00001349 u0 = u0 << s;
1350
1351 d1 = d >> biH;
Simon Butcher9803d072016-01-03 00:24:34 +00001352 d0 = d & uint_halfword_mask;
Simon Butcher15b15d12015-11-26 19:35:03 +00001353
1354 u0_msw = u0 >> biH;
Simon Butcher9803d072016-01-03 00:24:34 +00001355 u0_lsw = u0 & uint_halfword_mask;
Simon Butcher15b15d12015-11-26 19:35:03 +00001356
1357 /*
1358 * Find the first quotient and remainder
1359 */
1360 q1 = u1 / d1;
1361 r0 = u1 - d1 * q1;
1362
Gilles Peskine449bd832023-01-11 14:50:10 +01001363 while (q1 >= radix || (q1 * d0 > radix * r0 + u0_msw)) {
Simon Butcher15b15d12015-11-26 19:35:03 +00001364 q1 -= 1;
1365 r0 += d1;
1366
Gilles Peskine449bd832023-01-11 14:50:10 +01001367 if (r0 >= radix) {
1368 break;
1369 }
Simon Butcher15b15d12015-11-26 19:35:03 +00001370 }
1371
Gilles Peskine449bd832023-01-11 14:50:10 +01001372 rAX = (u1 * radix) + (u0_msw - q1 * d);
Simon Butcher15b15d12015-11-26 19:35:03 +00001373 q0 = rAX / d1;
1374 r0 = rAX - q0 * d1;
1375
Gilles Peskine449bd832023-01-11 14:50:10 +01001376 while (q0 >= radix || (q0 * d0 > radix * r0 + u0_lsw)) {
Simon Butcher15b15d12015-11-26 19:35:03 +00001377 q0 -= 1;
1378 r0 += d1;
1379
Gilles Peskine449bd832023-01-11 14:50:10 +01001380 if (r0 >= radix) {
1381 break;
1382 }
Simon Butcher15b15d12015-11-26 19:35:03 +00001383 }
1384
Gilles Peskine449bd832023-01-11 14:50:10 +01001385 if (r != NULL) {
1386 *r = (rAX * radix + u0_lsw - q0 * d) >> s;
1387 }
Simon Butcher15b15d12015-11-26 19:35:03 +00001388
1389 quotient = q1 * radix + q0;
1390
1391 return quotient;
1392#endif
1393}
1394
1395/*
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001396 * Division by mbedtls_mpi: A = Q * B + R (HAC 14.20)
Paul Bakker5121ce52009-01-03 21:22:43 +00001397 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001398int mbedtls_mpi_div_mpi(mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A,
1399 const mbedtls_mpi *B)
Paul Bakker5121ce52009-01-03 21:22:43 +00001400{
Janos Follath24eed8d2019-11-22 13:21:35 +00001401 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker23986e52011-04-24 08:57:21 +00001402 size_t i, n, t, k;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001403 mbedtls_mpi X, Y, Z, T1, T2;
Alexander Kd19a1932019-11-01 18:20:42 +03001404 mbedtls_mpi_uint TP2[3];
Paul Bakker5121ce52009-01-03 21:22:43 +00001405
Gilles Peskine449bd832023-01-11 14:50:10 +01001406 if (mbedtls_mpi_cmp_int(B, 0) == 0) {
1407 return MBEDTLS_ERR_MPI_DIVISION_BY_ZERO;
1408 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001409
Gilles Peskine449bd832023-01-11 14:50:10 +01001410 mbedtls_mpi_init(&X); mbedtls_mpi_init(&Y); mbedtls_mpi_init(&Z);
1411 mbedtls_mpi_init(&T1);
Alexander Kd19a1932019-11-01 18:20:42 +03001412 /*
1413 * Avoid dynamic memory allocations for constant-size T2.
1414 *
1415 * T2 is used for comparison only and the 3 limbs are assigned explicitly,
1416 * so nobody increase the size of the MPI and we're safe to use an on-stack
1417 * buffer.
1418 */
Alexander K35d6d462019-10-31 14:46:45 +03001419 T2.s = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +01001420 T2.n = sizeof(TP2) / sizeof(*TP2);
Alexander Kd19a1932019-11-01 18:20:42 +03001421 T2.p = TP2;
Paul Bakker5121ce52009-01-03 21:22:43 +00001422
Gilles Peskine449bd832023-01-11 14:50:10 +01001423 if (mbedtls_mpi_cmp_abs(A, B) < 0) {
1424 if (Q != NULL) {
1425 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(Q, 0));
1426 }
1427 if (R != NULL) {
1428 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(R, A));
1429 }
1430 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +00001431 }
1432
Gilles Peskine449bd832023-01-11 14:50:10 +01001433 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&X, A));
1434 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&Y, B));
Paul Bakker5121ce52009-01-03 21:22:43 +00001435 X.s = Y.s = 1;
1436
Gilles Peskine449bd832023-01-11 14:50:10 +01001437 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(&Z, A->n + 2));
1438 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&Z, 0));
1439 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(&T1, A->n + 2));
Paul Bakker5121ce52009-01-03 21:22:43 +00001440
Gilles Peskine449bd832023-01-11 14:50:10 +01001441 k = mbedtls_mpi_bitlen(&Y) % biL;
1442 if (k < biL - 1) {
Paul Bakker5121ce52009-01-03 21:22:43 +00001443 k = biL - 1 - k;
Gilles Peskine449bd832023-01-11 14:50:10 +01001444 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&X, k));
1445 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&Y, k));
1446 } else {
1447 k = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +00001448 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001449
1450 n = X.n - 1;
1451 t = Y.n - 1;
Gilles Peskine449bd832023-01-11 14:50:10 +01001452 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&Y, biL * (n - t)));
Paul Bakker5121ce52009-01-03 21:22:43 +00001453
Gilles Peskine449bd832023-01-11 14:50:10 +01001454 while (mbedtls_mpi_cmp_mpi(&X, &Y) >= 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00001455 Z.p[n - t]++;
Gilles Peskine449bd832023-01-11 14:50:10 +01001456 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&X, &X, &Y));
Paul Bakker5121ce52009-01-03 21:22:43 +00001457 }
Gilles Peskine449bd832023-01-11 14:50:10 +01001458 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&Y, biL * (n - t)));
Paul Bakker5121ce52009-01-03 21:22:43 +00001459
Gilles Peskine449bd832023-01-11 14:50:10 +01001460 for (i = n; i > t; i--) {
1461 if (X.p[i] >= Y.p[t]) {
1462 Z.p[i - t - 1] = ~(mbedtls_mpi_uint) 0u;
1463 } else {
1464 Z.p[i - t - 1] = mbedtls_int_div_int(X.p[i], X.p[i - 1],
1465 Y.p[t], NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +00001466 }
1467
Gilles Peskine449bd832023-01-11 14:50:10 +01001468 T2.p[0] = (i < 2) ? 0 : X.p[i - 2];
1469 T2.p[1] = (i < 1) ? 0 : X.p[i - 1];
Alexander K35d6d462019-10-31 14:46:45 +03001470 T2.p[2] = X.p[i];
1471
Paul Bakker5121ce52009-01-03 21:22:43 +00001472 Z.p[i - t - 1]++;
Gilles Peskine449bd832023-01-11 14:50:10 +01001473 do {
Paul Bakker5121ce52009-01-03 21:22:43 +00001474 Z.p[i - t - 1]--;
1475
Gilles Peskine449bd832023-01-11 14:50:10 +01001476 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&T1, 0));
1477 T1.p[0] = (t < 1) ? 0 : Y.p[t - 1];
Paul Bakker5121ce52009-01-03 21:22:43 +00001478 T1.p[1] = Y.p[t];
Gilles Peskine449bd832023-01-11 14:50:10 +01001479 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_int(&T1, &T1, Z.p[i - t - 1]));
1480 } while (mbedtls_mpi_cmp_mpi(&T1, &T2) > 0);
Paul Bakker5121ce52009-01-03 21:22:43 +00001481
Gilles Peskine449bd832023-01-11 14:50:10 +01001482 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_int(&T1, &Y, Z.p[i - t - 1]));
1483 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&T1, biL * (i - t - 1)));
1484 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&X, &X, &T1));
Paul Bakker5121ce52009-01-03 21:22:43 +00001485
Gilles Peskine449bd832023-01-11 14:50:10 +01001486 if (mbedtls_mpi_cmp_int(&X, 0) < 0) {
1487 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&T1, &Y));
1488 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&T1, biL * (i - t - 1)));
1489 MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&X, &X, &T1));
Paul Bakker5121ce52009-01-03 21:22:43 +00001490 Z.p[i - t - 1]--;
1491 }
1492 }
1493
Gilles Peskine449bd832023-01-11 14:50:10 +01001494 if (Q != NULL) {
1495 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(Q, &Z));
Paul Bakker5121ce52009-01-03 21:22:43 +00001496 Q->s = A->s * B->s;
1497 }
1498
Gilles Peskine449bd832023-01-11 14:50:10 +01001499 if (R != NULL) {
1500 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&X, k));
Paul Bakkerf02c5642012-11-13 10:25:21 +00001501 X.s = A->s;
Gilles Peskine449bd832023-01-11 14:50:10 +01001502 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(R, &X));
Paul Bakker5121ce52009-01-03 21:22:43 +00001503
Gilles Peskine449bd832023-01-11 14:50:10 +01001504 if (mbedtls_mpi_cmp_int(R, 0) == 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00001505 R->s = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +01001506 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001507 }
1508
1509cleanup:
1510
Gilles Peskine449bd832023-01-11 14:50:10 +01001511 mbedtls_mpi_free(&X); mbedtls_mpi_free(&Y); mbedtls_mpi_free(&Z);
1512 mbedtls_mpi_free(&T1);
1513 mbedtls_platform_zeroize(TP2, sizeof(TP2));
Paul Bakker5121ce52009-01-03 21:22:43 +00001514
Gilles Peskine449bd832023-01-11 14:50:10 +01001515 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001516}
1517
1518/*
1519 * Division by int: A = Q * b + R
Paul Bakker5121ce52009-01-03 21:22:43 +00001520 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001521int mbedtls_mpi_div_int(mbedtls_mpi *Q, mbedtls_mpi *R,
1522 const mbedtls_mpi *A,
1523 mbedtls_mpi_sint b)
Paul Bakker5121ce52009-01-03 21:22:43 +00001524{
Yuto Takano36c8ddc2021-07-05 09:10:52 +01001525 mbedtls_mpi B;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001526 mbedtls_mpi_uint p[1];
Paul Bakker5121ce52009-01-03 21:22:43 +00001527
Gilles Peskine449bd832023-01-11 14:50:10 +01001528 p[0] = mpi_sint_abs(b);
Dave Rodgmanf3df1052023-08-09 18:55:41 +01001529 B.s = TO_SIGN(b);
Yuto Takano36c8ddc2021-07-05 09:10:52 +01001530 B.n = 1;
1531 B.p = p;
Paul Bakker5121ce52009-01-03 21:22:43 +00001532
Gilles Peskine449bd832023-01-11 14:50:10 +01001533 return mbedtls_mpi_div_mpi(Q, R, A, &B);
Paul Bakker5121ce52009-01-03 21:22:43 +00001534}
1535
1536/*
1537 * Modulo: R = A mod B
1538 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001539int mbedtls_mpi_mod_mpi(mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B)
Paul Bakker5121ce52009-01-03 21:22:43 +00001540{
Janos Follath24eed8d2019-11-22 13:21:35 +00001541 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker5121ce52009-01-03 21:22:43 +00001542
Gilles Peskine449bd832023-01-11 14:50:10 +01001543 if (mbedtls_mpi_cmp_int(B, 0) < 0) {
1544 return MBEDTLS_ERR_MPI_NEGATIVE_VALUE;
1545 }
Paul Bakkerce40a6d2009-06-23 19:46:08 +00001546
Gilles Peskine449bd832023-01-11 14:50:10 +01001547 MBEDTLS_MPI_CHK(mbedtls_mpi_div_mpi(NULL, R, A, B));
Paul Bakker5121ce52009-01-03 21:22:43 +00001548
Gilles Peskine449bd832023-01-11 14:50:10 +01001549 while (mbedtls_mpi_cmp_int(R, 0) < 0) {
1550 MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(R, R, B));
1551 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001552
Gilles Peskine449bd832023-01-11 14:50:10 +01001553 while (mbedtls_mpi_cmp_mpi(R, B) >= 0) {
1554 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(R, R, B));
1555 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001556
1557cleanup:
1558
Gilles Peskine449bd832023-01-11 14:50:10 +01001559 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001560}
1561
1562/*
1563 * Modulo: r = A mod b
1564 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001565int mbedtls_mpi_mod_int(mbedtls_mpi_uint *r, const mbedtls_mpi *A, mbedtls_mpi_sint b)
Paul Bakker5121ce52009-01-03 21:22:43 +00001566{
Paul Bakker23986e52011-04-24 08:57:21 +00001567 size_t i;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001568 mbedtls_mpi_uint x, y, z;
Paul Bakker5121ce52009-01-03 21:22:43 +00001569
Gilles Peskine449bd832023-01-11 14:50:10 +01001570 if (b == 0) {
1571 return MBEDTLS_ERR_MPI_DIVISION_BY_ZERO;
1572 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001573
Gilles Peskine449bd832023-01-11 14:50:10 +01001574 if (b < 0) {
1575 return MBEDTLS_ERR_MPI_NEGATIVE_VALUE;
1576 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001577
1578 /*
1579 * handle trivial cases
1580 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001581 if (b == 1 || A->n == 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00001582 *r = 0;
Gilles Peskine449bd832023-01-11 14:50:10 +01001583 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +00001584 }
1585
Gilles Peskine449bd832023-01-11 14:50:10 +01001586 if (b == 2) {
Paul Bakker5121ce52009-01-03 21:22:43 +00001587 *r = A->p[0] & 1;
Gilles Peskine449bd832023-01-11 14:50:10 +01001588 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +00001589 }
1590
1591 /*
1592 * general case
1593 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001594 for (i = A->n, y = 0; i > 0; i--) {
Paul Bakker23986e52011-04-24 08:57:21 +00001595 x = A->p[i - 1];
Gilles Peskine449bd832023-01-11 14:50:10 +01001596 y = (y << biH) | (x >> biH);
Paul Bakker5121ce52009-01-03 21:22:43 +00001597 z = y / b;
1598 y -= z * b;
1599
1600 x <<= biH;
Gilles Peskine449bd832023-01-11 14:50:10 +01001601 y = (y << biH) | (x >> biH);
Paul Bakker5121ce52009-01-03 21:22:43 +00001602 z = y / b;
1603 y -= z * b;
1604 }
1605
Paul Bakkerce40a6d2009-06-23 19:46:08 +00001606 /*
1607 * If A is negative, then the current y represents a negative value.
1608 * Flipping it to the positive side.
1609 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001610 if (A->s < 0 && y != 0) {
Paul Bakkerce40a6d2009-06-23 19:46:08 +00001611 y = b - y;
Gilles Peskine449bd832023-01-11 14:50:10 +01001612 }
Paul Bakkerce40a6d2009-06-23 19:46:08 +00001613
Paul Bakker5121ce52009-01-03 21:22:43 +00001614 *r = y;
1615
Gilles Peskine449bd832023-01-11 14:50:10 +01001616 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +00001617}
1618
Janos Follath38ff70e2024-08-12 18:20:59 +01001619/*
1620 * Warning! If the parameter E_public has MBEDTLS_MPI_IS_PUBLIC as its value,
1621 * this function is not constant time with respect to the exponent (parameter E).
1622 */
1623static int mbedtls_mpi_exp_mod_optionally_safe(mbedtls_mpi *X, const mbedtls_mpi *A,
Janos Follatha5fc8f32024-08-12 20:11:06 +01001624 const mbedtls_mpi *E, int E_public,
1625 const mbedtls_mpi *N, mbedtls_mpi *prec_RR)
Paul Bakker5121ce52009-01-03 21:22:43 +00001626{
Janos Follath24eed8d2019-11-22 13:21:35 +00001627 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker5121ce52009-01-03 21:22:43 +00001628
Gilles Peskine449bd832023-01-11 14:50:10 +01001629 if (mbedtls_mpi_cmp_int(N, 0) <= 0 || (N->p[0] & 1) == 0) {
1630 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
1631 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001632
Gilles Peskine449bd832023-01-11 14:50:10 +01001633 if (mbedtls_mpi_cmp_int(E, 0) < 0) {
1634 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
1635 }
Paul Bakkerf6198c12012-05-16 08:02:29 +00001636
Gilles Peskine449bd832023-01-11 14:50:10 +01001637 if (mbedtls_mpi_bitlen(E) > MBEDTLS_MPI_MAX_BITS ||
1638 mbedtls_mpi_bitlen(N) > MBEDTLS_MPI_MAX_BITS) {
1639 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
1640 }
Chris Jones9246d042020-11-25 15:12:39 +00001641
Janos Follath583f0472024-02-19 11:16:44 +00001642 /*
1643 * Ensure that the exponent that we are passing to the core is not NULL.
1644 */
1645 if (E->n == 0) {
1646 ret = mbedtls_mpi_lset(X, 1);
1647 return ret;
1648 }
1649
Janos Follath424c2652024-02-21 09:26:36 +00001650 /*
1651 * Allocate working memory for mbedtls_mpi_core_exp_mod()
1652 */
1653 size_t T_limbs = mbedtls_mpi_core_exp_mod_working_limbs(N->n, E->n);
Janos Follath09025722024-02-21 11:50:25 +00001654 mbedtls_mpi_uint *T = (mbedtls_mpi_uint *) mbedtls_calloc(T_limbs, sizeof(mbedtls_mpi_uint));
Janos Follath424c2652024-02-21 09:26:36 +00001655 if (T == NULL) {
1656 return MBEDTLS_ERR_MPI_ALLOC_FAILED;
1657 }
1658
Janos Follath701ae1d2024-02-19 10:56:54 +00001659 mbedtls_mpi RR;
Janos Follath1ba40582024-02-13 12:36:13 +00001660 mbedtls_mpi_init(&RR);
Paul Bakker50546922012-05-19 08:40:49 +00001661
1662 /*
Paul Bakker5121ce52009-01-03 21:22:43 +00001663 * If 1st call, pre-compute R^2 mod N
1664 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001665 if (prec_RR == NULL || prec_RR->p == NULL) {
Janos Follath1ba40582024-02-13 12:36:13 +00001666 MBEDTLS_MPI_CHK(mbedtls_mpi_core_get_mont_r2_unsafe(&RR, N));
Paul Bakker5121ce52009-01-03 21:22:43 +00001667
Gilles Peskine449bd832023-01-11 14:50:10 +01001668 if (prec_RR != NULL) {
Janos Follath576087d2024-02-19 11:05:01 +00001669 *prec_RR = RR;
Gilles Peskine449bd832023-01-11 14:50:10 +01001670 }
1671 } else {
Janos Follath0512d172024-02-20 14:30:46 +00001672 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(prec_RR, N->n));
Janos Follath576087d2024-02-19 11:05:01 +00001673 RR = *prec_RR;
Paul Bakker5121ce52009-01-03 21:22:43 +00001674 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001675
1676 /*
Janos Follath1ba40582024-02-13 12:36:13 +00001677 * To preserve constness we need to make a copy of A. Using X for this to
1678 * save memory.
Paul Bakker5121ce52009-01-03 21:22:43 +00001679 */
Janos Follath1ba40582024-02-13 12:36:13 +00001680 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(X, A));
Paul Bakker5121ce52009-01-03 21:22:43 +00001681
1682 /*
Janos Follath1ba40582024-02-13 12:36:13 +00001683 * Compensate for negative A (and correct at the end).
Paul Bakker5121ce52009-01-03 21:22:43 +00001684 */
Janos Follath1ba40582024-02-13 12:36:13 +00001685 X->s = 1;
Paul Bakkerf6198c12012-05-16 08:02:29 +00001686
Janos Follath8e7d6a02022-10-04 13:27:40 +01001687 /*
Janos Follath467a5492024-02-19 11:27:38 +00001688 * Make sure that X is in a form that is safe for consumption by
1689 * the core functions.
1690 *
1691 * - The core functions will not touch the limbs of X above N->n. The
1692 * result will be correct if those limbs are 0, which the mod call
1693 * ensures.
1694 * - Also, X must have at least as many limbs as N for the calls to the
1695 * core functions.
Janos Follath8e7d6a02022-10-04 13:27:40 +01001696 */
Janos Follath1ba40582024-02-13 12:36:13 +00001697 if (mbedtls_mpi_cmp_mpi(X, N) >= 0) {
1698 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(X, X, N));
1699 }
1700 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, N->n));
1701
1702 /*
Janos Follath1ba40582024-02-13 12:36:13 +00001703 * Convert to and from Montgomery around mbedtls_mpi_core_exp_mod().
1704 */
Dave Rodgmand282e262024-03-11 15:28:48 +00001705 {
1706 mbedtls_mpi_uint mm = mbedtls_mpi_core_montmul_init(N->p);
1707 mbedtls_mpi_core_to_mont_rep(X->p, X->p, N->p, N->n, mm, RR.p, T);
Janos Follath38ff70e2024-08-12 18:20:59 +01001708 if (E_public == MBEDTLS_MPI_IS_PUBLIC) {
1709 mbedtls_mpi_core_exp_mod_unsafe(X->p, X->p, N->p, N->n, E->p, E->n, RR.p, T);
1710 } else {
1711 mbedtls_mpi_core_exp_mod(X->p, X->p, N->p, N->n, E->p, E->n, RR.p, T);
1712 }
Dave Rodgmand282e262024-03-11 15:28:48 +00001713 mbedtls_mpi_core_from_mont_rep(X->p, X->p, N->p, N->n, mm, T);
1714 }
Janos Follath1ba40582024-02-13 12:36:13 +00001715
1716 /*
1717 * Correct for negative A.
1718 */
Janos Follath583f0472024-02-19 11:16:44 +00001719 if (A->s == -1 && (E->p[0] & 1) != 0) {
Janos Follath86258f52024-02-21 11:25:41 +00001720 mbedtls_ct_condition_t is_x_non_zero = mbedtls_mpi_core_check_zero_ct(X->p, X->n);
Janos Follath4ec0fb52024-03-08 17:22:40 +00001721 X->s = mbedtls_ct_mpi_sign_if(is_x_non_zero, -1, 1);
Janos Follath86258f52024-02-21 11:25:41 +00001722
Janos Follath1ba40582024-02-13 12:36:13 +00001723 MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(X, N, X));
1724 }
Janos Follath8e7d6a02022-10-04 13:27:40 +01001725
Paul Bakker5121ce52009-01-03 21:22:43 +00001726cleanup:
1727
Janos Follath424c2652024-02-21 09:26:36 +00001728 mbedtls_mpi_zeroize_and_free(T, T_limbs);
Paul Bakker6c591fa2011-05-05 11:49:20 +00001729
Gilles Peskine449bd832023-01-11 14:50:10 +01001730 if (prec_RR == NULL || prec_RR->p == NULL) {
1731 mbedtls_mpi_free(&RR);
1732 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001733
Gilles Peskine449bd832023-01-11 14:50:10 +01001734 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001735}
1736
Manuel Pégourié-Gonnard75ed5872024-06-18 12:52:45 +02001737int mbedtls_mpi_exp_mod(mbedtls_mpi *X, const mbedtls_mpi *A,
1738 const mbedtls_mpi *E, const mbedtls_mpi *N,
1739 mbedtls_mpi *prec_RR)
1740{
Janos Follatha5fc8f32024-08-12 20:11:06 +01001741 return mbedtls_mpi_exp_mod_optionally_safe(X, A, E, MBEDTLS_MPI_IS_SECRET, N, prec_RR);
Manuel Pégourié-Gonnard75ed5872024-06-18 12:52:45 +02001742}
1743
Janos Follath38ff70e2024-08-12 18:20:59 +01001744int mbedtls_mpi_exp_mod_unsafe(mbedtls_mpi *X, const mbedtls_mpi *A,
1745 const mbedtls_mpi *E, const mbedtls_mpi *N,
1746 mbedtls_mpi *prec_RR)
1747{
Janos Follatha5fc8f32024-08-12 20:11:06 +01001748 return mbedtls_mpi_exp_mod_optionally_safe(X, A, E, MBEDTLS_MPI_IS_PUBLIC, N, prec_RR);
Janos Follath38ff70e2024-08-12 18:20:59 +01001749}
1750
Felix Conwaybd7ede32025-08-04 11:33:48 +01001751/* Constant-time GCD and/or modinv with odd modulus and A <= N */
1752int mbedtls_mpi_gcd_modinv_odd(mbedtls_mpi *G,
1753 mbedtls_mpi *I,
1754 const mbedtls_mpi *A,
1755 const mbedtls_mpi *N)
1756{
1757 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
1758 mbedtls_mpi local_g;
1759 mbedtls_mpi_uint *T = NULL;
1760 const size_t T_factor = I != NULL ? 5 : 4;
Felix Conwayeefdfe92025-08-05 14:35:53 +01001761 const mbedtls_mpi_uint zero = 0;
Felix Conwaybd7ede32025-08-04 11:33:48 +01001762
1763 /* Check requirements on A and N */
1764 if (mbedtls_mpi_cmp_int(A, 0) < 0 ||
1765 mbedtls_mpi_cmp_mpi(A, N) > 0 ||
1766 mbedtls_mpi_get_bit(N, 0) != 1 ||
1767 (I != NULL && mbedtls_mpi_cmp_int(N, 1) == 0)) {
1768 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
1769 }
1770
1771 /* Check aliasing requirements */
Felix Conwayd9c4c9c2025-08-05 14:33:32 +01001772 if (A == N || (I != NULL && (I == N || G == N))) {
Felix Conwaybd7ede32025-08-04 11:33:48 +01001773 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
1774 }
1775
1776 mbedtls_mpi_init(&local_g);
1777
1778 if (G == NULL) {
1779 G = &local_g;
1780 }
1781
Felix Conwaya1c95e32025-08-06 09:54:11 +01001782 /* We can't modify the values of G or I before use in the main function,
1783 * as they could be aliased to A or N. */
Felix Conwaybd7ede32025-08-04 11:33:48 +01001784 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(G, N->n));
Felix Conwaybd7ede32025-08-04 11:33:48 +01001785 if (I != NULL) {
1786 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(I, N->n));
Felix Conwaybd7ede32025-08-04 11:33:48 +01001787 }
1788
1789 T = mbedtls_calloc(sizeof(mbedtls_mpi_uint) * N->n, T_factor);
1790 if (T == NULL) {
1791 ret = MBEDTLS_ERR_MPI_ALLOC_FAILED;
1792 goto cleanup;
1793 }
1794
1795 mbedtls_mpi_uint *Ip = I != NULL ? I->p : NULL;
Felix Conwaya1c95e32025-08-06 09:54:11 +01001796 /* If A is 0 (null), then A->p would be null, and A->n would be 0,
1797 * which would be an issue if A->p and A->n were passed to
1798 * mbedtls_mpi_core_gcd_modinv_odd below. */
Felix Conwayeefdfe92025-08-05 14:35:53 +01001799 const mbedtls_mpi_uint *Ap = A->p != NULL ? A->p : &zero;
Felix Conwaya1c95e32025-08-06 09:54:11 +01001800 size_t An = A->n >= N->n ? N->n : A->p != NULL ? A->n : 1;
Felix Conwayeefdfe92025-08-05 14:35:53 +01001801 mbedtls_mpi_core_gcd_modinv_odd(G->p, Ip, Ap, An, N->p, N->n, T);
Felix Conwaybd7ede32025-08-04 11:33:48 +01001802
Felix Conwaya1c95e32025-08-06 09:54:11 +01001803 G->s = 1;
1804 if (I != NULL) {
1805 I->s = 1;
1806 }
1807
Felix Conwaybd7ede32025-08-04 11:33:48 +01001808 if (G->n > N->n) {
1809 memset(G->p + N->n, 0, ciL * (G->n - N->n));
1810 }
1811 if (I != NULL && I->n > N->n) {
1812 memset(I->p + N->n, 0, ciL * (I->n - N->n));
1813 }
1814
1815cleanup:
1816 mbedtls_mpi_free(&local_g);
1817 mbedtls_free(T);
1818 return ret;
1819}
1820
Paul Bakker5121ce52009-01-03 21:22:43 +00001821/*
Manuel Pégourié-Gonnardc6a9d842025-07-10 23:28:50 +02001822 * Greatest common divisor: G = gcd(A, B)
1823 * Wrapper around mbedtls_mpi_gcd_modinv() that removes its restrictions.
Paul Bakker5121ce52009-01-03 21:22:43 +00001824 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001825int mbedtls_mpi_gcd(mbedtls_mpi *G, const mbedtls_mpi *A, const mbedtls_mpi *B)
Paul Bakker5121ce52009-01-03 21:22:43 +00001826{
Janos Follath24eed8d2019-11-22 13:21:35 +00001827 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Alexander Ke8ad49f2019-08-16 16:16:07 +03001828 mbedtls_mpi TA, TB;
Paul Bakker5121ce52009-01-03 21:22:43 +00001829
Gilles Peskine449bd832023-01-11 14:50:10 +01001830 mbedtls_mpi_init(&TA); mbedtls_mpi_init(&TB);
Paul Bakker5121ce52009-01-03 21:22:43 +00001831
Manuel Pégourié-Gonnardc6a9d842025-07-10 23:28:50 +02001832 /* Make copies and take absolute values */
Gilles Peskine449bd832023-01-11 14:50:10 +01001833 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TA, A));
1834 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TB, B));
Paul Bakker5121ce52009-01-03 21:22:43 +00001835 TA.s = TB.s = 1;
Paul Bakker5121ce52009-01-03 21:22:43 +00001836
Manuel Pégourié-Gonnard381d4ba2025-08-04 10:57:13 +02001837 /* Make the two values the same (non-zero) number of limbs.
1838 * This is needed to use mbedtls_mpi_core functions below. */
Manuel Pégourié-Gonnardc6a9d842025-07-10 23:28:50 +02001839 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(&TA, TB.n != 0 ? TB.n : 1));
1840 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(&TB, TA.n)); // non-zero from above
Paul Bakker5121ce52009-01-03 21:22:43 +00001841
Manuel Pégourié-Gonnard381d4ba2025-08-04 10:57:13 +02001842 /* Handle special cases (that don't happen in crypto usage) */
1843 if (mbedtls_mpi_core_check_zero_ct(TA.p, TA.n) == MBEDTLS_CT_FALSE) {
Manuel Pégourié-Gonnard87e77d62025-08-11 10:45:41 +02001844 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(G, &TB)); // GCD(0, B) = abs(B)
1845 goto cleanup;
Manuel Pégourié-Gonnard381d4ba2025-08-04 10:57:13 +02001846 }
1847 if (mbedtls_mpi_core_check_zero_ct(TB.p, TB.n) == MBEDTLS_CT_FALSE) {
Manuel Pégourié-Gonnard87e77d62025-08-11 10:45:41 +02001848 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(G, &TA)); // GCD(A, 0) = abs(A)
Paul Bakker5121ce52009-01-03 21:22:43 +00001849 goto cleanup;
1850 }
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001851
Manuel Pégourié-Gonnard30f07322025-08-13 08:42:45 +02001852 /* Make boths inputs odd by putting powers of 2 on the side */
Manuel Pégourié-Gonnardc6a9d842025-07-10 23:28:50 +02001853 const size_t za = mbedtls_mpi_lsb(&TA);
1854 const size_t zb = mbedtls_mpi_lsb(&TB);
Manuel Pégourié-Gonnardc6a9d842025-07-10 23:28:50 +02001855 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TA, za));
1856 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TB, zb));
Paul Bakker5121ce52009-01-03 21:22:43 +00001857
Manuel Pégourié-Gonnardc6a9d842025-07-10 23:28:50 +02001858 /* Ensure A <= B: if B < A, swap them */
1859 mbedtls_ct_condition_t swap = mbedtls_mpi_core_lt_ct(TB.p, TA.p, TA.n);
1860 mbedtls_mpi_core_cond_swap(TA.p, TB.p, TA.n, swap);
Paul Bakker5121ce52009-01-03 21:22:43 +00001861
Manuel Pégourié-Gonnardc6a9d842025-07-10 23:28:50 +02001862 MBEDTLS_MPI_CHK(mbedtls_mpi_gcd_modinv_odd(G, NULL, &TA, &TB));
Gilles Peskine4df3f1f2021-06-15 22:09:39 +02001863
Manuel Pégourié-Gonnard30f07322025-08-13 08:42:45 +02001864 /* Re-inject the power of 2 we had previously put aside */
Manuel Pégourié-Gonnardc6a9d842025-07-10 23:28:50 +02001865 size_t zg = za > zb ? zb : za; // zg = min(za, zb)
1866 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(G, zg));
Paul Bakker5121ce52009-01-03 21:22:43 +00001867
1868cleanup:
1869
Gilles Peskine449bd832023-01-11 14:50:10 +01001870 mbedtls_mpi_free(&TA); mbedtls_mpi_free(&TB);
Paul Bakker5121ce52009-01-03 21:22:43 +00001871
Gilles Peskine449bd832023-01-11 14:50:10 +01001872 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001873}
1874
Paul Bakker33dc46b2014-04-30 16:11:39 +02001875/*
1876 * Fill X with size bytes of random.
Gilles Peskine22cdd0c2022-10-27 20:15:13 +02001877 * The bytes returned from the RNG are used in a specific order which
1878 * is suitable for deterministic ECDSA (see the specification of
1879 * mbedtls_mpi_random() and the implementation in mbedtls_mpi_fill_random()).
Paul Bakker33dc46b2014-04-30 16:11:39 +02001880 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001881int mbedtls_mpi_fill_random(mbedtls_mpi *X, size_t size,
1882 int (*f_rng)(void *, unsigned char *, size_t),
1883 void *p_rng)
Paul Bakker287781a2011-03-26 13:18:49 +00001884{
Janos Follath24eed8d2019-11-22 13:21:35 +00001885 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Gilles Peskine449bd832023-01-11 14:50:10 +01001886 const size_t limbs = CHARS_TO_LIMBS(size);
Hanno Beckerda1655a2017-10-18 14:21:44 +01001887
Hanno Beckerda1655a2017-10-18 14:21:44 +01001888 /* Ensure that target MPI has exactly the necessary number of limbs */
Gilles Peskine449bd832023-01-11 14:50:10 +01001889 MBEDTLS_MPI_CHK(mbedtls_mpi_resize_clear(X, limbs));
1890 if (size == 0) {
1891 return 0;
1892 }
Paul Bakker287781a2011-03-26 13:18:49 +00001893
Gilles Peskine449bd832023-01-11 14:50:10 +01001894 ret = mbedtls_mpi_core_fill_random(X->p, X->n, size, f_rng, p_rng);
Paul Bakker287781a2011-03-26 13:18:49 +00001895
1896cleanup:
Gilles Peskine449bd832023-01-11 14:50:10 +01001897 return ret;
Paul Bakker287781a2011-03-26 13:18:49 +00001898}
1899
Gilles Peskine449bd832023-01-11 14:50:10 +01001900int mbedtls_mpi_random(mbedtls_mpi *X,
1901 mbedtls_mpi_sint min,
1902 const mbedtls_mpi *N,
1903 int (*f_rng)(void *, unsigned char *, size_t),
1904 void *p_rng)
Gilles Peskine02ac93a2021-03-29 22:02:55 +02001905{
Gilles Peskine449bd832023-01-11 14:50:10 +01001906 if (min < 0) {
1907 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
1908 }
1909 if (mbedtls_mpi_cmp_int(N, min) <= 0) {
1910 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
1911 }
Gilles Peskine1e918f42021-03-29 22:14:51 +02001912
Gilles Peskine1a7df4e2021-04-01 15:57:18 +02001913 /* Ensure that target MPI has exactly the same number of limbs
1914 * as the upper bound, even if the upper bound has leading zeros.
Gilles Peskine6b7ce962022-12-15 15:04:33 +01001915 * This is necessary for mbedtls_mpi_core_random. */
Gilles Peskine449bd832023-01-11 14:50:10 +01001916 int ret = mbedtls_mpi_resize_clear(X, N->n);
1917 if (ret != 0) {
1918 return ret;
1919 }
Gilles Peskine1a7df4e2021-04-01 15:57:18 +02001920
Gilles Peskine449bd832023-01-11 14:50:10 +01001921 return mbedtls_mpi_core_random(X->p, min, N->p, X->n, f_rng, p_rng);
Gilles Peskine02ac93a2021-03-29 22:02:55 +02001922}
1923
Paul Bakker5121ce52009-01-03 21:22:43 +00001924/*
Manuel Pégourié-Gonnardcdfd1c92025-08-08 09:21:23 +02001925 * Modular inverse: X = A^-1 mod N with N odd (and A any range)
1926 */
1927static int mbedtls_mpi_inv_mod_odd(mbedtls_mpi *X,
1928 const mbedtls_mpi *A,
1929 const mbedtls_mpi *N)
1930{
1931 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
1932 mbedtls_mpi T, G;
1933
1934 mbedtls_mpi_init(&T);
1935 mbedtls_mpi_init(&G);
1936
1937 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&T, A, N));
1938 MBEDTLS_MPI_CHK(mbedtls_mpi_gcd_modinv_odd(&G, &T, &T, N));
1939 if (mbedtls_mpi_cmp_int(&G, 1) != 0) {
1940 ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
1941 goto cleanup;
1942 }
1943
1944 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(X, &T));
1945
1946cleanup:
1947 mbedtls_mpi_free(&T);
1948 mbedtls_mpi_free(&G);
1949
1950 return ret;
1951}
1952
1953/*
Manuel Pégourié-Gonnarde41709c2025-08-08 09:23:43 +02001954 * Compute X = A^-1 mod N with N even, A odd and 1 < A < N.
1955 *
1956 * This is not obvious because our constant-time modinv function only works with
1957 * an odd modulus, and here the modulus is even. The idea is that computing a
1958 * a^-1 mod b is really just computing the u coefficient in the Bézout relation
Manuel Pégourié-Gonnard7a5447f2025-08-12 09:18:28 +02001959 * a*u + b*v = 1 (assuming gcd(a,b) = 1, i.e. the inverse exists). But if we know
Manuel Pégourié-Gonnarde41709c2025-08-08 09:23:43 +02001960 * one of u, v in this relation then the other is easy to find. So we can
1961 * actually start by computing N^-1 mod A with gives us "the wrong half" of the
1962 * Bézout relation, from which we'll deduce the interesting half A^-1 mod N.
1963 *
1964 * Return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE if the inverse doesn't exist.
1965 */
1966static int mbedtls_mpi_inv_mod_even_in_range(mbedtls_mpi *X,
1967 mbedtls_mpi const *A,
1968 mbedtls_mpi const *N)
1969{
Manuel Pégourié-Gonnarda08faf92025-08-12 09:24:15 +02001970 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnarde41709c2025-08-08 09:23:43 +02001971 mbedtls_mpi I, G;
1972
1973 mbedtls_mpi_init(&I);
1974 mbedtls_mpi_init(&G);
1975
1976 /* Set I = N^-1 mod A */
1977 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&I, N, A));
1978 MBEDTLS_MPI_CHK(mbedtls_mpi_gcd_modinv_odd(&G, &I, &I, A));
1979 if (mbedtls_mpi_cmp_int(&G, 1) != 0) {
1980 ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
1981 goto cleanup;
1982 }
1983
1984 /* We know N * I = 1 + k * A for some k, which we can easily compute
1985 * as k = (N*I - 1) / A (we know there will be no remainder). */
1986 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&I, &I, N));
1987 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(&I, &I, 1));
1988 MBEDTLS_MPI_CHK(mbedtls_mpi_div_mpi(&G, NULL, &I, A));
1989
1990 /* Now we have a Bézout relation N * (previous value of I) - G * A = 1,
1991 * so A^-1 mod N is -G mod N, which is N - G.
1992 * Note that 0 < k < N since 0 < I < A, so G (k) is already in range. */
1993 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(X, N, &G));
1994
1995cleanup:
1996 mbedtls_mpi_free(&I);
1997 mbedtls_mpi_free(&G);
1998 return ret;
1999}
2000
2001/*
Manuel Pégourié-Gonnard1ac0a1e2025-08-08 09:25:28 +02002002 * Compute X = A^-1 mod N with N even and A odd (but in any range).
2003 *
2004 * Return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE if the inverse doesn't exist.
2005 */
2006static int mbedtls_mpi_inv_mod_even(mbedtls_mpi *X,
2007 mbedtls_mpi const *A,
2008 mbedtls_mpi const *N)
2009{
Manuel Pégourié-Gonnarda08faf92025-08-12 09:24:15 +02002010 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard1ac0a1e2025-08-08 09:25:28 +02002011 mbedtls_mpi AA;
2012
2013 mbedtls_mpi_init(&AA);
2014
2015 /* Bring A in the range [0, N). */
2016 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&AA, A, N));
2017
Manuel Pégourié-Gonnard7a5447f2025-08-12 09:18:28 +02002018 /* We know A >= 0 but the next function wants A > 1 */
Manuel Pégourié-Gonnard1ac0a1e2025-08-08 09:25:28 +02002019 int cmp = mbedtls_mpi_cmp_int(&AA, 1);
2020 if (cmp < 0) { // AA == 0
2021 ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2022 goto cleanup;
2023 }
2024 if (cmp == 0) { // AA = 1
2025 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(X, 1));
2026 goto cleanup;
2027 }
2028
2029 /* Now we know 1 < A < N, N is even and AA is still odd */
2030 MBEDTLS_MPI_CHK(mbedtls_mpi_inv_mod_even_in_range(X, &AA, N));
2031
2032cleanup:
2033 mbedtls_mpi_free(&AA);
2034 return ret;
2035}
2036
2037/*
Manuel Pégourié-Gonnard40dfc812025-08-08 09:27:29 +02002038 * Modular inverse: X = A^-1 mod N
2039 *
2040 * Wrapper around mbedtls_mpi_gcd_modinv_odd() that lifts its limitations.
Paul Bakker5121ce52009-01-03 21:22:43 +00002041 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002042int mbedtls_mpi_inv_mod(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *N)
Paul Bakker5121ce52009-01-03 21:22:43 +00002043{
Gilles Peskine449bd832023-01-11 14:50:10 +01002044 if (mbedtls_mpi_cmp_int(N, 1) <= 0) {
2045 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
2046 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002047
Manuel Pégourié-Gonnardcdfd1c92025-08-08 09:21:23 +02002048 if (mbedtls_mpi_get_bit(N, 0) == 1) {
2049 return mbedtls_mpi_inv_mod_odd(X, A, N);
2050 }
2051
Manuel Pégourié-Gonnard1ac0a1e2025-08-08 09:25:28 +02002052 if (mbedtls_mpi_get_bit(A, 0) == 1) {
2053 return mbedtls_mpi_inv_mod_even(X, A, N);
Manuel Pégourié-Gonnarde41709c2025-08-08 09:23:43 +02002054 }
2055
Manuel Pégourié-Gonnard7a5447f2025-08-12 09:18:28 +02002056 /* If A and N are both even, 2 divides their GCD, so no inverse. */
Manuel Pégourié-Gonnard40dfc812025-08-08 09:27:29 +02002057 return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
Paul Bakker5121ce52009-01-03 21:22:43 +00002058}
2059
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002060#if defined(MBEDTLS_GENPRIME)
Paul Bakkerd9374b02012-11-02 11:02:58 +00002061
Gilles Peskineb2bc1712019-02-08 17:27:11 +01002062/* Gaps between primes, starting at 3. https://oeis.org/A001223 */
2063static const unsigned char small_prime_gaps[] = {
2064 2, 2, 4, 2, 4, 2, 4, 6,
2065 2, 6, 4, 2, 4, 6, 6, 2,
2066 6, 4, 2, 6, 4, 6, 8, 4,
2067 2, 4, 2, 4, 14, 4, 6, 2,
2068 10, 2, 6, 6, 4, 6, 6, 2,
2069 10, 2, 4, 2, 12, 12, 4, 2,
2070 4, 6, 2, 10, 6, 6, 6, 2,
2071 6, 4, 2, 10, 14, 4, 2, 4,
2072 14, 6, 10, 2, 4, 6, 8, 6,
2073 6, 4, 6, 8, 4, 8, 10, 2,
2074 10, 2, 6, 4, 6, 8, 4, 2,
2075 4, 12, 8, 4, 8, 4, 6, 12,
2076 2, 18, 6, 10, 6, 6, 2, 6,
2077 10, 6, 6, 2, 6, 6, 4, 2,
2078 12, 10, 2, 4, 6, 6, 2, 12,
2079 4, 6, 8, 10, 8, 10, 8, 6,
2080 6, 4, 8, 6, 4, 8, 4, 14,
2081 10, 12, 2, 10, 2, 4, 2, 10,
2082 14, 4, 2, 4, 14, 4, 2, 4,
2083 20, 4, 8, 10, 8, 4, 6, 6,
2084 14, 4, 6, 6, 8, 6, /*reaches 997*/
Gilles Peskine30b03782023-08-22 11:06:47 +02002085 0 /* the last entry is effectively unused */
Paul Bakker5121ce52009-01-03 21:22:43 +00002086};
2087
2088/*
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002089 * Small divisors test (X must be positive)
2090 *
2091 * Return values:
2092 * 0: no small factor (possible prime, more tests needed)
2093 * 1: certain prime
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002094 * MBEDTLS_ERR_MPI_NOT_ACCEPTABLE: certain non-prime
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002095 * other negative: error
Paul Bakker5121ce52009-01-03 21:22:43 +00002096 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002097static int mpi_check_small_factors(const mbedtls_mpi *X)
Paul Bakker5121ce52009-01-03 21:22:43 +00002098{
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002099 int ret = 0;
2100 size_t i;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002101 mbedtls_mpi_uint r;
Gilles Peskineb2bc1712019-02-08 17:27:11 +01002102 unsigned p = 3; /* The first odd prime */
Paul Bakker5121ce52009-01-03 21:22:43 +00002103
Gilles Peskine449bd832023-01-11 14:50:10 +01002104 if ((X->p[0] & 1) == 0) {
2105 return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2106 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002107
Gilles Peskineb2bc1712019-02-08 17:27:11 +01002108 for (i = 0; i < sizeof(small_prime_gaps); p += small_prime_gaps[i], i++) {
2109 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_int(&r, X, p));
Gilles Peskine449bd832023-01-11 14:50:10 +01002110 if (r == 0) {
Gilles Peskineb2bc1712019-02-08 17:27:11 +01002111 if (mbedtls_mpi_cmp_int(X, p) == 0) {
2112 return 1;
2113 } else {
2114 return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2115 }
Gilles Peskine449bd832023-01-11 14:50:10 +01002116 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002117 }
2118
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002119cleanup:
Gilles Peskine449bd832023-01-11 14:50:10 +01002120 return ret;
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002121}
2122
2123/*
2124 * Miller-Rabin pseudo-primality test (HAC 4.24)
2125 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002126static int mpi_miller_rabin(const mbedtls_mpi *X, size_t rounds,
2127 int (*f_rng)(void *, unsigned char *, size_t),
2128 void *p_rng)
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002129{
Pascal Junodb99183d2015-03-11 16:49:45 +01002130 int ret, count;
Janos Follathda31fa12018-09-03 14:45:23 +01002131 size_t i, j, k, s;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002132 mbedtls_mpi W, R, T, A, RR;
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002133
Gilles Peskine449bd832023-01-11 14:50:10 +01002134 mbedtls_mpi_init(&W); mbedtls_mpi_init(&R);
2135 mbedtls_mpi_init(&T); mbedtls_mpi_init(&A);
2136 mbedtls_mpi_init(&RR);
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002137
Paul Bakker5121ce52009-01-03 21:22:43 +00002138 /*
2139 * W = |X| - 1
2140 * R = W >> lsb( W )
2141 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002142 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(&W, X, 1));
2143 s = mbedtls_mpi_lsb(&W);
2144 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&R, &W));
2145 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&R, s));
Paul Bakker5121ce52009-01-03 21:22:43 +00002146
Gilles Peskine449bd832023-01-11 14:50:10 +01002147 for (i = 0; i < rounds; i++) {
Paul Bakker5121ce52009-01-03 21:22:43 +00002148 /*
2149 * pick a random A, 1 < A < |X| - 1
2150 */
Pascal Junodb99183d2015-03-11 16:49:45 +01002151 count = 0;
2152 do {
Gilles Peskine449bd832023-01-11 14:50:10 +01002153 MBEDTLS_MPI_CHK(mbedtls_mpi_fill_random(&A, X->n * ciL, f_rng, p_rng));
Pascal Junodb99183d2015-03-11 16:49:45 +01002154
Gilles Peskine449bd832023-01-11 14:50:10 +01002155 j = mbedtls_mpi_bitlen(&A);
2156 k = mbedtls_mpi_bitlen(&W);
Pascal Junodb99183d2015-03-11 16:49:45 +01002157 if (j > k) {
Gilles Peskine449bd832023-01-11 14:50:10 +01002158 A.p[A.n - 1] &= ((mbedtls_mpi_uint) 1 << (k - (A.n - 1) * biL - 1)) - 1;
Pascal Junodb99183d2015-03-11 16:49:45 +01002159 }
2160
2161 if (count++ > 30) {
Jens Wiklanderf08aa3e2019-01-17 13:30:57 +01002162 ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2163 goto cleanup;
Pascal Junodb99183d2015-03-11 16:49:45 +01002164 }
2165
Gilles Peskine449bd832023-01-11 14:50:10 +01002166 } while (mbedtls_mpi_cmp_mpi(&A, &W) >= 0 ||
2167 mbedtls_mpi_cmp_int(&A, 1) <= 0);
Paul Bakker5121ce52009-01-03 21:22:43 +00002168
2169 /*
2170 * A = A^R mod |X|
2171 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002172 MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&A, &A, &R, X, &RR));
Paul Bakker5121ce52009-01-03 21:22:43 +00002173
Gilles Peskine449bd832023-01-11 14:50:10 +01002174 if (mbedtls_mpi_cmp_mpi(&A, &W) == 0 ||
2175 mbedtls_mpi_cmp_int(&A, 1) == 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00002176 continue;
Gilles Peskine449bd832023-01-11 14:50:10 +01002177 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002178
2179 j = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +01002180 while (j < s && mbedtls_mpi_cmp_mpi(&A, &W) != 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00002181 /*
2182 * A = A * A mod |X|
2183 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002184 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&T, &A, &A));
2185 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&A, &T, X));
Paul Bakker5121ce52009-01-03 21:22:43 +00002186
Gilles Peskine449bd832023-01-11 14:50:10 +01002187 if (mbedtls_mpi_cmp_int(&A, 1) == 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00002188 break;
Gilles Peskine449bd832023-01-11 14:50:10 +01002189 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002190
2191 j++;
2192 }
2193
2194 /*
2195 * not prime if A != |X| - 1 or A == 1
2196 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002197 if (mbedtls_mpi_cmp_mpi(&A, &W) != 0 ||
2198 mbedtls_mpi_cmp_int(&A, 1) == 0) {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002199 ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
Paul Bakker5121ce52009-01-03 21:22:43 +00002200 break;
2201 }
2202 }
2203
2204cleanup:
Gilles Peskine449bd832023-01-11 14:50:10 +01002205 mbedtls_mpi_free(&W); mbedtls_mpi_free(&R);
2206 mbedtls_mpi_free(&T); mbedtls_mpi_free(&A);
2207 mbedtls_mpi_free(&RR);
Paul Bakker5121ce52009-01-03 21:22:43 +00002208
Gilles Peskine449bd832023-01-11 14:50:10 +01002209 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00002210}
2211
2212/*
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002213 * Pseudo-primality test: small factors, then Miller-Rabin
2214 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002215int mbedtls_mpi_is_prime_ext(const mbedtls_mpi *X, int rounds,
2216 int (*f_rng)(void *, unsigned char *, size_t),
2217 void *p_rng)
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002218{
Janos Follath24eed8d2019-11-22 13:21:35 +00002219 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002220 mbedtls_mpi XX;
Manuel Pégourié-Gonnard7f4ed672014-10-14 20:56:02 +02002221
2222 XX.s = 1;
2223 XX.n = X->n;
2224 XX.p = X->p;
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002225
Gilles Peskine449bd832023-01-11 14:50:10 +01002226 if (mbedtls_mpi_cmp_int(&XX, 0) == 0 ||
2227 mbedtls_mpi_cmp_int(&XX, 1) == 0) {
2228 return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002229 }
2230
Gilles Peskine449bd832023-01-11 14:50:10 +01002231 if (mbedtls_mpi_cmp_int(&XX, 2) == 0) {
2232 return 0;
2233 }
2234
2235 if ((ret = mpi_check_small_factors(&XX)) != 0) {
2236 if (ret == 1) {
2237 return 0;
2238 }
2239
2240 return ret;
2241 }
2242
2243 return mpi_miller_rabin(&XX, rounds, f_rng, p_rng);
Janos Follathf301d232018-08-14 13:34:01 +01002244}
2245
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002246/*
Paul Bakker5121ce52009-01-03 21:22:43 +00002247 * Prime number generation
Jethro Beekman66689272018-02-14 19:24:10 -08002248 *
Janos Follathf301d232018-08-14 13:34:01 +01002249 * To generate an RSA key in a way recommended by FIPS 186-4, both primes must
2250 * be either 1024 bits or 1536 bits long, and flags must contain
2251 * MBEDTLS_MPI_GEN_PRIME_FLAG_LOW_ERR.
Paul Bakker5121ce52009-01-03 21:22:43 +00002252 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002253int mbedtls_mpi_gen_prime(mbedtls_mpi *X, size_t nbits, int flags,
2254 int (*f_rng)(void *, unsigned char *, size_t),
2255 void *p_rng)
Paul Bakker5121ce52009-01-03 21:22:43 +00002256{
Jethro Beekman66689272018-02-14 19:24:10 -08002257#ifdef MBEDTLS_HAVE_INT64
2258// ceil(2^63.5)
2259#define CEIL_MAXUINT_DIV_SQRT2 0xb504f333f9de6485ULL
2260#else
2261// ceil(2^31.5)
2262#define CEIL_MAXUINT_DIV_SQRT2 0xb504f334U
2263#endif
2264 int ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
Paul Bakker23986e52011-04-24 08:57:21 +00002265 size_t k, n;
Janos Follathda31fa12018-09-03 14:45:23 +01002266 int rounds;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002267 mbedtls_mpi_uint r;
2268 mbedtls_mpi Y;
Paul Bakker5121ce52009-01-03 21:22:43 +00002269
Gilles Peskine449bd832023-01-11 14:50:10 +01002270 if (nbits < 3 || nbits > MBEDTLS_MPI_MAX_BITS) {
2271 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
2272 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002273
Gilles Peskine449bd832023-01-11 14:50:10 +01002274 mbedtls_mpi_init(&Y);
Paul Bakker5121ce52009-01-03 21:22:43 +00002275
Gilles Peskine449bd832023-01-11 14:50:10 +01002276 n = BITS_TO_LIMBS(nbits);
Paul Bakker5121ce52009-01-03 21:22:43 +00002277
Gilles Peskine449bd832023-01-11 14:50:10 +01002278 if ((flags & MBEDTLS_MPI_GEN_PRIME_FLAG_LOW_ERR) == 0) {
Janos Follathda31fa12018-09-03 14:45:23 +01002279 /*
2280 * 2^-80 error probability, number of rounds chosen per HAC, table 4.4
2281 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002282 rounds = ((nbits >= 1300) ? 2 : (nbits >= 850) ? 3 :
2283 (nbits >= 650) ? 4 : (nbits >= 350) ? 8 :
2284 (nbits >= 250) ? 12 : (nbits >= 150) ? 18 : 27);
2285 } else {
Janos Follathda31fa12018-09-03 14:45:23 +01002286 /*
2287 * 2^-100 error probability, number of rounds computed based on HAC,
2288 * fact 4.48
2289 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002290 rounds = ((nbits >= 1450) ? 4 : (nbits >= 1150) ? 5 :
2291 (nbits >= 1000) ? 6 : (nbits >= 850) ? 7 :
2292 (nbits >= 750) ? 8 : (nbits >= 500) ? 13 :
2293 (nbits >= 250) ? 28 : (nbits >= 150) ? 40 : 51);
Janos Follathda31fa12018-09-03 14:45:23 +01002294 }
2295
Gilles Peskine449bd832023-01-11 14:50:10 +01002296 while (1) {
2297 MBEDTLS_MPI_CHK(mbedtls_mpi_fill_random(X, n * ciL, f_rng, p_rng));
Jethro Beekman66689272018-02-14 19:24:10 -08002298 /* 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 +01002299 if (X->p[n-1] < CEIL_MAXUINT_DIV_SQRT2) {
2300 continue;
2301 }
Jethro Beekman66689272018-02-14 19:24:10 -08002302
2303 k = n * biL;
Gilles Peskine449bd832023-01-11 14:50:10 +01002304 if (k > nbits) {
2305 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(X, k - nbits));
2306 }
Jethro Beekman66689272018-02-14 19:24:10 -08002307 X->p[0] |= 1;
2308
Gilles Peskine449bd832023-01-11 14:50:10 +01002309 if ((flags & MBEDTLS_MPI_GEN_PRIME_FLAG_DH) == 0) {
2310 ret = mbedtls_mpi_is_prime_ext(X, rounds, f_rng, p_rng);
Jethro Beekman66689272018-02-14 19:24:10 -08002311
Gilles Peskine449bd832023-01-11 14:50:10 +01002312 if (ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE) {
Paul Bakker5121ce52009-01-03 21:22:43 +00002313 goto cleanup;
Gilles Peskine449bd832023-01-11 14:50:10 +01002314 }
2315 } else {
Manuel Pégourié-Gonnardddf76152013-11-22 19:58:22 +01002316 /*
Tom Cosgrovece7f18c2022-07-28 05:50:56 +01002317 * A necessary condition for Y and X = 2Y + 1 to be prime
Jethro Beekman66689272018-02-14 19:24:10 -08002318 * is X = 2 mod 3 (which is equivalent to Y = 2 mod 3).
2319 * Make sure it is satisfied, while keeping X = 3 mod 4
Manuel Pégourié-Gonnardddf76152013-11-22 19:58:22 +01002320 */
Jethro Beekman66689272018-02-14 19:24:10 -08002321
2322 X->p[0] |= 2;
2323
Gilles Peskine449bd832023-01-11 14:50:10 +01002324 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_int(&r, X, 3));
2325 if (r == 0) {
2326 MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(X, X, 8));
2327 } else if (r == 1) {
2328 MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(X, X, 4));
2329 }
Jethro Beekman66689272018-02-14 19:24:10 -08002330
2331 /* Set Y = (X-1) / 2, which is X / 2 because X is odd */
Gilles Peskine449bd832023-01-11 14:50:10 +01002332 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&Y, X));
2333 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&Y, 1));
Jethro Beekman66689272018-02-14 19:24:10 -08002334
Gilles Peskine449bd832023-01-11 14:50:10 +01002335 while (1) {
Jethro Beekman66689272018-02-14 19:24:10 -08002336 /*
2337 * First, check small factors for X and Y
2338 * before doing Miller-Rabin on any of them
2339 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002340 if ((ret = mpi_check_small_factors(X)) == 0 &&
2341 (ret = mpi_check_small_factors(&Y)) == 0 &&
2342 (ret = mpi_miller_rabin(X, rounds, f_rng, p_rng))
2343 == 0 &&
2344 (ret = mpi_miller_rabin(&Y, rounds, f_rng, p_rng))
2345 == 0) {
Jethro Beekman66689272018-02-14 19:24:10 -08002346 goto cleanup;
Gilles Peskine449bd832023-01-11 14:50:10 +01002347 }
Jethro Beekman66689272018-02-14 19:24:10 -08002348
Gilles Peskine449bd832023-01-11 14:50:10 +01002349 if (ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE) {
Jethro Beekman66689272018-02-14 19:24:10 -08002350 goto cleanup;
Gilles Peskine449bd832023-01-11 14:50:10 +01002351 }
Jethro Beekman66689272018-02-14 19:24:10 -08002352
2353 /*
2354 * Next candidates. We want to preserve Y = (X-1) / 2 and
2355 * Y = 1 mod 2 and Y = 2 mod 3 (eq X = 3 mod 4 and X = 2 mod 3)
2356 * so up Y by 6 and X by 12.
2357 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002358 MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(X, X, 12));
2359 MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(&Y, &Y, 6));
Paul Bakker5121ce52009-01-03 21:22:43 +00002360 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002361 }
2362 }
2363
2364cleanup:
2365
Gilles Peskine449bd832023-01-11 14:50:10 +01002366 mbedtls_mpi_free(&Y);
Paul Bakker5121ce52009-01-03 21:22:43 +00002367
Gilles Peskine449bd832023-01-11 14:50:10 +01002368 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00002369}
2370
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002371#endif /* MBEDTLS_GENPRIME */
Paul Bakker5121ce52009-01-03 21:22:43 +00002372
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002373#if defined(MBEDTLS_SELF_TEST)
Paul Bakker5121ce52009-01-03 21:22:43 +00002374
Paul Bakker23986e52011-04-24 08:57:21 +00002375#define GCD_PAIR_COUNT 3
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002376
2377static const int gcd_pairs[GCD_PAIR_COUNT][3] =
2378{
2379 { 693, 609, 21 },
2380 { 1764, 868, 28 },
2381 { 768454923, 542167814, 1 }
2382};
2383
Paul Bakker5121ce52009-01-03 21:22:43 +00002384/*
2385 * Checkup routine
2386 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002387int mbedtls_mpi_self_test(int verbose)
Paul Bakker5121ce52009-01-03 21:22:43 +00002388{
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002389 int ret, i;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002390 mbedtls_mpi A, E, N, X, Y, U, V;
Paul Bakker5121ce52009-01-03 21:22:43 +00002391
Gilles Peskine449bd832023-01-11 14:50:10 +01002392 mbedtls_mpi_init(&A); mbedtls_mpi_init(&E); mbedtls_mpi_init(&N); mbedtls_mpi_init(&X);
2393 mbedtls_mpi_init(&Y); mbedtls_mpi_init(&U); mbedtls_mpi_init(&V);
Paul Bakker5121ce52009-01-03 21:22:43 +00002394
Gilles Peskine449bd832023-01-11 14:50:10 +01002395 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&A, 16,
2396 "EFE021C2645FD1DC586E69184AF4A31E" \
2397 "D5F53E93B5F123FA41680867BA110131" \
2398 "944FE7952E2517337780CB0DB80E61AA" \
2399 "E7C8DDC6C5C6AADEB34EB38A2F40D5E6"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002400
Gilles Peskine449bd832023-01-11 14:50:10 +01002401 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&E, 16,
2402 "B2E7EFD37075B9F03FF989C7C5051C20" \
2403 "34D2A323810251127E7BF8625A4F49A5" \
2404 "F3E27F4DA8BD59C47D6DAABA4C8127BD" \
2405 "5B5C25763222FEFCCFC38B832366C29E"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002406
Gilles Peskine449bd832023-01-11 14:50:10 +01002407 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&N, 16,
2408 "0066A198186C18C10B2F5ED9B522752A" \
2409 "9830B69916E535C8F047518A889A43A5" \
2410 "94B6BED27A168D31D4A52F88925AA8F5"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002411
Gilles Peskine449bd832023-01-11 14:50:10 +01002412 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&X, &A, &N));
Paul Bakker5121ce52009-01-03 21:22:43 +00002413
Gilles Peskine449bd832023-01-11 14:50:10 +01002414 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&U, 16,
2415 "602AB7ECA597A3D6B56FF9829A5E8B85" \
2416 "9E857EA95A03512E2BAE7391688D264A" \
2417 "A5663B0341DB9CCFD2C4C5F421FEC814" \
2418 "8001B72E848A38CAE1C65F78E56ABDEF" \
2419 "E12D3C039B8A02D6BE593F0BBBDA56F1" \
2420 "ECF677152EF804370C1A305CAF3B5BF1" \
2421 "30879B56C61DE584A0F53A2447A51E"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002422
Gilles Peskine449bd832023-01-11 14:50:10 +01002423 if (verbose != 0) {
2424 mbedtls_printf(" MPI test #1 (mul_mpi): ");
2425 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002426
Gilles Peskine449bd832023-01-11 14:50:10 +01002427 if (mbedtls_mpi_cmp_mpi(&X, &U) != 0) {
2428 if (verbose != 0) {
2429 mbedtls_printf("failed\n");
2430 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002431
Manuel Pégourié-Gonnard9e987ed2014-01-20 10:03:15 +01002432 ret = 1;
2433 goto cleanup;
Paul Bakker5121ce52009-01-03 21:22:43 +00002434 }
2435
Gilles Peskine449bd832023-01-11 14:50:10 +01002436 if (verbose != 0) {
2437 mbedtls_printf("passed\n");
2438 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002439
Gilles Peskine449bd832023-01-11 14:50:10 +01002440 MBEDTLS_MPI_CHK(mbedtls_mpi_div_mpi(&X, &Y, &A, &N));
Paul Bakker5121ce52009-01-03 21:22:43 +00002441
Gilles Peskine449bd832023-01-11 14:50:10 +01002442 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&U, 16,
2443 "256567336059E52CAE22925474705F39A94"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002444
Gilles Peskine449bd832023-01-11 14:50:10 +01002445 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&V, 16,
2446 "6613F26162223DF488E9CD48CC132C7A" \
2447 "0AC93C701B001B092E4E5B9F73BCD27B" \
2448 "9EE50D0657C77F374E903CDFA4C642"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002449
Gilles Peskine449bd832023-01-11 14:50:10 +01002450 if (verbose != 0) {
2451 mbedtls_printf(" MPI test #2 (div_mpi): ");
2452 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002453
Gilles Peskine449bd832023-01-11 14:50:10 +01002454 if (mbedtls_mpi_cmp_mpi(&X, &U) != 0 ||
2455 mbedtls_mpi_cmp_mpi(&Y, &V) != 0) {
2456 if (verbose != 0) {
2457 mbedtls_printf("failed\n");
2458 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002459
Manuel Pégourié-Gonnard9e987ed2014-01-20 10:03:15 +01002460 ret = 1;
2461 goto cleanup;
Paul Bakker5121ce52009-01-03 21:22:43 +00002462 }
2463
Gilles Peskine449bd832023-01-11 14:50:10 +01002464 if (verbose != 0) {
2465 mbedtls_printf("passed\n");
2466 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002467
Gilles Peskine449bd832023-01-11 14:50:10 +01002468 MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&X, &A, &E, &N, NULL));
Paul Bakker5121ce52009-01-03 21:22:43 +00002469
Gilles Peskine449bd832023-01-11 14:50:10 +01002470 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&U, 16,
2471 "36E139AEA55215609D2816998ED020BB" \
2472 "BD96C37890F65171D948E9BC7CBAA4D9" \
2473 "325D24D6A3C12710F10A09FA08AB87"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002474
Gilles Peskine449bd832023-01-11 14:50:10 +01002475 if (verbose != 0) {
2476 mbedtls_printf(" MPI test #3 (exp_mod): ");
2477 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002478
Gilles Peskine449bd832023-01-11 14:50:10 +01002479 if (mbedtls_mpi_cmp_mpi(&X, &U) != 0) {
2480 if (verbose != 0) {
2481 mbedtls_printf("failed\n");
2482 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002483
Manuel Pégourié-Gonnard9e987ed2014-01-20 10:03:15 +01002484 ret = 1;
2485 goto cleanup;
Paul Bakker5121ce52009-01-03 21:22:43 +00002486 }
2487
Gilles Peskine449bd832023-01-11 14:50:10 +01002488 if (verbose != 0) {
2489 mbedtls_printf("passed\n");
2490 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002491
Gilles Peskine449bd832023-01-11 14:50:10 +01002492 MBEDTLS_MPI_CHK(mbedtls_mpi_inv_mod(&X, &A, &N));
Paul Bakker5121ce52009-01-03 21:22:43 +00002493
Gilles Peskine449bd832023-01-11 14:50:10 +01002494 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&U, 16,
2495 "003A0AAEDD7E784FC07D8F9EC6E3BFD5" \
2496 "C3DBA76456363A10869622EAC2DD84EC" \
2497 "C5B8A74DAC4D09E03B5E0BE779F2DF61"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002498
Gilles Peskine449bd832023-01-11 14:50:10 +01002499 if (verbose != 0) {
2500 mbedtls_printf(" MPI test #4 (inv_mod): ");
2501 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002502
Gilles Peskine449bd832023-01-11 14:50:10 +01002503 if (mbedtls_mpi_cmp_mpi(&X, &U) != 0) {
2504 if (verbose != 0) {
2505 mbedtls_printf("failed\n");
2506 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002507
Manuel Pégourié-Gonnard9e987ed2014-01-20 10:03:15 +01002508 ret = 1;
2509 goto cleanup;
Paul Bakker5121ce52009-01-03 21:22:43 +00002510 }
2511
Gilles Peskine449bd832023-01-11 14:50:10 +01002512 if (verbose != 0) {
2513 mbedtls_printf("passed\n");
2514 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002515
Gilles Peskine449bd832023-01-11 14:50:10 +01002516 if (verbose != 0) {
2517 mbedtls_printf(" MPI test #5 (simple gcd): ");
2518 }
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002519
Gilles Peskine449bd832023-01-11 14:50:10 +01002520 for (i = 0; i < GCD_PAIR_COUNT; i++) {
2521 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&X, gcd_pairs[i][0]));
2522 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&Y, gcd_pairs[i][1]));
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002523
Gilles Peskine449bd832023-01-11 14:50:10 +01002524 MBEDTLS_MPI_CHK(mbedtls_mpi_gcd(&A, &X, &Y));
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002525
Gilles Peskine449bd832023-01-11 14:50:10 +01002526 if (mbedtls_mpi_cmp_int(&A, gcd_pairs[i][2]) != 0) {
2527 if (verbose != 0) {
2528 mbedtls_printf("failed at %d\n", i);
2529 }
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002530
Manuel Pégourié-Gonnard9e987ed2014-01-20 10:03:15 +01002531 ret = 1;
2532 goto cleanup;
2533 }
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002534 }
2535
Gilles Peskine449bd832023-01-11 14:50:10 +01002536 if (verbose != 0) {
2537 mbedtls_printf("passed\n");
2538 }
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002539
Paul Bakker5121ce52009-01-03 21:22:43 +00002540cleanup:
2541
Gilles Peskine449bd832023-01-11 14:50:10 +01002542 if (ret != 0 && verbose != 0) {
2543 mbedtls_printf("Unexpected error, return code = %08X\n", (unsigned int) ret);
2544 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002545
Gilles Peskine449bd832023-01-11 14:50:10 +01002546 mbedtls_mpi_free(&A); mbedtls_mpi_free(&E); mbedtls_mpi_free(&N); mbedtls_mpi_free(&X);
2547 mbedtls_mpi_free(&Y); mbedtls_mpi_free(&U); mbedtls_mpi_free(&V);
Paul Bakker5121ce52009-01-03 21:22:43 +00002548
Gilles Peskine449bd832023-01-11 14:50:10 +01002549 if (verbose != 0) {
2550 mbedtls_printf("\n");
2551 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002552
Gilles Peskine449bd832023-01-11 14:50:10 +01002553 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00002554}
2555
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002556#endif /* MBEDTLS_SELF_TEST */
Paul Bakker5121ce52009-01-03 21:22:43 +00002557
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002558#endif /* MBEDTLS_BIGNUM_C */