blob: 4f7ca16cda48443d49c194e5934d75ef8d32a1d8 [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
433/*
Manuel Pégourié-Gonnardc0696c22015-06-18 16:47:17 +0200434 * Return the number of less significant zero-bits
Paul Bakker5121ce52009-01-03 21:22:43 +0000435 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100436size_t mbedtls_mpi_lsb(const mbedtls_mpi *X)
Paul Bakker5121ce52009-01-03 21:22:43 +0000437{
Dave Rodgmanfa703e32023-08-09 18:56:07 +0100438 size_t i;
Paul Bakker5121ce52009-01-03 21:22:43 +0000439
Dave Rodgmanfa703e32023-08-09 18:56:07 +0100440#if defined(__has_builtin)
441#if (MBEDTLS_MPI_UINT_MAX == UINT_MAX) && __has_builtin(__builtin_ctz)
442 #define mbedtls_mpi_uint_ctz __builtin_ctz
443#elif (MBEDTLS_MPI_UINT_MAX == ULONG_MAX) && __has_builtin(__builtin_ctzl)
444 #define mbedtls_mpi_uint_ctz __builtin_ctzl
445#elif (MBEDTLS_MPI_UINT_MAX == ULLONG_MAX) && __has_builtin(__builtin_ctzll)
446 #define mbedtls_mpi_uint_ctz __builtin_ctzll
447#endif
448#endif
449
450#if defined(mbedtls_mpi_uint_ctz)
Gilles Peskine449bd832023-01-11 14:50:10 +0100451 for (i = 0; i < X->n; i++) {
Dave Rodgman960eca92023-08-09 20:43:18 +0100452 if (X->p[i] != 0) {
453 return i * biL + mbedtls_mpi_uint_ctz(X->p[i]);
454 }
Dave Rodgmanfa703e32023-08-09 18:56:07 +0100455 }
456#else
457 size_t count = 0;
458 for (i = 0; i < X->n; i++) {
459 for (size_t j = 0; j < biL; j++, count++) {
Gilles Peskine449bd832023-01-11 14:50:10 +0100460 if (((X->p[i] >> j) & 1) != 0) {
461 return count;
462 }
463 }
464 }
Dave Rodgmanfa703e32023-08-09 18:56:07 +0100465#endif
Paul Bakker5121ce52009-01-03 21:22:43 +0000466
Gilles Peskine449bd832023-01-11 14:50:10 +0100467 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000468}
469
470/*
Manuel Pégourié-Gonnardc0696c22015-06-18 16:47:17 +0200471 * Return the number of bits
Paul Bakker5121ce52009-01-03 21:22:43 +0000472 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100473size_t mbedtls_mpi_bitlen(const mbedtls_mpi *X)
Paul Bakker5121ce52009-01-03 21:22:43 +0000474{
Gilles Peskine449bd832023-01-11 14:50:10 +0100475 return mbedtls_mpi_core_bitlen(X->p, X->n);
Paul Bakker5121ce52009-01-03 21:22:43 +0000476}
477
478/*
479 * Return the total size in bytes
480 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100481size_t mbedtls_mpi_size(const mbedtls_mpi *X)
Paul Bakker5121ce52009-01-03 21:22:43 +0000482{
Gilles Peskine449bd832023-01-11 14:50:10 +0100483 return (mbedtls_mpi_bitlen(X) + 7) >> 3;
Paul Bakker5121ce52009-01-03 21:22:43 +0000484}
485
486/*
487 * Convert an ASCII character to digit value
488 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100489static int mpi_get_digit(mbedtls_mpi_uint *d, int radix, char c)
Paul Bakker5121ce52009-01-03 21:22:43 +0000490{
491 *d = 255;
492
Gilles Peskine449bd832023-01-11 14:50:10 +0100493 if (c >= 0x30 && c <= 0x39) {
494 *d = c - 0x30;
495 }
496 if (c >= 0x41 && c <= 0x46) {
497 *d = c - 0x37;
498 }
499 if (c >= 0x61 && c <= 0x66) {
500 *d = c - 0x57;
501 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000502
Gilles Peskine449bd832023-01-11 14:50:10 +0100503 if (*d >= (mbedtls_mpi_uint) radix) {
504 return MBEDTLS_ERR_MPI_INVALID_CHARACTER;
505 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000506
Gilles Peskine449bd832023-01-11 14:50:10 +0100507 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000508}
509
510/*
511 * Import from an ASCII string
512 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100513int mbedtls_mpi_read_string(mbedtls_mpi *X, int radix, const char *s)
Paul Bakker5121ce52009-01-03 21:22:43 +0000514{
Janos Follath24eed8d2019-11-22 13:21:35 +0000515 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker23986e52011-04-24 08:57:21 +0000516 size_t i, j, slen, n;
Gilles Peskine80f56732021-04-03 18:26:13 +0200517 int sign = 1;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200518 mbedtls_mpi_uint d;
519 mbedtls_mpi T;
Paul Bakker5121ce52009-01-03 21:22:43 +0000520
Gilles Peskine449bd832023-01-11 14:50:10 +0100521 if (radix < 2 || radix > 16) {
522 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
Gilles Peskine7cba8592021-06-08 18:32:34 +0200523 }
524
Gilles Peskine449bd832023-01-11 14:50:10 +0100525 mbedtls_mpi_init(&T);
526
527 if (s[0] == 0) {
528 mbedtls_mpi_free(X);
529 return 0;
530 }
531
532 if (s[0] == '-') {
Gilles Peskine80f56732021-04-03 18:26:13 +0200533 ++s;
534 sign = -1;
535 }
536
Gilles Peskine449bd832023-01-11 14:50:10 +0100537 slen = strlen(s);
Paul Bakkerff60ee62010-03-16 21:09:09 +0000538
Gilles Peskine449bd832023-01-11 14:50:10 +0100539 if (radix == 16) {
Dave Rodgman68ef1d62023-05-18 20:49:03 +0100540 if (slen > SIZE_MAX >> 2) {
Gilles Peskine449bd832023-01-11 14:50:10 +0100541 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
Paul Bakker5121ce52009-01-03 21:22:43 +0000542 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000543
Gilles Peskine449bd832023-01-11 14:50:10 +0100544 n = BITS_TO_LIMBS(slen << 2);
545
546 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, n));
547 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(X, 0));
548
549 for (i = slen, j = 0; i > 0; i--, j++) {
550 MBEDTLS_MPI_CHK(mpi_get_digit(&d, radix, s[i - 1]));
551 X->p[j / (2 * ciL)] |= d << ((j % (2 * ciL)) << 2);
552 }
553 } else {
554 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(X, 0));
555
556 for (i = 0; i < slen; i++) {
557 MBEDTLS_MPI_CHK(mpi_get_digit(&d, radix, s[i]));
558 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_int(&T, X, radix));
559 MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(X, &T, d));
Paul Bakker5121ce52009-01-03 21:22:43 +0000560 }
561 }
562
Gilles Peskine449bd832023-01-11 14:50:10 +0100563 if (sign < 0 && mbedtls_mpi_bitlen(X) != 0) {
Gilles Peskine80f56732021-04-03 18:26:13 +0200564 X->s = -1;
Gilles Peskine449bd832023-01-11 14:50:10 +0100565 }
Gilles Peskine80f56732021-04-03 18:26:13 +0200566
Paul Bakker5121ce52009-01-03 21:22:43 +0000567cleanup:
568
Gilles Peskine449bd832023-01-11 14:50:10 +0100569 mbedtls_mpi_free(&T);
Paul Bakker5121ce52009-01-03 21:22:43 +0000570
Gilles Peskine449bd832023-01-11 14:50:10 +0100571 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000572}
573
574/*
Ron Eldora16fa292018-11-20 14:07:01 +0200575 * Helper to write the digits high-order first.
Paul Bakker5121ce52009-01-03 21:22:43 +0000576 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100577static int mpi_write_hlp(mbedtls_mpi *X, int radix,
578 char **p, const size_t buflen)
Paul Bakker5121ce52009-01-03 21:22:43 +0000579{
Janos Follath24eed8d2019-11-22 13:21:35 +0000580 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200581 mbedtls_mpi_uint r;
Ron Eldora16fa292018-11-20 14:07:01 +0200582 size_t length = 0;
583 char *p_end = *p + buflen;
Paul Bakker5121ce52009-01-03 21:22:43 +0000584
Gilles Peskine449bd832023-01-11 14:50:10 +0100585 do {
586 if (length >= buflen) {
587 return MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL;
Ron Eldora16fa292018-11-20 14:07:01 +0200588 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000589
Gilles Peskine449bd832023-01-11 14:50:10 +0100590 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_int(&r, X, radix));
591 MBEDTLS_MPI_CHK(mbedtls_mpi_div_int(X, NULL, X, radix));
Ron Eldora16fa292018-11-20 14:07:01 +0200592 /*
593 * Write the residue in the current position, as an ASCII character.
594 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100595 if (r < 0xA) {
596 *(--p_end) = (char) ('0' + r);
597 } else {
598 *(--p_end) = (char) ('A' + (r - 0xA));
599 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000600
Ron Eldora16fa292018-11-20 14:07:01 +0200601 length++;
Gilles Peskine449bd832023-01-11 14:50:10 +0100602 } while (mbedtls_mpi_cmp_int(X, 0) != 0);
Paul Bakker5121ce52009-01-03 21:22:43 +0000603
Gilles Peskine449bd832023-01-11 14:50:10 +0100604 memmove(*p, p_end, length);
Ron Eldora16fa292018-11-20 14:07:01 +0200605 *p += length;
Paul Bakker5121ce52009-01-03 21:22:43 +0000606
607cleanup:
608
Gilles Peskine449bd832023-01-11 14:50:10 +0100609 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000610}
611
612/*
613 * Export into an ASCII string
614 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100615int mbedtls_mpi_write_string(const mbedtls_mpi *X, int radix,
616 char *buf, size_t buflen, size_t *olen)
Paul Bakker5121ce52009-01-03 21:22:43 +0000617{
Paul Bakker23986e52011-04-24 08:57:21 +0000618 int ret = 0;
619 size_t n;
Paul Bakker5121ce52009-01-03 21:22:43 +0000620 char *p;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200621 mbedtls_mpi T;
Paul Bakker5121ce52009-01-03 21:22:43 +0000622
Gilles Peskine449bd832023-01-11 14:50:10 +0100623 if (radix < 2 || radix > 16) {
624 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
625 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000626
Gilles Peskine449bd832023-01-11 14:50:10 +0100627 n = mbedtls_mpi_bitlen(X); /* Number of bits necessary to present `n`. */
628 if (radix >= 4) {
629 n >>= 1; /* Number of 4-adic digits necessary to present
Hanno Becker23cfea02019-02-04 09:45:07 +0000630 * `n`. If radix > 4, this might be a strict
631 * overapproximation of the number of
632 * radix-adic digits needed to present `n`. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100633 }
634 if (radix >= 16) {
635 n >>= 1; /* Number of hexadecimal digits necessary to
Hanno Becker23cfea02019-02-04 09:45:07 +0000636 * present `n`. */
637
Gilles Peskine449bd832023-01-11 14:50:10 +0100638 }
Janos Follath80470622019-03-06 13:43:02 +0000639 n += 1; /* Terminating null byte */
Hanno Becker23cfea02019-02-04 09:45:07 +0000640 n += 1; /* Compensate for the divisions above, which round down `n`
641 * in case it's not even. */
642 n += 1; /* Potential '-'-sign. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100643 n += (n & 1); /* Make n even to have enough space for hexadecimal writing,
Hanno Becker23cfea02019-02-04 09:45:07 +0000644 * which always uses an even number of hex-digits. */
Paul Bakker5121ce52009-01-03 21:22:43 +0000645
Gilles Peskine449bd832023-01-11 14:50:10 +0100646 if (buflen < n) {
Manuel Pégourié-Gonnardf79b4252015-06-02 15:41:48 +0100647 *olen = n;
Gilles Peskine449bd832023-01-11 14:50:10 +0100648 return MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL;
Paul Bakker5121ce52009-01-03 21:22:43 +0000649 }
650
Manuel Pégourié-Gonnardf79b4252015-06-02 15:41:48 +0100651 p = buf;
Gilles Peskine449bd832023-01-11 14:50:10 +0100652 mbedtls_mpi_init(&T);
Paul Bakker5121ce52009-01-03 21:22:43 +0000653
Gilles Peskine449bd832023-01-11 14:50:10 +0100654 if (X->s == -1) {
Paul Bakker5121ce52009-01-03 21:22:43 +0000655 *p++ = '-';
Hanno Beckerc983c812019-02-01 16:41:30 +0000656 buflen--;
657 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000658
Gilles Peskine449bd832023-01-11 14:50:10 +0100659 if (radix == 16) {
Paul Bakker23986e52011-04-24 08:57:21 +0000660 int c;
661 size_t i, j, k;
Paul Bakker5121ce52009-01-03 21:22:43 +0000662
Gilles Peskine449bd832023-01-11 14:50:10 +0100663 for (i = X->n, k = 0; i > 0; i--) {
664 for (j = ciL; j > 0; j--) {
665 c = (X->p[i - 1] >> ((j - 1) << 3)) & 0xFF;
Paul Bakker5121ce52009-01-03 21:22:43 +0000666
Gilles Peskine449bd832023-01-11 14:50:10 +0100667 if (c == 0 && k == 0 && (i + j) != 2) {
Paul Bakker5121ce52009-01-03 21:22:43 +0000668 continue;
Gilles Peskine449bd832023-01-11 14:50:10 +0100669 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000670
Paul Bakker98fe5ea2012-10-24 11:17:48 +0000671 *(p++) = "0123456789ABCDEF" [c / 16];
Paul Bakkerd2c167e2012-10-30 07:49:19 +0000672 *(p++) = "0123456789ABCDEF" [c % 16];
Paul Bakker5121ce52009-01-03 21:22:43 +0000673 k = 1;
674 }
675 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100676 } else {
677 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&T, X));
Paul Bakkerce40a6d2009-06-23 19:46:08 +0000678
Gilles Peskine449bd832023-01-11 14:50:10 +0100679 if (T.s == -1) {
Paul Bakkerce40a6d2009-06-23 19:46:08 +0000680 T.s = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +0100681 }
Paul Bakkerce40a6d2009-06-23 19:46:08 +0000682
Gilles Peskine449bd832023-01-11 14:50:10 +0100683 MBEDTLS_MPI_CHK(mpi_write_hlp(&T, radix, &p, buflen));
Paul Bakker5121ce52009-01-03 21:22:43 +0000684 }
685
686 *p++ = '\0';
Dave Rodgmane4a6f5a2023-11-04 12:20:09 +0000687 *olen = (size_t) (p - buf);
Paul Bakker5121ce52009-01-03 21:22:43 +0000688
689cleanup:
690
Gilles Peskine449bd832023-01-11 14:50:10 +0100691 mbedtls_mpi_free(&T);
Paul Bakker5121ce52009-01-03 21:22:43 +0000692
Gilles Peskine449bd832023-01-11 14:50:10 +0100693 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000694}
695
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200696#if defined(MBEDTLS_FS_IO)
Paul Bakker5121ce52009-01-03 21:22:43 +0000697/*
698 * Read X from an opened file
699 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100700int mbedtls_mpi_read_file(mbedtls_mpi *X, int radix, FILE *fin)
Paul Bakker5121ce52009-01-03 21:22:43 +0000701{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200702 mbedtls_mpi_uint d;
Paul Bakker23986e52011-04-24 08:57:21 +0000703 size_t slen;
Paul Bakker5121ce52009-01-03 21:22:43 +0000704 char *p;
Paul Bakkerfe3256e2011-11-25 12:11:43 +0000705 /*
Paul Bakkercb37aa52011-11-30 16:00:20 +0000706 * Buffer should have space for (short) label and decimal formatted MPI,
707 * newline characters and '\0'
Paul Bakkerfe3256e2011-11-25 12:11:43 +0000708 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100709 char s[MBEDTLS_MPI_RW_BUFFER_SIZE];
Paul Bakker5121ce52009-01-03 21:22:43 +0000710
Gilles Peskine449bd832023-01-11 14:50:10 +0100711 if (radix < 2 || radix > 16) {
712 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
713 }
Hanno Becker73d7d792018-12-11 10:35:51 +0000714
Gilles Peskine449bd832023-01-11 14:50:10 +0100715 memset(s, 0, sizeof(s));
716 if (fgets(s, sizeof(s) - 1, fin) == NULL) {
717 return MBEDTLS_ERR_MPI_FILE_IO_ERROR;
718 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000719
Gilles Peskine449bd832023-01-11 14:50:10 +0100720 slen = strlen(s);
721 if (slen == sizeof(s) - 2) {
722 return MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL;
723 }
Paul Bakkercb37aa52011-11-30 16:00:20 +0000724
Gilles Peskine449bd832023-01-11 14:50:10 +0100725 if (slen > 0 && s[slen - 1] == '\n') {
726 slen--; s[slen] = '\0';
727 }
728 if (slen > 0 && s[slen - 1] == '\r') {
729 slen--; s[slen] = '\0';
730 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000731
732 p = s + slen;
Gilles Peskine449bd832023-01-11 14:50:10 +0100733 while (p-- > s) {
734 if (mpi_get_digit(&d, radix, *p) != 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +0000735 break;
Gilles Peskine449bd832023-01-11 14:50:10 +0100736 }
737 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000738
Gilles Peskine449bd832023-01-11 14:50:10 +0100739 return mbedtls_mpi_read_string(X, radix, p + 1);
Paul Bakker5121ce52009-01-03 21:22:43 +0000740}
741
742/*
743 * Write X into an opened file (or stdout if fout == NULL)
744 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100745int mbedtls_mpi_write_file(const char *p, const mbedtls_mpi *X, int radix, FILE *fout)
Paul Bakker5121ce52009-01-03 21:22:43 +0000746{
Janos Follath24eed8d2019-11-22 13:21:35 +0000747 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker23986e52011-04-24 08:57:21 +0000748 size_t n, slen, plen;
Paul Bakkerfe3256e2011-11-25 12:11:43 +0000749 /*
Paul Bakker5531c6d2012-09-26 19:20:46 +0000750 * Buffer should have space for (short) label and decimal formatted MPI,
751 * newline characters and '\0'
Paul Bakkerfe3256e2011-11-25 12:11:43 +0000752 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100753 char s[MBEDTLS_MPI_RW_BUFFER_SIZE];
Hanno Becker73d7d792018-12-11 10:35:51 +0000754
Gilles Peskine449bd832023-01-11 14:50:10 +0100755 if (radix < 2 || radix > 16) {
756 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
757 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000758
Gilles Peskine449bd832023-01-11 14:50:10 +0100759 memset(s, 0, sizeof(s));
Paul Bakker5121ce52009-01-03 21:22:43 +0000760
Gilles Peskine449bd832023-01-11 14:50:10 +0100761 MBEDTLS_MPI_CHK(mbedtls_mpi_write_string(X, radix, s, sizeof(s) - 2, &n));
Paul Bakker5121ce52009-01-03 21:22:43 +0000762
Gilles Peskine449bd832023-01-11 14:50:10 +0100763 if (p == NULL) {
764 p = "";
765 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000766
Gilles Peskine449bd832023-01-11 14:50:10 +0100767 plen = strlen(p);
768 slen = strlen(s);
Paul Bakker5121ce52009-01-03 21:22:43 +0000769 s[slen++] = '\r';
770 s[slen++] = '\n';
771
Gilles Peskine449bd832023-01-11 14:50:10 +0100772 if (fout != NULL) {
773 if (fwrite(p, 1, plen, fout) != plen ||
774 fwrite(s, 1, slen, fout) != slen) {
775 return MBEDTLS_ERR_MPI_FILE_IO_ERROR;
776 }
777 } else {
778 mbedtls_printf("%s%s", p, s);
Paul Bakker5121ce52009-01-03 21:22:43 +0000779 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000780
781cleanup:
782
Gilles Peskine449bd832023-01-11 14:50:10 +0100783 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000784}
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200785#endif /* MBEDTLS_FS_IO */
Paul Bakker5121ce52009-01-03 21:22:43 +0000786
787/*
Janos Follatha778a942019-02-13 10:28:28 +0000788 * Import X from unsigned binary data, little endian
Przemyslaw Stekiel76960a72022-02-21 13:42:09 +0100789 *
790 * This function is guaranteed to return an MPI with exactly the necessary
791 * number of limbs (in particular, it does not skip 0s in the input).
Janos Follatha778a942019-02-13 10:28:28 +0000792 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100793int mbedtls_mpi_read_binary_le(mbedtls_mpi *X,
794 const unsigned char *buf, size_t buflen)
Janos Follatha778a942019-02-13 10:28:28 +0000795{
Janos Follath24eed8d2019-11-22 13:21:35 +0000796 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Gilles Peskine449bd832023-01-11 14:50:10 +0100797 const size_t limbs = CHARS_TO_LIMBS(buflen);
Janos Follatha778a942019-02-13 10:28:28 +0000798
799 /* Ensure that target MPI has exactly the necessary number of limbs */
Gilles Peskine449bd832023-01-11 14:50:10 +0100800 MBEDTLS_MPI_CHK(mbedtls_mpi_resize_clear(X, limbs));
Janos Follatha778a942019-02-13 10:28:28 +0000801
Gilles Peskine449bd832023-01-11 14:50:10 +0100802 MBEDTLS_MPI_CHK(mbedtls_mpi_core_read_le(X->p, X->n, buf, buflen));
Janos Follatha778a942019-02-13 10:28:28 +0000803
804cleanup:
805
Janos Follath171a7ef2019-02-15 16:17:45 +0000806 /*
807 * This function is also used to import keys. However, wiping the buffers
808 * upon failure is not necessary because failure only can happen before any
809 * input is copied.
810 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100811 return ret;
Janos Follatha778a942019-02-13 10:28:28 +0000812}
813
814/*
Paul Bakker5121ce52009-01-03 21:22:43 +0000815 * Import X from unsigned binary data, big endian
Przemyslaw Stekiel76960a72022-02-21 13:42:09 +0100816 *
817 * This function is guaranteed to return an MPI with exactly the necessary
818 * number of limbs (in particular, it does not skip 0s in the input).
Paul Bakker5121ce52009-01-03 21:22:43 +0000819 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100820int mbedtls_mpi_read_binary(mbedtls_mpi *X, const unsigned char *buf, size_t buflen)
Paul Bakker5121ce52009-01-03 21:22:43 +0000821{
Janos Follath24eed8d2019-11-22 13:21:35 +0000822 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Gilles Peskine449bd832023-01-11 14:50:10 +0100823 const size_t limbs = CHARS_TO_LIMBS(buflen);
Hanno Becker73d7d792018-12-11 10:35:51 +0000824
Hanno Becker073c1992017-10-17 15:17:27 +0100825 /* Ensure that target MPI has exactly the necessary number of limbs */
Gilles Peskine449bd832023-01-11 14:50:10 +0100826 MBEDTLS_MPI_CHK(mbedtls_mpi_resize_clear(X, limbs));
Paul Bakker5121ce52009-01-03 21:22:43 +0000827
Gilles Peskine449bd832023-01-11 14:50:10 +0100828 MBEDTLS_MPI_CHK(mbedtls_mpi_core_read_be(X->p, X->n, buf, buflen));
Paul Bakker5121ce52009-01-03 21:22:43 +0000829
830cleanup:
831
Janos Follath171a7ef2019-02-15 16:17:45 +0000832 /*
833 * This function is also used to import keys. However, wiping the buffers
834 * upon failure is not necessary because failure only can happen before any
835 * input is copied.
836 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100837 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000838}
839
840/*
Janos Follathe344d0f2019-02-19 16:17:40 +0000841 * Export X into unsigned binary data, little endian
842 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100843int mbedtls_mpi_write_binary_le(const mbedtls_mpi *X,
844 unsigned char *buf, size_t buflen)
Janos Follathe344d0f2019-02-19 16:17:40 +0000845{
Gilles Peskine449bd832023-01-11 14:50:10 +0100846 return mbedtls_mpi_core_write_le(X->p, X->n, buf, buflen);
Janos Follathe344d0f2019-02-19 16:17:40 +0000847}
848
849/*
Paul Bakker5121ce52009-01-03 21:22:43 +0000850 * Export X into unsigned binary data, big endian
851 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100852int mbedtls_mpi_write_binary(const mbedtls_mpi *X,
853 unsigned char *buf, size_t buflen)
Paul Bakker5121ce52009-01-03 21:22:43 +0000854{
Gilles Peskine449bd832023-01-11 14:50:10 +0100855 return mbedtls_mpi_core_write_be(X->p, X->n, buf, buflen);
Paul Bakker5121ce52009-01-03 21:22:43 +0000856}
857
858/*
859 * Left-shift: X <<= count
860 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100861int mbedtls_mpi_shift_l(mbedtls_mpi *X, size_t count)
Paul Bakker5121ce52009-01-03 21:22:43 +0000862{
Janos Follath24eed8d2019-11-22 13:21:35 +0000863 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Minos Galanakis0144b352023-05-02 14:02:32 +0100864 size_t i;
Paul Bakker5121ce52009-01-03 21:22:43 +0000865
Gilles Peskine449bd832023-01-11 14:50:10 +0100866 i = mbedtls_mpi_bitlen(X) + count;
Paul Bakker5121ce52009-01-03 21:22:43 +0000867
Gilles Peskine449bd832023-01-11 14:50:10 +0100868 if (X->n * biL < i) {
869 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, BITS_TO_LIMBS(i)));
870 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000871
872 ret = 0;
873
Minos Galanakis0144b352023-05-02 14:02:32 +0100874 mbedtls_mpi_core_shift_l(X->p, X->n, count);
Paul Bakker5121ce52009-01-03 21:22:43 +0000875cleanup:
876
Gilles Peskine449bd832023-01-11 14:50:10 +0100877 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000878}
879
880/*
881 * Right-shift: X >>= count
882 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100883int mbedtls_mpi_shift_r(mbedtls_mpi *X, size_t count)
Paul Bakker5121ce52009-01-03 21:22:43 +0000884{
Gilles Peskine449bd832023-01-11 14:50:10 +0100885 if (X->n != 0) {
886 mbedtls_mpi_core_shift_r(X->p, X->n, count);
887 }
888 return 0;
Gilles Peskine66414202022-09-21 15:36:16 +0200889}
890
Paul Bakker5121ce52009-01-03 21:22:43 +0000891/*
892 * Compare unsigned values
893 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100894int mbedtls_mpi_cmp_abs(const mbedtls_mpi *X, const mbedtls_mpi *Y)
Paul Bakker5121ce52009-01-03 21:22:43 +0000895{
Paul Bakker23986e52011-04-24 08:57:21 +0000896 size_t i, j;
Paul Bakker5121ce52009-01-03 21:22:43 +0000897
Gilles Peskine449bd832023-01-11 14:50:10 +0100898 for (i = X->n; i > 0; i--) {
899 if (X->p[i - 1] != 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +0000900 break;
Gilles Peskine449bd832023-01-11 14:50:10 +0100901 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000902 }
903
Gilles Peskine449bd832023-01-11 14:50:10 +0100904 for (j = Y->n; j > 0; j--) {
905 if (Y->p[j - 1] != 0) {
906 break;
907 }
908 }
909
Dave Rodgmanebcd7852023-08-09 18:56:42 +0100910 /* If i == j == 0, i.e. abs(X) == abs(Y),
911 * we end up returning 0 at the end of the function. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100912
913 if (i > j) {
914 return 1;
915 }
916 if (j > i) {
917 return -1;
918 }
919
920 for (; i > 0; i--) {
921 if (X->p[i - 1] > Y->p[i - 1]) {
922 return 1;
923 }
924 if (X->p[i - 1] < Y->p[i - 1]) {
925 return -1;
926 }
927 }
928
929 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000930}
931
932/*
933 * Compare signed values
934 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100935int mbedtls_mpi_cmp_mpi(const mbedtls_mpi *X, const mbedtls_mpi *Y)
Paul Bakker5121ce52009-01-03 21:22:43 +0000936{
Paul Bakker23986e52011-04-24 08:57:21 +0000937 size_t i, j;
Paul Bakker5121ce52009-01-03 21:22:43 +0000938
Gilles Peskine449bd832023-01-11 14:50:10 +0100939 for (i = X->n; i > 0; i--) {
940 if (X->p[i - 1] != 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +0000941 break;
Gilles Peskine449bd832023-01-11 14:50:10 +0100942 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000943 }
944
Gilles Peskine449bd832023-01-11 14:50:10 +0100945 for (j = Y->n; j > 0; j--) {
946 if (Y->p[j - 1] != 0) {
947 break;
948 }
949 }
950
951 if (i == 0 && j == 0) {
952 return 0;
953 }
954
955 if (i > j) {
956 return X->s;
957 }
958 if (j > i) {
959 return -Y->s;
960 }
961
962 if (X->s > 0 && Y->s < 0) {
963 return 1;
964 }
965 if (Y->s > 0 && X->s < 0) {
966 return -1;
967 }
968
969 for (; i > 0; i--) {
970 if (X->p[i - 1] > Y->p[i - 1]) {
971 return X->s;
972 }
973 if (X->p[i - 1] < Y->p[i - 1]) {
974 return -X->s;
975 }
976 }
977
978 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000979}
980
Janos Follathee6abce2019-09-05 14:47:19 +0100981/*
Paul Bakker5121ce52009-01-03 21:22:43 +0000982 * Compare signed values
983 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100984int mbedtls_mpi_cmp_int(const mbedtls_mpi *X, mbedtls_mpi_sint z)
Paul Bakker5121ce52009-01-03 21:22:43 +0000985{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200986 mbedtls_mpi Y;
987 mbedtls_mpi_uint p[1];
Paul Bakker5121ce52009-01-03 21:22:43 +0000988
Gilles Peskine449bd832023-01-11 14:50:10 +0100989 *p = mpi_sint_abs(z);
Dave Rodgmanf3df1052023-08-09 18:55:41 +0100990 Y.s = TO_SIGN(z);
Paul Bakker5121ce52009-01-03 21:22:43 +0000991 Y.n = 1;
992 Y.p = p;
993
Gilles Peskine449bd832023-01-11 14:50:10 +0100994 return mbedtls_mpi_cmp_mpi(X, &Y);
Paul Bakker5121ce52009-01-03 21:22:43 +0000995}
996
997/*
998 * Unsigned addition: X = |A| + |B| (HAC 14.7)
999 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001000int mbedtls_mpi_add_abs(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B)
Paul Bakker5121ce52009-01-03 21:22:43 +00001001{
Janos Follath24eed8d2019-11-22 13:21:35 +00001002 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Tom Cosgroveaf7d44b2022-08-24 14:05:26 +01001003 size_t j;
Agathiyan Bragadeeshc99840a2023-07-12 11:15:46 +01001004 mbedtls_mpi_uint *p;
1005 mbedtls_mpi_uint c;
Paul Bakker5121ce52009-01-03 21:22:43 +00001006
Gilles Peskine449bd832023-01-11 14:50:10 +01001007 if (X == B) {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001008 const mbedtls_mpi *T = A; A = X; B = T;
Paul Bakker5121ce52009-01-03 21:22:43 +00001009 }
1010
Gilles Peskine449bd832023-01-11 14:50:10 +01001011 if (X != A) {
1012 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(X, A));
1013 }
Paul Bakker9af723c2014-05-01 13:03:14 +02001014
Paul Bakkerf7ca7b92009-06-20 10:31:06 +00001015 /*
Tom Cosgroveaf7d44b2022-08-24 14:05:26 +01001016 * X must always be positive as a result of unsigned additions.
Paul Bakkerf7ca7b92009-06-20 10:31:06 +00001017 */
1018 X->s = 1;
Paul Bakker5121ce52009-01-03 21:22:43 +00001019
Gilles Peskine449bd832023-01-11 14:50:10 +01001020 for (j = B->n; j > 0; j--) {
1021 if (B->p[j - 1] != 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00001022 break;
Gilles Peskine449bd832023-01-11 14:50:10 +01001023 }
1024 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001025
Gilles Peskinedb14a9d2022-11-15 22:59:00 +01001026 /* Exit early to avoid undefined behavior on NULL+0 when X->n == 0
1027 * and B is 0 (of any size). */
Gilles Peskine449bd832023-01-11 14:50:10 +01001028 if (j == 0) {
1029 return 0;
1030 }
Gilles Peskinedb14a9d2022-11-15 22:59:00 +01001031
Gilles Peskine449bd832023-01-11 14:50:10 +01001032 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, j));
Paul Bakker5121ce52009-01-03 21:22:43 +00001033
Tom Cosgroveaf7d44b2022-08-24 14:05:26 +01001034 /* j is the number of non-zero limbs of B. Add those to X. */
Paul Bakker5121ce52009-01-03 21:22:43 +00001035
Agathiyan Bragadeeshc99840a2023-07-12 11:15:46 +01001036 p = X->p;
Tom Cosgroveaf7d44b2022-08-24 14:05:26 +01001037
Agathiyan Bragadeeshc99840a2023-07-12 11:15:46 +01001038 c = mbedtls_mpi_core_add(p, p, B->p, j);
Tom Cosgroveaf7d44b2022-08-24 14:05:26 +01001039
1040 p += j;
1041
1042 /* Now propagate any carry */
Paul Bakker5121ce52009-01-03 21:22:43 +00001043
Gilles Peskine449bd832023-01-11 14:50:10 +01001044 while (c != 0) {
1045 if (j >= X->n) {
1046 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, j + 1));
Tom Cosgroveaf7d44b2022-08-24 14:05:26 +01001047 p = X->p + j;
Paul Bakker5121ce52009-01-03 21:22:43 +00001048 }
1049
Gilles Peskine449bd832023-01-11 14:50:10 +01001050 *p += c; c = (*p < c); j++; p++;
Paul Bakker5121ce52009-01-03 21:22:43 +00001051 }
1052
1053cleanup:
1054
Gilles Peskine449bd832023-01-11 14:50:10 +01001055 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001056}
1057
Paul Bakker5121ce52009-01-03 21:22:43 +00001058/*
Gilles Peskine0e5faf62020-06-08 22:50:35 +02001059 * Unsigned subtraction: X = |A| - |B| (HAC 14.9, 14.10)
Paul Bakker5121ce52009-01-03 21:22:43 +00001060 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001061int mbedtls_mpi_sub_abs(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B)
Paul Bakker5121ce52009-01-03 21:22:43 +00001062{
Janos Follath24eed8d2019-11-22 13:21:35 +00001063 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker23986e52011-04-24 08:57:21 +00001064 size_t n;
Gilles Peskine0e5faf62020-06-08 22:50:35 +02001065 mbedtls_mpi_uint carry;
Paul Bakker5121ce52009-01-03 21:22:43 +00001066
Gilles Peskine449bd832023-01-11 14:50:10 +01001067 for (n = B->n; n > 0; n--) {
1068 if (B->p[n - 1] != 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00001069 break;
Gilles Peskine449bd832023-01-11 14:50:10 +01001070 }
1071 }
1072 if (n > A->n) {
Gilles Peskinec8a91772021-01-27 22:30:43 +01001073 /* B >= (2^ciL)^n > A */
1074 ret = MBEDTLS_ERR_MPI_NEGATIVE_VALUE;
1075 goto cleanup;
1076 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001077
Gilles Peskine449bd832023-01-11 14:50:10 +01001078 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, A->n));
Gilles Peskine1acf7cb2020-07-23 01:03:22 +02001079
1080 /* Set the high limbs of X to match A. Don't touch the lower limbs
1081 * because X might be aliased to B, and we must not overwrite the
1082 * significant digits of B. */
Aaron M. Uckoaf67d2c2023-01-17 11:52:22 -05001083 if (A->n > n && A != X) {
Gilles Peskine449bd832023-01-11 14:50:10 +01001084 memcpy(X->p + n, A->p + n, (A->n - n) * ciL);
1085 }
1086 if (X->n > A->n) {
1087 memset(X->p + A->n, 0, (X->n - A->n) * ciL);
1088 }
Gilles Peskine1acf7cb2020-07-23 01:03:22 +02001089
Gilles Peskine449bd832023-01-11 14:50:10 +01001090 carry = mbedtls_mpi_core_sub(X->p, A->p, B->p, n);
1091 if (carry != 0) {
Tom Cosgrove452c99c2022-08-25 10:07:07 +01001092 /* Propagate the carry through the rest of X. */
Gilles Peskine449bd832023-01-11 14:50:10 +01001093 carry = mbedtls_mpi_core_sub_int(X->p + n, X->p + n, carry, X->n - n);
Tom Cosgrove452c99c2022-08-25 10:07:07 +01001094
1095 /* If we have further carry/borrow, the result is negative. */
Gilles Peskine449bd832023-01-11 14:50:10 +01001096 if (carry != 0) {
Gilles Peskine89b41302020-07-23 01:16:46 +02001097 ret = MBEDTLS_ERR_MPI_NEGATIVE_VALUE;
1098 goto cleanup;
1099 }
Gilles Peskinec097e9e2020-06-08 21:58:22 +02001100 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001101
Gilles Peskine1acf7cb2020-07-23 01:03:22 +02001102 /* X should always be positive as a result of unsigned subtractions. */
1103 X->s = 1;
1104
Paul Bakker5121ce52009-01-03 21:22:43 +00001105cleanup:
Gilles Peskine449bd832023-01-11 14:50:10 +01001106 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001107}
1108
Gilles Peskine72ee1e32022-11-09 21:34:09 +01001109/* Common function for signed addition and subtraction.
1110 * Calculate A + B * flip_B where flip_B is 1 or -1.
Paul Bakker5121ce52009-01-03 21:22:43 +00001111 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001112static int add_sub_mpi(mbedtls_mpi *X,
1113 const mbedtls_mpi *A, const mbedtls_mpi *B,
1114 int flip_B)
Paul Bakker5121ce52009-01-03 21:22:43 +00001115{
Hanno Becker73d7d792018-12-11 10:35:51 +00001116 int ret, s;
Paul Bakker5121ce52009-01-03 21:22:43 +00001117
Hanno Becker73d7d792018-12-11 10:35:51 +00001118 s = A->s;
Gilles Peskine449bd832023-01-11 14:50:10 +01001119 if (A->s * B->s * flip_B < 0) {
1120 int cmp = mbedtls_mpi_cmp_abs(A, B);
1121 if (cmp >= 0) {
1122 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_abs(X, A, B));
Gilles Peskine4a768dd2022-11-09 22:02:16 +01001123 /* If |A| = |B|, the result is 0 and we must set the sign bit
1124 * to +1 regardless of which of A or B was negative. Otherwise,
1125 * since |A| > |B|, the sign is the sign of A. */
1126 X->s = cmp == 0 ? 1 : s;
Gilles Peskine449bd832023-01-11 14:50:10 +01001127 } else {
1128 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_abs(X, B, A));
Gilles Peskine4a768dd2022-11-09 22:02:16 +01001129 /* Since |A| < |B|, the sign is the opposite of A. */
Paul Bakker5121ce52009-01-03 21:22:43 +00001130 X->s = -s;
1131 }
Gilles Peskine449bd832023-01-11 14:50:10 +01001132 } else {
1133 MBEDTLS_MPI_CHK(mbedtls_mpi_add_abs(X, A, B));
Paul Bakker5121ce52009-01-03 21:22:43 +00001134 X->s = s;
1135 }
1136
1137cleanup:
1138
Gilles Peskine449bd832023-01-11 14:50:10 +01001139 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001140}
1141
1142/*
Gilles Peskine72ee1e32022-11-09 21:34:09 +01001143 * Signed addition: X = A + B
1144 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001145int mbedtls_mpi_add_mpi(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B)
Gilles Peskine72ee1e32022-11-09 21:34:09 +01001146{
Gilles Peskine449bd832023-01-11 14:50:10 +01001147 return add_sub_mpi(X, A, B, 1);
Gilles Peskine72ee1e32022-11-09 21:34:09 +01001148}
1149
1150/*
Paul Bakker60b1d102013-10-29 10:02:51 +01001151 * Signed subtraction: X = A - B
Paul Bakker5121ce52009-01-03 21:22:43 +00001152 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001153int mbedtls_mpi_sub_mpi(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B)
Paul Bakker5121ce52009-01-03 21:22:43 +00001154{
Gilles Peskine449bd832023-01-11 14:50:10 +01001155 return add_sub_mpi(X, A, B, -1);
Paul Bakker5121ce52009-01-03 21:22:43 +00001156}
1157
1158/*
1159 * Signed addition: X = A + b
1160 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001161int mbedtls_mpi_add_int(mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b)
Paul Bakker5121ce52009-01-03 21:22:43 +00001162{
Yuto Takano36c8ddc2021-07-05 09:10:52 +01001163 mbedtls_mpi B;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001164 mbedtls_mpi_uint p[1];
Paul Bakker5121ce52009-01-03 21:22:43 +00001165
Gilles Peskine449bd832023-01-11 14:50:10 +01001166 p[0] = mpi_sint_abs(b);
Dave Rodgmanf3df1052023-08-09 18:55:41 +01001167 B.s = TO_SIGN(b);
Yuto Takano36c8ddc2021-07-05 09:10:52 +01001168 B.n = 1;
1169 B.p = p;
Paul Bakker5121ce52009-01-03 21:22:43 +00001170
Gilles Peskine449bd832023-01-11 14:50:10 +01001171 return mbedtls_mpi_add_mpi(X, A, &B);
Paul Bakker5121ce52009-01-03 21:22:43 +00001172}
1173
1174/*
Paul Bakker60b1d102013-10-29 10:02:51 +01001175 * Signed subtraction: X = A - b
Paul Bakker5121ce52009-01-03 21:22:43 +00001176 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001177int mbedtls_mpi_sub_int(mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b)
Paul Bakker5121ce52009-01-03 21:22:43 +00001178{
Yuto Takano36c8ddc2021-07-05 09:10:52 +01001179 mbedtls_mpi B;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001180 mbedtls_mpi_uint p[1];
Paul Bakker5121ce52009-01-03 21:22:43 +00001181
Gilles Peskine449bd832023-01-11 14:50:10 +01001182 p[0] = mpi_sint_abs(b);
Dave Rodgmanf3df1052023-08-09 18:55:41 +01001183 B.s = TO_SIGN(b);
Yuto Takano36c8ddc2021-07-05 09:10:52 +01001184 B.n = 1;
1185 B.p = p;
Paul Bakker5121ce52009-01-03 21:22:43 +00001186
Gilles Peskine449bd832023-01-11 14:50:10 +01001187 return mbedtls_mpi_sub_mpi(X, A, &B);
Paul Bakker5121ce52009-01-03 21:22:43 +00001188}
1189
Paul Bakker5121ce52009-01-03 21:22:43 +00001190/*
1191 * Baseline multiplication: X = A * B (HAC 14.12)
1192 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001193int mbedtls_mpi_mul_mpi(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B)
Paul Bakker5121ce52009-01-03 21:22:43 +00001194{
Janos Follath24eed8d2019-11-22 13:21:35 +00001195 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Hanno Becker1772e052022-04-13 06:51:40 +01001196 size_t i, j;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001197 mbedtls_mpi TA, TB;
Hanno Beckerda763de2022-04-13 06:50:02 +01001198 int result_is_zero = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +00001199
Tom Cosgrove6af26f32022-08-24 16:40:55 +01001200 mbedtls_mpi_init(&TA);
1201 mbedtls_mpi_init(&TB);
Paul Bakker5121ce52009-01-03 21:22:43 +00001202
Gilles Peskine449bd832023-01-11 14:50:10 +01001203 if (X == A) {
1204 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TA, A)); A = &TA;
1205 }
1206 if (X == B) {
1207 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TB, B)); B = &TB;
1208 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001209
Gilles Peskine449bd832023-01-11 14:50:10 +01001210 for (i = A->n; i > 0; i--) {
1211 if (A->p[i - 1] != 0) {
Hanno Beckerda763de2022-04-13 06:50:02 +01001212 break;
Gilles Peskine449bd832023-01-11 14:50:10 +01001213 }
1214 }
1215 if (i == 0) {
Hanno Beckerda763de2022-04-13 06:50:02 +01001216 result_is_zero = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +01001217 }
Hanno Beckerda763de2022-04-13 06:50:02 +01001218
Gilles Peskine449bd832023-01-11 14:50:10 +01001219 for (j = B->n; j > 0; j--) {
1220 if (B->p[j - 1] != 0) {
Hanno Beckerda763de2022-04-13 06:50:02 +01001221 break;
Gilles Peskine449bd832023-01-11 14:50:10 +01001222 }
1223 }
1224 if (j == 0) {
Hanno Beckerda763de2022-04-13 06:50:02 +01001225 result_is_zero = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +01001226 }
Hanno Beckerda763de2022-04-13 06:50:02 +01001227
Gilles Peskine449bd832023-01-11 14:50:10 +01001228 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, i + j));
1229 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(X, 0));
Paul Bakker5121ce52009-01-03 21:22:43 +00001230
Tom Cosgrove6af26f32022-08-24 16:40:55 +01001231 mbedtls_mpi_core_mul(X->p, A->p, i, B->p, j);
Paul Bakker5121ce52009-01-03 21:22:43 +00001232
Hanno Beckerda763de2022-04-13 06:50:02 +01001233 /* If the result is 0, we don't shortcut the operation, which reduces
1234 * but does not eliminate side channels leaking the zero-ness. We do
1235 * need to take care to set the sign bit properly since the library does
1236 * not fully support an MPI object with a value of 0 and s == -1. */
Gilles Peskine449bd832023-01-11 14:50:10 +01001237 if (result_is_zero) {
Hanno Beckerda763de2022-04-13 06:50:02 +01001238 X->s = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +01001239 } else {
Hanno Beckerda763de2022-04-13 06:50:02 +01001240 X->s = A->s * B->s;
Gilles Peskine449bd832023-01-11 14:50:10 +01001241 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001242
1243cleanup:
1244
Gilles Peskine449bd832023-01-11 14:50:10 +01001245 mbedtls_mpi_free(&TB); mbedtls_mpi_free(&TA);
Paul Bakker5121ce52009-01-03 21:22:43 +00001246
Gilles Peskine449bd832023-01-11 14:50:10 +01001247 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001248}
1249
1250/*
1251 * Baseline multiplication: X = A * b
1252 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001253int mbedtls_mpi_mul_int(mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_uint b)
Paul Bakker5121ce52009-01-03 21:22:43 +00001254{
Hanno Becker35771312022-04-14 11:52:11 +01001255 size_t n = A->n;
Gilles Peskine449bd832023-01-11 14:50:10 +01001256 while (n > 0 && A->p[n - 1] == 0) {
Hanno Becker35771312022-04-14 11:52:11 +01001257 --n;
Gilles Peskine449bd832023-01-11 14:50:10 +01001258 }
Hanno Becker35771312022-04-14 11:52:11 +01001259
Hanno Becker74a11a32022-04-06 06:27:00 +01001260 /* The general method below doesn't work if b==0. */
Gilles Peskine449bd832023-01-11 14:50:10 +01001261 if (b == 0 || n == 0) {
1262 return mbedtls_mpi_lset(X, 0);
1263 }
Gilles Peskine8fd95c62020-07-23 21:58:50 +02001264
Hanno Beckeraef9cc42022-04-11 06:36:29 +01001265 /* Calculate A*b as A + A*(b-1) to take advantage of mbedtls_mpi_core_mla */
Gilles Peskine8fd95c62020-07-23 21:58:50 +02001266 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Gilles Peskinecd0dbf32020-07-24 00:09:04 +02001267 /* In general, A * b requires 1 limb more than b. If
1268 * A->p[n - 1] * b / b == A->p[n - 1], then A * b fits in the same
1269 * number of limbs as A and the call to grow() is not required since
Gilles Peskinee1bba7c2021-03-10 23:44:10 +01001270 * copy() will take care of the growth if needed. However, experimentally,
1271 * making the call to grow() unconditional causes slightly fewer
Gilles Peskinecd0dbf32020-07-24 00:09:04 +02001272 * calls to calloc() in ECP code, presumably because it reuses the
1273 * same mpi for a while and this way the mpi is more likely to directly
Hanno Becker9137b9c2022-04-12 10:51:54 +01001274 * grow to its final size.
1275 *
1276 * Note that calculating A*b as 0 + A*b doesn't work as-is because
1277 * A,X can be the same. */
Gilles Peskine449bd832023-01-11 14:50:10 +01001278 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, n + 1));
1279 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(X, A));
1280 mbedtls_mpi_core_mla(X->p, X->n, A->p, n, b - 1);
Gilles Peskine8fd95c62020-07-23 21:58:50 +02001281
1282cleanup:
Gilles Peskine449bd832023-01-11 14:50:10 +01001283 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001284}
1285
1286/*
Simon Butcherf5ba0452015-12-27 23:01:55 +00001287 * Unsigned integer divide - double mbedtls_mpi_uint dividend, u1/u0, and
1288 * mbedtls_mpi_uint divisor, d
Simon Butcher15b15d12015-11-26 19:35:03 +00001289 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001290static mbedtls_mpi_uint mbedtls_int_div_int(mbedtls_mpi_uint u1,
1291 mbedtls_mpi_uint u0,
1292 mbedtls_mpi_uint d,
1293 mbedtls_mpi_uint *r)
Simon Butcher15b15d12015-11-26 19:35:03 +00001294{
Manuel Pégourié-Gonnard16308882015-12-01 10:27:00 +01001295#if defined(MBEDTLS_HAVE_UDBL)
1296 mbedtls_t_udbl dividend, quotient;
Simon Butcherf5ba0452015-12-27 23:01:55 +00001297#else
Simon Butcher9803d072016-01-03 00:24:34 +00001298 const mbedtls_mpi_uint radix = (mbedtls_mpi_uint) 1 << biH;
Gilles Peskine449bd832023-01-11 14:50:10 +01001299 const mbedtls_mpi_uint uint_halfword_mask = ((mbedtls_mpi_uint) 1 << biH) - 1;
Simon Butcherf5ba0452015-12-27 23:01:55 +00001300 mbedtls_mpi_uint d0, d1, q0, q1, rAX, r0, quotient;
1301 mbedtls_mpi_uint u0_msw, u0_lsw;
Simon Butcher9803d072016-01-03 00:24:34 +00001302 size_t s;
Manuel Pégourié-Gonnard16308882015-12-01 10:27:00 +01001303#endif
1304
Simon Butcher15b15d12015-11-26 19:35:03 +00001305 /*
1306 * Check for overflow
1307 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001308 if (0 == d || u1 >= d) {
1309 if (r != NULL) {
1310 *r = ~(mbedtls_mpi_uint) 0u;
1311 }
Simon Butcher15b15d12015-11-26 19:35:03 +00001312
Gilles Peskine449bd832023-01-11 14:50:10 +01001313 return ~(mbedtls_mpi_uint) 0u;
Simon Butcher15b15d12015-11-26 19:35:03 +00001314 }
1315
1316#if defined(MBEDTLS_HAVE_UDBL)
Simon Butcher15b15d12015-11-26 19:35:03 +00001317 dividend = (mbedtls_t_udbl) u1 << biL;
1318 dividend |= (mbedtls_t_udbl) u0;
1319 quotient = dividend / d;
Gilles Peskine449bd832023-01-11 14:50:10 +01001320 if (quotient > ((mbedtls_t_udbl) 1 << biL) - 1) {
1321 quotient = ((mbedtls_t_udbl) 1 << biL) - 1;
1322 }
Simon Butcher15b15d12015-11-26 19:35:03 +00001323
Gilles Peskine449bd832023-01-11 14:50:10 +01001324 if (r != NULL) {
1325 *r = (mbedtls_mpi_uint) (dividend - (quotient * d));
1326 }
Simon Butcher15b15d12015-11-26 19:35:03 +00001327
1328 return (mbedtls_mpi_uint) quotient;
1329#else
Simon Butcher15b15d12015-11-26 19:35:03 +00001330
1331 /*
1332 * Algorithm D, Section 4.3.1 - The Art of Computer Programming
1333 * Vol. 2 - Seminumerical Algorithms, Knuth
1334 */
1335
1336 /*
1337 * Normalize the divisor, d, and dividend, u0, u1
1338 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001339 s = mbedtls_mpi_core_clz(d);
Simon Butcher15b15d12015-11-26 19:35:03 +00001340 d = d << s;
1341
1342 u1 = u1 << s;
Gilles Peskine449bd832023-01-11 14:50:10 +01001343 u1 |= (u0 >> (biL - s)) & (-(mbedtls_mpi_sint) s >> (biL - 1));
Simon Butcher15b15d12015-11-26 19:35:03 +00001344 u0 = u0 << s;
1345
1346 d1 = d >> biH;
Simon Butcher9803d072016-01-03 00:24:34 +00001347 d0 = d & uint_halfword_mask;
Simon Butcher15b15d12015-11-26 19:35:03 +00001348
1349 u0_msw = u0 >> biH;
Simon Butcher9803d072016-01-03 00:24:34 +00001350 u0_lsw = u0 & uint_halfword_mask;
Simon Butcher15b15d12015-11-26 19:35:03 +00001351
1352 /*
1353 * Find the first quotient and remainder
1354 */
1355 q1 = u1 / d1;
1356 r0 = u1 - d1 * q1;
1357
Gilles Peskine449bd832023-01-11 14:50:10 +01001358 while (q1 >= radix || (q1 * d0 > radix * r0 + u0_msw)) {
Simon Butcher15b15d12015-11-26 19:35:03 +00001359 q1 -= 1;
1360 r0 += d1;
1361
Gilles Peskine449bd832023-01-11 14:50:10 +01001362 if (r0 >= radix) {
1363 break;
1364 }
Simon Butcher15b15d12015-11-26 19:35:03 +00001365 }
1366
Gilles Peskine449bd832023-01-11 14:50:10 +01001367 rAX = (u1 * radix) + (u0_msw - q1 * d);
Simon Butcher15b15d12015-11-26 19:35:03 +00001368 q0 = rAX / d1;
1369 r0 = rAX - q0 * d1;
1370
Gilles Peskine449bd832023-01-11 14:50:10 +01001371 while (q0 >= radix || (q0 * d0 > radix * r0 + u0_lsw)) {
Simon Butcher15b15d12015-11-26 19:35:03 +00001372 q0 -= 1;
1373 r0 += d1;
1374
Gilles Peskine449bd832023-01-11 14:50:10 +01001375 if (r0 >= radix) {
1376 break;
1377 }
Simon Butcher15b15d12015-11-26 19:35:03 +00001378 }
1379
Gilles Peskine449bd832023-01-11 14:50:10 +01001380 if (r != NULL) {
1381 *r = (rAX * radix + u0_lsw - q0 * d) >> s;
1382 }
Simon Butcher15b15d12015-11-26 19:35:03 +00001383
1384 quotient = q1 * radix + q0;
1385
1386 return quotient;
1387#endif
1388}
1389
1390/*
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001391 * Division by mbedtls_mpi: A = Q * B + R (HAC 14.20)
Paul Bakker5121ce52009-01-03 21:22:43 +00001392 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001393int mbedtls_mpi_div_mpi(mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A,
1394 const mbedtls_mpi *B)
Paul Bakker5121ce52009-01-03 21:22:43 +00001395{
Janos Follath24eed8d2019-11-22 13:21:35 +00001396 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker23986e52011-04-24 08:57:21 +00001397 size_t i, n, t, k;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001398 mbedtls_mpi X, Y, Z, T1, T2;
Alexander Kd19a1932019-11-01 18:20:42 +03001399 mbedtls_mpi_uint TP2[3];
Paul Bakker5121ce52009-01-03 21:22:43 +00001400
Gilles Peskine449bd832023-01-11 14:50:10 +01001401 if (mbedtls_mpi_cmp_int(B, 0) == 0) {
1402 return MBEDTLS_ERR_MPI_DIVISION_BY_ZERO;
1403 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001404
Gilles Peskine449bd832023-01-11 14:50:10 +01001405 mbedtls_mpi_init(&X); mbedtls_mpi_init(&Y); mbedtls_mpi_init(&Z);
1406 mbedtls_mpi_init(&T1);
Alexander Kd19a1932019-11-01 18:20:42 +03001407 /*
1408 * Avoid dynamic memory allocations for constant-size T2.
1409 *
1410 * T2 is used for comparison only and the 3 limbs are assigned explicitly,
1411 * so nobody increase the size of the MPI and we're safe to use an on-stack
1412 * buffer.
1413 */
Alexander K35d6d462019-10-31 14:46:45 +03001414 T2.s = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +01001415 T2.n = sizeof(TP2) / sizeof(*TP2);
Alexander Kd19a1932019-11-01 18:20:42 +03001416 T2.p = TP2;
Paul Bakker5121ce52009-01-03 21:22:43 +00001417
Gilles Peskine449bd832023-01-11 14:50:10 +01001418 if (mbedtls_mpi_cmp_abs(A, B) < 0) {
1419 if (Q != NULL) {
1420 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(Q, 0));
1421 }
1422 if (R != NULL) {
1423 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(R, A));
1424 }
1425 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +00001426 }
1427
Gilles Peskine449bd832023-01-11 14:50:10 +01001428 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&X, A));
1429 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&Y, B));
Paul Bakker5121ce52009-01-03 21:22:43 +00001430 X.s = Y.s = 1;
1431
Gilles Peskine449bd832023-01-11 14:50:10 +01001432 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(&Z, A->n + 2));
1433 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&Z, 0));
1434 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(&T1, A->n + 2));
Paul Bakker5121ce52009-01-03 21:22:43 +00001435
Gilles Peskine449bd832023-01-11 14:50:10 +01001436 k = mbedtls_mpi_bitlen(&Y) % biL;
1437 if (k < biL - 1) {
Paul Bakker5121ce52009-01-03 21:22:43 +00001438 k = biL - 1 - k;
Gilles Peskine449bd832023-01-11 14:50:10 +01001439 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&X, k));
1440 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&Y, k));
1441 } else {
1442 k = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +00001443 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001444
1445 n = X.n - 1;
1446 t = Y.n - 1;
Gilles Peskine449bd832023-01-11 14:50:10 +01001447 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&Y, biL * (n - t)));
Paul Bakker5121ce52009-01-03 21:22:43 +00001448
Gilles Peskine449bd832023-01-11 14:50:10 +01001449 while (mbedtls_mpi_cmp_mpi(&X, &Y) >= 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00001450 Z.p[n - t]++;
Gilles Peskine449bd832023-01-11 14:50:10 +01001451 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&X, &X, &Y));
Paul Bakker5121ce52009-01-03 21:22:43 +00001452 }
Gilles Peskine449bd832023-01-11 14:50:10 +01001453 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&Y, biL * (n - t)));
Paul Bakker5121ce52009-01-03 21:22:43 +00001454
Gilles Peskine449bd832023-01-11 14:50:10 +01001455 for (i = n; i > t; i--) {
1456 if (X.p[i] >= Y.p[t]) {
1457 Z.p[i - t - 1] = ~(mbedtls_mpi_uint) 0u;
1458 } else {
1459 Z.p[i - t - 1] = mbedtls_int_div_int(X.p[i], X.p[i - 1],
1460 Y.p[t], NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +00001461 }
1462
Gilles Peskine449bd832023-01-11 14:50:10 +01001463 T2.p[0] = (i < 2) ? 0 : X.p[i - 2];
1464 T2.p[1] = (i < 1) ? 0 : X.p[i - 1];
Alexander K35d6d462019-10-31 14:46:45 +03001465 T2.p[2] = X.p[i];
1466
Paul Bakker5121ce52009-01-03 21:22:43 +00001467 Z.p[i - t - 1]++;
Gilles Peskine449bd832023-01-11 14:50:10 +01001468 do {
Paul Bakker5121ce52009-01-03 21:22:43 +00001469 Z.p[i - t - 1]--;
1470
Gilles Peskine449bd832023-01-11 14:50:10 +01001471 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&T1, 0));
1472 T1.p[0] = (t < 1) ? 0 : Y.p[t - 1];
Paul Bakker5121ce52009-01-03 21:22:43 +00001473 T1.p[1] = Y.p[t];
Gilles Peskine449bd832023-01-11 14:50:10 +01001474 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_int(&T1, &T1, Z.p[i - t - 1]));
1475 } while (mbedtls_mpi_cmp_mpi(&T1, &T2) > 0);
Paul Bakker5121ce52009-01-03 21:22:43 +00001476
Gilles Peskine449bd832023-01-11 14:50:10 +01001477 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_int(&T1, &Y, Z.p[i - t - 1]));
1478 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&T1, biL * (i - t - 1)));
1479 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&X, &X, &T1));
Paul Bakker5121ce52009-01-03 21:22:43 +00001480
Gilles Peskine449bd832023-01-11 14:50:10 +01001481 if (mbedtls_mpi_cmp_int(&X, 0) < 0) {
1482 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&T1, &Y));
1483 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&T1, biL * (i - t - 1)));
1484 MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&X, &X, &T1));
Paul Bakker5121ce52009-01-03 21:22:43 +00001485 Z.p[i - t - 1]--;
1486 }
1487 }
1488
Gilles Peskine449bd832023-01-11 14:50:10 +01001489 if (Q != NULL) {
1490 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(Q, &Z));
Paul Bakker5121ce52009-01-03 21:22:43 +00001491 Q->s = A->s * B->s;
1492 }
1493
Gilles Peskine449bd832023-01-11 14:50:10 +01001494 if (R != NULL) {
1495 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&X, k));
Paul Bakkerf02c5642012-11-13 10:25:21 +00001496 X.s = A->s;
Gilles Peskine449bd832023-01-11 14:50:10 +01001497 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(R, &X));
Paul Bakker5121ce52009-01-03 21:22:43 +00001498
Gilles Peskine449bd832023-01-11 14:50:10 +01001499 if (mbedtls_mpi_cmp_int(R, 0) == 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00001500 R->s = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +01001501 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001502 }
1503
1504cleanup:
1505
Gilles Peskine449bd832023-01-11 14:50:10 +01001506 mbedtls_mpi_free(&X); mbedtls_mpi_free(&Y); mbedtls_mpi_free(&Z);
1507 mbedtls_mpi_free(&T1);
1508 mbedtls_platform_zeroize(TP2, sizeof(TP2));
Paul Bakker5121ce52009-01-03 21:22:43 +00001509
Gilles Peskine449bd832023-01-11 14:50:10 +01001510 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001511}
1512
1513/*
1514 * Division by int: A = Q * b + R
Paul Bakker5121ce52009-01-03 21:22:43 +00001515 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001516int mbedtls_mpi_div_int(mbedtls_mpi *Q, mbedtls_mpi *R,
1517 const mbedtls_mpi *A,
1518 mbedtls_mpi_sint b)
Paul Bakker5121ce52009-01-03 21:22:43 +00001519{
Yuto Takano36c8ddc2021-07-05 09:10:52 +01001520 mbedtls_mpi B;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001521 mbedtls_mpi_uint p[1];
Paul Bakker5121ce52009-01-03 21:22:43 +00001522
Gilles Peskine449bd832023-01-11 14:50:10 +01001523 p[0] = mpi_sint_abs(b);
Dave Rodgmanf3df1052023-08-09 18:55:41 +01001524 B.s = TO_SIGN(b);
Yuto Takano36c8ddc2021-07-05 09:10:52 +01001525 B.n = 1;
1526 B.p = p;
Paul Bakker5121ce52009-01-03 21:22:43 +00001527
Gilles Peskine449bd832023-01-11 14:50:10 +01001528 return mbedtls_mpi_div_mpi(Q, R, A, &B);
Paul Bakker5121ce52009-01-03 21:22:43 +00001529}
1530
1531/*
1532 * Modulo: R = A mod B
1533 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001534int mbedtls_mpi_mod_mpi(mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B)
Paul Bakker5121ce52009-01-03 21:22:43 +00001535{
Janos Follath24eed8d2019-11-22 13:21:35 +00001536 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker5121ce52009-01-03 21:22:43 +00001537
Gilles Peskine449bd832023-01-11 14:50:10 +01001538 if (mbedtls_mpi_cmp_int(B, 0) < 0) {
1539 return MBEDTLS_ERR_MPI_NEGATIVE_VALUE;
1540 }
Paul Bakkerce40a6d2009-06-23 19:46:08 +00001541
Gilles Peskine449bd832023-01-11 14:50:10 +01001542 MBEDTLS_MPI_CHK(mbedtls_mpi_div_mpi(NULL, R, A, B));
Paul Bakker5121ce52009-01-03 21:22:43 +00001543
Gilles Peskine449bd832023-01-11 14:50:10 +01001544 while (mbedtls_mpi_cmp_int(R, 0) < 0) {
1545 MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(R, R, B));
1546 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001547
Gilles Peskine449bd832023-01-11 14:50:10 +01001548 while (mbedtls_mpi_cmp_mpi(R, B) >= 0) {
1549 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(R, R, B));
1550 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001551
1552cleanup:
1553
Gilles Peskine449bd832023-01-11 14:50:10 +01001554 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001555}
1556
1557/*
1558 * Modulo: r = A mod b
1559 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001560int mbedtls_mpi_mod_int(mbedtls_mpi_uint *r, const mbedtls_mpi *A, mbedtls_mpi_sint b)
Paul Bakker5121ce52009-01-03 21:22:43 +00001561{
Paul Bakker23986e52011-04-24 08:57:21 +00001562 size_t i;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001563 mbedtls_mpi_uint x, y, z;
Paul Bakker5121ce52009-01-03 21:22:43 +00001564
Gilles Peskine449bd832023-01-11 14:50:10 +01001565 if (b == 0) {
1566 return MBEDTLS_ERR_MPI_DIVISION_BY_ZERO;
1567 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001568
Gilles Peskine449bd832023-01-11 14:50:10 +01001569 if (b < 0) {
1570 return MBEDTLS_ERR_MPI_NEGATIVE_VALUE;
1571 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001572
1573 /*
1574 * handle trivial cases
1575 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001576 if (b == 1 || A->n == 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00001577 *r = 0;
Gilles Peskine449bd832023-01-11 14:50:10 +01001578 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +00001579 }
1580
Gilles Peskine449bd832023-01-11 14:50:10 +01001581 if (b == 2) {
Paul Bakker5121ce52009-01-03 21:22:43 +00001582 *r = A->p[0] & 1;
Gilles Peskine449bd832023-01-11 14:50:10 +01001583 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +00001584 }
1585
1586 /*
1587 * general case
1588 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001589 for (i = A->n, y = 0; i > 0; i--) {
Paul Bakker23986e52011-04-24 08:57:21 +00001590 x = A->p[i - 1];
Gilles Peskine449bd832023-01-11 14:50:10 +01001591 y = (y << biH) | (x >> biH);
Paul Bakker5121ce52009-01-03 21:22:43 +00001592 z = y / b;
1593 y -= z * b;
1594
1595 x <<= biH;
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
Paul Bakkerce40a6d2009-06-23 19:46:08 +00001601 /*
1602 * If A is negative, then the current y represents a negative value.
1603 * Flipping it to the positive side.
1604 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001605 if (A->s < 0 && y != 0) {
Paul Bakkerce40a6d2009-06-23 19:46:08 +00001606 y = b - y;
Gilles Peskine449bd832023-01-11 14:50:10 +01001607 }
Paul Bakkerce40a6d2009-06-23 19:46:08 +00001608
Paul Bakker5121ce52009-01-03 21:22:43 +00001609 *r = y;
1610
Gilles Peskine449bd832023-01-11 14:50:10 +01001611 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +00001612}
1613
Janos Follath38ff70e2024-08-12 18:20:59 +01001614/*
1615 * Warning! If the parameter E_public has MBEDTLS_MPI_IS_PUBLIC as its value,
1616 * this function is not constant time with respect to the exponent (parameter E).
1617 */
1618static int mbedtls_mpi_exp_mod_optionally_safe(mbedtls_mpi *X, const mbedtls_mpi *A,
Janos Follatha5fc8f32024-08-12 20:11:06 +01001619 const mbedtls_mpi *E, int E_public,
1620 const mbedtls_mpi *N, mbedtls_mpi *prec_RR)
Paul Bakker5121ce52009-01-03 21:22:43 +00001621{
Janos Follath24eed8d2019-11-22 13:21:35 +00001622 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker5121ce52009-01-03 21:22:43 +00001623
Gilles Peskine449bd832023-01-11 14:50:10 +01001624 if (mbedtls_mpi_cmp_int(N, 0) <= 0 || (N->p[0] & 1) == 0) {
1625 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
1626 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001627
Gilles Peskine449bd832023-01-11 14:50:10 +01001628 if (mbedtls_mpi_cmp_int(E, 0) < 0) {
1629 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
1630 }
Paul Bakkerf6198c12012-05-16 08:02:29 +00001631
Gilles Peskine449bd832023-01-11 14:50:10 +01001632 if (mbedtls_mpi_bitlen(E) > MBEDTLS_MPI_MAX_BITS ||
1633 mbedtls_mpi_bitlen(N) > MBEDTLS_MPI_MAX_BITS) {
1634 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
1635 }
Chris Jones9246d042020-11-25 15:12:39 +00001636
Janos Follath583f0472024-02-19 11:16:44 +00001637 /*
1638 * Ensure that the exponent that we are passing to the core is not NULL.
1639 */
1640 if (E->n == 0) {
1641 ret = mbedtls_mpi_lset(X, 1);
1642 return ret;
1643 }
1644
Janos Follath424c2652024-02-21 09:26:36 +00001645 /*
1646 * Allocate working memory for mbedtls_mpi_core_exp_mod()
1647 */
1648 size_t T_limbs = mbedtls_mpi_core_exp_mod_working_limbs(N->n, E->n);
Janos Follath09025722024-02-21 11:50:25 +00001649 mbedtls_mpi_uint *T = (mbedtls_mpi_uint *) mbedtls_calloc(T_limbs, sizeof(mbedtls_mpi_uint));
Janos Follath424c2652024-02-21 09:26:36 +00001650 if (T == NULL) {
1651 return MBEDTLS_ERR_MPI_ALLOC_FAILED;
1652 }
1653
Janos Follath701ae1d2024-02-19 10:56:54 +00001654 mbedtls_mpi RR;
Janos Follath1ba40582024-02-13 12:36:13 +00001655 mbedtls_mpi_init(&RR);
Paul Bakker50546922012-05-19 08:40:49 +00001656
1657 /*
Paul Bakker5121ce52009-01-03 21:22:43 +00001658 * If 1st call, pre-compute R^2 mod N
1659 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001660 if (prec_RR == NULL || prec_RR->p == NULL) {
Janos Follath1ba40582024-02-13 12:36:13 +00001661 MBEDTLS_MPI_CHK(mbedtls_mpi_core_get_mont_r2_unsafe(&RR, N));
Paul Bakker5121ce52009-01-03 21:22:43 +00001662
Gilles Peskine449bd832023-01-11 14:50:10 +01001663 if (prec_RR != NULL) {
Janos Follath576087d2024-02-19 11:05:01 +00001664 *prec_RR = RR;
Gilles Peskine449bd832023-01-11 14:50:10 +01001665 }
1666 } else {
Janos Follath0512d172024-02-20 14:30:46 +00001667 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(prec_RR, N->n));
Janos Follath576087d2024-02-19 11:05:01 +00001668 RR = *prec_RR;
Paul Bakker5121ce52009-01-03 21:22:43 +00001669 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001670
1671 /*
Janos Follath1ba40582024-02-13 12:36:13 +00001672 * To preserve constness we need to make a copy of A. Using X for this to
1673 * save memory.
Paul Bakker5121ce52009-01-03 21:22:43 +00001674 */
Janos Follath1ba40582024-02-13 12:36:13 +00001675 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(X, A));
Paul Bakker5121ce52009-01-03 21:22:43 +00001676
1677 /*
Janos Follath1ba40582024-02-13 12:36:13 +00001678 * Compensate for negative A (and correct at the end).
Paul Bakker5121ce52009-01-03 21:22:43 +00001679 */
Janos Follath1ba40582024-02-13 12:36:13 +00001680 X->s = 1;
Paul Bakkerf6198c12012-05-16 08:02:29 +00001681
Janos Follath8e7d6a02022-10-04 13:27:40 +01001682 /*
Janos Follath467a5492024-02-19 11:27:38 +00001683 * Make sure that X is in a form that is safe for consumption by
1684 * the core functions.
1685 *
1686 * - The core functions will not touch the limbs of X above N->n. The
1687 * result will be correct if those limbs are 0, which the mod call
1688 * ensures.
1689 * - Also, X must have at least as many limbs as N for the calls to the
1690 * core functions.
Janos Follath8e7d6a02022-10-04 13:27:40 +01001691 */
Janos Follath1ba40582024-02-13 12:36:13 +00001692 if (mbedtls_mpi_cmp_mpi(X, N) >= 0) {
1693 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(X, X, N));
1694 }
1695 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, N->n));
1696
1697 /*
Janos Follath1ba40582024-02-13 12:36:13 +00001698 * Convert to and from Montgomery around mbedtls_mpi_core_exp_mod().
1699 */
Dave Rodgmand282e262024-03-11 15:28:48 +00001700 {
1701 mbedtls_mpi_uint mm = mbedtls_mpi_core_montmul_init(N->p);
1702 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 +01001703 if (E_public == MBEDTLS_MPI_IS_PUBLIC) {
1704 mbedtls_mpi_core_exp_mod_unsafe(X->p, X->p, N->p, N->n, E->p, E->n, RR.p, T);
1705 } else {
1706 mbedtls_mpi_core_exp_mod(X->p, X->p, N->p, N->n, E->p, E->n, RR.p, T);
1707 }
Dave Rodgmand282e262024-03-11 15:28:48 +00001708 mbedtls_mpi_core_from_mont_rep(X->p, X->p, N->p, N->n, mm, T);
1709 }
Janos Follath1ba40582024-02-13 12:36:13 +00001710
1711 /*
1712 * Correct for negative A.
1713 */
Janos Follath583f0472024-02-19 11:16:44 +00001714 if (A->s == -1 && (E->p[0] & 1) != 0) {
Janos Follath86258f52024-02-21 11:25:41 +00001715 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 +00001716 X->s = mbedtls_ct_mpi_sign_if(is_x_non_zero, -1, 1);
Janos Follath86258f52024-02-21 11:25:41 +00001717
Janos Follath1ba40582024-02-13 12:36:13 +00001718 MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(X, N, X));
1719 }
Janos Follath8e7d6a02022-10-04 13:27:40 +01001720
Paul Bakker5121ce52009-01-03 21:22:43 +00001721cleanup:
1722
Janos Follath424c2652024-02-21 09:26:36 +00001723 mbedtls_mpi_zeroize_and_free(T, T_limbs);
Paul Bakker6c591fa2011-05-05 11:49:20 +00001724
Gilles Peskine449bd832023-01-11 14:50:10 +01001725 if (prec_RR == NULL || prec_RR->p == NULL) {
1726 mbedtls_mpi_free(&RR);
1727 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001728
Gilles Peskine449bd832023-01-11 14:50:10 +01001729 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001730}
1731
Manuel Pégourié-Gonnard75ed5872024-06-18 12:52:45 +02001732int mbedtls_mpi_exp_mod(mbedtls_mpi *X, const mbedtls_mpi *A,
1733 const mbedtls_mpi *E, const mbedtls_mpi *N,
1734 mbedtls_mpi *prec_RR)
1735{
Janos Follatha5fc8f32024-08-12 20:11:06 +01001736 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 +02001737}
1738
Janos Follath38ff70e2024-08-12 18:20:59 +01001739int mbedtls_mpi_exp_mod_unsafe(mbedtls_mpi *X, const mbedtls_mpi *A,
1740 const mbedtls_mpi *E, const mbedtls_mpi *N,
1741 mbedtls_mpi *prec_RR)
1742{
Janos Follatha5fc8f32024-08-12 20:11:06 +01001743 return mbedtls_mpi_exp_mod_optionally_safe(X, A, E, MBEDTLS_MPI_IS_PUBLIC, N, prec_RR);
Janos Follath38ff70e2024-08-12 18:20:59 +01001744}
1745
Felix Conwaybd7ede32025-08-04 11:33:48 +01001746/* Constant-time GCD and/or modinv with odd modulus and A <= N */
1747int mbedtls_mpi_gcd_modinv_odd(mbedtls_mpi *G,
1748 mbedtls_mpi *I,
1749 const mbedtls_mpi *A,
1750 const mbedtls_mpi *N)
1751{
1752 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
1753 mbedtls_mpi local_g;
1754 mbedtls_mpi_uint *T = NULL;
1755 const size_t T_factor = I != NULL ? 5 : 4;
Felix Conwayeefdfe92025-08-05 14:35:53 +01001756 const mbedtls_mpi_uint zero = 0;
Felix Conwaybd7ede32025-08-04 11:33:48 +01001757
1758 /* Check requirements on A and N */
1759 if (mbedtls_mpi_cmp_int(A, 0) < 0 ||
1760 mbedtls_mpi_cmp_mpi(A, N) > 0 ||
1761 mbedtls_mpi_get_bit(N, 0) != 1 ||
1762 (I != NULL && mbedtls_mpi_cmp_int(N, 1) == 0)) {
1763 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
1764 }
1765
1766 /* Check aliasing requirements */
Felix Conwayd9c4c9c2025-08-05 14:33:32 +01001767 if (A == N || (I != NULL && (I == N || G == N))) {
Felix Conwaybd7ede32025-08-04 11:33:48 +01001768 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
1769 }
1770
1771 mbedtls_mpi_init(&local_g);
1772
1773 if (G == NULL) {
1774 G = &local_g;
1775 }
1776
Felix Conwaya1c95e32025-08-06 09:54:11 +01001777 /* We can't modify the values of G or I before use in the main function,
1778 * as they could be aliased to A or N. */
Felix Conwaybd7ede32025-08-04 11:33:48 +01001779 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(G, N->n));
Felix Conwaybd7ede32025-08-04 11:33:48 +01001780 if (I != NULL) {
1781 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(I, N->n));
Felix Conwaybd7ede32025-08-04 11:33:48 +01001782 }
1783
1784 T = mbedtls_calloc(sizeof(mbedtls_mpi_uint) * N->n, T_factor);
1785 if (T == NULL) {
1786 ret = MBEDTLS_ERR_MPI_ALLOC_FAILED;
1787 goto cleanup;
1788 }
1789
1790 mbedtls_mpi_uint *Ip = I != NULL ? I->p : NULL;
Felix Conwaya1c95e32025-08-06 09:54:11 +01001791 /* If A is 0 (null), then A->p would be null, and A->n would be 0,
1792 * which would be an issue if A->p and A->n were passed to
1793 * mbedtls_mpi_core_gcd_modinv_odd below. */
Felix Conwayeefdfe92025-08-05 14:35:53 +01001794 const mbedtls_mpi_uint *Ap = A->p != NULL ? A->p : &zero;
Felix Conwaya1c95e32025-08-06 09:54:11 +01001795 size_t An = A->n >= N->n ? N->n : A->p != NULL ? A->n : 1;
Felix Conwayeefdfe92025-08-05 14:35:53 +01001796 mbedtls_mpi_core_gcd_modinv_odd(G->p, Ip, Ap, An, N->p, N->n, T);
Felix Conwaybd7ede32025-08-04 11:33:48 +01001797
Felix Conwaya1c95e32025-08-06 09:54:11 +01001798 G->s = 1;
1799 if (I != NULL) {
1800 I->s = 1;
1801 }
1802
Felix Conwaybd7ede32025-08-04 11:33:48 +01001803 if (G->n > N->n) {
1804 memset(G->p + N->n, 0, ciL * (G->n - N->n));
1805 }
1806 if (I != NULL && I->n > N->n) {
1807 memset(I->p + N->n, 0, ciL * (I->n - N->n));
1808 }
1809
1810cleanup:
1811 mbedtls_mpi_free(&local_g);
1812 mbedtls_free(T);
1813 return ret;
1814}
1815
Paul Bakker5121ce52009-01-03 21:22:43 +00001816/*
1817 * Greatest common divisor: G = gcd(A, B) (HAC 14.54)
1818 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001819int mbedtls_mpi_gcd(mbedtls_mpi *G, const mbedtls_mpi *A, const mbedtls_mpi *B)
Paul Bakker5121ce52009-01-03 21:22:43 +00001820{
Janos Follath24eed8d2019-11-22 13:21:35 +00001821 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker23986e52011-04-24 08:57:21 +00001822 size_t lz, lzt;
Alexander Ke8ad49f2019-08-16 16:16:07 +03001823 mbedtls_mpi TA, TB;
Paul Bakker5121ce52009-01-03 21:22:43 +00001824
Gilles Peskine449bd832023-01-11 14:50:10 +01001825 mbedtls_mpi_init(&TA); mbedtls_mpi_init(&TB);
Paul Bakker5121ce52009-01-03 21:22:43 +00001826
Gilles Peskine449bd832023-01-11 14:50:10 +01001827 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TA, A));
1828 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TB, B));
Paul Bakker5121ce52009-01-03 21:22:43 +00001829
Gilles Peskine449bd832023-01-11 14:50:10 +01001830 lz = mbedtls_mpi_lsb(&TA);
1831 lzt = mbedtls_mpi_lsb(&TB);
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00001832
Gilles Peskine27253bc2021-06-09 13:26:43 +02001833 /* The loop below gives the correct result when A==0 but not when B==0.
1834 * So have a special case for B==0. Leverage the fact that we just
1835 * calculated the lsb and lsb(B)==0 iff B is odd or 0 to make the test
1836 * slightly more efficient than cmp_int(). */
Gilles Peskine449bd832023-01-11 14:50:10 +01001837 if (lzt == 0 && mbedtls_mpi_get_bit(&TB, 0) == 0) {
1838 ret = mbedtls_mpi_copy(G, A);
Gilles Peskine27253bc2021-06-09 13:26:43 +02001839 goto cleanup;
1840 }
1841
Gilles Peskine449bd832023-01-11 14:50:10 +01001842 if (lzt < lz) {
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00001843 lz = lzt;
Gilles Peskine449bd832023-01-11 14:50:10 +01001844 }
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00001845
Paul Bakker5121ce52009-01-03 21:22:43 +00001846 TA.s = TB.s = 1;
1847
Gilles Peskine2a63c5b2021-06-16 13:42:04 +02001848 /* We mostly follow the procedure described in HAC 14.54, but with some
1849 * minor differences:
1850 * - Sequences of multiplications or divisions by 2 are grouped into a
1851 * single shift operation.
Gilles Peskineb09c7ee2021-06-21 18:58:39 +02001852 * - The procedure in HAC assumes that 0 < TB <= TA.
1853 * - The condition TB <= TA is not actually necessary for correctness.
1854 * TA and TB have symmetric roles except for the loop termination
1855 * condition, and the shifts at the beginning of the loop body
1856 * remove any significance from the ordering of TA vs TB before
1857 * the shifts.
1858 * - If TA = 0, the loop goes through 0 iterations and the result is
1859 * correctly TB.
1860 * - The case TB = 0 was short-circuited above.
Gilles Peskine2a63c5b2021-06-16 13:42:04 +02001861 *
1862 * For the correctness proof below, decompose the original values of
1863 * A and B as
1864 * A = sa * 2^a * A' with A'=0 or A' odd, and sa = +-1
1865 * B = sb * 2^b * B' with B'=0 or B' odd, and sb = +-1
1866 * Then gcd(A, B) = 2^{min(a,b)} * gcd(A',B'),
1867 * and gcd(A',B') is odd or 0.
1868 *
1869 * At the beginning, we have TA = |A| and TB = |B| so gcd(A,B) = gcd(TA,TB).
1870 * The code maintains the following invariant:
1871 * gcd(A,B) = 2^k * gcd(TA,TB) for some k (I)
Gilles Peskine4df3f1f2021-06-15 22:09:39 +02001872 */
1873
Gilles Peskine2a63c5b2021-06-16 13:42:04 +02001874 /* Proof that the loop terminates:
1875 * At each iteration, either the right-shift by 1 is made on a nonzero
1876 * value and the nonnegative integer bitlen(TA) + bitlen(TB) decreases
1877 * by at least 1, or the right-shift by 1 is made on zero and then
1878 * TA becomes 0 which ends the loop (TB cannot be 0 if it is right-shifted
1879 * since in that case TB is calculated from TB-TA with the condition TB>TA).
1880 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001881 while (mbedtls_mpi_cmp_int(&TA, 0) != 0) {
Gilles Peskine2a63c5b2021-06-16 13:42:04 +02001882 /* Divisions by 2 preserve the invariant (I). */
Gilles Peskine449bd832023-01-11 14:50:10 +01001883 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TA, mbedtls_mpi_lsb(&TA)));
1884 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TB, mbedtls_mpi_lsb(&TB)));
Paul Bakker5121ce52009-01-03 21:22:43 +00001885
Gilles Peskine2a63c5b2021-06-16 13:42:04 +02001886 /* Set either TA or TB to |TA-TB|/2. Since TA and TB are both odd,
1887 * TA-TB is even so the division by 2 has an integer result.
1888 * Invariant (I) is preserved since any odd divisor of both TA and TB
1889 * also divides |TA-TB|/2, and any odd divisor of both TA and |TA-TB|/2
Shaun Case8b0ecbc2021-12-20 21:14:10 -08001890 * also divides TB, and any odd divisor of both TB and |TA-TB|/2 also
Gilles Peskine2a63c5b2021-06-16 13:42:04 +02001891 * divides TA.
1892 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001893 if (mbedtls_mpi_cmp_mpi(&TA, &TB) >= 0) {
1894 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_abs(&TA, &TA, &TB));
1895 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TA, 1));
1896 } else {
1897 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_abs(&TB, &TB, &TA));
1898 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TB, 1));
Paul Bakker5121ce52009-01-03 21:22:43 +00001899 }
Gilles Peskine2a63c5b2021-06-16 13:42:04 +02001900 /* Note that one of TA or TB is still odd. */
Paul Bakker5121ce52009-01-03 21:22:43 +00001901 }
1902
Gilles Peskine2a63c5b2021-06-16 13:42:04 +02001903 /* By invariant (I), gcd(A,B) = 2^k * gcd(TA,TB) for some k.
1904 * At the loop exit, TA = 0, so gcd(TA,TB) = TB.
1905 * - If there was at least one loop iteration, then one of TA or TB is odd,
1906 * and TA = 0, so TB is odd and gcd(TA,TB) = gcd(A',B'). In this case,
1907 * lz = min(a,b) so gcd(A,B) = 2^lz * TB.
1908 * - If there was no loop iteration, then A was 0, and gcd(A,B) = B.
Gilles Peskine4d3fd362021-06-21 11:40:38 +02001909 * In this case, lz = 0 and B = TB so gcd(A,B) = B = 2^lz * TB as well.
Gilles Peskine2a63c5b2021-06-16 13:42:04 +02001910 */
1911
Gilles Peskine449bd832023-01-11 14:50:10 +01001912 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&TB, lz));
1913 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(G, &TB));
Paul Bakker5121ce52009-01-03 21:22:43 +00001914
1915cleanup:
1916
Gilles Peskine449bd832023-01-11 14:50:10 +01001917 mbedtls_mpi_free(&TA); mbedtls_mpi_free(&TB);
Paul Bakker5121ce52009-01-03 21:22:43 +00001918
Gilles Peskine449bd832023-01-11 14:50:10 +01001919 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001920}
1921
Paul Bakker33dc46b2014-04-30 16:11:39 +02001922/*
1923 * Fill X with size bytes of random.
Gilles Peskine22cdd0c2022-10-27 20:15:13 +02001924 * The bytes returned from the RNG are used in a specific order which
1925 * is suitable for deterministic ECDSA (see the specification of
1926 * mbedtls_mpi_random() and the implementation in mbedtls_mpi_fill_random()).
Paul Bakker33dc46b2014-04-30 16:11:39 +02001927 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001928int mbedtls_mpi_fill_random(mbedtls_mpi *X, size_t size,
1929 int (*f_rng)(void *, unsigned char *, size_t),
1930 void *p_rng)
Paul Bakker287781a2011-03-26 13:18:49 +00001931{
Janos Follath24eed8d2019-11-22 13:21:35 +00001932 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Gilles Peskine449bd832023-01-11 14:50:10 +01001933 const size_t limbs = CHARS_TO_LIMBS(size);
Hanno Beckerda1655a2017-10-18 14:21:44 +01001934
Hanno Beckerda1655a2017-10-18 14:21:44 +01001935 /* Ensure that target MPI has exactly the necessary number of limbs */
Gilles Peskine449bd832023-01-11 14:50:10 +01001936 MBEDTLS_MPI_CHK(mbedtls_mpi_resize_clear(X, limbs));
1937 if (size == 0) {
1938 return 0;
1939 }
Paul Bakker287781a2011-03-26 13:18:49 +00001940
Gilles Peskine449bd832023-01-11 14:50:10 +01001941 ret = mbedtls_mpi_core_fill_random(X->p, X->n, size, f_rng, p_rng);
Paul Bakker287781a2011-03-26 13:18:49 +00001942
1943cleanup:
Gilles Peskine449bd832023-01-11 14:50:10 +01001944 return ret;
Paul Bakker287781a2011-03-26 13:18:49 +00001945}
1946
Gilles Peskine449bd832023-01-11 14:50:10 +01001947int mbedtls_mpi_random(mbedtls_mpi *X,
1948 mbedtls_mpi_sint min,
1949 const mbedtls_mpi *N,
1950 int (*f_rng)(void *, unsigned char *, size_t),
1951 void *p_rng)
Gilles Peskine02ac93a2021-03-29 22:02:55 +02001952{
Gilles Peskine449bd832023-01-11 14:50:10 +01001953 if (min < 0) {
1954 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
1955 }
1956 if (mbedtls_mpi_cmp_int(N, min) <= 0) {
1957 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
1958 }
Gilles Peskine1e918f42021-03-29 22:14:51 +02001959
Gilles Peskine1a7df4e2021-04-01 15:57:18 +02001960 /* Ensure that target MPI has exactly the same number of limbs
1961 * as the upper bound, even if the upper bound has leading zeros.
Gilles Peskine6b7ce962022-12-15 15:04:33 +01001962 * This is necessary for mbedtls_mpi_core_random. */
Gilles Peskine449bd832023-01-11 14:50:10 +01001963 int ret = mbedtls_mpi_resize_clear(X, N->n);
1964 if (ret != 0) {
1965 return ret;
1966 }
Gilles Peskine1a7df4e2021-04-01 15:57:18 +02001967
Gilles Peskine449bd832023-01-11 14:50:10 +01001968 return mbedtls_mpi_core_random(X->p, min, N->p, X->n, f_rng, p_rng);
Gilles Peskine02ac93a2021-03-29 22:02:55 +02001969}
1970
Paul Bakker5121ce52009-01-03 21:22:43 +00001971/*
1972 * Modular inverse: X = A^-1 mod N (HAC 14.61 / 14.64)
1973 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001974int mbedtls_mpi_inv_mod(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *N)
Paul Bakker5121ce52009-01-03 21:22:43 +00001975{
Janos Follath24eed8d2019-11-22 13:21:35 +00001976 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001977 mbedtls_mpi G, TA, TU, U1, U2, TB, TV, V1, V2;
Paul Bakker5121ce52009-01-03 21:22:43 +00001978
Gilles Peskine449bd832023-01-11 14:50:10 +01001979 if (mbedtls_mpi_cmp_int(N, 1) <= 0) {
1980 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
1981 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001982
Gilles Peskine449bd832023-01-11 14:50:10 +01001983 mbedtls_mpi_init(&TA); mbedtls_mpi_init(&TU); mbedtls_mpi_init(&U1); mbedtls_mpi_init(&U2);
1984 mbedtls_mpi_init(&G); mbedtls_mpi_init(&TB); mbedtls_mpi_init(&TV);
1985 mbedtls_mpi_init(&V1); mbedtls_mpi_init(&V2);
Paul Bakker5121ce52009-01-03 21:22:43 +00001986
Gilles Peskine449bd832023-01-11 14:50:10 +01001987 MBEDTLS_MPI_CHK(mbedtls_mpi_gcd(&G, A, N));
Paul Bakker5121ce52009-01-03 21:22:43 +00001988
Gilles Peskine449bd832023-01-11 14:50:10 +01001989 if (mbedtls_mpi_cmp_int(&G, 1) != 0) {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001990 ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
Paul Bakker5121ce52009-01-03 21:22:43 +00001991 goto cleanup;
1992 }
1993
Gilles Peskine449bd832023-01-11 14:50:10 +01001994 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&TA, A, N));
1995 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TU, &TA));
1996 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TB, N));
1997 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TV, N));
Paul Bakker5121ce52009-01-03 21:22:43 +00001998
Gilles Peskine449bd832023-01-11 14:50:10 +01001999 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&U1, 1));
2000 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&U2, 0));
2001 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&V1, 0));
2002 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&V2, 1));
Paul Bakker5121ce52009-01-03 21:22:43 +00002003
Gilles Peskine449bd832023-01-11 14:50:10 +01002004 do {
2005 while ((TU.p[0] & 1) == 0) {
2006 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TU, 1));
Paul Bakker5121ce52009-01-03 21:22:43 +00002007
Gilles Peskine449bd832023-01-11 14:50:10 +01002008 if ((U1.p[0] & 1) != 0 || (U2.p[0] & 1) != 0) {
2009 MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&U1, &U1, &TB));
2010 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&U2, &U2, &TA));
Paul Bakker5121ce52009-01-03 21:22:43 +00002011 }
2012
Gilles Peskine449bd832023-01-11 14:50:10 +01002013 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&U1, 1));
2014 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&U2, 1));
Paul Bakker5121ce52009-01-03 21:22:43 +00002015 }
2016
Gilles Peskine449bd832023-01-11 14:50:10 +01002017 while ((TV.p[0] & 1) == 0) {
2018 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TV, 1));
Paul Bakker5121ce52009-01-03 21:22:43 +00002019
Gilles Peskine449bd832023-01-11 14:50:10 +01002020 if ((V1.p[0] & 1) != 0 || (V2.p[0] & 1) != 0) {
2021 MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&V1, &V1, &TB));
2022 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&V2, &V2, &TA));
Paul Bakker5121ce52009-01-03 21:22:43 +00002023 }
2024
Gilles Peskine449bd832023-01-11 14:50:10 +01002025 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&V1, 1));
2026 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&V2, 1));
Paul Bakker5121ce52009-01-03 21:22:43 +00002027 }
2028
Gilles Peskine449bd832023-01-11 14:50:10 +01002029 if (mbedtls_mpi_cmp_mpi(&TU, &TV) >= 0) {
2030 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&TU, &TU, &TV));
2031 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&U1, &U1, &V1));
2032 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&U2, &U2, &V2));
2033 } else {
2034 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&TV, &TV, &TU));
2035 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&V1, &V1, &U1));
2036 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&V2, &V2, &U2));
Paul Bakker5121ce52009-01-03 21:22:43 +00002037 }
Gilles Peskine449bd832023-01-11 14:50:10 +01002038 } while (mbedtls_mpi_cmp_int(&TU, 0) != 0);
2039
2040 while (mbedtls_mpi_cmp_int(&V1, 0) < 0) {
2041 MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&V1, &V1, N));
Paul Bakker5121ce52009-01-03 21:22:43 +00002042 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002043
Gilles Peskine449bd832023-01-11 14:50:10 +01002044 while (mbedtls_mpi_cmp_mpi(&V1, N) >= 0) {
2045 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&V1, &V1, N));
2046 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002047
Gilles Peskine449bd832023-01-11 14:50:10 +01002048 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(X, &V1));
Paul Bakker5121ce52009-01-03 21:22:43 +00002049
2050cleanup:
2051
Gilles Peskine449bd832023-01-11 14:50:10 +01002052 mbedtls_mpi_free(&TA); mbedtls_mpi_free(&TU); mbedtls_mpi_free(&U1); mbedtls_mpi_free(&U2);
2053 mbedtls_mpi_free(&G); mbedtls_mpi_free(&TB); mbedtls_mpi_free(&TV);
2054 mbedtls_mpi_free(&V1); mbedtls_mpi_free(&V2);
Paul Bakker5121ce52009-01-03 21:22:43 +00002055
Gilles Peskine449bd832023-01-11 14:50:10 +01002056 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00002057}
2058
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002059#if defined(MBEDTLS_GENPRIME)
Paul Bakkerd9374b02012-11-02 11:02:58 +00002060
Gilles Peskineb2bc1712019-02-08 17:27:11 +01002061/* Gaps between primes, starting at 3. https://oeis.org/A001223 */
2062static const unsigned char small_prime_gaps[] = {
2063 2, 2, 4, 2, 4, 2, 4, 6,
2064 2, 6, 4, 2, 4, 6, 6, 2,
2065 6, 4, 2, 6, 4, 6, 8, 4,
2066 2, 4, 2, 4, 14, 4, 6, 2,
2067 10, 2, 6, 6, 4, 6, 6, 2,
2068 10, 2, 4, 2, 12, 12, 4, 2,
2069 4, 6, 2, 10, 6, 6, 6, 2,
2070 6, 4, 2, 10, 14, 4, 2, 4,
2071 14, 6, 10, 2, 4, 6, 8, 6,
2072 6, 4, 6, 8, 4, 8, 10, 2,
2073 10, 2, 6, 4, 6, 8, 4, 2,
2074 4, 12, 8, 4, 8, 4, 6, 12,
2075 2, 18, 6, 10, 6, 6, 2, 6,
2076 10, 6, 6, 2, 6, 6, 4, 2,
2077 12, 10, 2, 4, 6, 6, 2, 12,
2078 4, 6, 8, 10, 8, 10, 8, 6,
2079 6, 4, 8, 6, 4, 8, 4, 14,
2080 10, 12, 2, 10, 2, 4, 2, 10,
2081 14, 4, 2, 4, 14, 4, 2, 4,
2082 20, 4, 8, 10, 8, 4, 6, 6,
2083 14, 4, 6, 6, 8, 6, /*reaches 997*/
Gilles Peskine30b03782023-08-22 11:06:47 +02002084 0 /* the last entry is effectively unused */
Paul Bakker5121ce52009-01-03 21:22:43 +00002085};
2086
2087/*
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002088 * Small divisors test (X must be positive)
2089 *
2090 * Return values:
2091 * 0: no small factor (possible prime, more tests needed)
2092 * 1: certain prime
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002093 * MBEDTLS_ERR_MPI_NOT_ACCEPTABLE: certain non-prime
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002094 * other negative: error
Paul Bakker5121ce52009-01-03 21:22:43 +00002095 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002096static int mpi_check_small_factors(const mbedtls_mpi *X)
Paul Bakker5121ce52009-01-03 21:22:43 +00002097{
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002098 int ret = 0;
2099 size_t i;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002100 mbedtls_mpi_uint r;
Gilles Peskineb2bc1712019-02-08 17:27:11 +01002101 unsigned p = 3; /* The first odd prime */
Paul Bakker5121ce52009-01-03 21:22:43 +00002102
Gilles Peskine449bd832023-01-11 14:50:10 +01002103 if ((X->p[0] & 1) == 0) {
2104 return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2105 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002106
Gilles Peskineb2bc1712019-02-08 17:27:11 +01002107 for (i = 0; i < sizeof(small_prime_gaps); p += small_prime_gaps[i], i++) {
2108 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_int(&r, X, p));
Gilles Peskine449bd832023-01-11 14:50:10 +01002109 if (r == 0) {
Gilles Peskineb2bc1712019-02-08 17:27:11 +01002110 if (mbedtls_mpi_cmp_int(X, p) == 0) {
2111 return 1;
2112 } else {
2113 return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2114 }
Gilles Peskine449bd832023-01-11 14:50:10 +01002115 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002116 }
2117
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002118cleanup:
Gilles Peskine449bd832023-01-11 14:50:10 +01002119 return ret;
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002120}
2121
2122/*
2123 * Miller-Rabin pseudo-primality test (HAC 4.24)
2124 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002125static int mpi_miller_rabin(const mbedtls_mpi *X, size_t rounds,
2126 int (*f_rng)(void *, unsigned char *, size_t),
2127 void *p_rng)
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002128{
Pascal Junodb99183d2015-03-11 16:49:45 +01002129 int ret, count;
Janos Follathda31fa12018-09-03 14:45:23 +01002130 size_t i, j, k, s;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002131 mbedtls_mpi W, R, T, A, RR;
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002132
Gilles Peskine449bd832023-01-11 14:50:10 +01002133 mbedtls_mpi_init(&W); mbedtls_mpi_init(&R);
2134 mbedtls_mpi_init(&T); mbedtls_mpi_init(&A);
2135 mbedtls_mpi_init(&RR);
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002136
Paul Bakker5121ce52009-01-03 21:22:43 +00002137 /*
2138 * W = |X| - 1
2139 * R = W >> lsb( W )
2140 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002141 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(&W, X, 1));
2142 s = mbedtls_mpi_lsb(&W);
2143 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&R, &W));
2144 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&R, s));
Paul Bakker5121ce52009-01-03 21:22:43 +00002145
Gilles Peskine449bd832023-01-11 14:50:10 +01002146 for (i = 0; i < rounds; i++) {
Paul Bakker5121ce52009-01-03 21:22:43 +00002147 /*
2148 * pick a random A, 1 < A < |X| - 1
2149 */
Pascal Junodb99183d2015-03-11 16:49:45 +01002150 count = 0;
2151 do {
Gilles Peskine449bd832023-01-11 14:50:10 +01002152 MBEDTLS_MPI_CHK(mbedtls_mpi_fill_random(&A, X->n * ciL, f_rng, p_rng));
Pascal Junodb99183d2015-03-11 16:49:45 +01002153
Gilles Peskine449bd832023-01-11 14:50:10 +01002154 j = mbedtls_mpi_bitlen(&A);
2155 k = mbedtls_mpi_bitlen(&W);
Pascal Junodb99183d2015-03-11 16:49:45 +01002156 if (j > k) {
Gilles Peskine449bd832023-01-11 14:50:10 +01002157 A.p[A.n - 1] &= ((mbedtls_mpi_uint) 1 << (k - (A.n - 1) * biL - 1)) - 1;
Pascal Junodb99183d2015-03-11 16:49:45 +01002158 }
2159
2160 if (count++ > 30) {
Jens Wiklanderf08aa3e2019-01-17 13:30:57 +01002161 ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2162 goto cleanup;
Pascal Junodb99183d2015-03-11 16:49:45 +01002163 }
2164
Gilles Peskine449bd832023-01-11 14:50:10 +01002165 } while (mbedtls_mpi_cmp_mpi(&A, &W) >= 0 ||
2166 mbedtls_mpi_cmp_int(&A, 1) <= 0);
Paul Bakker5121ce52009-01-03 21:22:43 +00002167
2168 /*
2169 * A = A^R mod |X|
2170 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002171 MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&A, &A, &R, X, &RR));
Paul Bakker5121ce52009-01-03 21:22:43 +00002172
Gilles Peskine449bd832023-01-11 14:50:10 +01002173 if (mbedtls_mpi_cmp_mpi(&A, &W) == 0 ||
2174 mbedtls_mpi_cmp_int(&A, 1) == 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00002175 continue;
Gilles Peskine449bd832023-01-11 14:50:10 +01002176 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002177
2178 j = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +01002179 while (j < s && mbedtls_mpi_cmp_mpi(&A, &W) != 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00002180 /*
2181 * A = A * A mod |X|
2182 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002183 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&T, &A, &A));
2184 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&A, &T, X));
Paul Bakker5121ce52009-01-03 21:22:43 +00002185
Gilles Peskine449bd832023-01-11 14:50:10 +01002186 if (mbedtls_mpi_cmp_int(&A, 1) == 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00002187 break;
Gilles Peskine449bd832023-01-11 14:50:10 +01002188 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002189
2190 j++;
2191 }
2192
2193 /*
2194 * not prime if A != |X| - 1 or A == 1
2195 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002196 if (mbedtls_mpi_cmp_mpi(&A, &W) != 0 ||
2197 mbedtls_mpi_cmp_int(&A, 1) == 0) {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002198 ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
Paul Bakker5121ce52009-01-03 21:22:43 +00002199 break;
2200 }
2201 }
2202
2203cleanup:
Gilles Peskine449bd832023-01-11 14:50:10 +01002204 mbedtls_mpi_free(&W); mbedtls_mpi_free(&R);
2205 mbedtls_mpi_free(&T); mbedtls_mpi_free(&A);
2206 mbedtls_mpi_free(&RR);
Paul Bakker5121ce52009-01-03 21:22:43 +00002207
Gilles Peskine449bd832023-01-11 14:50:10 +01002208 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00002209}
2210
2211/*
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002212 * Pseudo-primality test: small factors, then Miller-Rabin
2213 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002214int mbedtls_mpi_is_prime_ext(const mbedtls_mpi *X, int rounds,
2215 int (*f_rng)(void *, unsigned char *, size_t),
2216 void *p_rng)
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002217{
Janos Follath24eed8d2019-11-22 13:21:35 +00002218 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002219 mbedtls_mpi XX;
Manuel Pégourié-Gonnard7f4ed672014-10-14 20:56:02 +02002220
2221 XX.s = 1;
2222 XX.n = X->n;
2223 XX.p = X->p;
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002224
Gilles Peskine449bd832023-01-11 14:50:10 +01002225 if (mbedtls_mpi_cmp_int(&XX, 0) == 0 ||
2226 mbedtls_mpi_cmp_int(&XX, 1) == 0) {
2227 return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002228 }
2229
Gilles Peskine449bd832023-01-11 14:50:10 +01002230 if (mbedtls_mpi_cmp_int(&XX, 2) == 0) {
2231 return 0;
2232 }
2233
2234 if ((ret = mpi_check_small_factors(&XX)) != 0) {
2235 if (ret == 1) {
2236 return 0;
2237 }
2238
2239 return ret;
2240 }
2241
2242 return mpi_miller_rabin(&XX, rounds, f_rng, p_rng);
Janos Follathf301d232018-08-14 13:34:01 +01002243}
2244
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002245/*
Paul Bakker5121ce52009-01-03 21:22:43 +00002246 * Prime number generation
Jethro Beekman66689272018-02-14 19:24:10 -08002247 *
Janos Follathf301d232018-08-14 13:34:01 +01002248 * To generate an RSA key in a way recommended by FIPS 186-4, both primes must
2249 * be either 1024 bits or 1536 bits long, and flags must contain
2250 * MBEDTLS_MPI_GEN_PRIME_FLAG_LOW_ERR.
Paul Bakker5121ce52009-01-03 21:22:43 +00002251 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002252int mbedtls_mpi_gen_prime(mbedtls_mpi *X, size_t nbits, int flags,
2253 int (*f_rng)(void *, unsigned char *, size_t),
2254 void *p_rng)
Paul Bakker5121ce52009-01-03 21:22:43 +00002255{
Jethro Beekman66689272018-02-14 19:24:10 -08002256#ifdef MBEDTLS_HAVE_INT64
2257// ceil(2^63.5)
2258#define CEIL_MAXUINT_DIV_SQRT2 0xb504f333f9de6485ULL
2259#else
2260// ceil(2^31.5)
2261#define CEIL_MAXUINT_DIV_SQRT2 0xb504f334U
2262#endif
2263 int ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
Paul Bakker23986e52011-04-24 08:57:21 +00002264 size_t k, n;
Janos Follathda31fa12018-09-03 14:45:23 +01002265 int rounds;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002266 mbedtls_mpi_uint r;
2267 mbedtls_mpi Y;
Paul Bakker5121ce52009-01-03 21:22:43 +00002268
Gilles Peskine449bd832023-01-11 14:50:10 +01002269 if (nbits < 3 || nbits > MBEDTLS_MPI_MAX_BITS) {
2270 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
2271 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002272
Gilles Peskine449bd832023-01-11 14:50:10 +01002273 mbedtls_mpi_init(&Y);
Paul Bakker5121ce52009-01-03 21:22:43 +00002274
Gilles Peskine449bd832023-01-11 14:50:10 +01002275 n = BITS_TO_LIMBS(nbits);
Paul Bakker5121ce52009-01-03 21:22:43 +00002276
Gilles Peskine449bd832023-01-11 14:50:10 +01002277 if ((flags & MBEDTLS_MPI_GEN_PRIME_FLAG_LOW_ERR) == 0) {
Janos Follathda31fa12018-09-03 14:45:23 +01002278 /*
2279 * 2^-80 error probability, number of rounds chosen per HAC, table 4.4
2280 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002281 rounds = ((nbits >= 1300) ? 2 : (nbits >= 850) ? 3 :
2282 (nbits >= 650) ? 4 : (nbits >= 350) ? 8 :
2283 (nbits >= 250) ? 12 : (nbits >= 150) ? 18 : 27);
2284 } else {
Janos Follathda31fa12018-09-03 14:45:23 +01002285 /*
2286 * 2^-100 error probability, number of rounds computed based on HAC,
2287 * fact 4.48
2288 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002289 rounds = ((nbits >= 1450) ? 4 : (nbits >= 1150) ? 5 :
2290 (nbits >= 1000) ? 6 : (nbits >= 850) ? 7 :
2291 (nbits >= 750) ? 8 : (nbits >= 500) ? 13 :
2292 (nbits >= 250) ? 28 : (nbits >= 150) ? 40 : 51);
Janos Follathda31fa12018-09-03 14:45:23 +01002293 }
2294
Gilles Peskine449bd832023-01-11 14:50:10 +01002295 while (1) {
2296 MBEDTLS_MPI_CHK(mbedtls_mpi_fill_random(X, n * ciL, f_rng, p_rng));
Jethro Beekman66689272018-02-14 19:24:10 -08002297 /* 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 +01002298 if (X->p[n-1] < CEIL_MAXUINT_DIV_SQRT2) {
2299 continue;
2300 }
Jethro Beekman66689272018-02-14 19:24:10 -08002301
2302 k = n * biL;
Gilles Peskine449bd832023-01-11 14:50:10 +01002303 if (k > nbits) {
2304 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(X, k - nbits));
2305 }
Jethro Beekman66689272018-02-14 19:24:10 -08002306 X->p[0] |= 1;
2307
Gilles Peskine449bd832023-01-11 14:50:10 +01002308 if ((flags & MBEDTLS_MPI_GEN_PRIME_FLAG_DH) == 0) {
2309 ret = mbedtls_mpi_is_prime_ext(X, rounds, f_rng, p_rng);
Jethro Beekman66689272018-02-14 19:24:10 -08002310
Gilles Peskine449bd832023-01-11 14:50:10 +01002311 if (ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE) {
Paul Bakker5121ce52009-01-03 21:22:43 +00002312 goto cleanup;
Gilles Peskine449bd832023-01-11 14:50:10 +01002313 }
2314 } else {
Manuel Pégourié-Gonnardddf76152013-11-22 19:58:22 +01002315 /*
Tom Cosgrovece7f18c2022-07-28 05:50:56 +01002316 * A necessary condition for Y and X = 2Y + 1 to be prime
Jethro Beekman66689272018-02-14 19:24:10 -08002317 * is X = 2 mod 3 (which is equivalent to Y = 2 mod 3).
2318 * Make sure it is satisfied, while keeping X = 3 mod 4
Manuel Pégourié-Gonnardddf76152013-11-22 19:58:22 +01002319 */
Jethro Beekman66689272018-02-14 19:24:10 -08002320
2321 X->p[0] |= 2;
2322
Gilles Peskine449bd832023-01-11 14:50:10 +01002323 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_int(&r, X, 3));
2324 if (r == 0) {
2325 MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(X, X, 8));
2326 } else if (r == 1) {
2327 MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(X, X, 4));
2328 }
Jethro Beekman66689272018-02-14 19:24:10 -08002329
2330 /* Set Y = (X-1) / 2, which is X / 2 because X is odd */
Gilles Peskine449bd832023-01-11 14:50:10 +01002331 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&Y, X));
2332 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&Y, 1));
Jethro Beekman66689272018-02-14 19:24:10 -08002333
Gilles Peskine449bd832023-01-11 14:50:10 +01002334 while (1) {
Jethro Beekman66689272018-02-14 19:24:10 -08002335 /*
2336 * First, check small factors for X and Y
2337 * before doing Miller-Rabin on any of them
2338 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002339 if ((ret = mpi_check_small_factors(X)) == 0 &&
2340 (ret = mpi_check_small_factors(&Y)) == 0 &&
2341 (ret = mpi_miller_rabin(X, rounds, f_rng, p_rng))
2342 == 0 &&
2343 (ret = mpi_miller_rabin(&Y, rounds, f_rng, p_rng))
2344 == 0) {
Jethro Beekman66689272018-02-14 19:24:10 -08002345 goto cleanup;
Gilles Peskine449bd832023-01-11 14:50:10 +01002346 }
Jethro Beekman66689272018-02-14 19:24:10 -08002347
Gilles Peskine449bd832023-01-11 14:50:10 +01002348 if (ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE) {
Jethro Beekman66689272018-02-14 19:24:10 -08002349 goto cleanup;
Gilles Peskine449bd832023-01-11 14:50:10 +01002350 }
Jethro Beekman66689272018-02-14 19:24:10 -08002351
2352 /*
2353 * Next candidates. We want to preserve Y = (X-1) / 2 and
2354 * Y = 1 mod 2 and Y = 2 mod 3 (eq X = 3 mod 4 and X = 2 mod 3)
2355 * so up Y by 6 and X by 12.
2356 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002357 MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(X, X, 12));
2358 MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(&Y, &Y, 6));
Paul Bakker5121ce52009-01-03 21:22:43 +00002359 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002360 }
2361 }
2362
2363cleanup:
2364
Gilles Peskine449bd832023-01-11 14:50:10 +01002365 mbedtls_mpi_free(&Y);
Paul Bakker5121ce52009-01-03 21:22:43 +00002366
Gilles Peskine449bd832023-01-11 14:50:10 +01002367 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00002368}
2369
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002370#endif /* MBEDTLS_GENPRIME */
Paul Bakker5121ce52009-01-03 21:22:43 +00002371
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002372#if defined(MBEDTLS_SELF_TEST)
Paul Bakker5121ce52009-01-03 21:22:43 +00002373
Paul Bakker23986e52011-04-24 08:57:21 +00002374#define GCD_PAIR_COUNT 3
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002375
2376static const int gcd_pairs[GCD_PAIR_COUNT][3] =
2377{
2378 { 693, 609, 21 },
2379 { 1764, 868, 28 },
2380 { 768454923, 542167814, 1 }
2381};
2382
Paul Bakker5121ce52009-01-03 21:22:43 +00002383/*
2384 * Checkup routine
2385 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002386int mbedtls_mpi_self_test(int verbose)
Paul Bakker5121ce52009-01-03 21:22:43 +00002387{
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002388 int ret, i;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002389 mbedtls_mpi A, E, N, X, Y, U, V;
Paul Bakker5121ce52009-01-03 21:22:43 +00002390
Gilles Peskine449bd832023-01-11 14:50:10 +01002391 mbedtls_mpi_init(&A); mbedtls_mpi_init(&E); mbedtls_mpi_init(&N); mbedtls_mpi_init(&X);
2392 mbedtls_mpi_init(&Y); mbedtls_mpi_init(&U); mbedtls_mpi_init(&V);
Paul Bakker5121ce52009-01-03 21:22:43 +00002393
Gilles Peskine449bd832023-01-11 14:50:10 +01002394 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&A, 16,
2395 "EFE021C2645FD1DC586E69184AF4A31E" \
2396 "D5F53E93B5F123FA41680867BA110131" \
2397 "944FE7952E2517337780CB0DB80E61AA" \
2398 "E7C8DDC6C5C6AADEB34EB38A2F40D5E6"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002399
Gilles Peskine449bd832023-01-11 14:50:10 +01002400 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&E, 16,
2401 "B2E7EFD37075B9F03FF989C7C5051C20" \
2402 "34D2A323810251127E7BF8625A4F49A5" \
2403 "F3E27F4DA8BD59C47D6DAABA4C8127BD" \
2404 "5B5C25763222FEFCCFC38B832366C29E"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002405
Gilles Peskine449bd832023-01-11 14:50:10 +01002406 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&N, 16,
2407 "0066A198186C18C10B2F5ED9B522752A" \
2408 "9830B69916E535C8F047518A889A43A5" \
2409 "94B6BED27A168D31D4A52F88925AA8F5"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002410
Gilles Peskine449bd832023-01-11 14:50:10 +01002411 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&X, &A, &N));
Paul Bakker5121ce52009-01-03 21:22:43 +00002412
Gilles Peskine449bd832023-01-11 14:50:10 +01002413 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&U, 16,
2414 "602AB7ECA597A3D6B56FF9829A5E8B85" \
2415 "9E857EA95A03512E2BAE7391688D264A" \
2416 "A5663B0341DB9CCFD2C4C5F421FEC814" \
2417 "8001B72E848A38CAE1C65F78E56ABDEF" \
2418 "E12D3C039B8A02D6BE593F0BBBDA56F1" \
2419 "ECF677152EF804370C1A305CAF3B5BF1" \
2420 "30879B56C61DE584A0F53A2447A51E"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002421
Gilles Peskine449bd832023-01-11 14:50:10 +01002422 if (verbose != 0) {
2423 mbedtls_printf(" MPI test #1 (mul_mpi): ");
2424 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002425
Gilles Peskine449bd832023-01-11 14:50:10 +01002426 if (mbedtls_mpi_cmp_mpi(&X, &U) != 0) {
2427 if (verbose != 0) {
2428 mbedtls_printf("failed\n");
2429 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002430
Manuel Pégourié-Gonnard9e987ed2014-01-20 10:03:15 +01002431 ret = 1;
2432 goto cleanup;
Paul Bakker5121ce52009-01-03 21:22:43 +00002433 }
2434
Gilles Peskine449bd832023-01-11 14:50:10 +01002435 if (verbose != 0) {
2436 mbedtls_printf("passed\n");
2437 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002438
Gilles Peskine449bd832023-01-11 14:50:10 +01002439 MBEDTLS_MPI_CHK(mbedtls_mpi_div_mpi(&X, &Y, &A, &N));
Paul Bakker5121ce52009-01-03 21:22:43 +00002440
Gilles Peskine449bd832023-01-11 14:50:10 +01002441 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&U, 16,
2442 "256567336059E52CAE22925474705F39A94"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002443
Gilles Peskine449bd832023-01-11 14:50:10 +01002444 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&V, 16,
2445 "6613F26162223DF488E9CD48CC132C7A" \
2446 "0AC93C701B001B092E4E5B9F73BCD27B" \
2447 "9EE50D0657C77F374E903CDFA4C642"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002448
Gilles Peskine449bd832023-01-11 14:50:10 +01002449 if (verbose != 0) {
2450 mbedtls_printf(" MPI test #2 (div_mpi): ");
2451 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002452
Gilles Peskine449bd832023-01-11 14:50:10 +01002453 if (mbedtls_mpi_cmp_mpi(&X, &U) != 0 ||
2454 mbedtls_mpi_cmp_mpi(&Y, &V) != 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 MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&X, &A, &E, &N, NULL));
Paul Bakker5121ce52009-01-03 21:22:43 +00002468
Gilles Peskine449bd832023-01-11 14:50:10 +01002469 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&U, 16,
2470 "36E139AEA55215609D2816998ED020BB" \
2471 "BD96C37890F65171D948E9BC7CBAA4D9" \
2472 "325D24D6A3C12710F10A09FA08AB87"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002473
Gilles Peskine449bd832023-01-11 14:50:10 +01002474 if (verbose != 0) {
2475 mbedtls_printf(" MPI test #3 (exp_mod): ");
2476 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002477
Gilles Peskine449bd832023-01-11 14:50:10 +01002478 if (mbedtls_mpi_cmp_mpi(&X, &U) != 0) {
2479 if (verbose != 0) {
2480 mbedtls_printf("failed\n");
2481 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002482
Manuel Pégourié-Gonnard9e987ed2014-01-20 10:03:15 +01002483 ret = 1;
2484 goto cleanup;
Paul Bakker5121ce52009-01-03 21:22:43 +00002485 }
2486
Gilles Peskine449bd832023-01-11 14:50:10 +01002487 if (verbose != 0) {
2488 mbedtls_printf("passed\n");
2489 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002490
Gilles Peskine449bd832023-01-11 14:50:10 +01002491 MBEDTLS_MPI_CHK(mbedtls_mpi_inv_mod(&X, &A, &N));
Paul Bakker5121ce52009-01-03 21:22:43 +00002492
Gilles Peskine449bd832023-01-11 14:50:10 +01002493 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&U, 16,
2494 "003A0AAEDD7E784FC07D8F9EC6E3BFD5" \
2495 "C3DBA76456363A10869622EAC2DD84EC" \
2496 "C5B8A74DAC4D09E03B5E0BE779F2DF61"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002497
Gilles Peskine449bd832023-01-11 14:50:10 +01002498 if (verbose != 0) {
2499 mbedtls_printf(" MPI test #4 (inv_mod): ");
2500 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002501
Gilles Peskine449bd832023-01-11 14:50:10 +01002502 if (mbedtls_mpi_cmp_mpi(&X, &U) != 0) {
2503 if (verbose != 0) {
2504 mbedtls_printf("failed\n");
2505 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002506
Manuel Pégourié-Gonnard9e987ed2014-01-20 10:03:15 +01002507 ret = 1;
2508 goto cleanup;
Paul Bakker5121ce52009-01-03 21:22:43 +00002509 }
2510
Gilles Peskine449bd832023-01-11 14:50:10 +01002511 if (verbose != 0) {
2512 mbedtls_printf("passed\n");
2513 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002514
Gilles Peskine449bd832023-01-11 14:50:10 +01002515 if (verbose != 0) {
2516 mbedtls_printf(" MPI test #5 (simple gcd): ");
2517 }
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002518
Gilles Peskine449bd832023-01-11 14:50:10 +01002519 for (i = 0; i < GCD_PAIR_COUNT; i++) {
2520 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&X, gcd_pairs[i][0]));
2521 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&Y, gcd_pairs[i][1]));
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002522
Gilles Peskine449bd832023-01-11 14:50:10 +01002523 MBEDTLS_MPI_CHK(mbedtls_mpi_gcd(&A, &X, &Y));
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002524
Gilles Peskine449bd832023-01-11 14:50:10 +01002525 if (mbedtls_mpi_cmp_int(&A, gcd_pairs[i][2]) != 0) {
2526 if (verbose != 0) {
2527 mbedtls_printf("failed at %d\n", i);
2528 }
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002529
Manuel Pégourié-Gonnard9e987ed2014-01-20 10:03:15 +01002530 ret = 1;
2531 goto cleanup;
2532 }
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002533 }
2534
Gilles Peskine449bd832023-01-11 14:50:10 +01002535 if (verbose != 0) {
2536 mbedtls_printf("passed\n");
2537 }
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002538
Paul Bakker5121ce52009-01-03 21:22:43 +00002539cleanup:
2540
Gilles Peskine449bd832023-01-11 14:50:10 +01002541 if (ret != 0 && verbose != 0) {
2542 mbedtls_printf("Unexpected error, return code = %08X\n", (unsigned int) ret);
2543 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002544
Gilles Peskine449bd832023-01-11 14:50:10 +01002545 mbedtls_mpi_free(&A); mbedtls_mpi_free(&E); mbedtls_mpi_free(&N); mbedtls_mpi_free(&X);
2546 mbedtls_mpi_free(&Y); mbedtls_mpi_free(&U); mbedtls_mpi_free(&V);
Paul Bakker5121ce52009-01-03 21:22:43 +00002547
Gilles Peskine449bd832023-01-11 14:50:10 +01002548 if (verbose != 0) {
2549 mbedtls_printf("\n");
2550 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002551
Gilles Peskine449bd832023-01-11 14:50:10 +01002552 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00002553}
2554
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002555#endif /* MBEDTLS_SELF_TEST */
Paul Bakker5121ce52009-01-03 21:22:43 +00002556
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002557#endif /* MBEDTLS_BIGNUM_C */