blob: 358714839c7edee8a8edf34cee5a91ad6f315588 [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;
1836
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
Gilles Peskine2a63c5b2021-06-16 13:42:04 +02001841
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)
1849 goto cleanup;
Manuel Pégourié-Gonnard381d4ba2025-08-04 10:57:13 +02001850 }
1851
Manuel Pégourié-Gonnardc6a9d842025-07-10 23:28:50 +02001852 const size_t za = mbedtls_mpi_lsb(&TA);
1853 const size_t zb = mbedtls_mpi_lsb(&TB);
1854
1855 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TA, za));
1856 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TB, zb));
1857
1858 /* 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);
1861
1862 MBEDTLS_MPI_CHK(mbedtls_mpi_gcd_modinv_odd(G, NULL, &TA, &TB));
1863
1864 size_t zg = za > zb ? zb : za; // zg = min(za, zb)
1865 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(G, zg));
Paul Bakker5121ce52009-01-03 21:22:43 +00001866
1867cleanup:
1868
Gilles Peskine449bd832023-01-11 14:50:10 +01001869 mbedtls_mpi_free(&TA); mbedtls_mpi_free(&TB);
Paul Bakker5121ce52009-01-03 21:22:43 +00001870
Gilles Peskine449bd832023-01-11 14:50:10 +01001871 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001872}
1873
Paul Bakker33dc46b2014-04-30 16:11:39 +02001874/*
1875 * Fill X with size bytes of random.
Gilles Peskine22cdd0c2022-10-27 20:15:13 +02001876 * The bytes returned from the RNG are used in a specific order which
1877 * is suitable for deterministic ECDSA (see the specification of
1878 * mbedtls_mpi_random() and the implementation in mbedtls_mpi_fill_random()).
Paul Bakker33dc46b2014-04-30 16:11:39 +02001879 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001880int mbedtls_mpi_fill_random(mbedtls_mpi *X, size_t size,
1881 int (*f_rng)(void *, unsigned char *, size_t),
1882 void *p_rng)
Paul Bakker287781a2011-03-26 13:18:49 +00001883{
Janos Follath24eed8d2019-11-22 13:21:35 +00001884 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Gilles Peskine449bd832023-01-11 14:50:10 +01001885 const size_t limbs = CHARS_TO_LIMBS(size);
Hanno Beckerda1655a2017-10-18 14:21:44 +01001886
Hanno Beckerda1655a2017-10-18 14:21:44 +01001887 /* Ensure that target MPI has exactly the necessary number of limbs */
Gilles Peskine449bd832023-01-11 14:50:10 +01001888 MBEDTLS_MPI_CHK(mbedtls_mpi_resize_clear(X, limbs));
1889 if (size == 0) {
1890 return 0;
1891 }
Paul Bakker287781a2011-03-26 13:18:49 +00001892
Gilles Peskine449bd832023-01-11 14:50:10 +01001893 ret = mbedtls_mpi_core_fill_random(X->p, X->n, size, f_rng, p_rng);
Paul Bakker287781a2011-03-26 13:18:49 +00001894
1895cleanup:
Gilles Peskine449bd832023-01-11 14:50:10 +01001896 return ret;
Paul Bakker287781a2011-03-26 13:18:49 +00001897}
1898
Gilles Peskine449bd832023-01-11 14:50:10 +01001899int mbedtls_mpi_random(mbedtls_mpi *X,
1900 mbedtls_mpi_sint min,
1901 const mbedtls_mpi *N,
1902 int (*f_rng)(void *, unsigned char *, size_t),
1903 void *p_rng)
Gilles Peskine02ac93a2021-03-29 22:02:55 +02001904{
Gilles Peskine449bd832023-01-11 14:50:10 +01001905 if (min < 0) {
1906 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
1907 }
1908 if (mbedtls_mpi_cmp_int(N, min) <= 0) {
1909 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
1910 }
Gilles Peskine1e918f42021-03-29 22:14:51 +02001911
Gilles Peskine1a7df4e2021-04-01 15:57:18 +02001912 /* Ensure that target MPI has exactly the same number of limbs
1913 * as the upper bound, even if the upper bound has leading zeros.
Gilles Peskine6b7ce962022-12-15 15:04:33 +01001914 * This is necessary for mbedtls_mpi_core_random. */
Gilles Peskine449bd832023-01-11 14:50:10 +01001915 int ret = mbedtls_mpi_resize_clear(X, N->n);
1916 if (ret != 0) {
1917 return ret;
1918 }
Gilles Peskine1a7df4e2021-04-01 15:57:18 +02001919
Gilles Peskine449bd832023-01-11 14:50:10 +01001920 return mbedtls_mpi_core_random(X->p, min, N->p, X->n, f_rng, p_rng);
Gilles Peskine02ac93a2021-03-29 22:02:55 +02001921}
1922
Paul Bakker5121ce52009-01-03 21:22:43 +00001923/*
1924 * Modular inverse: X = A^-1 mod N (HAC 14.61 / 14.64)
1925 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001926int mbedtls_mpi_inv_mod(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *N)
Paul Bakker5121ce52009-01-03 21:22:43 +00001927{
Janos Follath24eed8d2019-11-22 13:21:35 +00001928 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001929 mbedtls_mpi G, TA, TU, U1, U2, TB, TV, V1, V2;
Paul Bakker5121ce52009-01-03 21:22:43 +00001930
Gilles Peskine449bd832023-01-11 14:50:10 +01001931 if (mbedtls_mpi_cmp_int(N, 1) <= 0) {
1932 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
1933 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001934
Gilles Peskine449bd832023-01-11 14:50:10 +01001935 mbedtls_mpi_init(&TA); mbedtls_mpi_init(&TU); mbedtls_mpi_init(&U1); mbedtls_mpi_init(&U2);
1936 mbedtls_mpi_init(&G); mbedtls_mpi_init(&TB); mbedtls_mpi_init(&TV);
1937 mbedtls_mpi_init(&V1); mbedtls_mpi_init(&V2);
Paul Bakker5121ce52009-01-03 21:22:43 +00001938
Gilles Peskine449bd832023-01-11 14:50:10 +01001939 MBEDTLS_MPI_CHK(mbedtls_mpi_gcd(&G, A, N));
Paul Bakker5121ce52009-01-03 21:22:43 +00001940
Gilles Peskine449bd832023-01-11 14:50:10 +01001941 if (mbedtls_mpi_cmp_int(&G, 1) != 0) {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001942 ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
Paul Bakker5121ce52009-01-03 21:22:43 +00001943 goto cleanup;
1944 }
1945
Gilles Peskine449bd832023-01-11 14:50:10 +01001946 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&TA, A, N));
1947 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TU, &TA));
1948 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TB, N));
1949 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TV, N));
Paul Bakker5121ce52009-01-03 21:22:43 +00001950
Gilles Peskine449bd832023-01-11 14:50:10 +01001951 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&U1, 1));
1952 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&U2, 0));
1953 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&V1, 0));
1954 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&V2, 1));
Paul Bakker5121ce52009-01-03 21:22:43 +00001955
Gilles Peskine449bd832023-01-11 14:50:10 +01001956 do {
1957 while ((TU.p[0] & 1) == 0) {
1958 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TU, 1));
Paul Bakker5121ce52009-01-03 21:22:43 +00001959
Gilles Peskine449bd832023-01-11 14:50:10 +01001960 if ((U1.p[0] & 1) != 0 || (U2.p[0] & 1) != 0) {
1961 MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&U1, &U1, &TB));
1962 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&U2, &U2, &TA));
Paul Bakker5121ce52009-01-03 21:22:43 +00001963 }
1964
Gilles Peskine449bd832023-01-11 14:50:10 +01001965 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&U1, 1));
1966 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&U2, 1));
Paul Bakker5121ce52009-01-03 21:22:43 +00001967 }
1968
Gilles Peskine449bd832023-01-11 14:50:10 +01001969 while ((TV.p[0] & 1) == 0) {
1970 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TV, 1));
Paul Bakker5121ce52009-01-03 21:22:43 +00001971
Gilles Peskine449bd832023-01-11 14:50:10 +01001972 if ((V1.p[0] & 1) != 0 || (V2.p[0] & 1) != 0) {
1973 MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&V1, &V1, &TB));
1974 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&V2, &V2, &TA));
Paul Bakker5121ce52009-01-03 21:22:43 +00001975 }
1976
Gilles Peskine449bd832023-01-11 14:50:10 +01001977 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&V1, 1));
1978 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&V2, 1));
Paul Bakker5121ce52009-01-03 21:22:43 +00001979 }
1980
Gilles Peskine449bd832023-01-11 14:50:10 +01001981 if (mbedtls_mpi_cmp_mpi(&TU, &TV) >= 0) {
1982 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&TU, &TU, &TV));
1983 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&U1, &U1, &V1));
1984 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&U2, &U2, &V2));
1985 } else {
1986 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&TV, &TV, &TU));
1987 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&V1, &V1, &U1));
1988 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&V2, &V2, &U2));
Paul Bakker5121ce52009-01-03 21:22:43 +00001989 }
Gilles Peskine449bd832023-01-11 14:50:10 +01001990 } while (mbedtls_mpi_cmp_int(&TU, 0) != 0);
1991
1992 while (mbedtls_mpi_cmp_int(&V1, 0) < 0) {
1993 MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&V1, &V1, N));
Paul Bakker5121ce52009-01-03 21:22:43 +00001994 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001995
Gilles Peskine449bd832023-01-11 14:50:10 +01001996 while (mbedtls_mpi_cmp_mpi(&V1, N) >= 0) {
1997 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&V1, &V1, N));
1998 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001999
Gilles Peskine449bd832023-01-11 14:50:10 +01002000 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(X, &V1));
Paul Bakker5121ce52009-01-03 21:22:43 +00002001
2002cleanup:
2003
Gilles Peskine449bd832023-01-11 14:50:10 +01002004 mbedtls_mpi_free(&TA); mbedtls_mpi_free(&TU); mbedtls_mpi_free(&U1); mbedtls_mpi_free(&U2);
2005 mbedtls_mpi_free(&G); mbedtls_mpi_free(&TB); mbedtls_mpi_free(&TV);
2006 mbedtls_mpi_free(&V1); mbedtls_mpi_free(&V2);
Paul Bakker5121ce52009-01-03 21:22:43 +00002007
Gilles Peskine449bd832023-01-11 14:50:10 +01002008 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00002009}
2010
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002011#if defined(MBEDTLS_GENPRIME)
Paul Bakkerd9374b02012-11-02 11:02:58 +00002012
Gilles Peskineb2bc1712019-02-08 17:27:11 +01002013/* Gaps between primes, starting at 3. https://oeis.org/A001223 */
2014static const unsigned char small_prime_gaps[] = {
2015 2, 2, 4, 2, 4, 2, 4, 6,
2016 2, 6, 4, 2, 4, 6, 6, 2,
2017 6, 4, 2, 6, 4, 6, 8, 4,
2018 2, 4, 2, 4, 14, 4, 6, 2,
2019 10, 2, 6, 6, 4, 6, 6, 2,
2020 10, 2, 4, 2, 12, 12, 4, 2,
2021 4, 6, 2, 10, 6, 6, 6, 2,
2022 6, 4, 2, 10, 14, 4, 2, 4,
2023 14, 6, 10, 2, 4, 6, 8, 6,
2024 6, 4, 6, 8, 4, 8, 10, 2,
2025 10, 2, 6, 4, 6, 8, 4, 2,
2026 4, 12, 8, 4, 8, 4, 6, 12,
2027 2, 18, 6, 10, 6, 6, 2, 6,
2028 10, 6, 6, 2, 6, 6, 4, 2,
2029 12, 10, 2, 4, 6, 6, 2, 12,
2030 4, 6, 8, 10, 8, 10, 8, 6,
2031 6, 4, 8, 6, 4, 8, 4, 14,
2032 10, 12, 2, 10, 2, 4, 2, 10,
2033 14, 4, 2, 4, 14, 4, 2, 4,
2034 20, 4, 8, 10, 8, 4, 6, 6,
2035 14, 4, 6, 6, 8, 6, /*reaches 997*/
Gilles Peskine30b03782023-08-22 11:06:47 +02002036 0 /* the last entry is effectively unused */
Paul Bakker5121ce52009-01-03 21:22:43 +00002037};
2038
2039/*
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002040 * Small divisors test (X must be positive)
2041 *
2042 * Return values:
2043 * 0: no small factor (possible prime, more tests needed)
2044 * 1: certain prime
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002045 * MBEDTLS_ERR_MPI_NOT_ACCEPTABLE: certain non-prime
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002046 * other negative: error
Paul Bakker5121ce52009-01-03 21:22:43 +00002047 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002048static int mpi_check_small_factors(const mbedtls_mpi *X)
Paul Bakker5121ce52009-01-03 21:22:43 +00002049{
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002050 int ret = 0;
2051 size_t i;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002052 mbedtls_mpi_uint r;
Gilles Peskineb2bc1712019-02-08 17:27:11 +01002053 unsigned p = 3; /* The first odd prime */
Paul Bakker5121ce52009-01-03 21:22:43 +00002054
Gilles Peskine449bd832023-01-11 14:50:10 +01002055 if ((X->p[0] & 1) == 0) {
2056 return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2057 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002058
Gilles Peskineb2bc1712019-02-08 17:27:11 +01002059 for (i = 0; i < sizeof(small_prime_gaps); p += small_prime_gaps[i], i++) {
2060 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_int(&r, X, p));
Gilles Peskine449bd832023-01-11 14:50:10 +01002061 if (r == 0) {
Gilles Peskineb2bc1712019-02-08 17:27:11 +01002062 if (mbedtls_mpi_cmp_int(X, p) == 0) {
2063 return 1;
2064 } else {
2065 return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2066 }
Gilles Peskine449bd832023-01-11 14:50:10 +01002067 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002068 }
2069
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002070cleanup:
Gilles Peskine449bd832023-01-11 14:50:10 +01002071 return ret;
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002072}
2073
2074/*
2075 * Miller-Rabin pseudo-primality test (HAC 4.24)
2076 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002077static int mpi_miller_rabin(const mbedtls_mpi *X, size_t rounds,
2078 int (*f_rng)(void *, unsigned char *, size_t),
2079 void *p_rng)
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002080{
Pascal Junodb99183d2015-03-11 16:49:45 +01002081 int ret, count;
Janos Follathda31fa12018-09-03 14:45:23 +01002082 size_t i, j, k, s;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002083 mbedtls_mpi W, R, T, A, RR;
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002084
Gilles Peskine449bd832023-01-11 14:50:10 +01002085 mbedtls_mpi_init(&W); mbedtls_mpi_init(&R);
2086 mbedtls_mpi_init(&T); mbedtls_mpi_init(&A);
2087 mbedtls_mpi_init(&RR);
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002088
Paul Bakker5121ce52009-01-03 21:22:43 +00002089 /*
2090 * W = |X| - 1
2091 * R = W >> lsb( W )
2092 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002093 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(&W, X, 1));
2094 s = mbedtls_mpi_lsb(&W);
2095 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&R, &W));
2096 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&R, s));
Paul Bakker5121ce52009-01-03 21:22:43 +00002097
Gilles Peskine449bd832023-01-11 14:50:10 +01002098 for (i = 0; i < rounds; i++) {
Paul Bakker5121ce52009-01-03 21:22:43 +00002099 /*
2100 * pick a random A, 1 < A < |X| - 1
2101 */
Pascal Junodb99183d2015-03-11 16:49:45 +01002102 count = 0;
2103 do {
Gilles Peskine449bd832023-01-11 14:50:10 +01002104 MBEDTLS_MPI_CHK(mbedtls_mpi_fill_random(&A, X->n * ciL, f_rng, p_rng));
Pascal Junodb99183d2015-03-11 16:49:45 +01002105
Gilles Peskine449bd832023-01-11 14:50:10 +01002106 j = mbedtls_mpi_bitlen(&A);
2107 k = mbedtls_mpi_bitlen(&W);
Pascal Junodb99183d2015-03-11 16:49:45 +01002108 if (j > k) {
Gilles Peskine449bd832023-01-11 14:50:10 +01002109 A.p[A.n - 1] &= ((mbedtls_mpi_uint) 1 << (k - (A.n - 1) * biL - 1)) - 1;
Pascal Junodb99183d2015-03-11 16:49:45 +01002110 }
2111
2112 if (count++ > 30) {
Jens Wiklanderf08aa3e2019-01-17 13:30:57 +01002113 ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2114 goto cleanup;
Pascal Junodb99183d2015-03-11 16:49:45 +01002115 }
2116
Gilles Peskine449bd832023-01-11 14:50:10 +01002117 } while (mbedtls_mpi_cmp_mpi(&A, &W) >= 0 ||
2118 mbedtls_mpi_cmp_int(&A, 1) <= 0);
Paul Bakker5121ce52009-01-03 21:22:43 +00002119
2120 /*
2121 * A = A^R mod |X|
2122 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002123 MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&A, &A, &R, X, &RR));
Paul Bakker5121ce52009-01-03 21:22:43 +00002124
Gilles Peskine449bd832023-01-11 14:50:10 +01002125 if (mbedtls_mpi_cmp_mpi(&A, &W) == 0 ||
2126 mbedtls_mpi_cmp_int(&A, 1) == 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00002127 continue;
Gilles Peskine449bd832023-01-11 14:50:10 +01002128 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002129
2130 j = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +01002131 while (j < s && mbedtls_mpi_cmp_mpi(&A, &W) != 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00002132 /*
2133 * A = A * A mod |X|
2134 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002135 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&T, &A, &A));
2136 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&A, &T, X));
Paul Bakker5121ce52009-01-03 21:22:43 +00002137
Gilles Peskine449bd832023-01-11 14:50:10 +01002138 if (mbedtls_mpi_cmp_int(&A, 1) == 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00002139 break;
Gilles Peskine449bd832023-01-11 14:50:10 +01002140 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002141
2142 j++;
2143 }
2144
2145 /*
2146 * not prime if A != |X| - 1 or A == 1
2147 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002148 if (mbedtls_mpi_cmp_mpi(&A, &W) != 0 ||
2149 mbedtls_mpi_cmp_int(&A, 1) == 0) {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002150 ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
Paul Bakker5121ce52009-01-03 21:22:43 +00002151 break;
2152 }
2153 }
2154
2155cleanup:
Gilles Peskine449bd832023-01-11 14:50:10 +01002156 mbedtls_mpi_free(&W); mbedtls_mpi_free(&R);
2157 mbedtls_mpi_free(&T); mbedtls_mpi_free(&A);
2158 mbedtls_mpi_free(&RR);
Paul Bakker5121ce52009-01-03 21:22:43 +00002159
Gilles Peskine449bd832023-01-11 14:50:10 +01002160 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00002161}
2162
2163/*
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002164 * Pseudo-primality test: small factors, then Miller-Rabin
2165 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002166int mbedtls_mpi_is_prime_ext(const mbedtls_mpi *X, int rounds,
2167 int (*f_rng)(void *, unsigned char *, size_t),
2168 void *p_rng)
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002169{
Janos Follath24eed8d2019-11-22 13:21:35 +00002170 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002171 mbedtls_mpi XX;
Manuel Pégourié-Gonnard7f4ed672014-10-14 20:56:02 +02002172
2173 XX.s = 1;
2174 XX.n = X->n;
2175 XX.p = X->p;
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002176
Gilles Peskine449bd832023-01-11 14:50:10 +01002177 if (mbedtls_mpi_cmp_int(&XX, 0) == 0 ||
2178 mbedtls_mpi_cmp_int(&XX, 1) == 0) {
2179 return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002180 }
2181
Gilles Peskine449bd832023-01-11 14:50:10 +01002182 if (mbedtls_mpi_cmp_int(&XX, 2) == 0) {
2183 return 0;
2184 }
2185
2186 if ((ret = mpi_check_small_factors(&XX)) != 0) {
2187 if (ret == 1) {
2188 return 0;
2189 }
2190
2191 return ret;
2192 }
2193
2194 return mpi_miller_rabin(&XX, rounds, f_rng, p_rng);
Janos Follathf301d232018-08-14 13:34:01 +01002195}
2196
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002197/*
Paul Bakker5121ce52009-01-03 21:22:43 +00002198 * Prime number generation
Jethro Beekman66689272018-02-14 19:24:10 -08002199 *
Janos Follathf301d232018-08-14 13:34:01 +01002200 * To generate an RSA key in a way recommended by FIPS 186-4, both primes must
2201 * be either 1024 bits or 1536 bits long, and flags must contain
2202 * MBEDTLS_MPI_GEN_PRIME_FLAG_LOW_ERR.
Paul Bakker5121ce52009-01-03 21:22:43 +00002203 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002204int mbedtls_mpi_gen_prime(mbedtls_mpi *X, size_t nbits, int flags,
2205 int (*f_rng)(void *, unsigned char *, size_t),
2206 void *p_rng)
Paul Bakker5121ce52009-01-03 21:22:43 +00002207{
Jethro Beekman66689272018-02-14 19:24:10 -08002208#ifdef MBEDTLS_HAVE_INT64
2209// ceil(2^63.5)
2210#define CEIL_MAXUINT_DIV_SQRT2 0xb504f333f9de6485ULL
2211#else
2212// ceil(2^31.5)
2213#define CEIL_MAXUINT_DIV_SQRT2 0xb504f334U
2214#endif
2215 int ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
Paul Bakker23986e52011-04-24 08:57:21 +00002216 size_t k, n;
Janos Follathda31fa12018-09-03 14:45:23 +01002217 int rounds;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002218 mbedtls_mpi_uint r;
2219 mbedtls_mpi Y;
Paul Bakker5121ce52009-01-03 21:22:43 +00002220
Gilles Peskine449bd832023-01-11 14:50:10 +01002221 if (nbits < 3 || nbits > MBEDTLS_MPI_MAX_BITS) {
2222 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
2223 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002224
Gilles Peskine449bd832023-01-11 14:50:10 +01002225 mbedtls_mpi_init(&Y);
Paul Bakker5121ce52009-01-03 21:22:43 +00002226
Gilles Peskine449bd832023-01-11 14:50:10 +01002227 n = BITS_TO_LIMBS(nbits);
Paul Bakker5121ce52009-01-03 21:22:43 +00002228
Gilles Peskine449bd832023-01-11 14:50:10 +01002229 if ((flags & MBEDTLS_MPI_GEN_PRIME_FLAG_LOW_ERR) == 0) {
Janos Follathda31fa12018-09-03 14:45:23 +01002230 /*
2231 * 2^-80 error probability, number of rounds chosen per HAC, table 4.4
2232 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002233 rounds = ((nbits >= 1300) ? 2 : (nbits >= 850) ? 3 :
2234 (nbits >= 650) ? 4 : (nbits >= 350) ? 8 :
2235 (nbits >= 250) ? 12 : (nbits >= 150) ? 18 : 27);
2236 } else {
Janos Follathda31fa12018-09-03 14:45:23 +01002237 /*
2238 * 2^-100 error probability, number of rounds computed based on HAC,
2239 * fact 4.48
2240 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002241 rounds = ((nbits >= 1450) ? 4 : (nbits >= 1150) ? 5 :
2242 (nbits >= 1000) ? 6 : (nbits >= 850) ? 7 :
2243 (nbits >= 750) ? 8 : (nbits >= 500) ? 13 :
2244 (nbits >= 250) ? 28 : (nbits >= 150) ? 40 : 51);
Janos Follathda31fa12018-09-03 14:45:23 +01002245 }
2246
Gilles Peskine449bd832023-01-11 14:50:10 +01002247 while (1) {
2248 MBEDTLS_MPI_CHK(mbedtls_mpi_fill_random(X, n * ciL, f_rng, p_rng));
Jethro Beekman66689272018-02-14 19:24:10 -08002249 /* 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 +01002250 if (X->p[n-1] < CEIL_MAXUINT_DIV_SQRT2) {
2251 continue;
2252 }
Jethro Beekman66689272018-02-14 19:24:10 -08002253
2254 k = n * biL;
Gilles Peskine449bd832023-01-11 14:50:10 +01002255 if (k > nbits) {
2256 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(X, k - nbits));
2257 }
Jethro Beekman66689272018-02-14 19:24:10 -08002258 X->p[0] |= 1;
2259
Gilles Peskine449bd832023-01-11 14:50:10 +01002260 if ((flags & MBEDTLS_MPI_GEN_PRIME_FLAG_DH) == 0) {
2261 ret = mbedtls_mpi_is_prime_ext(X, rounds, f_rng, p_rng);
Jethro Beekman66689272018-02-14 19:24:10 -08002262
Gilles Peskine449bd832023-01-11 14:50:10 +01002263 if (ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE) {
Paul Bakker5121ce52009-01-03 21:22:43 +00002264 goto cleanup;
Gilles Peskine449bd832023-01-11 14:50:10 +01002265 }
2266 } else {
Manuel Pégourié-Gonnardddf76152013-11-22 19:58:22 +01002267 /*
Tom Cosgrovece7f18c2022-07-28 05:50:56 +01002268 * A necessary condition for Y and X = 2Y + 1 to be prime
Jethro Beekman66689272018-02-14 19:24:10 -08002269 * is X = 2 mod 3 (which is equivalent to Y = 2 mod 3).
2270 * Make sure it is satisfied, while keeping X = 3 mod 4
Manuel Pégourié-Gonnardddf76152013-11-22 19:58:22 +01002271 */
Jethro Beekman66689272018-02-14 19:24:10 -08002272
2273 X->p[0] |= 2;
2274
Gilles Peskine449bd832023-01-11 14:50:10 +01002275 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_int(&r, X, 3));
2276 if (r == 0) {
2277 MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(X, X, 8));
2278 } else if (r == 1) {
2279 MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(X, X, 4));
2280 }
Jethro Beekman66689272018-02-14 19:24:10 -08002281
2282 /* Set Y = (X-1) / 2, which is X / 2 because X is odd */
Gilles Peskine449bd832023-01-11 14:50:10 +01002283 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&Y, X));
2284 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&Y, 1));
Jethro Beekman66689272018-02-14 19:24:10 -08002285
Gilles Peskine449bd832023-01-11 14:50:10 +01002286 while (1) {
Jethro Beekman66689272018-02-14 19:24:10 -08002287 /*
2288 * First, check small factors for X and Y
2289 * before doing Miller-Rabin on any of them
2290 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002291 if ((ret = mpi_check_small_factors(X)) == 0 &&
2292 (ret = mpi_check_small_factors(&Y)) == 0 &&
2293 (ret = mpi_miller_rabin(X, rounds, f_rng, p_rng))
2294 == 0 &&
2295 (ret = mpi_miller_rabin(&Y, rounds, f_rng, p_rng))
2296 == 0) {
Jethro Beekman66689272018-02-14 19:24:10 -08002297 goto cleanup;
Gilles Peskine449bd832023-01-11 14:50:10 +01002298 }
Jethro Beekman66689272018-02-14 19:24:10 -08002299
Gilles Peskine449bd832023-01-11 14:50:10 +01002300 if (ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE) {
Jethro Beekman66689272018-02-14 19:24:10 -08002301 goto cleanup;
Gilles Peskine449bd832023-01-11 14:50:10 +01002302 }
Jethro Beekman66689272018-02-14 19:24:10 -08002303
2304 /*
2305 * Next candidates. We want to preserve Y = (X-1) / 2 and
2306 * Y = 1 mod 2 and Y = 2 mod 3 (eq X = 3 mod 4 and X = 2 mod 3)
2307 * so up Y by 6 and X by 12.
2308 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002309 MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(X, X, 12));
2310 MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(&Y, &Y, 6));
Paul Bakker5121ce52009-01-03 21:22:43 +00002311 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002312 }
2313 }
2314
2315cleanup:
2316
Gilles Peskine449bd832023-01-11 14:50:10 +01002317 mbedtls_mpi_free(&Y);
Paul Bakker5121ce52009-01-03 21:22:43 +00002318
Gilles Peskine449bd832023-01-11 14:50:10 +01002319 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00002320}
2321
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002322#endif /* MBEDTLS_GENPRIME */
Paul Bakker5121ce52009-01-03 21:22:43 +00002323
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002324#if defined(MBEDTLS_SELF_TEST)
Paul Bakker5121ce52009-01-03 21:22:43 +00002325
Paul Bakker23986e52011-04-24 08:57:21 +00002326#define GCD_PAIR_COUNT 3
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002327
2328static const int gcd_pairs[GCD_PAIR_COUNT][3] =
2329{
2330 { 693, 609, 21 },
2331 { 1764, 868, 28 },
2332 { 768454923, 542167814, 1 }
2333};
2334
Paul Bakker5121ce52009-01-03 21:22:43 +00002335/*
2336 * Checkup routine
2337 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002338int mbedtls_mpi_self_test(int verbose)
Paul Bakker5121ce52009-01-03 21:22:43 +00002339{
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002340 int ret, i;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002341 mbedtls_mpi A, E, N, X, Y, U, V;
Paul Bakker5121ce52009-01-03 21:22:43 +00002342
Gilles Peskine449bd832023-01-11 14:50:10 +01002343 mbedtls_mpi_init(&A); mbedtls_mpi_init(&E); mbedtls_mpi_init(&N); mbedtls_mpi_init(&X);
2344 mbedtls_mpi_init(&Y); mbedtls_mpi_init(&U); mbedtls_mpi_init(&V);
Paul Bakker5121ce52009-01-03 21:22:43 +00002345
Gilles Peskine449bd832023-01-11 14:50:10 +01002346 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&A, 16,
2347 "EFE021C2645FD1DC586E69184AF4A31E" \
2348 "D5F53E93B5F123FA41680867BA110131" \
2349 "944FE7952E2517337780CB0DB80E61AA" \
2350 "E7C8DDC6C5C6AADEB34EB38A2F40D5E6"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002351
Gilles Peskine449bd832023-01-11 14:50:10 +01002352 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&E, 16,
2353 "B2E7EFD37075B9F03FF989C7C5051C20" \
2354 "34D2A323810251127E7BF8625A4F49A5" \
2355 "F3E27F4DA8BD59C47D6DAABA4C8127BD" \
2356 "5B5C25763222FEFCCFC38B832366C29E"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002357
Gilles Peskine449bd832023-01-11 14:50:10 +01002358 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&N, 16,
2359 "0066A198186C18C10B2F5ED9B522752A" \
2360 "9830B69916E535C8F047518A889A43A5" \
2361 "94B6BED27A168D31D4A52F88925AA8F5"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002362
Gilles Peskine449bd832023-01-11 14:50:10 +01002363 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&X, &A, &N));
Paul Bakker5121ce52009-01-03 21:22:43 +00002364
Gilles Peskine449bd832023-01-11 14:50:10 +01002365 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&U, 16,
2366 "602AB7ECA597A3D6B56FF9829A5E8B85" \
2367 "9E857EA95A03512E2BAE7391688D264A" \
2368 "A5663B0341DB9CCFD2C4C5F421FEC814" \
2369 "8001B72E848A38CAE1C65F78E56ABDEF" \
2370 "E12D3C039B8A02D6BE593F0BBBDA56F1" \
2371 "ECF677152EF804370C1A305CAF3B5BF1" \
2372 "30879B56C61DE584A0F53A2447A51E"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002373
Gilles Peskine449bd832023-01-11 14:50:10 +01002374 if (verbose != 0) {
2375 mbedtls_printf(" MPI test #1 (mul_mpi): ");
2376 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002377
Gilles Peskine449bd832023-01-11 14:50:10 +01002378 if (mbedtls_mpi_cmp_mpi(&X, &U) != 0) {
2379 if (verbose != 0) {
2380 mbedtls_printf("failed\n");
2381 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002382
Manuel Pégourié-Gonnard9e987ed2014-01-20 10:03:15 +01002383 ret = 1;
2384 goto cleanup;
Paul Bakker5121ce52009-01-03 21:22:43 +00002385 }
2386
Gilles Peskine449bd832023-01-11 14:50:10 +01002387 if (verbose != 0) {
2388 mbedtls_printf("passed\n");
2389 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002390
Gilles Peskine449bd832023-01-11 14:50:10 +01002391 MBEDTLS_MPI_CHK(mbedtls_mpi_div_mpi(&X, &Y, &A, &N));
Paul Bakker5121ce52009-01-03 21:22:43 +00002392
Gilles Peskine449bd832023-01-11 14:50:10 +01002393 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&U, 16,
2394 "256567336059E52CAE22925474705F39A94"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002395
Gilles Peskine449bd832023-01-11 14:50:10 +01002396 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&V, 16,
2397 "6613F26162223DF488E9CD48CC132C7A" \
2398 "0AC93C701B001B092E4E5B9F73BCD27B" \
2399 "9EE50D0657C77F374E903CDFA4C642"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002400
Gilles Peskine449bd832023-01-11 14:50:10 +01002401 if (verbose != 0) {
2402 mbedtls_printf(" MPI test #2 (div_mpi): ");
2403 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002404
Gilles Peskine449bd832023-01-11 14:50:10 +01002405 if (mbedtls_mpi_cmp_mpi(&X, &U) != 0 ||
2406 mbedtls_mpi_cmp_mpi(&Y, &V) != 0) {
2407 if (verbose != 0) {
2408 mbedtls_printf("failed\n");
2409 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002410
Manuel Pégourié-Gonnard9e987ed2014-01-20 10:03:15 +01002411 ret = 1;
2412 goto cleanup;
Paul Bakker5121ce52009-01-03 21:22:43 +00002413 }
2414
Gilles Peskine449bd832023-01-11 14:50:10 +01002415 if (verbose != 0) {
2416 mbedtls_printf("passed\n");
2417 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002418
Gilles Peskine449bd832023-01-11 14:50:10 +01002419 MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&X, &A, &E, &N, NULL));
Paul Bakker5121ce52009-01-03 21:22:43 +00002420
Gilles Peskine449bd832023-01-11 14:50:10 +01002421 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&U, 16,
2422 "36E139AEA55215609D2816998ED020BB" \
2423 "BD96C37890F65171D948E9BC7CBAA4D9" \
2424 "325D24D6A3C12710F10A09FA08AB87"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002425
Gilles Peskine449bd832023-01-11 14:50:10 +01002426 if (verbose != 0) {
2427 mbedtls_printf(" MPI test #3 (exp_mod): ");
2428 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002429
Gilles Peskine449bd832023-01-11 14:50:10 +01002430 if (mbedtls_mpi_cmp_mpi(&X, &U) != 0) {
2431 if (verbose != 0) {
2432 mbedtls_printf("failed\n");
2433 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002434
Manuel Pégourié-Gonnard9e987ed2014-01-20 10:03:15 +01002435 ret = 1;
2436 goto cleanup;
Paul Bakker5121ce52009-01-03 21:22:43 +00002437 }
2438
Gilles Peskine449bd832023-01-11 14:50:10 +01002439 if (verbose != 0) {
2440 mbedtls_printf("passed\n");
2441 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002442
Gilles Peskine449bd832023-01-11 14:50:10 +01002443 MBEDTLS_MPI_CHK(mbedtls_mpi_inv_mod(&X, &A, &N));
Paul Bakker5121ce52009-01-03 21:22:43 +00002444
Gilles Peskine449bd832023-01-11 14:50:10 +01002445 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&U, 16,
2446 "003A0AAEDD7E784FC07D8F9EC6E3BFD5" \
2447 "C3DBA76456363A10869622EAC2DD84EC" \
2448 "C5B8A74DAC4D09E03B5E0BE779F2DF61"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002449
Gilles Peskine449bd832023-01-11 14:50:10 +01002450 if (verbose != 0) {
2451 mbedtls_printf(" MPI test #4 (inv_mod): ");
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 if (verbose != 0) {
2456 mbedtls_printf("failed\n");
2457 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002458
Manuel Pégourié-Gonnard9e987ed2014-01-20 10:03:15 +01002459 ret = 1;
2460 goto cleanup;
Paul Bakker5121ce52009-01-03 21:22:43 +00002461 }
2462
Gilles Peskine449bd832023-01-11 14:50:10 +01002463 if (verbose != 0) {
2464 mbedtls_printf("passed\n");
2465 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002466
Gilles Peskine449bd832023-01-11 14:50:10 +01002467 if (verbose != 0) {
2468 mbedtls_printf(" MPI test #5 (simple gcd): ");
2469 }
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002470
Gilles Peskine449bd832023-01-11 14:50:10 +01002471 for (i = 0; i < GCD_PAIR_COUNT; i++) {
2472 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&X, gcd_pairs[i][0]));
2473 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&Y, gcd_pairs[i][1]));
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002474
Gilles Peskine449bd832023-01-11 14:50:10 +01002475 MBEDTLS_MPI_CHK(mbedtls_mpi_gcd(&A, &X, &Y));
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002476
Gilles Peskine449bd832023-01-11 14:50:10 +01002477 if (mbedtls_mpi_cmp_int(&A, gcd_pairs[i][2]) != 0) {
2478 if (verbose != 0) {
2479 mbedtls_printf("failed at %d\n", i);
2480 }
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002481
Manuel Pégourié-Gonnard9e987ed2014-01-20 10:03:15 +01002482 ret = 1;
2483 goto cleanup;
2484 }
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002485 }
2486
Gilles Peskine449bd832023-01-11 14:50:10 +01002487 if (verbose != 0) {
2488 mbedtls_printf("passed\n");
2489 }
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002490
Paul Bakker5121ce52009-01-03 21:22:43 +00002491cleanup:
2492
Gilles Peskine449bd832023-01-11 14:50:10 +01002493 if (ret != 0 && verbose != 0) {
2494 mbedtls_printf("Unexpected error, return code = %08X\n", (unsigned int) ret);
2495 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002496
Gilles Peskine449bd832023-01-11 14:50:10 +01002497 mbedtls_mpi_free(&A); mbedtls_mpi_free(&E); mbedtls_mpi_free(&N); mbedtls_mpi_free(&X);
2498 mbedtls_mpi_free(&Y); mbedtls_mpi_free(&U); mbedtls_mpi_free(&V);
Paul Bakker5121ce52009-01-03 21:22:43 +00002499
Gilles Peskine449bd832023-01-11 14:50:10 +01002500 if (verbose != 0) {
2501 mbedtls_printf("\n");
2502 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002503
Gilles Peskine449bd832023-01-11 14:50:10 +01002504 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00002505}
2506
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002507#endif /* MBEDTLS_SELF_TEST */
Paul Bakker5121ce52009-01-03 21:22:43 +00002508
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002509#endif /* MBEDTLS_BIGNUM_C */