blob: 7c265e04da4e0c6c551dccaaec38459fd11e7e0e [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
Manuel Pégourié-Gonnard37ff1402015-09-04 14:21:07 +02005 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License"); you may
8 * not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
Paul Bakker5121ce52009-01-03 21:22:43 +000018 */
Simon Butcher15b15d12015-11-26 19:35:03 +000019
Paul Bakker5121ce52009-01-03 21:22:43 +000020/*
Simon Butcher15b15d12015-11-26 19:35:03 +000021 * The following sources were referenced in the design of this Multi-precision
22 * Integer library:
Paul Bakker5121ce52009-01-03 21:22:43 +000023 *
Simon Butcher15b15d12015-11-26 19:35:03 +000024 * [1] Handbook of Applied Cryptography - 1997
25 * Menezes, van Oorschot and Vanstone
26 *
27 * [2] Multi-Precision Math
28 * Tom St Denis
29 * https://github.com/libtom/libtommath/blob/develop/tommath.pdf
30 *
31 * [3] GNU Multi-Precision Arithmetic Library
32 * https://gmplib.org/manual/index.html
33 *
Simon Butcherf5ba0452015-12-27 23:01:55 +000034 */
Paul Bakker5121ce52009-01-03 21:22:43 +000035
Gilles Peskinedb09ef62020-06-03 01:43:33 +020036#include "common.h"
Paul Bakker5121ce52009-01-03 21:22:43 +000037
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020038#if defined(MBEDTLS_BIGNUM_C)
Paul Bakker5121ce52009-01-03 21:22:43 +000039
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000040#include "mbedtls/bignum.h"
Janos Follath4614b9a2022-07-21 15:34:47 +010041#include "bignum_core.h"
Chris Jones4c5819c2021-03-03 17:45:34 +000042#include "bn_mul.h"
Andres Amaya Garcia1f6301b2018-04-17 09:51:09 -050043#include "mbedtls/platform_util.h"
Janos Follath24eed8d2019-11-22 13:21:35 +000044#include "mbedtls/error.h"
Gabor Mezei22c9a6f2021-10-20 12:09:35 +020045#include "constant_time_internal.h"
Paul Bakker5121ce52009-01-03 21:22:43 +000046
Dave Rodgman351c71b2021-12-06 17:50:53 +000047#include <limits.h>
Rich Evans00ab4702015-02-06 13:43:58 +000048#include <string.h>
49
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000050#include "mbedtls/platform.h"
Paul Bakker6e339b52013-07-03 13:37:05 +020051
Gilles Peskine449bd832023-01-11 14:50:10 +010052#define MPI_VALIDATE_RET(cond) \
53 MBEDTLS_INTERNAL_VALIDATE_RET(cond, MBEDTLS_ERR_MPI_BAD_INPUT_DATA)
54#define MPI_VALIDATE(cond) \
55 MBEDTLS_INTERNAL_VALIDATE(cond)
Gabor Mezei66669142022-08-03 12:52:26 +020056
Dave Rodgman7d4f0192023-05-09 14:01:05 +010057/*
58 * Compare signed values in constant time
59 */
60int mbedtls_mpi_lt_mpi_ct(const mbedtls_mpi *X,
61 const mbedtls_mpi *Y,
62 unsigned *ret)
63{
Dave Rodgman1f39f032023-08-01 09:19:16 +010064 mbedtls_ct_condition_t different_sign, X_is_negative, Y_is_negative, result;
Dave Rodgman7d4f0192023-05-09 14:01:05 +010065
66 MPI_VALIDATE_RET(X != NULL);
67 MPI_VALIDATE_RET(Y != NULL);
68 MPI_VALIDATE_RET(ret != NULL);
69
70 if (X->n != Y->n) {
71 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
72 }
73
74 /*
Dave Rodgmanb69239c2023-08-09 14:53:18 +010075 * Set N_is_negative to MBEDTLS_CT_FALSE if N >= 0, MBEDTLS_CT_TRUE if N < 0.
Dave Rodgman7d4f0192023-05-09 14:01:05 +010076 * We know that N->s == 1 if N >= 0 and N->s == -1 if N < 0.
77 */
Dave Rodgman1a7a5622023-05-17 13:47:56 +010078 X_is_negative = mbedtls_ct_bool((X->s & 2) >> 1);
79 Y_is_negative = mbedtls_ct_bool((Y->s & 2) >> 1);
Dave Rodgman7d4f0192023-05-09 14:01:05 +010080
81 /*
82 * If the signs are different, then the positive operand is the bigger.
83 * That is if X is negative (X_is_negative == 1), then X < Y is true and it
84 * is false if X is positive (X_is_negative == 0).
85 */
Dave Rodgman1cfc43c2023-09-19 16:18:59 +010086 different_sign = mbedtls_ct_bool_ne(X_is_negative, Y_is_negative); // true if different sign
Dave Rodgman1f39f032023-08-01 09:19:16 +010087 result = mbedtls_ct_bool_and(different_sign, X_is_negative);
Dave Rodgman7d4f0192023-05-09 14:01:05 +010088
Dave Rodgman32d72602023-07-31 12:28:05 +010089 /*
90 * Assuming signs are the same, compare X and Y. We switch the comparison
Dave Rodgman1a7a5622023-05-17 13:47:56 +010091 * order if they are negative so that we get the right result, regardles of
92 * sign.
Dave Rodgman7d4f0192023-05-09 14:01:05 +010093 */
Dave Rodgman7d4f0192023-05-09 14:01:05 +010094
Dave Rodgman32d72602023-07-31 12:28:05 +010095 /* This array is used to conditionally swap the pointers in const time */
Dave Rodgman1a7a5622023-05-17 13:47:56 +010096 void * const p[2] = { X->p, Y->p };
Dave Rodgman98ddc012023-08-10 12:11:31 +010097 size_t i = mbedtls_ct_size_if_else_0(X_is_negative, 1);
Dave Rodgman2c764842023-05-18 13:28:21 +010098 mbedtls_ct_condition_t lt = mbedtls_mpi_core_lt_ct(p[i], p[i ^ 1], X->n);
Dave Rodgman7d4f0192023-05-09 14:01:05 +010099
Dave Rodgman32d72602023-07-31 12:28:05 +0100100 /*
Dave Rodgman1f39f032023-08-01 09:19:16 +0100101 * Store in result iff the signs are the same (i.e., iff different_sign == false). If
Dave Rodgman32d72602023-07-31 12:28:05 +0100102 * the signs differ, result has already been set, so we don't change it.
103 */
Dave Rodgman1f39f032023-08-01 09:19:16 +0100104 result = mbedtls_ct_bool_or(result,
105 mbedtls_ct_bool_and(mbedtls_ct_bool_not(different_sign), lt));
Dave Rodgman1a7a5622023-05-17 13:47:56 +0100106
Dave Rodgman98ddc012023-08-10 12:11:31 +0100107 *ret = mbedtls_ct_uint_if_else_0(result, 1);
Dave Rodgman7d4f0192023-05-09 14:01:05 +0100108
109 return 0;
110}
111
112/*
113 * Conditionally assign X = Y, without leaking information
114 * about whether the assignment was made or not.
115 * (Leaking information about the respective sizes of X and Y is ok however.)
116 */
117#if defined(_MSC_VER) && defined(_M_ARM64) && (_MSC_FULL_VER < 193131103)
118/*
119 * MSVC miscompiles this function if it's inlined prior to Visual Studio 2022 version 17.1. See:
120 * https://developercommunity.visualstudio.com/t/c-compiler-miscompiles-part-of-mbedtls-library-on/1646989
121 */
122__declspec(noinline)
123#endif
124int mbedtls_mpi_safe_cond_assign(mbedtls_mpi *X,
125 const mbedtls_mpi *Y,
126 unsigned char assign)
127{
128 int ret = 0;
129 MPI_VALIDATE_RET(X != NULL);
130 MPI_VALIDATE_RET(Y != NULL);
131
Dave Rodgman7d4f0192023-05-09 14:01:05 +0100132 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, Y->n));
133
Dave Rodgman7e9af052023-09-28 17:08:16 +0100134 {
135 mbedtls_ct_condition_t do_assign = mbedtls_ct_bool(assign);
Dave Rodgman589ccb82023-05-17 13:55:01 +0100136
Dave Rodgman7e9af052023-09-28 17:08:16 +0100137 X->s = (int) mbedtls_ct_uint_if(do_assign, Y->s, X->s);
Dave Rodgman7d4f0192023-05-09 14:01:05 +0100138
Dave Rodgman7e9af052023-09-28 17:08:16 +0100139 mbedtls_mpi_core_cond_assign(X->p, Y->p, Y->n, do_assign);
Dave Rodgman7d4f0192023-05-09 14:01:05 +0100140
Dave Rodgman7e9af052023-09-28 17:08:16 +0100141 mbedtls_ct_condition_t do_not_assign = mbedtls_ct_bool_not(do_assign);
142 for (size_t i = Y->n; i < X->n; i++) {
143 X->p[i] = mbedtls_ct_mpi_uint_if_else_0(do_not_assign, X->p[i]);
144 }
Dave Rodgman7d4f0192023-05-09 14:01:05 +0100145 }
146
147cleanup:
148 return ret;
149}
150
151/*
152 * Conditionally swap X and Y, without leaking information
153 * about whether the swap was made or not.
154 * Here it is not ok to simply swap the pointers, which would lead to
155 * different memory access patterns when X and Y are used afterwards.
156 */
157int mbedtls_mpi_safe_cond_swap(mbedtls_mpi *X,
158 mbedtls_mpi *Y,
159 unsigned char swap)
160{
161 int ret = 0;
162 int s;
163 MPI_VALIDATE_RET(X != NULL);
164 MPI_VALIDATE_RET(Y != NULL);
165
166 if (X == Y) {
167 return 0;
168 }
169
Dave Rodgmancd2e38b2023-05-17 13:31:55 +0100170 mbedtls_ct_condition_t do_swap = mbedtls_ct_bool(swap);
171
Dave Rodgman7d4f0192023-05-09 14:01:05 +0100172 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, Y->n));
173 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(Y, X->n));
174
175 s = X->s;
Dave Rodgman2b4486a2023-05-17 15:51:59 +0100176 X->s = (int) mbedtls_ct_uint_if(do_swap, Y->s, X->s);
177 Y->s = (int) mbedtls_ct_uint_if(do_swap, s, Y->s);
Dave Rodgman7d4f0192023-05-09 14:01:05 +0100178
Dave Rodgmancd2e38b2023-05-17 13:31:55 +0100179 mbedtls_mpi_core_cond_swap(X->p, Y->p, X->n, do_swap);
Dave Rodgman7d4f0192023-05-09 14:01:05 +0100180
181cleanup:
182 return ret;
183}
184
Andres Amaya Garcia1f6301b2018-04-17 09:51:09 -0500185/* Implementation that should never be optimized out by the compiler */
Tom Cosgrovebc345e82023-07-25 15:17:39 +0100186#define mbedtls_mpi_zeroize_and_free(v, n) mbedtls_zeroize_and_free(v, ciL * (n))
Andres Amaya Garcia1f6301b2018-04-17 09:51:09 -0500187
Paul Bakker5121ce52009-01-03 21:22:43 +0000188/*
Paul Bakker6c591fa2011-05-05 11:49:20 +0000189 * Initialize one MPI
Paul Bakker5121ce52009-01-03 21:22:43 +0000190 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100191void mbedtls_mpi_init(mbedtls_mpi *X)
Paul Bakker5121ce52009-01-03 21:22:43 +0000192{
Gilles Peskine449bd832023-01-11 14:50:10 +0100193 MPI_VALIDATE(X != NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +0000194
Paul Bakker6c591fa2011-05-05 11:49:20 +0000195 X->s = 1;
196 X->n = 0;
197 X->p = NULL;
Paul Bakker5121ce52009-01-03 21:22:43 +0000198}
199
200/*
Paul Bakker6c591fa2011-05-05 11:49:20 +0000201 * Unallocate one MPI
Paul Bakker5121ce52009-01-03 21:22:43 +0000202 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100203void mbedtls_mpi_free(mbedtls_mpi *X)
Paul Bakker5121ce52009-01-03 21:22:43 +0000204{
Gilles Peskine449bd832023-01-11 14:50:10 +0100205 if (X == NULL) {
Paul Bakker6c591fa2011-05-05 11:49:20 +0000206 return;
Gilles Peskine449bd832023-01-11 14:50:10 +0100207 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000208
Gilles Peskine449bd832023-01-11 14:50:10 +0100209 if (X->p != NULL) {
Tom Cosgrove46259f62023-07-18 16:44:14 +0100210 mbedtls_mpi_zeroize_and_free(X->p, X->n);
Paul Bakker5121ce52009-01-03 21:22:43 +0000211 }
212
Paul Bakker6c591fa2011-05-05 11:49:20 +0000213 X->s = 1;
214 X->n = 0;
215 X->p = NULL;
Paul Bakker5121ce52009-01-03 21:22:43 +0000216}
217
218/*
219 * Enlarge to the specified number of limbs
220 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100221int mbedtls_mpi_grow(mbedtls_mpi *X, size_t nblimbs)
Paul Bakker5121ce52009-01-03 21:22:43 +0000222{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200223 mbedtls_mpi_uint *p;
Gilles Peskine449bd832023-01-11 14:50:10 +0100224 MPI_VALIDATE_RET(X != NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +0000225
Gilles Peskine449bd832023-01-11 14:50:10 +0100226 if (nblimbs > MBEDTLS_MPI_MAX_LIMBS) {
227 return MBEDTLS_ERR_MPI_ALLOC_FAILED;
228 }
Paul Bakkerf9688572011-05-05 10:00:45 +0000229
Gilles Peskine449bd832023-01-11 14:50:10 +0100230 if (X->n < nblimbs) {
231 if ((p = (mbedtls_mpi_uint *) mbedtls_calloc(nblimbs, ciL)) == NULL) {
232 return MBEDTLS_ERR_MPI_ALLOC_FAILED;
233 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000234
Gilles Peskine449bd832023-01-11 14:50:10 +0100235 if (X->p != NULL) {
236 memcpy(p, X->p, X->n * ciL);
Tom Cosgrove46259f62023-07-18 16:44:14 +0100237 mbedtls_mpi_zeroize_and_free(X->p, X->n);
Paul Bakker5121ce52009-01-03 21:22:43 +0000238 }
239
Gilles Peskine053022f2023-06-29 19:26:48 +0200240 /* nblimbs fits in n because we ensure that MBEDTLS_MPI_MAX_LIMBS
241 * fits, and we've checked that nblimbs <= MBEDTLS_MPI_MAX_LIMBS. */
242 X->n = (unsigned short) nblimbs;
Paul Bakker5121ce52009-01-03 21:22:43 +0000243 X->p = p;
244 }
245
Gilles Peskine449bd832023-01-11 14:50:10 +0100246 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000247}
248
249/*
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100250 * Resize down as much as possible,
251 * while keeping at least the specified number of limbs
252 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100253int mbedtls_mpi_shrink(mbedtls_mpi *X, size_t nblimbs)
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100254{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200255 mbedtls_mpi_uint *p;
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100256 size_t i;
Gilles Peskine449bd832023-01-11 14:50:10 +0100257 MPI_VALIDATE_RET(X != NULL);
Hanno Becker73d7d792018-12-11 10:35:51 +0000258
Gilles Peskine449bd832023-01-11 14:50:10 +0100259 if (nblimbs > MBEDTLS_MPI_MAX_LIMBS) {
260 return MBEDTLS_ERR_MPI_ALLOC_FAILED;
261 }
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100262
Gilles Peskinee2f563e2020-01-20 21:17:43 +0100263 /* Actually resize up if there are currently fewer than nblimbs limbs. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100264 if (X->n <= nblimbs) {
265 return mbedtls_mpi_grow(X, nblimbs);
266 }
Gilles Peskine322752b2020-01-21 13:59:51 +0100267 /* After this point, then X->n > nblimbs and in particular X->n > 0. */
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100268
Gilles Peskine449bd832023-01-11 14:50:10 +0100269 for (i = X->n - 1; i > 0; i--) {
270 if (X->p[i] != 0) {
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100271 break;
Gilles Peskine449bd832023-01-11 14:50:10 +0100272 }
273 }
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100274 i++;
275
Gilles Peskine449bd832023-01-11 14:50:10 +0100276 if (i < nblimbs) {
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100277 i = nblimbs;
Gilles Peskine449bd832023-01-11 14:50:10 +0100278 }
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100279
Gilles Peskine449bd832023-01-11 14:50:10 +0100280 if ((p = (mbedtls_mpi_uint *) mbedtls_calloc(i, ciL)) == NULL) {
281 return MBEDTLS_ERR_MPI_ALLOC_FAILED;
282 }
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100283
Gilles Peskine449bd832023-01-11 14:50:10 +0100284 if (X->p != NULL) {
285 memcpy(p, X->p, i * ciL);
Tom Cosgrove46259f62023-07-18 16:44:14 +0100286 mbedtls_mpi_zeroize_and_free(X->p, X->n);
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100287 }
288
Gilles Peskine053022f2023-06-29 19:26:48 +0200289 /* i fits in n because we ensure that MBEDTLS_MPI_MAX_LIMBS
290 * fits, and we've checked that i <= nblimbs <= MBEDTLS_MPI_MAX_LIMBS. */
291 X->n = (unsigned short) i;
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100292 X->p = p;
293
Gilles Peskine449bd832023-01-11 14:50:10 +0100294 return 0;
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100295}
296
Gilles Peskineed32b572021-06-02 22:17:52 +0200297/* Resize X to have exactly n limbs and set it to 0. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100298static int mbedtls_mpi_resize_clear(mbedtls_mpi *X, size_t limbs)
Gilles Peskineed32b572021-06-02 22:17:52 +0200299{
Gilles Peskine449bd832023-01-11 14:50:10 +0100300 if (limbs == 0) {
301 mbedtls_mpi_free(X);
302 return 0;
303 } else if (X->n == limbs) {
304 memset(X->p, 0, limbs * ciL);
Gilles Peskineed32b572021-06-02 22:17:52 +0200305 X->s = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +0100306 return 0;
307 } else {
308 mbedtls_mpi_free(X);
309 return mbedtls_mpi_grow(X, limbs);
Gilles Peskineed32b572021-06-02 22:17:52 +0200310 }
311}
312
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100313/*
Gilles Peskine3da1a8f2021-06-08 23:17:42 +0200314 * Copy the contents of Y into X.
315 *
316 * This function is not constant-time. Leading zeros in Y may be removed.
317 *
318 * Ensure that X does not shrink. This is not guaranteed by the public API,
319 * but some code in the bignum module relies on this property, for example
320 * in mbedtls_mpi_exp_mod().
Paul Bakker5121ce52009-01-03 21:22:43 +0000321 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100322int mbedtls_mpi_copy(mbedtls_mpi *X, const mbedtls_mpi *Y)
Paul Bakker5121ce52009-01-03 21:22:43 +0000323{
Gilles Peskine4e4be7c2018-03-21 16:29:03 +0100324 int ret = 0;
Paul Bakker23986e52011-04-24 08:57:21 +0000325 size_t i;
Gilles Peskine449bd832023-01-11 14:50:10 +0100326 MPI_VALIDATE_RET(X != NULL);
327 MPI_VALIDATE_RET(Y != NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +0000328
Gilles Peskine449bd832023-01-11 14:50:10 +0100329 if (X == Y) {
330 return 0;
Manuel Pégourié-Gonnardf4999932013-08-12 17:02:59 +0200331 }
332
Gilles Peskine449bd832023-01-11 14:50:10 +0100333 if (Y->n == 0) {
334 if (X->n != 0) {
335 X->s = 1;
336 memset(X->p, 0, X->n * ciL);
337 }
338 return 0;
339 }
340
341 for (i = Y->n - 1; i > 0; i--) {
342 if (Y->p[i] != 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +0000343 break;
Gilles Peskine449bd832023-01-11 14:50:10 +0100344 }
345 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000346 i++;
347
348 X->s = Y->s;
349
Gilles Peskine449bd832023-01-11 14:50:10 +0100350 if (X->n < i) {
351 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, i));
352 } else {
353 memset(X->p + i, 0, (X->n - i) * ciL);
Gilles Peskine4e4be7c2018-03-21 16:29:03 +0100354 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000355
Gilles Peskine449bd832023-01-11 14:50:10 +0100356 memcpy(X->p, Y->p, i * ciL);
Paul Bakker5121ce52009-01-03 21:22:43 +0000357
358cleanup:
359
Gilles Peskine449bd832023-01-11 14:50:10 +0100360 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000361}
362
363/*
364 * Swap the contents of X and Y
365 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100366void mbedtls_mpi_swap(mbedtls_mpi *X, mbedtls_mpi *Y)
Paul Bakker5121ce52009-01-03 21:22:43 +0000367{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200368 mbedtls_mpi T;
Gilles Peskine449bd832023-01-11 14:50:10 +0100369 MPI_VALIDATE(X != NULL);
370 MPI_VALIDATE(Y != NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +0000371
Gilles Peskine449bd832023-01-11 14:50:10 +0100372 memcpy(&T, X, sizeof(mbedtls_mpi));
373 memcpy(X, Y, sizeof(mbedtls_mpi));
374 memcpy(Y, &T, sizeof(mbedtls_mpi));
Paul Bakker5121ce52009-01-03 21:22:43 +0000375}
376
Gilles Peskine449bd832023-01-11 14:50:10 +0100377static inline mbedtls_mpi_uint mpi_sint_abs(mbedtls_mpi_sint z)
Gilles Peskineef7f4e42022-11-15 23:25:27 +0100378{
Gilles Peskine449bd832023-01-11 14:50:10 +0100379 if (z >= 0) {
380 return z;
381 }
Gilles Peskineef7f4e42022-11-15 23:25:27 +0100382 /* Take care to handle the most negative value (-2^(biL-1)) correctly.
383 * A naive -z would have undefined behavior.
384 * Write this in a way that makes popular compilers happy (GCC, Clang,
385 * MSVC). */
Gilles Peskine449bd832023-01-11 14:50:10 +0100386 return (mbedtls_mpi_uint) 0 - (mbedtls_mpi_uint) z;
Gilles Peskineef7f4e42022-11-15 23:25:27 +0100387}
388
Dave Rodgmanf3df1052023-08-09 18:55:41 +0100389/* Convert x to a sign, i.e. to 1, if x is positive, or -1, if x is negative.
390 * This looks awkward but generates smaller code than (x < 0 ? -1 : 1) */
Dave Rodgman73d85912023-09-28 17:00:50 +0100391#define TO_SIGN(x) ((mbedtls_mpi_sint) (((mbedtls_mpi_uint) x) >> (biL - 1)) * -2 + 1)
Dave Rodgmanf3df1052023-08-09 18:55:41 +0100392
Paul Bakker5121ce52009-01-03 21:22:43 +0000393/*
394 * Set value from integer
395 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100396int mbedtls_mpi_lset(mbedtls_mpi *X, mbedtls_mpi_sint z)
Paul Bakker5121ce52009-01-03 21:22:43 +0000397{
Janos Follath24eed8d2019-11-22 13:21:35 +0000398 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Gilles Peskine449bd832023-01-11 14:50:10 +0100399 MPI_VALIDATE_RET(X != NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +0000400
Gilles Peskine449bd832023-01-11 14:50:10 +0100401 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, 1));
402 memset(X->p, 0, X->n * ciL);
Paul Bakker5121ce52009-01-03 21:22:43 +0000403
Gilles Peskine449bd832023-01-11 14:50:10 +0100404 X->p[0] = mpi_sint_abs(z);
Dave Rodgmanf3df1052023-08-09 18:55:41 +0100405 X->s = TO_SIGN(z);
Paul Bakker5121ce52009-01-03 21:22:43 +0000406
407cleanup:
408
Gilles Peskine449bd832023-01-11 14:50:10 +0100409 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000410}
411
412/*
Paul Bakker2f5947e2011-05-18 15:47:11 +0000413 * Get a specific bit
414 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100415int mbedtls_mpi_get_bit(const mbedtls_mpi *X, size_t pos)
Paul Bakker2f5947e2011-05-18 15:47:11 +0000416{
Gilles Peskine449bd832023-01-11 14:50:10 +0100417 MPI_VALIDATE_RET(X != NULL);
Hanno Becker73d7d792018-12-11 10:35:51 +0000418
Gilles Peskine449bd832023-01-11 14:50:10 +0100419 if (X->n * biL <= pos) {
420 return 0;
421 }
Paul Bakker2f5947e2011-05-18 15:47:11 +0000422
Gilles Peskine449bd832023-01-11 14:50:10 +0100423 return (X->p[pos / biL] >> (pos % biL)) & 0x01;
Paul Bakker2f5947e2011-05-18 15:47:11 +0000424}
425
426/*
427 * Set a bit to a specific value of 0 or 1
428 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100429int mbedtls_mpi_set_bit(mbedtls_mpi *X, size_t pos, unsigned char val)
Paul Bakker2f5947e2011-05-18 15:47:11 +0000430{
431 int ret = 0;
432 size_t off = pos / biL;
433 size_t idx = pos % biL;
Gilles Peskine449bd832023-01-11 14:50:10 +0100434 MPI_VALIDATE_RET(X != NULL);
Paul Bakker2f5947e2011-05-18 15:47:11 +0000435
Gilles Peskine449bd832023-01-11 14:50:10 +0100436 if (val != 0 && val != 1) {
437 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
Paul Bakker2f5947e2011-05-18 15:47:11 +0000438 }
439
Gilles Peskine449bd832023-01-11 14:50:10 +0100440 if (X->n * biL <= pos) {
441 if (val == 0) {
442 return 0;
443 }
444
445 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, off + 1));
446 }
447
448 X->p[off] &= ~((mbedtls_mpi_uint) 0x01 << idx);
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200449 X->p[off] |= (mbedtls_mpi_uint) val << idx;
Paul Bakker2f5947e2011-05-18 15:47:11 +0000450
451cleanup:
Paul Bakker9af723c2014-05-01 13:03:14 +0200452
Gilles Peskine449bd832023-01-11 14:50:10 +0100453 return ret;
Paul Bakker2f5947e2011-05-18 15:47:11 +0000454}
455
456/*
Manuel Pégourié-Gonnardc0696c22015-06-18 16:47:17 +0200457 * Return the number of less significant zero-bits
Paul Bakker5121ce52009-01-03 21:22:43 +0000458 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100459size_t mbedtls_mpi_lsb(const mbedtls_mpi *X)
Paul Bakker5121ce52009-01-03 21:22:43 +0000460{
Dave Rodgmanfa703e32023-08-09 18:56:07 +0100461 size_t i;
Gilles Peskine449bd832023-01-11 14:50:10 +0100462 MBEDTLS_INTERNAL_VALIDATE_RET(X != NULL, 0);
Paul Bakker5121ce52009-01-03 21:22:43 +0000463
Dave Rodgmanfa703e32023-08-09 18:56:07 +0100464#if defined(__has_builtin)
465#if (MBEDTLS_MPI_UINT_MAX == UINT_MAX) && __has_builtin(__builtin_ctz)
466 #define mbedtls_mpi_uint_ctz __builtin_ctz
467#elif (MBEDTLS_MPI_UINT_MAX == ULONG_MAX) && __has_builtin(__builtin_ctzl)
468 #define mbedtls_mpi_uint_ctz __builtin_ctzl
469#elif (MBEDTLS_MPI_UINT_MAX == ULLONG_MAX) && __has_builtin(__builtin_ctzll)
470 #define mbedtls_mpi_uint_ctz __builtin_ctzll
471#endif
472#endif
473
474#if defined(mbedtls_mpi_uint_ctz)
Gilles Peskine449bd832023-01-11 14:50:10 +0100475 for (i = 0; i < X->n; i++) {
Dave Rodgman960eca92023-08-09 20:43:18 +0100476 if (X->p[i] != 0) {
477 return i * biL + mbedtls_mpi_uint_ctz(X->p[i]);
478 }
Dave Rodgmanfa703e32023-08-09 18:56:07 +0100479 }
480#else
481 size_t count = 0;
482 for (i = 0; i < X->n; i++) {
483 for (size_t j = 0; j < biL; j++, count++) {
Gilles Peskine449bd832023-01-11 14:50:10 +0100484 if (((X->p[i] >> j) & 1) != 0) {
485 return count;
486 }
487 }
488 }
Dave Rodgmanfa703e32023-08-09 18:56:07 +0100489#endif
Paul Bakker5121ce52009-01-03 21:22:43 +0000490
Gilles Peskine449bd832023-01-11 14:50:10 +0100491 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000492}
493
494/*
Manuel Pégourié-Gonnardc0696c22015-06-18 16:47:17 +0200495 * Return the number of bits
Paul Bakker5121ce52009-01-03 21:22:43 +0000496 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100497size_t mbedtls_mpi_bitlen(const mbedtls_mpi *X)
Paul Bakker5121ce52009-01-03 21:22:43 +0000498{
Gilles Peskine449bd832023-01-11 14:50:10 +0100499 return mbedtls_mpi_core_bitlen(X->p, X->n);
Paul Bakker5121ce52009-01-03 21:22:43 +0000500}
501
502/*
503 * Return the total size in bytes
504 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100505size_t mbedtls_mpi_size(const mbedtls_mpi *X)
Paul Bakker5121ce52009-01-03 21:22:43 +0000506{
Gilles Peskine449bd832023-01-11 14:50:10 +0100507 return (mbedtls_mpi_bitlen(X) + 7) >> 3;
Paul Bakker5121ce52009-01-03 21:22:43 +0000508}
509
510/*
511 * Convert an ASCII character to digit value
512 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100513static int mpi_get_digit(mbedtls_mpi_uint *d, int radix, char c)
Paul Bakker5121ce52009-01-03 21:22:43 +0000514{
515 *d = 255;
516
Gilles Peskine449bd832023-01-11 14:50:10 +0100517 if (c >= 0x30 && c <= 0x39) {
518 *d = c - 0x30;
519 }
520 if (c >= 0x41 && c <= 0x46) {
521 *d = c - 0x37;
522 }
523 if (c >= 0x61 && c <= 0x66) {
524 *d = c - 0x57;
525 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000526
Gilles Peskine449bd832023-01-11 14:50:10 +0100527 if (*d >= (mbedtls_mpi_uint) radix) {
528 return MBEDTLS_ERR_MPI_INVALID_CHARACTER;
529 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000530
Gilles Peskine449bd832023-01-11 14:50:10 +0100531 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000532}
533
534/*
535 * Import from an ASCII string
536 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100537int mbedtls_mpi_read_string(mbedtls_mpi *X, int radix, const char *s)
Paul Bakker5121ce52009-01-03 21:22:43 +0000538{
Janos Follath24eed8d2019-11-22 13:21:35 +0000539 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker23986e52011-04-24 08:57:21 +0000540 size_t i, j, slen, n;
Gilles Peskine80f56732021-04-03 18:26:13 +0200541 int sign = 1;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200542 mbedtls_mpi_uint d;
543 mbedtls_mpi T;
Gilles Peskine449bd832023-01-11 14:50:10 +0100544 MPI_VALIDATE_RET(X != NULL);
545 MPI_VALIDATE_RET(s != NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +0000546
Gilles Peskine449bd832023-01-11 14:50:10 +0100547 if (radix < 2 || radix > 16) {
548 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
Gilles Peskine7cba8592021-06-08 18:32:34 +0200549 }
550
Gilles Peskine449bd832023-01-11 14:50:10 +0100551 mbedtls_mpi_init(&T);
552
553 if (s[0] == 0) {
554 mbedtls_mpi_free(X);
555 return 0;
556 }
557
558 if (s[0] == '-') {
Gilles Peskine80f56732021-04-03 18:26:13 +0200559 ++s;
560 sign = -1;
561 }
562
Gilles Peskine449bd832023-01-11 14:50:10 +0100563 slen = strlen(s);
Paul Bakkerff60ee62010-03-16 21:09:09 +0000564
Gilles Peskine449bd832023-01-11 14:50:10 +0100565 if (radix == 16) {
Dave Rodgman68ef1d62023-05-18 20:49:03 +0100566 if (slen > SIZE_MAX >> 2) {
Gilles Peskine449bd832023-01-11 14:50:10 +0100567 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
Paul Bakker5121ce52009-01-03 21:22:43 +0000568 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000569
Gilles Peskine449bd832023-01-11 14:50:10 +0100570 n = BITS_TO_LIMBS(slen << 2);
571
572 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, n));
573 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(X, 0));
574
575 for (i = slen, j = 0; i > 0; i--, j++) {
576 MBEDTLS_MPI_CHK(mpi_get_digit(&d, radix, s[i - 1]));
577 X->p[j / (2 * ciL)] |= d << ((j % (2 * ciL)) << 2);
578 }
579 } else {
580 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(X, 0));
581
582 for (i = 0; i < slen; i++) {
583 MBEDTLS_MPI_CHK(mpi_get_digit(&d, radix, s[i]));
584 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_int(&T, X, radix));
585 MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(X, &T, d));
Paul Bakker5121ce52009-01-03 21:22:43 +0000586 }
587 }
588
Gilles Peskine449bd832023-01-11 14:50:10 +0100589 if (sign < 0 && mbedtls_mpi_bitlen(X) != 0) {
Gilles Peskine80f56732021-04-03 18:26:13 +0200590 X->s = -1;
Gilles Peskine449bd832023-01-11 14:50:10 +0100591 }
Gilles Peskine80f56732021-04-03 18:26:13 +0200592
Paul Bakker5121ce52009-01-03 21:22:43 +0000593cleanup:
594
Gilles Peskine449bd832023-01-11 14:50:10 +0100595 mbedtls_mpi_free(&T);
Paul Bakker5121ce52009-01-03 21:22:43 +0000596
Gilles Peskine449bd832023-01-11 14:50:10 +0100597 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000598}
599
600/*
Ron Eldora16fa292018-11-20 14:07:01 +0200601 * Helper to write the digits high-order first.
Paul Bakker5121ce52009-01-03 21:22:43 +0000602 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100603static int mpi_write_hlp(mbedtls_mpi *X, int radix,
604 char **p, const size_t buflen)
Paul Bakker5121ce52009-01-03 21:22:43 +0000605{
Janos Follath24eed8d2019-11-22 13:21:35 +0000606 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200607 mbedtls_mpi_uint r;
Ron Eldora16fa292018-11-20 14:07:01 +0200608 size_t length = 0;
609 char *p_end = *p + buflen;
Paul Bakker5121ce52009-01-03 21:22:43 +0000610
Gilles Peskine449bd832023-01-11 14:50:10 +0100611 do {
612 if (length >= buflen) {
613 return MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL;
Ron Eldora16fa292018-11-20 14:07:01 +0200614 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000615
Gilles Peskine449bd832023-01-11 14:50:10 +0100616 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_int(&r, X, radix));
617 MBEDTLS_MPI_CHK(mbedtls_mpi_div_int(X, NULL, X, radix));
Ron Eldora16fa292018-11-20 14:07:01 +0200618 /*
619 * Write the residue in the current position, as an ASCII character.
620 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100621 if (r < 0xA) {
622 *(--p_end) = (char) ('0' + r);
623 } else {
624 *(--p_end) = (char) ('A' + (r - 0xA));
625 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000626
Ron Eldora16fa292018-11-20 14:07:01 +0200627 length++;
Gilles Peskine449bd832023-01-11 14:50:10 +0100628 } while (mbedtls_mpi_cmp_int(X, 0) != 0);
Paul Bakker5121ce52009-01-03 21:22:43 +0000629
Gilles Peskine449bd832023-01-11 14:50:10 +0100630 memmove(*p, p_end, length);
Ron Eldora16fa292018-11-20 14:07:01 +0200631 *p += length;
Paul Bakker5121ce52009-01-03 21:22:43 +0000632
633cleanup:
634
Gilles Peskine449bd832023-01-11 14:50:10 +0100635 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000636}
637
638/*
639 * Export into an ASCII string
640 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100641int mbedtls_mpi_write_string(const mbedtls_mpi *X, int radix,
642 char *buf, size_t buflen, size_t *olen)
Paul Bakker5121ce52009-01-03 21:22:43 +0000643{
Paul Bakker23986e52011-04-24 08:57:21 +0000644 int ret = 0;
645 size_t n;
Paul Bakker5121ce52009-01-03 21:22:43 +0000646 char *p;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200647 mbedtls_mpi T;
Gilles Peskine449bd832023-01-11 14:50:10 +0100648 MPI_VALIDATE_RET(X != NULL);
649 MPI_VALIDATE_RET(olen != NULL);
650 MPI_VALIDATE_RET(buflen == 0 || buf != NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +0000651
Gilles Peskine449bd832023-01-11 14:50:10 +0100652 if (radix < 2 || radix > 16) {
653 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
654 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000655
Gilles Peskine449bd832023-01-11 14:50:10 +0100656 n = mbedtls_mpi_bitlen(X); /* Number of bits necessary to present `n`. */
657 if (radix >= 4) {
658 n >>= 1; /* Number of 4-adic digits necessary to present
Hanno Becker23cfea02019-02-04 09:45:07 +0000659 * `n`. If radix > 4, this might be a strict
660 * overapproximation of the number of
661 * radix-adic digits needed to present `n`. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100662 }
663 if (radix >= 16) {
664 n >>= 1; /* Number of hexadecimal digits necessary to
Hanno Becker23cfea02019-02-04 09:45:07 +0000665 * present `n`. */
666
Gilles Peskine449bd832023-01-11 14:50:10 +0100667 }
Janos Follath80470622019-03-06 13:43:02 +0000668 n += 1; /* Terminating null byte */
Hanno Becker23cfea02019-02-04 09:45:07 +0000669 n += 1; /* Compensate for the divisions above, which round down `n`
670 * in case it's not even. */
671 n += 1; /* Potential '-'-sign. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100672 n += (n & 1); /* Make n even to have enough space for hexadecimal writing,
Hanno Becker23cfea02019-02-04 09:45:07 +0000673 * which always uses an even number of hex-digits. */
Paul Bakker5121ce52009-01-03 21:22:43 +0000674
Gilles Peskine449bd832023-01-11 14:50:10 +0100675 if (buflen < n) {
Manuel Pégourié-Gonnardf79b4252015-06-02 15:41:48 +0100676 *olen = n;
Gilles Peskine449bd832023-01-11 14:50:10 +0100677 return MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL;
Paul Bakker5121ce52009-01-03 21:22:43 +0000678 }
679
Manuel Pégourié-Gonnardf79b4252015-06-02 15:41:48 +0100680 p = buf;
Gilles Peskine449bd832023-01-11 14:50:10 +0100681 mbedtls_mpi_init(&T);
Paul Bakker5121ce52009-01-03 21:22:43 +0000682
Gilles Peskine449bd832023-01-11 14:50:10 +0100683 if (X->s == -1) {
Paul Bakker5121ce52009-01-03 21:22:43 +0000684 *p++ = '-';
Hanno Beckerc983c812019-02-01 16:41:30 +0000685 buflen--;
686 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000687
Gilles Peskine449bd832023-01-11 14:50:10 +0100688 if (radix == 16) {
Paul Bakker23986e52011-04-24 08:57:21 +0000689 int c;
690 size_t i, j, k;
Paul Bakker5121ce52009-01-03 21:22:43 +0000691
Gilles Peskine449bd832023-01-11 14:50:10 +0100692 for (i = X->n, k = 0; i > 0; i--) {
693 for (j = ciL; j > 0; j--) {
694 c = (X->p[i - 1] >> ((j - 1) << 3)) & 0xFF;
Paul Bakker5121ce52009-01-03 21:22:43 +0000695
Gilles Peskine449bd832023-01-11 14:50:10 +0100696 if (c == 0 && k == 0 && (i + j) != 2) {
Paul Bakker5121ce52009-01-03 21:22:43 +0000697 continue;
Gilles Peskine449bd832023-01-11 14:50:10 +0100698 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000699
Paul Bakker98fe5ea2012-10-24 11:17:48 +0000700 *(p++) = "0123456789ABCDEF" [c / 16];
Paul Bakkerd2c167e2012-10-30 07:49:19 +0000701 *(p++) = "0123456789ABCDEF" [c % 16];
Paul Bakker5121ce52009-01-03 21:22:43 +0000702 k = 1;
703 }
704 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100705 } else {
706 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&T, X));
Paul Bakkerce40a6d2009-06-23 19:46:08 +0000707
Gilles Peskine449bd832023-01-11 14:50:10 +0100708 if (T.s == -1) {
Paul Bakkerce40a6d2009-06-23 19:46:08 +0000709 T.s = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +0100710 }
Paul Bakkerce40a6d2009-06-23 19:46:08 +0000711
Gilles Peskine449bd832023-01-11 14:50:10 +0100712 MBEDTLS_MPI_CHK(mpi_write_hlp(&T, radix, &p, buflen));
Paul Bakker5121ce52009-01-03 21:22:43 +0000713 }
714
715 *p++ = '\0';
Manuel Pégourié-Gonnardf79b4252015-06-02 15:41:48 +0100716 *olen = p - buf;
Paul Bakker5121ce52009-01-03 21:22:43 +0000717
718cleanup:
719
Gilles Peskine449bd832023-01-11 14:50:10 +0100720 mbedtls_mpi_free(&T);
Paul Bakker5121ce52009-01-03 21:22:43 +0000721
Gilles Peskine449bd832023-01-11 14:50:10 +0100722 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000723}
724
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200725#if defined(MBEDTLS_FS_IO)
Paul Bakker5121ce52009-01-03 21:22:43 +0000726/*
727 * Read X from an opened file
728 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100729int mbedtls_mpi_read_file(mbedtls_mpi *X, int radix, FILE *fin)
Paul Bakker5121ce52009-01-03 21:22:43 +0000730{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200731 mbedtls_mpi_uint d;
Paul Bakker23986e52011-04-24 08:57:21 +0000732 size_t slen;
Paul Bakker5121ce52009-01-03 21:22:43 +0000733 char *p;
Paul Bakkerfe3256e2011-11-25 12:11:43 +0000734 /*
Paul Bakkercb37aa52011-11-30 16:00:20 +0000735 * Buffer should have space for (short) label and decimal formatted MPI,
736 * newline characters and '\0'
Paul Bakkerfe3256e2011-11-25 12:11:43 +0000737 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100738 char s[MBEDTLS_MPI_RW_BUFFER_SIZE];
Paul Bakker5121ce52009-01-03 21:22:43 +0000739
Gilles Peskine449bd832023-01-11 14:50:10 +0100740 MPI_VALIDATE_RET(X != NULL);
741 MPI_VALIDATE_RET(fin != NULL);
Hanno Becker73d7d792018-12-11 10:35:51 +0000742
Gilles Peskine449bd832023-01-11 14:50:10 +0100743 if (radix < 2 || radix > 16) {
744 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
745 }
Hanno Becker73d7d792018-12-11 10:35:51 +0000746
Gilles Peskine449bd832023-01-11 14:50:10 +0100747 memset(s, 0, sizeof(s));
748 if (fgets(s, sizeof(s) - 1, fin) == NULL) {
749 return MBEDTLS_ERR_MPI_FILE_IO_ERROR;
750 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000751
Gilles Peskine449bd832023-01-11 14:50:10 +0100752 slen = strlen(s);
753 if (slen == sizeof(s) - 2) {
754 return MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL;
755 }
Paul Bakkercb37aa52011-11-30 16:00:20 +0000756
Gilles Peskine449bd832023-01-11 14:50:10 +0100757 if (slen > 0 && s[slen - 1] == '\n') {
758 slen--; s[slen] = '\0';
759 }
760 if (slen > 0 && s[slen - 1] == '\r') {
761 slen--; s[slen] = '\0';
762 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000763
764 p = s + slen;
Gilles Peskine449bd832023-01-11 14:50:10 +0100765 while (p-- > s) {
766 if (mpi_get_digit(&d, radix, *p) != 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +0000767 break;
Gilles Peskine449bd832023-01-11 14:50:10 +0100768 }
769 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000770
Gilles Peskine449bd832023-01-11 14:50:10 +0100771 return mbedtls_mpi_read_string(X, radix, p + 1);
Paul Bakker5121ce52009-01-03 21:22:43 +0000772}
773
774/*
775 * Write X into an opened file (or stdout if fout == NULL)
776 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100777int mbedtls_mpi_write_file(const char *p, const mbedtls_mpi *X, int radix, FILE *fout)
Paul Bakker5121ce52009-01-03 21:22:43 +0000778{
Janos Follath24eed8d2019-11-22 13:21:35 +0000779 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker23986e52011-04-24 08:57:21 +0000780 size_t n, slen, plen;
Paul Bakkerfe3256e2011-11-25 12:11:43 +0000781 /*
Paul Bakker5531c6d2012-09-26 19:20:46 +0000782 * Buffer should have space for (short) label and decimal formatted MPI,
783 * newline characters and '\0'
Paul Bakkerfe3256e2011-11-25 12:11:43 +0000784 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100785 char s[MBEDTLS_MPI_RW_BUFFER_SIZE];
786 MPI_VALIDATE_RET(X != NULL);
Hanno Becker73d7d792018-12-11 10:35:51 +0000787
Gilles Peskine449bd832023-01-11 14:50:10 +0100788 if (radix < 2 || radix > 16) {
789 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
790 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000791
Gilles Peskine449bd832023-01-11 14:50:10 +0100792 memset(s, 0, sizeof(s));
Paul Bakker5121ce52009-01-03 21:22:43 +0000793
Gilles Peskine449bd832023-01-11 14:50:10 +0100794 MBEDTLS_MPI_CHK(mbedtls_mpi_write_string(X, radix, s, sizeof(s) - 2, &n));
Paul Bakker5121ce52009-01-03 21:22:43 +0000795
Gilles Peskine449bd832023-01-11 14:50:10 +0100796 if (p == NULL) {
797 p = "";
798 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000799
Gilles Peskine449bd832023-01-11 14:50:10 +0100800 plen = strlen(p);
801 slen = strlen(s);
Paul Bakker5121ce52009-01-03 21:22:43 +0000802 s[slen++] = '\r';
803 s[slen++] = '\n';
804
Gilles Peskine449bd832023-01-11 14:50:10 +0100805 if (fout != NULL) {
806 if (fwrite(p, 1, plen, fout) != plen ||
807 fwrite(s, 1, slen, fout) != slen) {
808 return MBEDTLS_ERR_MPI_FILE_IO_ERROR;
809 }
810 } else {
811 mbedtls_printf("%s%s", p, s);
Paul Bakker5121ce52009-01-03 21:22:43 +0000812 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000813
814cleanup:
815
Gilles Peskine449bd832023-01-11 14:50:10 +0100816 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000817}
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200818#endif /* MBEDTLS_FS_IO */
Paul Bakker5121ce52009-01-03 21:22:43 +0000819
820/*
Janos Follatha778a942019-02-13 10:28:28 +0000821 * Import X from unsigned binary data, little endian
Przemyslaw Stekiel76960a72022-02-21 13:42:09 +0100822 *
823 * This function is guaranteed to return an MPI with exactly the necessary
824 * number of limbs (in particular, it does not skip 0s in the input).
Janos Follatha778a942019-02-13 10:28:28 +0000825 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100826int mbedtls_mpi_read_binary_le(mbedtls_mpi *X,
827 const unsigned char *buf, size_t buflen)
Janos Follatha778a942019-02-13 10:28:28 +0000828{
Janos Follath24eed8d2019-11-22 13:21:35 +0000829 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Gilles Peskine449bd832023-01-11 14:50:10 +0100830 const size_t limbs = CHARS_TO_LIMBS(buflen);
Janos Follatha778a942019-02-13 10:28:28 +0000831
832 /* Ensure that target MPI has exactly the necessary number of limbs */
Gilles Peskine449bd832023-01-11 14:50:10 +0100833 MBEDTLS_MPI_CHK(mbedtls_mpi_resize_clear(X, limbs));
Janos Follatha778a942019-02-13 10:28:28 +0000834
Gilles Peskine449bd832023-01-11 14:50:10 +0100835 MBEDTLS_MPI_CHK(mbedtls_mpi_core_read_le(X->p, X->n, buf, buflen));
Janos Follatha778a942019-02-13 10:28:28 +0000836
837cleanup:
838
Janos Follath171a7ef2019-02-15 16:17:45 +0000839 /*
840 * This function is also used to import keys. However, wiping the buffers
841 * upon failure is not necessary because failure only can happen before any
842 * input is copied.
843 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100844 return ret;
Janos Follatha778a942019-02-13 10:28:28 +0000845}
846
847/*
Paul Bakker5121ce52009-01-03 21:22:43 +0000848 * Import X from unsigned binary data, big endian
Przemyslaw Stekiel76960a72022-02-21 13:42:09 +0100849 *
850 * This function is guaranteed to return an MPI with exactly the necessary
851 * number of limbs (in particular, it does not skip 0s in the input).
Paul Bakker5121ce52009-01-03 21:22:43 +0000852 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100853int mbedtls_mpi_read_binary(mbedtls_mpi *X, const unsigned char *buf, size_t buflen)
Paul Bakker5121ce52009-01-03 21:22:43 +0000854{
Janos Follath24eed8d2019-11-22 13:21:35 +0000855 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Gilles Peskine449bd832023-01-11 14:50:10 +0100856 const size_t limbs = CHARS_TO_LIMBS(buflen);
Paul Bakker5121ce52009-01-03 21:22:43 +0000857
Gilles Peskine449bd832023-01-11 14:50:10 +0100858 MPI_VALIDATE_RET(X != NULL);
859 MPI_VALIDATE_RET(buflen == 0 || buf != NULL);
Hanno Becker73d7d792018-12-11 10:35:51 +0000860
Hanno Becker073c1992017-10-17 15:17:27 +0100861 /* Ensure that target MPI has exactly the necessary number of limbs */
Gilles Peskine449bd832023-01-11 14:50:10 +0100862 MBEDTLS_MPI_CHK(mbedtls_mpi_resize_clear(X, limbs));
Paul Bakker5121ce52009-01-03 21:22:43 +0000863
Gilles Peskine449bd832023-01-11 14:50:10 +0100864 MBEDTLS_MPI_CHK(mbedtls_mpi_core_read_be(X->p, X->n, buf, buflen));
Paul Bakker5121ce52009-01-03 21:22:43 +0000865
866cleanup:
867
Janos Follath171a7ef2019-02-15 16:17:45 +0000868 /*
869 * This function is also used to import keys. However, wiping the buffers
870 * upon failure is not necessary because failure only can happen before any
871 * input is copied.
872 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100873 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000874}
875
876/*
Janos Follathe344d0f2019-02-19 16:17:40 +0000877 * Export X into unsigned binary data, little endian
878 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100879int mbedtls_mpi_write_binary_le(const mbedtls_mpi *X,
880 unsigned char *buf, size_t buflen)
Janos Follathe344d0f2019-02-19 16:17:40 +0000881{
Gilles Peskine449bd832023-01-11 14:50:10 +0100882 return mbedtls_mpi_core_write_le(X->p, X->n, buf, buflen);
Janos Follathe344d0f2019-02-19 16:17:40 +0000883}
884
885/*
Paul Bakker5121ce52009-01-03 21:22:43 +0000886 * Export X into unsigned binary data, big endian
887 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100888int mbedtls_mpi_write_binary(const mbedtls_mpi *X,
889 unsigned char *buf, size_t buflen)
Paul Bakker5121ce52009-01-03 21:22:43 +0000890{
Gilles Peskine449bd832023-01-11 14:50:10 +0100891 return mbedtls_mpi_core_write_be(X->p, X->n, buf, buflen);
Paul Bakker5121ce52009-01-03 21:22:43 +0000892}
893
894/*
895 * Left-shift: X <<= count
896 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100897int mbedtls_mpi_shift_l(mbedtls_mpi *X, size_t count)
Paul Bakker5121ce52009-01-03 21:22:43 +0000898{
Janos Follath24eed8d2019-11-22 13:21:35 +0000899 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Minos Galanakis0144b352023-05-02 14:02:32 +0100900 size_t i;
Gilles Peskine449bd832023-01-11 14:50:10 +0100901 MPI_VALIDATE_RET(X != NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +0000902
Gilles Peskine449bd832023-01-11 14:50:10 +0100903 i = mbedtls_mpi_bitlen(X) + count;
Paul Bakker5121ce52009-01-03 21:22:43 +0000904
Gilles Peskine449bd832023-01-11 14:50:10 +0100905 if (X->n * biL < i) {
906 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, BITS_TO_LIMBS(i)));
907 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000908
909 ret = 0;
910
Minos Galanakis0144b352023-05-02 14:02:32 +0100911 mbedtls_mpi_core_shift_l(X->p, X->n, count);
Paul Bakker5121ce52009-01-03 21:22:43 +0000912cleanup:
913
Gilles Peskine449bd832023-01-11 14:50:10 +0100914 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000915}
916
917/*
918 * Right-shift: X >>= count
919 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100920int mbedtls_mpi_shift_r(mbedtls_mpi *X, size_t count)
Paul Bakker5121ce52009-01-03 21:22:43 +0000921{
Gilles Peskine449bd832023-01-11 14:50:10 +0100922 MPI_VALIDATE_RET(X != NULL);
923 if (X->n != 0) {
924 mbedtls_mpi_core_shift_r(X->p, X->n, count);
925 }
926 return 0;
Gilles Peskine66414202022-09-21 15:36:16 +0200927}
928
Paul Bakker5121ce52009-01-03 21:22:43 +0000929/*
930 * Compare unsigned values
931 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100932int mbedtls_mpi_cmp_abs(const mbedtls_mpi *X, const mbedtls_mpi *Y)
Paul Bakker5121ce52009-01-03 21:22:43 +0000933{
Paul Bakker23986e52011-04-24 08:57:21 +0000934 size_t i, j;
Gilles Peskine449bd832023-01-11 14:50:10 +0100935 MPI_VALIDATE_RET(X != NULL);
936 MPI_VALIDATE_RET(Y != NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +0000937
Gilles Peskine449bd832023-01-11 14:50:10 +0100938 for (i = X->n; i > 0; i--) {
939 if (X->p[i - 1] != 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +0000940 break;
Gilles Peskine449bd832023-01-11 14:50:10 +0100941 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000942 }
943
Gilles Peskine449bd832023-01-11 14:50:10 +0100944 for (j = Y->n; j > 0; j--) {
945 if (Y->p[j - 1] != 0) {
946 break;
947 }
948 }
949
Dave Rodgmanebcd7852023-08-09 18:56:42 +0100950 /* If i == j == 0, i.e. abs(X) == abs(Y),
951 * we end up returning 0 at the end of the function. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100952
953 if (i > j) {
954 return 1;
955 }
956 if (j > i) {
957 return -1;
958 }
959
960 for (; i > 0; i--) {
961 if (X->p[i - 1] > Y->p[i - 1]) {
962 return 1;
963 }
964 if (X->p[i - 1] < Y->p[i - 1]) {
965 return -1;
966 }
967 }
968
969 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000970}
971
972/*
973 * Compare signed values
974 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100975int mbedtls_mpi_cmp_mpi(const mbedtls_mpi *X, const mbedtls_mpi *Y)
Paul Bakker5121ce52009-01-03 21:22:43 +0000976{
Paul Bakker23986e52011-04-24 08:57:21 +0000977 size_t i, j;
Gilles Peskine449bd832023-01-11 14:50:10 +0100978 MPI_VALIDATE_RET(X != NULL);
979 MPI_VALIDATE_RET(Y != NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +0000980
Gilles Peskine449bd832023-01-11 14:50:10 +0100981 for (i = X->n; i > 0; i--) {
982 if (X->p[i - 1] != 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +0000983 break;
Gilles Peskine449bd832023-01-11 14:50:10 +0100984 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000985 }
986
Gilles Peskine449bd832023-01-11 14:50:10 +0100987 for (j = Y->n; j > 0; j--) {
988 if (Y->p[j - 1] != 0) {
989 break;
990 }
991 }
992
993 if (i == 0 && j == 0) {
994 return 0;
995 }
996
997 if (i > j) {
998 return X->s;
999 }
1000 if (j > i) {
1001 return -Y->s;
1002 }
1003
1004 if (X->s > 0 && Y->s < 0) {
1005 return 1;
1006 }
1007 if (Y->s > 0 && X->s < 0) {
1008 return -1;
1009 }
1010
1011 for (; i > 0; i--) {
1012 if (X->p[i - 1] > Y->p[i - 1]) {
1013 return X->s;
1014 }
1015 if (X->p[i - 1] < Y->p[i - 1]) {
1016 return -X->s;
1017 }
1018 }
1019
1020 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +00001021}
1022
Janos Follathee6abce2019-09-05 14:47:19 +01001023/*
Paul Bakker5121ce52009-01-03 21:22:43 +00001024 * Compare signed values
1025 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001026int mbedtls_mpi_cmp_int(const mbedtls_mpi *X, mbedtls_mpi_sint z)
Paul Bakker5121ce52009-01-03 21:22:43 +00001027{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001028 mbedtls_mpi Y;
1029 mbedtls_mpi_uint p[1];
Gilles Peskine449bd832023-01-11 14:50:10 +01001030 MPI_VALIDATE_RET(X != NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +00001031
Gilles Peskine449bd832023-01-11 14:50:10 +01001032 *p = mpi_sint_abs(z);
Dave Rodgmanf3df1052023-08-09 18:55:41 +01001033 Y.s = TO_SIGN(z);
Paul Bakker5121ce52009-01-03 21:22:43 +00001034 Y.n = 1;
1035 Y.p = p;
1036
Gilles Peskine449bd832023-01-11 14:50:10 +01001037 return mbedtls_mpi_cmp_mpi(X, &Y);
Paul Bakker5121ce52009-01-03 21:22:43 +00001038}
1039
1040/*
1041 * Unsigned addition: X = |A| + |B| (HAC 14.7)
1042 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001043int mbedtls_mpi_add_abs(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B)
Paul Bakker5121ce52009-01-03 21:22:43 +00001044{
Janos Follath24eed8d2019-11-22 13:21:35 +00001045 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Tom Cosgroveaf7d44b2022-08-24 14:05:26 +01001046 size_t j;
Agathiyan Bragadeeshc99840a2023-07-12 11:15:46 +01001047 mbedtls_mpi_uint *p;
1048 mbedtls_mpi_uint c;
Gilles Peskine449bd832023-01-11 14:50:10 +01001049 MPI_VALIDATE_RET(X != NULL);
1050 MPI_VALIDATE_RET(A != NULL);
1051 MPI_VALIDATE_RET(B != NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +00001052
Gilles Peskine449bd832023-01-11 14:50:10 +01001053 if (X == B) {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001054 const mbedtls_mpi *T = A; A = X; B = T;
Paul Bakker5121ce52009-01-03 21:22:43 +00001055 }
1056
Gilles Peskine449bd832023-01-11 14:50:10 +01001057 if (X != A) {
1058 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(X, A));
1059 }
Paul Bakker9af723c2014-05-01 13:03:14 +02001060
Paul Bakkerf7ca7b92009-06-20 10:31:06 +00001061 /*
Tom Cosgroveaf7d44b2022-08-24 14:05:26 +01001062 * X must always be positive as a result of unsigned additions.
Paul Bakkerf7ca7b92009-06-20 10:31:06 +00001063 */
1064 X->s = 1;
Paul Bakker5121ce52009-01-03 21:22:43 +00001065
Gilles Peskine449bd832023-01-11 14:50:10 +01001066 for (j = B->n; j > 0; j--) {
1067 if (B->p[j - 1] != 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00001068 break;
Gilles Peskine449bd832023-01-11 14:50:10 +01001069 }
1070 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001071
Gilles Peskinedb14a9d2022-11-15 22:59:00 +01001072 /* Exit early to avoid undefined behavior on NULL+0 when X->n == 0
1073 * and B is 0 (of any size). */
Gilles Peskine449bd832023-01-11 14:50:10 +01001074 if (j == 0) {
1075 return 0;
1076 }
Gilles Peskinedb14a9d2022-11-15 22:59:00 +01001077
Gilles Peskine449bd832023-01-11 14:50:10 +01001078 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, j));
Paul Bakker5121ce52009-01-03 21:22:43 +00001079
Tom Cosgroveaf7d44b2022-08-24 14:05:26 +01001080 /* j is the number of non-zero limbs of B. Add those to X. */
Paul Bakker5121ce52009-01-03 21:22:43 +00001081
Agathiyan Bragadeeshc99840a2023-07-12 11:15:46 +01001082 p = X->p;
Tom Cosgroveaf7d44b2022-08-24 14:05:26 +01001083
Agathiyan Bragadeeshc99840a2023-07-12 11:15:46 +01001084 c = mbedtls_mpi_core_add(p, p, B->p, j);
Tom Cosgroveaf7d44b2022-08-24 14:05:26 +01001085
1086 p += j;
1087
1088 /* Now propagate any carry */
Paul Bakker5121ce52009-01-03 21:22:43 +00001089
Gilles Peskine449bd832023-01-11 14:50:10 +01001090 while (c != 0) {
1091 if (j >= X->n) {
1092 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, j + 1));
Tom Cosgroveaf7d44b2022-08-24 14:05:26 +01001093 p = X->p + j;
Paul Bakker5121ce52009-01-03 21:22:43 +00001094 }
1095
Gilles Peskine449bd832023-01-11 14:50:10 +01001096 *p += c; c = (*p < c); j++; p++;
Paul Bakker5121ce52009-01-03 21:22:43 +00001097 }
1098
1099cleanup:
1100
Gilles Peskine449bd832023-01-11 14:50:10 +01001101 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001102}
1103
Paul Bakker5121ce52009-01-03 21:22:43 +00001104/*
Gilles Peskine0e5faf62020-06-08 22:50:35 +02001105 * Unsigned subtraction: X = |A| - |B| (HAC 14.9, 14.10)
Paul Bakker5121ce52009-01-03 21:22:43 +00001106 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001107int mbedtls_mpi_sub_abs(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B)
Paul Bakker5121ce52009-01-03 21:22:43 +00001108{
Janos Follath24eed8d2019-11-22 13:21:35 +00001109 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker23986e52011-04-24 08:57:21 +00001110 size_t n;
Gilles Peskine0e5faf62020-06-08 22:50:35 +02001111 mbedtls_mpi_uint carry;
Gilles Peskine449bd832023-01-11 14:50:10 +01001112 MPI_VALIDATE_RET(X != NULL);
1113 MPI_VALIDATE_RET(A != NULL);
1114 MPI_VALIDATE_RET(B != NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +00001115
Gilles Peskine449bd832023-01-11 14:50:10 +01001116 for (n = B->n; n > 0; n--) {
1117 if (B->p[n - 1] != 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00001118 break;
Gilles Peskine449bd832023-01-11 14:50:10 +01001119 }
1120 }
1121 if (n > A->n) {
Gilles Peskinec8a91772021-01-27 22:30:43 +01001122 /* B >= (2^ciL)^n > A */
1123 ret = MBEDTLS_ERR_MPI_NEGATIVE_VALUE;
1124 goto cleanup;
1125 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001126
Gilles Peskine449bd832023-01-11 14:50:10 +01001127 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, A->n));
Gilles Peskine1acf7cb2020-07-23 01:03:22 +02001128
1129 /* Set the high limbs of X to match A. Don't touch the lower limbs
1130 * because X might be aliased to B, and we must not overwrite the
1131 * significant digits of B. */
Aaron M. Uckoaf67d2c2023-01-17 11:52:22 -05001132 if (A->n > n && A != X) {
Gilles Peskine449bd832023-01-11 14:50:10 +01001133 memcpy(X->p + n, A->p + n, (A->n - n) * ciL);
1134 }
1135 if (X->n > A->n) {
1136 memset(X->p + A->n, 0, (X->n - A->n) * ciL);
1137 }
Gilles Peskine1acf7cb2020-07-23 01:03:22 +02001138
Gilles Peskine449bd832023-01-11 14:50:10 +01001139 carry = mbedtls_mpi_core_sub(X->p, A->p, B->p, n);
1140 if (carry != 0) {
Tom Cosgrove452c99c2022-08-25 10:07:07 +01001141 /* Propagate the carry through the rest of X. */
Gilles Peskine449bd832023-01-11 14:50:10 +01001142 carry = mbedtls_mpi_core_sub_int(X->p + n, X->p + n, carry, X->n - n);
Tom Cosgrove452c99c2022-08-25 10:07:07 +01001143
1144 /* If we have further carry/borrow, the result is negative. */
Gilles Peskine449bd832023-01-11 14:50:10 +01001145 if (carry != 0) {
Gilles Peskine89b41302020-07-23 01:16:46 +02001146 ret = MBEDTLS_ERR_MPI_NEGATIVE_VALUE;
1147 goto cleanup;
1148 }
Gilles Peskinec097e9e2020-06-08 21:58:22 +02001149 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001150
Gilles Peskine1acf7cb2020-07-23 01:03:22 +02001151 /* X should always be positive as a result of unsigned subtractions. */
1152 X->s = 1;
1153
Paul Bakker5121ce52009-01-03 21:22:43 +00001154cleanup:
Gilles Peskine449bd832023-01-11 14:50:10 +01001155 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001156}
1157
Gilles Peskine72ee1e32022-11-09 21:34:09 +01001158/* Common function for signed addition and subtraction.
1159 * Calculate A + B * flip_B where flip_B is 1 or -1.
Paul Bakker5121ce52009-01-03 21:22:43 +00001160 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001161static int add_sub_mpi(mbedtls_mpi *X,
1162 const mbedtls_mpi *A, const mbedtls_mpi *B,
1163 int flip_B)
Paul Bakker5121ce52009-01-03 21:22:43 +00001164{
Hanno Becker73d7d792018-12-11 10:35:51 +00001165 int ret, s;
Gilles Peskine449bd832023-01-11 14:50:10 +01001166 MPI_VALIDATE_RET(X != NULL);
1167 MPI_VALIDATE_RET(A != NULL);
1168 MPI_VALIDATE_RET(B != NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +00001169
Hanno Becker73d7d792018-12-11 10:35:51 +00001170 s = A->s;
Gilles Peskine449bd832023-01-11 14:50:10 +01001171 if (A->s * B->s * flip_B < 0) {
1172 int cmp = mbedtls_mpi_cmp_abs(A, B);
1173 if (cmp >= 0) {
1174 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_abs(X, A, B));
Gilles Peskine4a768dd2022-11-09 22:02:16 +01001175 /* If |A| = |B|, the result is 0 and we must set the sign bit
1176 * to +1 regardless of which of A or B was negative. Otherwise,
1177 * since |A| > |B|, the sign is the sign of A. */
1178 X->s = cmp == 0 ? 1 : s;
Gilles Peskine449bd832023-01-11 14:50:10 +01001179 } else {
1180 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_abs(X, B, A));
Gilles Peskine4a768dd2022-11-09 22:02:16 +01001181 /* Since |A| < |B|, the sign is the opposite of A. */
Paul Bakker5121ce52009-01-03 21:22:43 +00001182 X->s = -s;
1183 }
Gilles Peskine449bd832023-01-11 14:50:10 +01001184 } else {
1185 MBEDTLS_MPI_CHK(mbedtls_mpi_add_abs(X, A, B));
Paul Bakker5121ce52009-01-03 21:22:43 +00001186 X->s = s;
1187 }
1188
1189cleanup:
1190
Gilles Peskine449bd832023-01-11 14:50:10 +01001191 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001192}
1193
1194/*
Gilles Peskine72ee1e32022-11-09 21:34:09 +01001195 * Signed addition: X = A + B
1196 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001197int mbedtls_mpi_add_mpi(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B)
Gilles Peskine72ee1e32022-11-09 21:34:09 +01001198{
Gilles Peskine449bd832023-01-11 14:50:10 +01001199 return add_sub_mpi(X, A, B, 1);
Gilles Peskine72ee1e32022-11-09 21:34:09 +01001200}
1201
1202/*
Paul Bakker60b1d102013-10-29 10:02:51 +01001203 * Signed subtraction: X = A - B
Paul Bakker5121ce52009-01-03 21:22:43 +00001204 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001205int mbedtls_mpi_sub_mpi(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B)
Paul Bakker5121ce52009-01-03 21:22:43 +00001206{
Gilles Peskine449bd832023-01-11 14:50:10 +01001207 return add_sub_mpi(X, A, B, -1);
Paul Bakker5121ce52009-01-03 21:22:43 +00001208}
1209
1210/*
1211 * Signed addition: X = A + b
1212 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001213int mbedtls_mpi_add_int(mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b)
Paul Bakker5121ce52009-01-03 21:22:43 +00001214{
Yuto Takano36c8ddc2021-07-05 09:10:52 +01001215 mbedtls_mpi B;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001216 mbedtls_mpi_uint p[1];
Gilles Peskine449bd832023-01-11 14:50:10 +01001217 MPI_VALIDATE_RET(X != NULL);
1218 MPI_VALIDATE_RET(A != NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +00001219
Gilles Peskine449bd832023-01-11 14:50:10 +01001220 p[0] = mpi_sint_abs(b);
Dave Rodgmanf3df1052023-08-09 18:55:41 +01001221 B.s = TO_SIGN(b);
Yuto Takano36c8ddc2021-07-05 09:10:52 +01001222 B.n = 1;
1223 B.p = p;
Paul Bakker5121ce52009-01-03 21:22:43 +00001224
Gilles Peskine449bd832023-01-11 14:50:10 +01001225 return mbedtls_mpi_add_mpi(X, A, &B);
Paul Bakker5121ce52009-01-03 21:22:43 +00001226}
1227
1228/*
Paul Bakker60b1d102013-10-29 10:02:51 +01001229 * Signed subtraction: X = A - b
Paul Bakker5121ce52009-01-03 21:22:43 +00001230 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001231int mbedtls_mpi_sub_int(mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b)
Paul Bakker5121ce52009-01-03 21:22:43 +00001232{
Yuto Takano36c8ddc2021-07-05 09:10:52 +01001233 mbedtls_mpi B;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001234 mbedtls_mpi_uint p[1];
Gilles Peskine449bd832023-01-11 14:50:10 +01001235 MPI_VALIDATE_RET(X != NULL);
1236 MPI_VALIDATE_RET(A != NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +00001237
Gilles Peskine449bd832023-01-11 14:50:10 +01001238 p[0] = mpi_sint_abs(b);
Dave Rodgmanf3df1052023-08-09 18:55:41 +01001239 B.s = TO_SIGN(b);
Yuto Takano36c8ddc2021-07-05 09:10:52 +01001240 B.n = 1;
1241 B.p = p;
Paul Bakker5121ce52009-01-03 21:22:43 +00001242
Gilles Peskine449bd832023-01-11 14:50:10 +01001243 return mbedtls_mpi_sub_mpi(X, A, &B);
Paul Bakker5121ce52009-01-03 21:22:43 +00001244}
1245
Paul Bakker5121ce52009-01-03 21:22:43 +00001246/*
1247 * Baseline multiplication: X = A * B (HAC 14.12)
1248 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001249int mbedtls_mpi_mul_mpi(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B)
Paul Bakker5121ce52009-01-03 21:22:43 +00001250{
Janos Follath24eed8d2019-11-22 13:21:35 +00001251 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Hanno Becker1772e052022-04-13 06:51:40 +01001252 size_t i, j;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001253 mbedtls_mpi TA, TB;
Hanno Beckerda763de2022-04-13 06:50:02 +01001254 int result_is_zero = 0;
Gilles Peskine449bd832023-01-11 14:50:10 +01001255 MPI_VALIDATE_RET(X != NULL);
1256 MPI_VALIDATE_RET(A != NULL);
1257 MPI_VALIDATE_RET(B != NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +00001258
Tom Cosgrove6af26f32022-08-24 16:40:55 +01001259 mbedtls_mpi_init(&TA);
1260 mbedtls_mpi_init(&TB);
Paul Bakker5121ce52009-01-03 21:22:43 +00001261
Gilles Peskine449bd832023-01-11 14:50:10 +01001262 if (X == A) {
1263 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TA, A)); A = &TA;
1264 }
1265 if (X == B) {
1266 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TB, B)); B = &TB;
1267 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001268
Gilles Peskine449bd832023-01-11 14:50:10 +01001269 for (i = A->n; i > 0; i--) {
1270 if (A->p[i - 1] != 0) {
Hanno Beckerda763de2022-04-13 06:50:02 +01001271 break;
Gilles Peskine449bd832023-01-11 14:50:10 +01001272 }
1273 }
1274 if (i == 0) {
Hanno Beckerda763de2022-04-13 06:50:02 +01001275 result_is_zero = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +01001276 }
Hanno Beckerda763de2022-04-13 06:50:02 +01001277
Gilles Peskine449bd832023-01-11 14:50:10 +01001278 for (j = B->n; j > 0; j--) {
1279 if (B->p[j - 1] != 0) {
Hanno Beckerda763de2022-04-13 06:50:02 +01001280 break;
Gilles Peskine449bd832023-01-11 14:50:10 +01001281 }
1282 }
1283 if (j == 0) {
Hanno Beckerda763de2022-04-13 06:50:02 +01001284 result_is_zero = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +01001285 }
Hanno Beckerda763de2022-04-13 06:50:02 +01001286
Gilles Peskine449bd832023-01-11 14:50:10 +01001287 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, i + j));
1288 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(X, 0));
Paul Bakker5121ce52009-01-03 21:22:43 +00001289
Tom Cosgrove6af26f32022-08-24 16:40:55 +01001290 mbedtls_mpi_core_mul(X->p, A->p, i, B->p, j);
Paul Bakker5121ce52009-01-03 21:22:43 +00001291
Hanno Beckerda763de2022-04-13 06:50:02 +01001292 /* If the result is 0, we don't shortcut the operation, which reduces
1293 * but does not eliminate side channels leaking the zero-ness. We do
1294 * need to take care to set the sign bit properly since the library does
1295 * not fully support an MPI object with a value of 0 and s == -1. */
Gilles Peskine449bd832023-01-11 14:50:10 +01001296 if (result_is_zero) {
Hanno Beckerda763de2022-04-13 06:50:02 +01001297 X->s = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +01001298 } else {
Hanno Beckerda763de2022-04-13 06:50:02 +01001299 X->s = A->s * B->s;
Gilles Peskine449bd832023-01-11 14:50:10 +01001300 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001301
1302cleanup:
1303
Gilles Peskine449bd832023-01-11 14:50:10 +01001304 mbedtls_mpi_free(&TB); mbedtls_mpi_free(&TA);
Paul Bakker5121ce52009-01-03 21:22:43 +00001305
Gilles Peskine449bd832023-01-11 14:50:10 +01001306 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001307}
1308
1309/*
1310 * Baseline multiplication: X = A * b
1311 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001312int mbedtls_mpi_mul_int(mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_uint b)
Paul Bakker5121ce52009-01-03 21:22:43 +00001313{
Gilles Peskine449bd832023-01-11 14:50:10 +01001314 MPI_VALIDATE_RET(X != NULL);
1315 MPI_VALIDATE_RET(A != NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +00001316
Hanno Becker35771312022-04-14 11:52:11 +01001317 size_t n = A->n;
Gilles Peskine449bd832023-01-11 14:50:10 +01001318 while (n > 0 && A->p[n - 1] == 0) {
Hanno Becker35771312022-04-14 11:52:11 +01001319 --n;
Gilles Peskine449bd832023-01-11 14:50:10 +01001320 }
Hanno Becker35771312022-04-14 11:52:11 +01001321
Hanno Becker74a11a32022-04-06 06:27:00 +01001322 /* The general method below doesn't work if b==0. */
Gilles Peskine449bd832023-01-11 14:50:10 +01001323 if (b == 0 || n == 0) {
1324 return mbedtls_mpi_lset(X, 0);
1325 }
Gilles Peskine8fd95c62020-07-23 21:58:50 +02001326
Hanno Beckeraef9cc42022-04-11 06:36:29 +01001327 /* Calculate A*b as A + A*(b-1) to take advantage of mbedtls_mpi_core_mla */
Gilles Peskine8fd95c62020-07-23 21:58:50 +02001328 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Gilles Peskinecd0dbf32020-07-24 00:09:04 +02001329 /* In general, A * b requires 1 limb more than b. If
1330 * A->p[n - 1] * b / b == A->p[n - 1], then A * b fits in the same
1331 * number of limbs as A and the call to grow() is not required since
Gilles Peskinee1bba7c2021-03-10 23:44:10 +01001332 * copy() will take care of the growth if needed. However, experimentally,
1333 * making the call to grow() unconditional causes slightly fewer
Gilles Peskinecd0dbf32020-07-24 00:09:04 +02001334 * calls to calloc() in ECP code, presumably because it reuses the
1335 * same mpi for a while and this way the mpi is more likely to directly
Hanno Becker9137b9c2022-04-12 10:51:54 +01001336 * grow to its final size.
1337 *
1338 * Note that calculating A*b as 0 + A*b doesn't work as-is because
1339 * A,X can be the same. */
Gilles Peskine449bd832023-01-11 14:50:10 +01001340 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, n + 1));
1341 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(X, A));
1342 mbedtls_mpi_core_mla(X->p, X->n, A->p, n, b - 1);
Gilles Peskine8fd95c62020-07-23 21:58:50 +02001343
1344cleanup:
Gilles Peskine449bd832023-01-11 14:50:10 +01001345 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001346}
1347
1348/*
Simon Butcherf5ba0452015-12-27 23:01:55 +00001349 * Unsigned integer divide - double mbedtls_mpi_uint dividend, u1/u0, and
1350 * mbedtls_mpi_uint divisor, d
Simon Butcher15b15d12015-11-26 19:35:03 +00001351 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001352static mbedtls_mpi_uint mbedtls_int_div_int(mbedtls_mpi_uint u1,
1353 mbedtls_mpi_uint u0,
1354 mbedtls_mpi_uint d,
1355 mbedtls_mpi_uint *r)
Simon Butcher15b15d12015-11-26 19:35:03 +00001356{
Manuel Pégourié-Gonnard16308882015-12-01 10:27:00 +01001357#if defined(MBEDTLS_HAVE_UDBL)
1358 mbedtls_t_udbl dividend, quotient;
Simon Butcherf5ba0452015-12-27 23:01:55 +00001359#else
Simon Butcher9803d072016-01-03 00:24:34 +00001360 const mbedtls_mpi_uint radix = (mbedtls_mpi_uint) 1 << biH;
Gilles Peskine449bd832023-01-11 14:50:10 +01001361 const mbedtls_mpi_uint uint_halfword_mask = ((mbedtls_mpi_uint) 1 << biH) - 1;
Simon Butcherf5ba0452015-12-27 23:01:55 +00001362 mbedtls_mpi_uint d0, d1, q0, q1, rAX, r0, quotient;
1363 mbedtls_mpi_uint u0_msw, u0_lsw;
Simon Butcher9803d072016-01-03 00:24:34 +00001364 size_t s;
Manuel Pégourié-Gonnard16308882015-12-01 10:27:00 +01001365#endif
1366
Simon Butcher15b15d12015-11-26 19:35:03 +00001367 /*
1368 * Check for overflow
1369 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001370 if (0 == d || u1 >= d) {
1371 if (r != NULL) {
1372 *r = ~(mbedtls_mpi_uint) 0u;
1373 }
Simon Butcher15b15d12015-11-26 19:35:03 +00001374
Gilles Peskine449bd832023-01-11 14:50:10 +01001375 return ~(mbedtls_mpi_uint) 0u;
Simon Butcher15b15d12015-11-26 19:35:03 +00001376 }
1377
1378#if defined(MBEDTLS_HAVE_UDBL)
Simon Butcher15b15d12015-11-26 19:35:03 +00001379 dividend = (mbedtls_t_udbl) u1 << biL;
1380 dividend |= (mbedtls_t_udbl) u0;
1381 quotient = dividend / d;
Gilles Peskine449bd832023-01-11 14:50:10 +01001382 if (quotient > ((mbedtls_t_udbl) 1 << biL) - 1) {
1383 quotient = ((mbedtls_t_udbl) 1 << biL) - 1;
1384 }
Simon Butcher15b15d12015-11-26 19:35:03 +00001385
Gilles Peskine449bd832023-01-11 14:50:10 +01001386 if (r != NULL) {
1387 *r = (mbedtls_mpi_uint) (dividend - (quotient * d));
1388 }
Simon Butcher15b15d12015-11-26 19:35:03 +00001389
1390 return (mbedtls_mpi_uint) quotient;
1391#else
Simon Butcher15b15d12015-11-26 19:35:03 +00001392
1393 /*
1394 * Algorithm D, Section 4.3.1 - The Art of Computer Programming
1395 * Vol. 2 - Seminumerical Algorithms, Knuth
1396 */
1397
1398 /*
1399 * Normalize the divisor, d, and dividend, u0, u1
1400 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001401 s = mbedtls_mpi_core_clz(d);
Simon Butcher15b15d12015-11-26 19:35:03 +00001402 d = d << s;
1403
1404 u1 = u1 << s;
Gilles Peskine449bd832023-01-11 14:50:10 +01001405 u1 |= (u0 >> (biL - s)) & (-(mbedtls_mpi_sint) s >> (biL - 1));
Simon Butcher15b15d12015-11-26 19:35:03 +00001406 u0 = u0 << s;
1407
1408 d1 = d >> biH;
Simon Butcher9803d072016-01-03 00:24:34 +00001409 d0 = d & uint_halfword_mask;
Simon Butcher15b15d12015-11-26 19:35:03 +00001410
1411 u0_msw = u0 >> biH;
Simon Butcher9803d072016-01-03 00:24:34 +00001412 u0_lsw = u0 & uint_halfword_mask;
Simon Butcher15b15d12015-11-26 19:35:03 +00001413
1414 /*
1415 * Find the first quotient and remainder
1416 */
1417 q1 = u1 / d1;
1418 r0 = u1 - d1 * q1;
1419
Gilles Peskine449bd832023-01-11 14:50:10 +01001420 while (q1 >= radix || (q1 * d0 > radix * r0 + u0_msw)) {
Simon Butcher15b15d12015-11-26 19:35:03 +00001421 q1 -= 1;
1422 r0 += d1;
1423
Gilles Peskine449bd832023-01-11 14:50:10 +01001424 if (r0 >= radix) {
1425 break;
1426 }
Simon Butcher15b15d12015-11-26 19:35:03 +00001427 }
1428
Gilles Peskine449bd832023-01-11 14:50:10 +01001429 rAX = (u1 * radix) + (u0_msw - q1 * d);
Simon Butcher15b15d12015-11-26 19:35:03 +00001430 q0 = rAX / d1;
1431 r0 = rAX - q0 * d1;
1432
Gilles Peskine449bd832023-01-11 14:50:10 +01001433 while (q0 >= radix || (q0 * d0 > radix * r0 + u0_lsw)) {
Simon Butcher15b15d12015-11-26 19:35:03 +00001434 q0 -= 1;
1435 r0 += d1;
1436
Gilles Peskine449bd832023-01-11 14:50:10 +01001437 if (r0 >= radix) {
1438 break;
1439 }
Simon Butcher15b15d12015-11-26 19:35:03 +00001440 }
1441
Gilles Peskine449bd832023-01-11 14:50:10 +01001442 if (r != NULL) {
1443 *r = (rAX * radix + u0_lsw - q0 * d) >> s;
1444 }
Simon Butcher15b15d12015-11-26 19:35:03 +00001445
1446 quotient = q1 * radix + q0;
1447
1448 return quotient;
1449#endif
1450}
1451
1452/*
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001453 * Division by mbedtls_mpi: A = Q * B + R (HAC 14.20)
Paul Bakker5121ce52009-01-03 21:22:43 +00001454 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001455int mbedtls_mpi_div_mpi(mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A,
1456 const mbedtls_mpi *B)
Paul Bakker5121ce52009-01-03 21:22:43 +00001457{
Janos Follath24eed8d2019-11-22 13:21:35 +00001458 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker23986e52011-04-24 08:57:21 +00001459 size_t i, n, t, k;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001460 mbedtls_mpi X, Y, Z, T1, T2;
Alexander Kd19a1932019-11-01 18:20:42 +03001461 mbedtls_mpi_uint TP2[3];
Gilles Peskine449bd832023-01-11 14:50:10 +01001462 MPI_VALIDATE_RET(A != NULL);
1463 MPI_VALIDATE_RET(B != NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +00001464
Gilles Peskine449bd832023-01-11 14:50:10 +01001465 if (mbedtls_mpi_cmp_int(B, 0) == 0) {
1466 return MBEDTLS_ERR_MPI_DIVISION_BY_ZERO;
1467 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001468
Gilles Peskine449bd832023-01-11 14:50:10 +01001469 mbedtls_mpi_init(&X); mbedtls_mpi_init(&Y); mbedtls_mpi_init(&Z);
1470 mbedtls_mpi_init(&T1);
Alexander Kd19a1932019-11-01 18:20:42 +03001471 /*
1472 * Avoid dynamic memory allocations for constant-size T2.
1473 *
1474 * T2 is used for comparison only and the 3 limbs are assigned explicitly,
1475 * so nobody increase the size of the MPI and we're safe to use an on-stack
1476 * buffer.
1477 */
Alexander K35d6d462019-10-31 14:46:45 +03001478 T2.s = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +01001479 T2.n = sizeof(TP2) / sizeof(*TP2);
Alexander Kd19a1932019-11-01 18:20:42 +03001480 T2.p = TP2;
Paul Bakker5121ce52009-01-03 21:22:43 +00001481
Gilles Peskine449bd832023-01-11 14:50:10 +01001482 if (mbedtls_mpi_cmp_abs(A, B) < 0) {
1483 if (Q != NULL) {
1484 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(Q, 0));
1485 }
1486 if (R != NULL) {
1487 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(R, A));
1488 }
1489 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +00001490 }
1491
Gilles Peskine449bd832023-01-11 14:50:10 +01001492 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&X, A));
1493 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&Y, B));
Paul Bakker5121ce52009-01-03 21:22:43 +00001494 X.s = Y.s = 1;
1495
Gilles Peskine449bd832023-01-11 14:50:10 +01001496 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(&Z, A->n + 2));
1497 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&Z, 0));
1498 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(&T1, A->n + 2));
Paul Bakker5121ce52009-01-03 21:22:43 +00001499
Gilles Peskine449bd832023-01-11 14:50:10 +01001500 k = mbedtls_mpi_bitlen(&Y) % biL;
1501 if (k < biL - 1) {
Paul Bakker5121ce52009-01-03 21:22:43 +00001502 k = biL - 1 - k;
Gilles Peskine449bd832023-01-11 14:50:10 +01001503 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&X, k));
1504 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&Y, k));
1505 } else {
1506 k = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +00001507 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001508
1509 n = X.n - 1;
1510 t = Y.n - 1;
Gilles Peskine449bd832023-01-11 14:50:10 +01001511 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&Y, biL * (n - t)));
Paul Bakker5121ce52009-01-03 21:22:43 +00001512
Gilles Peskine449bd832023-01-11 14:50:10 +01001513 while (mbedtls_mpi_cmp_mpi(&X, &Y) >= 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00001514 Z.p[n - t]++;
Gilles Peskine449bd832023-01-11 14:50:10 +01001515 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&X, &X, &Y));
Paul Bakker5121ce52009-01-03 21:22:43 +00001516 }
Gilles Peskine449bd832023-01-11 14:50:10 +01001517 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&Y, biL * (n - t)));
Paul Bakker5121ce52009-01-03 21:22:43 +00001518
Gilles Peskine449bd832023-01-11 14:50:10 +01001519 for (i = n; i > t; i--) {
1520 if (X.p[i] >= Y.p[t]) {
1521 Z.p[i - t - 1] = ~(mbedtls_mpi_uint) 0u;
1522 } else {
1523 Z.p[i - t - 1] = mbedtls_int_div_int(X.p[i], X.p[i - 1],
1524 Y.p[t], NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +00001525 }
1526
Gilles Peskine449bd832023-01-11 14:50:10 +01001527 T2.p[0] = (i < 2) ? 0 : X.p[i - 2];
1528 T2.p[1] = (i < 1) ? 0 : X.p[i - 1];
Alexander K35d6d462019-10-31 14:46:45 +03001529 T2.p[2] = X.p[i];
1530
Paul Bakker5121ce52009-01-03 21:22:43 +00001531 Z.p[i - t - 1]++;
Gilles Peskine449bd832023-01-11 14:50:10 +01001532 do {
Paul Bakker5121ce52009-01-03 21:22:43 +00001533 Z.p[i - t - 1]--;
1534
Gilles Peskine449bd832023-01-11 14:50:10 +01001535 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&T1, 0));
1536 T1.p[0] = (t < 1) ? 0 : Y.p[t - 1];
Paul Bakker5121ce52009-01-03 21:22:43 +00001537 T1.p[1] = Y.p[t];
Gilles Peskine449bd832023-01-11 14:50:10 +01001538 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_int(&T1, &T1, Z.p[i - t - 1]));
1539 } while (mbedtls_mpi_cmp_mpi(&T1, &T2) > 0);
Paul Bakker5121ce52009-01-03 21:22:43 +00001540
Gilles Peskine449bd832023-01-11 14:50:10 +01001541 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_int(&T1, &Y, Z.p[i - t - 1]));
1542 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&T1, biL * (i - t - 1)));
1543 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&X, &X, &T1));
Paul Bakker5121ce52009-01-03 21:22:43 +00001544
Gilles Peskine449bd832023-01-11 14:50:10 +01001545 if (mbedtls_mpi_cmp_int(&X, 0) < 0) {
1546 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&T1, &Y));
1547 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&T1, biL * (i - t - 1)));
1548 MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&X, &X, &T1));
Paul Bakker5121ce52009-01-03 21:22:43 +00001549 Z.p[i - t - 1]--;
1550 }
1551 }
1552
Gilles Peskine449bd832023-01-11 14:50:10 +01001553 if (Q != NULL) {
1554 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(Q, &Z));
Paul Bakker5121ce52009-01-03 21:22:43 +00001555 Q->s = A->s * B->s;
1556 }
1557
Gilles Peskine449bd832023-01-11 14:50:10 +01001558 if (R != NULL) {
1559 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&X, k));
Paul Bakkerf02c5642012-11-13 10:25:21 +00001560 X.s = A->s;
Gilles Peskine449bd832023-01-11 14:50:10 +01001561 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(R, &X));
Paul Bakker5121ce52009-01-03 21:22:43 +00001562
Gilles Peskine449bd832023-01-11 14:50:10 +01001563 if (mbedtls_mpi_cmp_int(R, 0) == 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00001564 R->s = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +01001565 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001566 }
1567
1568cleanup:
1569
Gilles Peskine449bd832023-01-11 14:50:10 +01001570 mbedtls_mpi_free(&X); mbedtls_mpi_free(&Y); mbedtls_mpi_free(&Z);
1571 mbedtls_mpi_free(&T1);
1572 mbedtls_platform_zeroize(TP2, sizeof(TP2));
Paul Bakker5121ce52009-01-03 21:22:43 +00001573
Gilles Peskine449bd832023-01-11 14:50:10 +01001574 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001575}
1576
1577/*
1578 * Division by int: A = Q * b + R
Paul Bakker5121ce52009-01-03 21:22:43 +00001579 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001580int mbedtls_mpi_div_int(mbedtls_mpi *Q, mbedtls_mpi *R,
1581 const mbedtls_mpi *A,
1582 mbedtls_mpi_sint b)
Paul Bakker5121ce52009-01-03 21:22:43 +00001583{
Yuto Takano36c8ddc2021-07-05 09:10:52 +01001584 mbedtls_mpi B;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001585 mbedtls_mpi_uint p[1];
Gilles Peskine449bd832023-01-11 14:50:10 +01001586 MPI_VALIDATE_RET(A != NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +00001587
Gilles Peskine449bd832023-01-11 14:50:10 +01001588 p[0] = mpi_sint_abs(b);
Dave Rodgmanf3df1052023-08-09 18:55:41 +01001589 B.s = TO_SIGN(b);
Yuto Takano36c8ddc2021-07-05 09:10:52 +01001590 B.n = 1;
1591 B.p = p;
Paul Bakker5121ce52009-01-03 21:22:43 +00001592
Gilles Peskine449bd832023-01-11 14:50:10 +01001593 return mbedtls_mpi_div_mpi(Q, R, A, &B);
Paul Bakker5121ce52009-01-03 21:22:43 +00001594}
1595
1596/*
1597 * Modulo: R = A mod B
1598 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001599int mbedtls_mpi_mod_mpi(mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B)
Paul Bakker5121ce52009-01-03 21:22:43 +00001600{
Janos Follath24eed8d2019-11-22 13:21:35 +00001601 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Gilles Peskine449bd832023-01-11 14:50:10 +01001602 MPI_VALIDATE_RET(R != NULL);
1603 MPI_VALIDATE_RET(A != NULL);
1604 MPI_VALIDATE_RET(B != NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +00001605
Gilles Peskine449bd832023-01-11 14:50:10 +01001606 if (mbedtls_mpi_cmp_int(B, 0) < 0) {
1607 return MBEDTLS_ERR_MPI_NEGATIVE_VALUE;
1608 }
Paul Bakkerce40a6d2009-06-23 19:46:08 +00001609
Gilles Peskine449bd832023-01-11 14:50:10 +01001610 MBEDTLS_MPI_CHK(mbedtls_mpi_div_mpi(NULL, R, A, B));
Paul Bakker5121ce52009-01-03 21:22:43 +00001611
Gilles Peskine449bd832023-01-11 14:50:10 +01001612 while (mbedtls_mpi_cmp_int(R, 0) < 0) {
1613 MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(R, R, B));
1614 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001615
Gilles Peskine449bd832023-01-11 14:50:10 +01001616 while (mbedtls_mpi_cmp_mpi(R, B) >= 0) {
1617 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(R, R, B));
1618 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001619
1620cleanup:
1621
Gilles Peskine449bd832023-01-11 14:50:10 +01001622 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001623}
1624
1625/*
1626 * Modulo: r = A mod b
1627 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001628int mbedtls_mpi_mod_int(mbedtls_mpi_uint *r, const mbedtls_mpi *A, mbedtls_mpi_sint b)
Paul Bakker5121ce52009-01-03 21:22:43 +00001629{
Paul Bakker23986e52011-04-24 08:57:21 +00001630 size_t i;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001631 mbedtls_mpi_uint x, y, z;
Gilles Peskine449bd832023-01-11 14:50:10 +01001632 MPI_VALIDATE_RET(r != NULL);
1633 MPI_VALIDATE_RET(A != NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +00001634
Gilles Peskine449bd832023-01-11 14:50:10 +01001635 if (b == 0) {
1636 return MBEDTLS_ERR_MPI_DIVISION_BY_ZERO;
1637 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001638
Gilles Peskine449bd832023-01-11 14:50:10 +01001639 if (b < 0) {
1640 return MBEDTLS_ERR_MPI_NEGATIVE_VALUE;
1641 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001642
1643 /*
1644 * handle trivial cases
1645 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001646 if (b == 1 || A->n == 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00001647 *r = 0;
Gilles Peskine449bd832023-01-11 14:50:10 +01001648 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +00001649 }
1650
Gilles Peskine449bd832023-01-11 14:50:10 +01001651 if (b == 2) {
Paul Bakker5121ce52009-01-03 21:22:43 +00001652 *r = A->p[0] & 1;
Gilles Peskine449bd832023-01-11 14:50:10 +01001653 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +00001654 }
1655
1656 /*
1657 * general case
1658 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001659 for (i = A->n, y = 0; i > 0; i--) {
Paul Bakker23986e52011-04-24 08:57:21 +00001660 x = A->p[i - 1];
Gilles Peskine449bd832023-01-11 14:50:10 +01001661 y = (y << biH) | (x >> biH);
Paul Bakker5121ce52009-01-03 21:22:43 +00001662 z = y / b;
1663 y -= z * b;
1664
1665 x <<= biH;
Gilles Peskine449bd832023-01-11 14:50:10 +01001666 y = (y << biH) | (x >> biH);
Paul Bakker5121ce52009-01-03 21:22:43 +00001667 z = y / b;
1668 y -= z * b;
1669 }
1670
Paul Bakkerce40a6d2009-06-23 19:46:08 +00001671 /*
1672 * If A is negative, then the current y represents a negative value.
1673 * Flipping it to the positive side.
1674 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001675 if (A->s < 0 && y != 0) {
Paul Bakkerce40a6d2009-06-23 19:46:08 +00001676 y = b - y;
Gilles Peskine449bd832023-01-11 14:50:10 +01001677 }
Paul Bakkerce40a6d2009-06-23 19:46:08 +00001678
Paul Bakker5121ce52009-01-03 21:22:43 +00001679 *r = y;
1680
Gilles Peskine449bd832023-01-11 14:50:10 +01001681 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +00001682}
1683
Gilles Peskine449bd832023-01-11 14:50:10 +01001684static void mpi_montg_init(mbedtls_mpi_uint *mm, const mbedtls_mpi *N)
Paul Bakker5121ce52009-01-03 21:22:43 +00001685{
Gilles Peskine449bd832023-01-11 14:50:10 +01001686 *mm = mbedtls_mpi_core_montmul_init(N->p);
Paul Bakker5121ce52009-01-03 21:22:43 +00001687}
1688
Tom Cosgrove93842842022-08-05 16:59:43 +01001689/** Montgomery multiplication: A = A * B * R^-1 mod N (HAC 14.36)
1690 *
1691 * \param[in,out] A One of the numbers to multiply.
1692 * It must have at least as many limbs as N
1693 * (A->n >= N->n), and any limbs beyond n are ignored.
1694 * On successful completion, A contains the result of
1695 * the multiplication A * B * R^-1 mod N where
1696 * R = (2^ciL)^n.
1697 * \param[in] B One of the numbers to multiply.
1698 * It must be nonzero and must not have more limbs than N
1699 * (B->n <= N->n).
Tom Cosgrove40d22942022-08-17 06:42:44 +01001700 * \param[in] N The modulus. \p N must be odd.
Tom Cosgrove93842842022-08-05 16:59:43 +01001701 * \param mm The value calculated by `mpi_montg_init(&mm, N)`.
1702 * This is -N^-1 mod 2^ciL.
1703 * \param[in,out] T A bignum for temporary storage.
1704 * It must be at least twice the limb size of N plus 1
1705 * (T->n >= 2 * N->n + 1).
1706 * Its initial content is unused and
1707 * its final content is indeterminate.
Tom Cosgrove5dd97e62022-08-30 14:31:49 +01001708 * It does not get reallocated.
Tom Cosgrove93842842022-08-05 16:59:43 +01001709 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001710static void mpi_montmul(mbedtls_mpi *A, const mbedtls_mpi *B,
1711 const mbedtls_mpi *N, mbedtls_mpi_uint mm,
1712 mbedtls_mpi *T)
Paul Bakker5121ce52009-01-03 21:22:43 +00001713{
Gilles Peskine449bd832023-01-11 14:50:10 +01001714 mbedtls_mpi_core_montmul(A->p, A->p, B->p, B->n, N->p, N->n, mm, T->p);
Paul Bakker5121ce52009-01-03 21:22:43 +00001715}
1716
1717/*
1718 * Montgomery reduction: A = A * R^-1 mod N
Gilles Peskine2a82f722020-06-04 15:00:49 +02001719 *
Tom Cosgrove93842842022-08-05 16:59:43 +01001720 * See mpi_montmul() regarding constraints and guarantees on the parameters.
Paul Bakker5121ce52009-01-03 21:22:43 +00001721 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001722static void mpi_montred(mbedtls_mpi *A, const mbedtls_mpi *N,
1723 mbedtls_mpi_uint mm, mbedtls_mpi *T)
Paul Bakker5121ce52009-01-03 21:22:43 +00001724{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001725 mbedtls_mpi_uint z = 1;
1726 mbedtls_mpi U;
Gilles Peskine053022f2023-06-29 19:26:48 +02001727 U.n = 1;
1728 U.s = 1;
Paul Bakker5121ce52009-01-03 21:22:43 +00001729 U.p = &z;
1730
Gilles Peskine449bd832023-01-11 14:50:10 +01001731 mpi_montmul(A, &U, N, mm, T);
Paul Bakker5121ce52009-01-03 21:22:43 +00001732}
1733
Manuel Pégourié-Gonnard1297ef32021-03-09 11:22:20 +01001734/**
1735 * Select an MPI from a table without leaking the index.
1736 *
1737 * This is functionally equivalent to mbedtls_mpi_copy(R, T[idx]) except it
1738 * reads the entire table in order to avoid leaking the value of idx to an
1739 * attacker able to observe memory access patterns.
1740 *
1741 * \param[out] R Where to write the selected MPI.
1742 * \param[in] T The table to read from.
1743 * \param[in] T_size The number of elements in the table.
1744 * \param[in] idx The index of the element to select;
1745 * this must satisfy 0 <= idx < T_size.
1746 *
1747 * \return \c 0 on success, or a negative error code.
1748 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001749static int mpi_select(mbedtls_mpi *R, const mbedtls_mpi *T, size_t T_size, size_t idx)
Manuel Pégourié-Gonnard1297ef32021-03-09 11:22:20 +01001750{
1751 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
1752
Gilles Peskine449bd832023-01-11 14:50:10 +01001753 for (size_t i = 0; i < T_size; i++) {
1754 MBEDTLS_MPI_CHK(mbedtls_mpi_safe_cond_assign(R, &T[i],
Dave Rodgmanb7825ce2023-08-10 11:58:18 +01001755 (unsigned char) mbedtls_ct_uint_eq(i, idx)));
Manuel Pégourié-Gonnard92413ef2021-06-03 10:42:46 +02001756 }
Manuel Pégourié-Gonnard1297ef32021-03-09 11:22:20 +01001757cleanup:
Gilles Peskine449bd832023-01-11 14:50:10 +01001758 return ret;
Manuel Pégourié-Gonnard1297ef32021-03-09 11:22:20 +01001759}
1760
Paul Bakker5121ce52009-01-03 21:22:43 +00001761/*
1762 * Sliding-window exponentiation: X = A^E mod N (HAC 14.85)
1763 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001764int mbedtls_mpi_exp_mod(mbedtls_mpi *X, const mbedtls_mpi *A,
1765 const mbedtls_mpi *E, const mbedtls_mpi *N,
1766 mbedtls_mpi *prec_RR)
Paul Bakker5121ce52009-01-03 21:22:43 +00001767{
Janos Follath24eed8d2019-11-22 13:21:35 +00001768 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Janos Follath74601202022-11-21 15:54:20 +00001769 size_t window_bitsize;
Paul Bakker23986e52011-04-24 08:57:21 +00001770 size_t i, j, nblimbs;
1771 size_t bufsize, nbits;
Paul Elliott1748de12023-02-13 15:35:35 +00001772 size_t exponent_bits_in_window = 0;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001773 mbedtls_mpi_uint ei, mm, state;
Gilles Peskine449bd832023-01-11 14:50:10 +01001774 mbedtls_mpi RR, T, W[(size_t) 1 << MBEDTLS_MPI_WINDOW_SIZE], WW, Apos;
Paul Bakkerf6198c12012-05-16 08:02:29 +00001775 int neg;
Paul Bakker5121ce52009-01-03 21:22:43 +00001776
Gilles Peskine449bd832023-01-11 14:50:10 +01001777 MPI_VALIDATE_RET(X != NULL);
1778 MPI_VALIDATE_RET(A != NULL);
1779 MPI_VALIDATE_RET(E != NULL);
1780 MPI_VALIDATE_RET(N != NULL);
Hanno Becker73d7d792018-12-11 10:35:51 +00001781
Gilles Peskine449bd832023-01-11 14:50:10 +01001782 if (mbedtls_mpi_cmp_int(N, 0) <= 0 || (N->p[0] & 1) == 0) {
1783 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
1784 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001785
Gilles Peskine449bd832023-01-11 14:50:10 +01001786 if (mbedtls_mpi_cmp_int(E, 0) < 0) {
1787 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
1788 }
Paul Bakkerf6198c12012-05-16 08:02:29 +00001789
Gilles Peskine449bd832023-01-11 14:50:10 +01001790 if (mbedtls_mpi_bitlen(E) > MBEDTLS_MPI_MAX_BITS ||
1791 mbedtls_mpi_bitlen(N) > MBEDTLS_MPI_MAX_BITS) {
1792 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
1793 }
Chris Jones9246d042020-11-25 15:12:39 +00001794
Paul Bakkerf6198c12012-05-16 08:02:29 +00001795 /*
Paul Bakker5121ce52009-01-03 21:22:43 +00001796 * Init temps and window size
1797 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001798 mpi_montg_init(&mm, N);
1799 mbedtls_mpi_init(&RR); mbedtls_mpi_init(&T);
1800 mbedtls_mpi_init(&Apos);
1801 mbedtls_mpi_init(&WW);
1802 memset(W, 0, sizeof(W));
Paul Bakker5121ce52009-01-03 21:22:43 +00001803
Gilles Peskine449bd832023-01-11 14:50:10 +01001804 i = mbedtls_mpi_bitlen(E);
Paul Bakker5121ce52009-01-03 21:22:43 +00001805
Gilles Peskine449bd832023-01-11 14:50:10 +01001806 window_bitsize = (i > 671) ? 6 : (i > 239) ? 5 :
1807 (i > 79) ? 4 : (i > 23) ? 3 : 1;
Paul Bakker5121ce52009-01-03 21:22:43 +00001808
Gilles Peskine449bd832023-01-11 14:50:10 +01001809#if (MBEDTLS_MPI_WINDOW_SIZE < 6)
1810 if (window_bitsize > MBEDTLS_MPI_WINDOW_SIZE) {
Janos Follath7fa11b82022-11-21 14:48:02 +00001811 window_bitsize = MBEDTLS_MPI_WINDOW_SIZE;
Gilles Peskine449bd832023-01-11 14:50:10 +01001812 }
Peter Kolbuse6bcad32018-12-11 14:01:44 -06001813#endif
Paul Bakkerb6d5f082011-11-25 11:52:11 +00001814
Janos Follathc8d66d52022-11-22 10:47:10 +00001815 const size_t w_table_used_size = (size_t) 1 << window_bitsize;
Janos Follath06000952022-11-22 10:18:06 +00001816
Paul Bakker5121ce52009-01-03 21:22:43 +00001817 /*
Janos Follathbe54ca72022-11-21 16:14:54 +00001818 * This function is not constant-trace: its memory accesses depend on the
1819 * exponent value. To defend against timing attacks, callers (such as RSA
1820 * and DHM) should use exponent blinding. However this is not enough if the
1821 * adversary can find the exponent in a single trace, so this function
1822 * takes extra precautions against adversaries who can observe memory
1823 * access patterns.
Janos Follathf08b40e2022-11-11 15:56:38 +00001824 *
Janos Follathbe54ca72022-11-21 16:14:54 +00001825 * This function performs a series of multiplications by table elements and
1826 * squarings, and we want the prevent the adversary from finding out which
1827 * table element was used, and from distinguishing between multiplications
1828 * and squarings. Firstly, when multiplying by an element of the window
1829 * W[i], we do a constant-trace table lookup to obfuscate i. This leaves
1830 * squarings as having a different memory access patterns from other
Gilles Peskinee6cb45e2023-08-10 15:59:28 +02001831 * multiplications. So secondly, we put the accumulator in the table as
1832 * well, and also do a constant-trace table lookup to multiply by the
1833 * accumulator which is W[x_index].
Janos Follathbe54ca72022-11-21 16:14:54 +00001834 *
1835 * This way, all multiplications take the form of a lookup-and-multiply.
1836 * The number of lookup-and-multiply operations inside each iteration of
1837 * the main loop still depends on the bits of the exponent, but since the
1838 * other operations in the loop don't have an easily recognizable memory
1839 * trace, an adversary is unlikely to be able to observe the exact
1840 * patterns.
1841 *
1842 * An adversary may still be able to recover the exponent if they can
1843 * observe both memory accesses and branches. However, branch prediction
1844 * exploitation typically requires many traces of execution over the same
1845 * data, which is defeated by randomized blinding.
Janos Follath8e7d6a02022-10-04 13:27:40 +01001846 */
Janos Follathc8d66d52022-11-22 10:47:10 +00001847 const size_t x_index = 0;
Gilles Peskine449bd832023-01-11 14:50:10 +01001848 mbedtls_mpi_init(&W[x_index]);
Janos Follath84461482022-11-21 14:31:22 +00001849
Paul Bakker5121ce52009-01-03 21:22:43 +00001850 j = N->n + 1;
Gilles Peskinee6cb45e2023-08-10 15:59:28 +02001851 /* All W[i] including the accumulator must have at least N->n limbs for
1852 * the mpi_montmul() and mpi_montred() calls later. Here we ensure that
1853 * W[1] and the accumulator W[x_index] are large enough. later we'll grow
1854 * other W[i] to the same length. They must not be shrunk midway through
1855 * this function!
Paul Bakker5121ce52009-01-03 21:22:43 +00001856 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001857 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(&W[x_index], j));
1858 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(&W[1], j));
1859 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(&T, j * 2));
Paul Bakker5121ce52009-01-03 21:22:43 +00001860
1861 /*
Paul Bakker50546922012-05-19 08:40:49 +00001862 * Compensate for negative A (and correct at the end)
1863 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001864 neg = (A->s == -1);
1865 if (neg) {
1866 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&Apos, A));
Paul Bakker50546922012-05-19 08:40:49 +00001867 Apos.s = 1;
1868 A = &Apos;
1869 }
1870
1871 /*
Paul Bakker5121ce52009-01-03 21:22:43 +00001872 * If 1st call, pre-compute R^2 mod N
1873 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001874 if (prec_RR == NULL || prec_RR->p == NULL) {
1875 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&RR, 1));
1876 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&RR, N->n * 2 * biL));
1877 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&RR, &RR, N));
Paul Bakker5121ce52009-01-03 21:22:43 +00001878
Gilles Peskine449bd832023-01-11 14:50:10 +01001879 if (prec_RR != NULL) {
1880 memcpy(prec_RR, &RR, sizeof(mbedtls_mpi));
1881 }
1882 } else {
1883 memcpy(&RR, prec_RR, sizeof(mbedtls_mpi));
Paul Bakker5121ce52009-01-03 21:22:43 +00001884 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001885
1886 /*
1887 * W[1] = A * R^2 * R^-1 mod N = A * R mod N
1888 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001889 if (mbedtls_mpi_cmp_mpi(A, N) >= 0) {
1890 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&W[1], A, N));
Gilles Peskine3da1a8f2021-06-08 23:17:42 +02001891 /* This should be a no-op because W[1] is already that large before
1892 * mbedtls_mpi_mod_mpi(), but it's necessary to avoid an overflow
Tom Cosgrove93842842022-08-05 16:59:43 +01001893 * in mpi_montmul() below, so let's make sure. */
Gilles Peskine449bd832023-01-11 14:50:10 +01001894 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(&W[1], N->n + 1));
1895 } else {
1896 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&W[1], A));
Gilles Peskine3da1a8f2021-06-08 23:17:42 +02001897 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001898
Gilles Peskine3da1a8f2021-06-08 23:17:42 +02001899 /* Note that this is safe because W[1] always has at least N->n limbs
1900 * (it grew above and was preserved by mbedtls_mpi_copy()). */
Gilles Peskine449bd832023-01-11 14:50:10 +01001901 mpi_montmul(&W[1], &RR, N, mm, &T);
Paul Bakker5121ce52009-01-03 21:22:43 +00001902
1903 /*
Janos Follath8e7d6a02022-10-04 13:27:40 +01001904 * W[x_index] = R^2 * R^-1 mod N = R mod N
Paul Bakker5121ce52009-01-03 21:22:43 +00001905 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001906 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&W[x_index], &RR));
1907 mpi_montred(&W[x_index], N, mm, &T);
Paul Bakker5121ce52009-01-03 21:22:43 +00001908
Janos Follathc8d66d52022-11-22 10:47:10 +00001909
Gilles Peskine449bd832023-01-11 14:50:10 +01001910 if (window_bitsize > 1) {
Paul Bakker5121ce52009-01-03 21:22:43 +00001911 /*
Janos Follath74601202022-11-21 15:54:20 +00001912 * W[i] = W[1] ^ i
1913 *
1914 * The first bit of the sliding window is always 1 and therefore we
1915 * only need to store the second half of the table.
Janos Follathc8d66d52022-11-22 10:47:10 +00001916 *
1917 * (There are two special elements in the table: W[0] for the
1918 * accumulator/result and W[1] for A in Montgomery form. Both of these
1919 * are already set at this point.)
Paul Bakker5121ce52009-01-03 21:22:43 +00001920 */
Janos Follath74601202022-11-21 15:54:20 +00001921 j = w_table_used_size / 2;
Paul Bakker5121ce52009-01-03 21:22:43 +00001922
Gilles Peskine449bd832023-01-11 14:50:10 +01001923 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(&W[j], N->n + 1));
1924 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&W[j], &W[1]));
Paul Bakker5121ce52009-01-03 21:22:43 +00001925
Gilles Peskine449bd832023-01-11 14:50:10 +01001926 for (i = 0; i < window_bitsize - 1; i++) {
1927 mpi_montmul(&W[j], &W[j], N, mm, &T);
1928 }
Paul Bakker0d7702c2013-10-29 16:18:35 +01001929
Paul Bakker5121ce52009-01-03 21:22:43 +00001930 /*
1931 * W[i] = W[i - 1] * W[1]
1932 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001933 for (i = j + 1; i < w_table_used_size; i++) {
1934 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(&W[i], N->n + 1));
1935 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&W[i], &W[i - 1]));
Paul Bakker5121ce52009-01-03 21:22:43 +00001936
Gilles Peskine449bd832023-01-11 14:50:10 +01001937 mpi_montmul(&W[i], &W[1], N, mm, &T);
Paul Bakker5121ce52009-01-03 21:22:43 +00001938 }
1939 }
1940
1941 nblimbs = E->n;
1942 bufsize = 0;
1943 nbits = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +00001944 state = 0;
1945
Gilles Peskine449bd832023-01-11 14:50:10 +01001946 while (1) {
1947 if (bufsize == 0) {
1948 if (nblimbs == 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00001949 break;
Gilles Peskine449bd832023-01-11 14:50:10 +01001950 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001951
Paul Bakker0d7702c2013-10-29 16:18:35 +01001952 nblimbs--;
1953
Gilles Peskine449bd832023-01-11 14:50:10 +01001954 bufsize = sizeof(mbedtls_mpi_uint) << 3;
Paul Bakker5121ce52009-01-03 21:22:43 +00001955 }
1956
1957 bufsize--;
1958
1959 ei = (E->p[nblimbs] >> bufsize) & 1;
1960
1961 /*
1962 * skip leading 0s
1963 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001964 if (ei == 0 && state == 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00001965 continue;
Gilles Peskine449bd832023-01-11 14:50:10 +01001966 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001967
Gilles Peskine449bd832023-01-11 14:50:10 +01001968 if (ei == 0 && state == 1) {
Paul Bakker5121ce52009-01-03 21:22:43 +00001969 /*
Janos Follath8e7d6a02022-10-04 13:27:40 +01001970 * out of window, square W[x_index]
Paul Bakker5121ce52009-01-03 21:22:43 +00001971 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001972 MBEDTLS_MPI_CHK(mpi_select(&WW, W, w_table_used_size, x_index));
1973 mpi_montmul(&W[x_index], &WW, N, mm, &T);
Paul Bakker5121ce52009-01-03 21:22:43 +00001974 continue;
1975 }
1976
1977 /*
1978 * add ei to current window
1979 */
1980 state = 2;
1981
1982 nbits++;
Gilles Peskine449bd832023-01-11 14:50:10 +01001983 exponent_bits_in_window |= (ei << (window_bitsize - nbits));
Paul Bakker5121ce52009-01-03 21:22:43 +00001984
Gilles Peskine449bd832023-01-11 14:50:10 +01001985 if (nbits == window_bitsize) {
Paul Bakker5121ce52009-01-03 21:22:43 +00001986 /*
Janos Follath7fa11b82022-11-21 14:48:02 +00001987 * W[x_index] = W[x_index]^window_bitsize R^-1 mod N
Paul Bakker5121ce52009-01-03 21:22:43 +00001988 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001989 for (i = 0; i < window_bitsize; i++) {
1990 MBEDTLS_MPI_CHK(mpi_select(&WW, W, w_table_used_size,
1991 x_index));
1992 mpi_montmul(&W[x_index], &WW, N, mm, &T);
Janos Follathb764ee12022-10-04 14:00:09 +01001993 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001994
1995 /*
Janos Follath7fa11b82022-11-21 14:48:02 +00001996 * W[x_index] = W[x_index] * W[exponent_bits_in_window] R^-1 mod N
Paul Bakker5121ce52009-01-03 21:22:43 +00001997 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001998 MBEDTLS_MPI_CHK(mpi_select(&WW, W, w_table_used_size,
1999 exponent_bits_in_window));
2000 mpi_montmul(&W[x_index], &WW, N, mm, &T);
Paul Bakker5121ce52009-01-03 21:22:43 +00002001
2002 state--;
2003 nbits = 0;
Janos Follath7fa11b82022-11-21 14:48:02 +00002004 exponent_bits_in_window = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +00002005 }
2006 }
2007
2008 /*
2009 * process the remaining bits
2010 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002011 for (i = 0; i < nbits; i++) {
2012 MBEDTLS_MPI_CHK(mpi_select(&WW, W, w_table_used_size, x_index));
2013 mpi_montmul(&W[x_index], &WW, N, mm, &T);
Paul Bakker5121ce52009-01-03 21:22:43 +00002014
Janos Follath7fa11b82022-11-21 14:48:02 +00002015 exponent_bits_in_window <<= 1;
Paul Bakker5121ce52009-01-03 21:22:43 +00002016
Gilles Peskine449bd832023-01-11 14:50:10 +01002017 if ((exponent_bits_in_window & ((size_t) 1 << window_bitsize)) != 0) {
2018 MBEDTLS_MPI_CHK(mpi_select(&WW, W, w_table_used_size, 1));
2019 mpi_montmul(&W[x_index], &WW, N, mm, &T);
Janos Follathb764ee12022-10-04 14:00:09 +01002020 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002021 }
2022
2023 /*
Janos Follath8e7d6a02022-10-04 13:27:40 +01002024 * W[x_index] = A^E * R * R^-1 mod N = A^E mod N
Paul Bakker5121ce52009-01-03 21:22:43 +00002025 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002026 mpi_montred(&W[x_index], N, mm, &T);
Paul Bakker5121ce52009-01-03 21:22:43 +00002027
Gilles Peskine449bd832023-01-11 14:50:10 +01002028 if (neg && E->n != 0 && (E->p[0] & 1) != 0) {
Janos Follath8e7d6a02022-10-04 13:27:40 +01002029 W[x_index].s = -1;
Gilles Peskine449bd832023-01-11 14:50:10 +01002030 MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&W[x_index], N, &W[x_index]));
Paul Bakkerf6198c12012-05-16 08:02:29 +00002031 }
2032
Janos Follath8e7d6a02022-10-04 13:27:40 +01002033 /*
2034 * Load the result in the output variable.
2035 */
Chien Wonge2caf412023-08-01 21:38:46 +08002036 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(X, &W[x_index]));
Janos Follath8e7d6a02022-10-04 13:27:40 +01002037
Paul Bakker5121ce52009-01-03 21:22:43 +00002038cleanup:
2039
Janos Follathb2c2fca2022-11-21 15:05:31 +00002040 /* The first bit of the sliding window is always 1 and therefore the first
2041 * half of the table was unused. */
Gilles Peskine449bd832023-01-11 14:50:10 +01002042 for (i = w_table_used_size/2; i < w_table_used_size; i++) {
2043 mbedtls_mpi_free(&W[i]);
2044 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002045
Gilles Peskine449bd832023-01-11 14:50:10 +01002046 mbedtls_mpi_free(&W[x_index]);
2047 mbedtls_mpi_free(&W[1]);
2048 mbedtls_mpi_free(&T);
2049 mbedtls_mpi_free(&Apos);
2050 mbedtls_mpi_free(&WW);
Paul Bakker6c591fa2011-05-05 11:49:20 +00002051
Gilles Peskine449bd832023-01-11 14:50:10 +01002052 if (prec_RR == NULL || prec_RR->p == NULL) {
2053 mbedtls_mpi_free(&RR);
2054 }
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
Paul Bakker5121ce52009-01-03 21:22:43 +00002059/*
2060 * Greatest common divisor: G = gcd(A, B) (HAC 14.54)
2061 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002062int mbedtls_mpi_gcd(mbedtls_mpi *G, const mbedtls_mpi *A, const mbedtls_mpi *B)
Paul Bakker5121ce52009-01-03 21:22:43 +00002063{
Janos Follath24eed8d2019-11-22 13:21:35 +00002064 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker23986e52011-04-24 08:57:21 +00002065 size_t lz, lzt;
Alexander Ke8ad49f2019-08-16 16:16:07 +03002066 mbedtls_mpi TA, TB;
Paul Bakker5121ce52009-01-03 21:22:43 +00002067
Gilles Peskine449bd832023-01-11 14:50:10 +01002068 MPI_VALIDATE_RET(G != NULL);
2069 MPI_VALIDATE_RET(A != NULL);
2070 MPI_VALIDATE_RET(B != NULL);
Hanno Becker73d7d792018-12-11 10:35:51 +00002071
Gilles Peskine449bd832023-01-11 14:50:10 +01002072 mbedtls_mpi_init(&TA); mbedtls_mpi_init(&TB);
Paul Bakker5121ce52009-01-03 21:22:43 +00002073
Gilles Peskine449bd832023-01-11 14:50:10 +01002074 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TA, A));
2075 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TB, B));
Paul Bakker5121ce52009-01-03 21:22:43 +00002076
Gilles Peskine449bd832023-01-11 14:50:10 +01002077 lz = mbedtls_mpi_lsb(&TA);
2078 lzt = mbedtls_mpi_lsb(&TB);
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002079
Gilles Peskine27253bc2021-06-09 13:26:43 +02002080 /* The loop below gives the correct result when A==0 but not when B==0.
2081 * So have a special case for B==0. Leverage the fact that we just
2082 * calculated the lsb and lsb(B)==0 iff B is odd or 0 to make the test
2083 * slightly more efficient than cmp_int(). */
Gilles Peskine449bd832023-01-11 14:50:10 +01002084 if (lzt == 0 && mbedtls_mpi_get_bit(&TB, 0) == 0) {
2085 ret = mbedtls_mpi_copy(G, A);
Gilles Peskine27253bc2021-06-09 13:26:43 +02002086 goto cleanup;
2087 }
2088
Gilles Peskine449bd832023-01-11 14:50:10 +01002089 if (lzt < lz) {
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002090 lz = lzt;
Gilles Peskine449bd832023-01-11 14:50:10 +01002091 }
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002092
Paul Bakker5121ce52009-01-03 21:22:43 +00002093 TA.s = TB.s = 1;
2094
Gilles Peskine2a63c5b2021-06-16 13:42:04 +02002095 /* We mostly follow the procedure described in HAC 14.54, but with some
2096 * minor differences:
2097 * - Sequences of multiplications or divisions by 2 are grouped into a
2098 * single shift operation.
Gilles Peskineb09c7ee2021-06-21 18:58:39 +02002099 * - The procedure in HAC assumes that 0 < TB <= TA.
2100 * - The condition TB <= TA is not actually necessary for correctness.
2101 * TA and TB have symmetric roles except for the loop termination
2102 * condition, and the shifts at the beginning of the loop body
2103 * remove any significance from the ordering of TA vs TB before
2104 * the shifts.
2105 * - If TA = 0, the loop goes through 0 iterations and the result is
2106 * correctly TB.
2107 * - The case TB = 0 was short-circuited above.
Gilles Peskine2a63c5b2021-06-16 13:42:04 +02002108 *
2109 * For the correctness proof below, decompose the original values of
2110 * A and B as
2111 * A = sa * 2^a * A' with A'=0 or A' odd, and sa = +-1
2112 * B = sb * 2^b * B' with B'=0 or B' odd, and sb = +-1
2113 * Then gcd(A, B) = 2^{min(a,b)} * gcd(A',B'),
2114 * and gcd(A',B') is odd or 0.
2115 *
2116 * At the beginning, we have TA = |A| and TB = |B| so gcd(A,B) = gcd(TA,TB).
2117 * The code maintains the following invariant:
2118 * gcd(A,B) = 2^k * gcd(TA,TB) for some k (I)
Gilles Peskine4df3f1f2021-06-15 22:09:39 +02002119 */
2120
Gilles Peskine2a63c5b2021-06-16 13:42:04 +02002121 /* Proof that the loop terminates:
2122 * At each iteration, either the right-shift by 1 is made on a nonzero
2123 * value and the nonnegative integer bitlen(TA) + bitlen(TB) decreases
2124 * by at least 1, or the right-shift by 1 is made on zero and then
2125 * TA becomes 0 which ends the loop (TB cannot be 0 if it is right-shifted
2126 * since in that case TB is calculated from TB-TA with the condition TB>TA).
2127 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002128 while (mbedtls_mpi_cmp_int(&TA, 0) != 0) {
Gilles Peskine2a63c5b2021-06-16 13:42:04 +02002129 /* Divisions by 2 preserve the invariant (I). */
Gilles Peskine449bd832023-01-11 14:50:10 +01002130 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TA, mbedtls_mpi_lsb(&TA)));
2131 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TB, mbedtls_mpi_lsb(&TB)));
Paul Bakker5121ce52009-01-03 21:22:43 +00002132
Gilles Peskine2a63c5b2021-06-16 13:42:04 +02002133 /* Set either TA or TB to |TA-TB|/2. Since TA and TB are both odd,
2134 * TA-TB is even so the division by 2 has an integer result.
2135 * Invariant (I) is preserved since any odd divisor of both TA and TB
2136 * also divides |TA-TB|/2, and any odd divisor of both TA and |TA-TB|/2
Shaun Case8b0ecbc2021-12-20 21:14:10 -08002137 * also divides TB, and any odd divisor of both TB and |TA-TB|/2 also
Gilles Peskine2a63c5b2021-06-16 13:42:04 +02002138 * divides TA.
2139 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002140 if (mbedtls_mpi_cmp_mpi(&TA, &TB) >= 0) {
2141 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_abs(&TA, &TA, &TB));
2142 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TA, 1));
2143 } else {
2144 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_abs(&TB, &TB, &TA));
2145 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TB, 1));
Paul Bakker5121ce52009-01-03 21:22:43 +00002146 }
Gilles Peskine2a63c5b2021-06-16 13:42:04 +02002147 /* Note that one of TA or TB is still odd. */
Paul Bakker5121ce52009-01-03 21:22:43 +00002148 }
2149
Gilles Peskine2a63c5b2021-06-16 13:42:04 +02002150 /* By invariant (I), gcd(A,B) = 2^k * gcd(TA,TB) for some k.
2151 * At the loop exit, TA = 0, so gcd(TA,TB) = TB.
2152 * - If there was at least one loop iteration, then one of TA or TB is odd,
2153 * and TA = 0, so TB is odd and gcd(TA,TB) = gcd(A',B'). In this case,
2154 * lz = min(a,b) so gcd(A,B) = 2^lz * TB.
2155 * - If there was no loop iteration, then A was 0, and gcd(A,B) = B.
Gilles Peskine4d3fd362021-06-21 11:40:38 +02002156 * 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 +02002157 */
2158
Gilles Peskine449bd832023-01-11 14:50:10 +01002159 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&TB, lz));
2160 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(G, &TB));
Paul Bakker5121ce52009-01-03 21:22:43 +00002161
2162cleanup:
2163
Gilles Peskine449bd832023-01-11 14:50:10 +01002164 mbedtls_mpi_free(&TA); mbedtls_mpi_free(&TB);
Paul Bakker5121ce52009-01-03 21:22:43 +00002165
Gilles Peskine449bd832023-01-11 14:50:10 +01002166 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00002167}
2168
Paul Bakker33dc46b2014-04-30 16:11:39 +02002169/*
2170 * Fill X with size bytes of random.
Gilles Peskine22cdd0c2022-10-27 20:15:13 +02002171 * The bytes returned from the RNG are used in a specific order which
2172 * is suitable for deterministic ECDSA (see the specification of
2173 * mbedtls_mpi_random() and the implementation in mbedtls_mpi_fill_random()).
Paul Bakker33dc46b2014-04-30 16:11:39 +02002174 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002175int mbedtls_mpi_fill_random(mbedtls_mpi *X, size_t size,
2176 int (*f_rng)(void *, unsigned char *, size_t),
2177 void *p_rng)
Paul Bakker287781a2011-03-26 13:18:49 +00002178{
Janos Follath24eed8d2019-11-22 13:21:35 +00002179 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Gilles Peskine449bd832023-01-11 14:50:10 +01002180 const size_t limbs = CHARS_TO_LIMBS(size);
Hanno Beckerda1655a2017-10-18 14:21:44 +01002181
Gilles Peskine449bd832023-01-11 14:50:10 +01002182 MPI_VALIDATE_RET(X != NULL);
2183 MPI_VALIDATE_RET(f_rng != NULL);
Paul Bakker33dc46b2014-04-30 16:11:39 +02002184
Hanno Beckerda1655a2017-10-18 14:21:44 +01002185 /* Ensure that target MPI has exactly the necessary number of limbs */
Gilles Peskine449bd832023-01-11 14:50:10 +01002186 MBEDTLS_MPI_CHK(mbedtls_mpi_resize_clear(X, limbs));
2187 if (size == 0) {
2188 return 0;
2189 }
Paul Bakker287781a2011-03-26 13:18:49 +00002190
Gilles Peskine449bd832023-01-11 14:50:10 +01002191 ret = mbedtls_mpi_core_fill_random(X->p, X->n, size, f_rng, p_rng);
Paul Bakker287781a2011-03-26 13:18:49 +00002192
2193cleanup:
Gilles Peskine449bd832023-01-11 14:50:10 +01002194 return ret;
Paul Bakker287781a2011-03-26 13:18:49 +00002195}
2196
Gilles Peskine449bd832023-01-11 14:50:10 +01002197int mbedtls_mpi_random(mbedtls_mpi *X,
2198 mbedtls_mpi_sint min,
2199 const mbedtls_mpi *N,
2200 int (*f_rng)(void *, unsigned char *, size_t),
2201 void *p_rng)
Gilles Peskine02ac93a2021-03-29 22:02:55 +02002202{
Gilles Peskine449bd832023-01-11 14:50:10 +01002203 if (min < 0) {
2204 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
2205 }
2206 if (mbedtls_mpi_cmp_int(N, min) <= 0) {
2207 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
2208 }
Gilles Peskine1e918f42021-03-29 22:14:51 +02002209
Gilles Peskine1a7df4e2021-04-01 15:57:18 +02002210 /* Ensure that target MPI has exactly the same number of limbs
2211 * as the upper bound, even if the upper bound has leading zeros.
Gilles Peskine6b7ce962022-12-15 15:04:33 +01002212 * This is necessary for mbedtls_mpi_core_random. */
Gilles Peskine449bd832023-01-11 14:50:10 +01002213 int ret = mbedtls_mpi_resize_clear(X, N->n);
2214 if (ret != 0) {
2215 return ret;
2216 }
Gilles Peskine1a7df4e2021-04-01 15:57:18 +02002217
Gilles Peskine449bd832023-01-11 14:50:10 +01002218 return mbedtls_mpi_core_random(X->p, min, N->p, X->n, f_rng, p_rng);
Gilles Peskine02ac93a2021-03-29 22:02:55 +02002219}
2220
Paul Bakker5121ce52009-01-03 21:22:43 +00002221/*
2222 * Modular inverse: X = A^-1 mod N (HAC 14.61 / 14.64)
2223 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002224int mbedtls_mpi_inv_mod(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *N)
Paul Bakker5121ce52009-01-03 21:22:43 +00002225{
Janos Follath24eed8d2019-11-22 13:21:35 +00002226 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002227 mbedtls_mpi G, TA, TU, U1, U2, TB, TV, V1, V2;
Gilles Peskine449bd832023-01-11 14:50:10 +01002228 MPI_VALIDATE_RET(X != NULL);
2229 MPI_VALIDATE_RET(A != NULL);
2230 MPI_VALIDATE_RET(N != NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +00002231
Gilles Peskine449bd832023-01-11 14:50:10 +01002232 if (mbedtls_mpi_cmp_int(N, 1) <= 0) {
2233 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
2234 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002235
Gilles Peskine449bd832023-01-11 14:50:10 +01002236 mbedtls_mpi_init(&TA); mbedtls_mpi_init(&TU); mbedtls_mpi_init(&U1); mbedtls_mpi_init(&U2);
2237 mbedtls_mpi_init(&G); mbedtls_mpi_init(&TB); mbedtls_mpi_init(&TV);
2238 mbedtls_mpi_init(&V1); mbedtls_mpi_init(&V2);
Paul Bakker5121ce52009-01-03 21:22:43 +00002239
Gilles Peskine449bd832023-01-11 14:50:10 +01002240 MBEDTLS_MPI_CHK(mbedtls_mpi_gcd(&G, A, N));
Paul Bakker5121ce52009-01-03 21:22:43 +00002241
Gilles Peskine449bd832023-01-11 14:50:10 +01002242 if (mbedtls_mpi_cmp_int(&G, 1) != 0) {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002243 ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
Paul Bakker5121ce52009-01-03 21:22:43 +00002244 goto cleanup;
2245 }
2246
Gilles Peskine449bd832023-01-11 14:50:10 +01002247 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&TA, A, N));
2248 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TU, &TA));
2249 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TB, N));
2250 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TV, N));
Paul Bakker5121ce52009-01-03 21:22:43 +00002251
Gilles Peskine449bd832023-01-11 14:50:10 +01002252 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&U1, 1));
2253 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&U2, 0));
2254 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&V1, 0));
2255 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&V2, 1));
Paul Bakker5121ce52009-01-03 21:22:43 +00002256
Gilles Peskine449bd832023-01-11 14:50:10 +01002257 do {
2258 while ((TU.p[0] & 1) == 0) {
2259 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TU, 1));
Paul Bakker5121ce52009-01-03 21:22:43 +00002260
Gilles Peskine449bd832023-01-11 14:50:10 +01002261 if ((U1.p[0] & 1) != 0 || (U2.p[0] & 1) != 0) {
2262 MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&U1, &U1, &TB));
2263 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&U2, &U2, &TA));
Paul Bakker5121ce52009-01-03 21:22:43 +00002264 }
2265
Gilles Peskine449bd832023-01-11 14:50:10 +01002266 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&U1, 1));
2267 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&U2, 1));
Paul Bakker5121ce52009-01-03 21:22:43 +00002268 }
2269
Gilles Peskine449bd832023-01-11 14:50:10 +01002270 while ((TV.p[0] & 1) == 0) {
2271 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TV, 1));
Paul Bakker5121ce52009-01-03 21:22:43 +00002272
Gilles Peskine449bd832023-01-11 14:50:10 +01002273 if ((V1.p[0] & 1) != 0 || (V2.p[0] & 1) != 0) {
2274 MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&V1, &V1, &TB));
2275 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&V2, &V2, &TA));
Paul Bakker5121ce52009-01-03 21:22:43 +00002276 }
2277
Gilles Peskine449bd832023-01-11 14:50:10 +01002278 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&V1, 1));
2279 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&V2, 1));
Paul Bakker5121ce52009-01-03 21:22:43 +00002280 }
2281
Gilles Peskine449bd832023-01-11 14:50:10 +01002282 if (mbedtls_mpi_cmp_mpi(&TU, &TV) >= 0) {
2283 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&TU, &TU, &TV));
2284 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&U1, &U1, &V1));
2285 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&U2, &U2, &V2));
2286 } else {
2287 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&TV, &TV, &TU));
2288 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&V1, &V1, &U1));
2289 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&V2, &V2, &U2));
Paul Bakker5121ce52009-01-03 21:22:43 +00002290 }
Gilles Peskine449bd832023-01-11 14:50:10 +01002291 } while (mbedtls_mpi_cmp_int(&TU, 0) != 0);
2292
2293 while (mbedtls_mpi_cmp_int(&V1, 0) < 0) {
2294 MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&V1, &V1, N));
Paul Bakker5121ce52009-01-03 21:22:43 +00002295 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002296
Gilles Peskine449bd832023-01-11 14:50:10 +01002297 while (mbedtls_mpi_cmp_mpi(&V1, N) >= 0) {
2298 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&V1, &V1, N));
2299 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002300
Gilles Peskine449bd832023-01-11 14:50:10 +01002301 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(X, &V1));
Paul Bakker5121ce52009-01-03 21:22:43 +00002302
2303cleanup:
2304
Gilles Peskine449bd832023-01-11 14:50:10 +01002305 mbedtls_mpi_free(&TA); mbedtls_mpi_free(&TU); mbedtls_mpi_free(&U1); mbedtls_mpi_free(&U2);
2306 mbedtls_mpi_free(&G); mbedtls_mpi_free(&TB); mbedtls_mpi_free(&TV);
2307 mbedtls_mpi_free(&V1); mbedtls_mpi_free(&V2);
Paul Bakker5121ce52009-01-03 21:22:43 +00002308
Gilles Peskine449bd832023-01-11 14:50:10 +01002309 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00002310}
2311
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002312#if defined(MBEDTLS_GENPRIME)
Paul Bakkerd9374b02012-11-02 11:02:58 +00002313
Gilles Peskineb2bc1712019-02-08 17:27:11 +01002314/* Gaps between primes, starting at 3. https://oeis.org/A001223 */
2315static const unsigned char small_prime_gaps[] = {
2316 2, 2, 4, 2, 4, 2, 4, 6,
2317 2, 6, 4, 2, 4, 6, 6, 2,
2318 6, 4, 2, 6, 4, 6, 8, 4,
2319 2, 4, 2, 4, 14, 4, 6, 2,
2320 10, 2, 6, 6, 4, 6, 6, 2,
2321 10, 2, 4, 2, 12, 12, 4, 2,
2322 4, 6, 2, 10, 6, 6, 6, 2,
2323 6, 4, 2, 10, 14, 4, 2, 4,
2324 14, 6, 10, 2, 4, 6, 8, 6,
2325 6, 4, 6, 8, 4, 8, 10, 2,
2326 10, 2, 6, 4, 6, 8, 4, 2,
2327 4, 12, 8, 4, 8, 4, 6, 12,
2328 2, 18, 6, 10, 6, 6, 2, 6,
2329 10, 6, 6, 2, 6, 6, 4, 2,
2330 12, 10, 2, 4, 6, 6, 2, 12,
2331 4, 6, 8, 10, 8, 10, 8, 6,
2332 6, 4, 8, 6, 4, 8, 4, 14,
2333 10, 12, 2, 10, 2, 4, 2, 10,
2334 14, 4, 2, 4, 14, 4, 2, 4,
2335 20, 4, 8, 10, 8, 4, 6, 6,
2336 14, 4, 6, 6, 8, 6, /*reaches 997*/
Gilles Peskine30b03782023-08-22 11:06:47 +02002337 0 /* the last entry is effectively unused */
Paul Bakker5121ce52009-01-03 21:22:43 +00002338};
2339
2340/*
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002341 * Small divisors test (X must be positive)
2342 *
2343 * Return values:
2344 * 0: no small factor (possible prime, more tests needed)
2345 * 1: certain prime
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002346 * MBEDTLS_ERR_MPI_NOT_ACCEPTABLE: certain non-prime
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002347 * other negative: error
Paul Bakker5121ce52009-01-03 21:22:43 +00002348 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002349static int mpi_check_small_factors(const mbedtls_mpi *X)
Paul Bakker5121ce52009-01-03 21:22:43 +00002350{
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002351 int ret = 0;
2352 size_t i;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002353 mbedtls_mpi_uint r;
Gilles Peskineb2bc1712019-02-08 17:27:11 +01002354 unsigned p = 3; /* The first odd prime */
Paul Bakker5121ce52009-01-03 21:22:43 +00002355
Gilles Peskine449bd832023-01-11 14:50:10 +01002356 if ((X->p[0] & 1) == 0) {
2357 return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2358 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002359
Gilles Peskineb2bc1712019-02-08 17:27:11 +01002360 for (i = 0; i < sizeof(small_prime_gaps); p += small_prime_gaps[i], i++) {
2361 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_int(&r, X, p));
Gilles Peskine449bd832023-01-11 14:50:10 +01002362 if (r == 0) {
Gilles Peskineb2bc1712019-02-08 17:27:11 +01002363 if (mbedtls_mpi_cmp_int(X, p) == 0) {
2364 return 1;
2365 } else {
2366 return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2367 }
Gilles Peskine449bd832023-01-11 14:50:10 +01002368 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002369 }
2370
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002371cleanup:
Gilles Peskine449bd832023-01-11 14:50:10 +01002372 return ret;
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002373}
2374
2375/*
2376 * Miller-Rabin pseudo-primality test (HAC 4.24)
2377 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002378static int mpi_miller_rabin(const mbedtls_mpi *X, size_t rounds,
2379 int (*f_rng)(void *, unsigned char *, size_t),
2380 void *p_rng)
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002381{
Pascal Junodb99183d2015-03-11 16:49:45 +01002382 int ret, count;
Janos Follathda31fa12018-09-03 14:45:23 +01002383 size_t i, j, k, s;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002384 mbedtls_mpi W, R, T, A, RR;
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002385
Gilles Peskine449bd832023-01-11 14:50:10 +01002386 MPI_VALIDATE_RET(X != NULL);
2387 MPI_VALIDATE_RET(f_rng != NULL);
Hanno Becker73d7d792018-12-11 10:35:51 +00002388
Gilles Peskine449bd832023-01-11 14:50:10 +01002389 mbedtls_mpi_init(&W); mbedtls_mpi_init(&R);
2390 mbedtls_mpi_init(&T); mbedtls_mpi_init(&A);
2391 mbedtls_mpi_init(&RR);
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002392
Paul Bakker5121ce52009-01-03 21:22:43 +00002393 /*
2394 * W = |X| - 1
2395 * R = W >> lsb( W )
2396 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002397 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(&W, X, 1));
2398 s = mbedtls_mpi_lsb(&W);
2399 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&R, &W));
2400 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&R, s));
Paul Bakker5121ce52009-01-03 21:22:43 +00002401
Gilles Peskine449bd832023-01-11 14:50:10 +01002402 for (i = 0; i < rounds; i++) {
Paul Bakker5121ce52009-01-03 21:22:43 +00002403 /*
2404 * pick a random A, 1 < A < |X| - 1
2405 */
Pascal Junodb99183d2015-03-11 16:49:45 +01002406 count = 0;
2407 do {
Gilles Peskine449bd832023-01-11 14:50:10 +01002408 MBEDTLS_MPI_CHK(mbedtls_mpi_fill_random(&A, X->n * ciL, f_rng, p_rng));
Pascal Junodb99183d2015-03-11 16:49:45 +01002409
Gilles Peskine449bd832023-01-11 14:50:10 +01002410 j = mbedtls_mpi_bitlen(&A);
2411 k = mbedtls_mpi_bitlen(&W);
Pascal Junodb99183d2015-03-11 16:49:45 +01002412 if (j > k) {
Gilles Peskine449bd832023-01-11 14:50:10 +01002413 A.p[A.n - 1] &= ((mbedtls_mpi_uint) 1 << (k - (A.n - 1) * biL - 1)) - 1;
Pascal Junodb99183d2015-03-11 16:49:45 +01002414 }
2415
2416 if (count++ > 30) {
Jens Wiklanderf08aa3e2019-01-17 13:30:57 +01002417 ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2418 goto cleanup;
Pascal Junodb99183d2015-03-11 16:49:45 +01002419 }
2420
Gilles Peskine449bd832023-01-11 14:50:10 +01002421 } while (mbedtls_mpi_cmp_mpi(&A, &W) >= 0 ||
2422 mbedtls_mpi_cmp_int(&A, 1) <= 0);
Paul Bakker5121ce52009-01-03 21:22:43 +00002423
2424 /*
2425 * A = A^R mod |X|
2426 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002427 MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&A, &A, &R, X, &RR));
Paul Bakker5121ce52009-01-03 21:22:43 +00002428
Gilles Peskine449bd832023-01-11 14:50:10 +01002429 if (mbedtls_mpi_cmp_mpi(&A, &W) == 0 ||
2430 mbedtls_mpi_cmp_int(&A, 1) == 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00002431 continue;
Gilles Peskine449bd832023-01-11 14:50:10 +01002432 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002433
2434 j = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +01002435 while (j < s && mbedtls_mpi_cmp_mpi(&A, &W) != 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00002436 /*
2437 * A = A * A mod |X|
2438 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002439 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&T, &A, &A));
2440 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&A, &T, X));
Paul Bakker5121ce52009-01-03 21:22:43 +00002441
Gilles Peskine449bd832023-01-11 14:50:10 +01002442 if (mbedtls_mpi_cmp_int(&A, 1) == 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00002443 break;
Gilles Peskine449bd832023-01-11 14:50:10 +01002444 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002445
2446 j++;
2447 }
2448
2449 /*
2450 * not prime if A != |X| - 1 or A == 1
2451 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002452 if (mbedtls_mpi_cmp_mpi(&A, &W) != 0 ||
2453 mbedtls_mpi_cmp_int(&A, 1) == 0) {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002454 ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
Paul Bakker5121ce52009-01-03 21:22:43 +00002455 break;
2456 }
2457 }
2458
2459cleanup:
Gilles Peskine449bd832023-01-11 14:50:10 +01002460 mbedtls_mpi_free(&W); mbedtls_mpi_free(&R);
2461 mbedtls_mpi_free(&T); mbedtls_mpi_free(&A);
2462 mbedtls_mpi_free(&RR);
Paul Bakker5121ce52009-01-03 21:22:43 +00002463
Gilles Peskine449bd832023-01-11 14:50:10 +01002464 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00002465}
2466
2467/*
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002468 * Pseudo-primality test: small factors, then Miller-Rabin
2469 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002470int mbedtls_mpi_is_prime_ext(const mbedtls_mpi *X, int rounds,
2471 int (*f_rng)(void *, unsigned char *, size_t),
2472 void *p_rng)
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002473{
Janos Follath24eed8d2019-11-22 13:21:35 +00002474 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002475 mbedtls_mpi XX;
Gilles Peskine449bd832023-01-11 14:50:10 +01002476 MPI_VALIDATE_RET(X != NULL);
2477 MPI_VALIDATE_RET(f_rng != NULL);
Manuel Pégourié-Gonnard7f4ed672014-10-14 20:56:02 +02002478
2479 XX.s = 1;
2480 XX.n = X->n;
2481 XX.p = X->p;
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002482
Gilles Peskine449bd832023-01-11 14:50:10 +01002483 if (mbedtls_mpi_cmp_int(&XX, 0) == 0 ||
2484 mbedtls_mpi_cmp_int(&XX, 1) == 0) {
2485 return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002486 }
2487
Gilles Peskine449bd832023-01-11 14:50:10 +01002488 if (mbedtls_mpi_cmp_int(&XX, 2) == 0) {
2489 return 0;
2490 }
2491
2492 if ((ret = mpi_check_small_factors(&XX)) != 0) {
2493 if (ret == 1) {
2494 return 0;
2495 }
2496
2497 return ret;
2498 }
2499
2500 return mpi_miller_rabin(&XX, rounds, f_rng, p_rng);
Janos Follathf301d232018-08-14 13:34:01 +01002501}
2502
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002503/*
Paul Bakker5121ce52009-01-03 21:22:43 +00002504 * Prime number generation
Jethro Beekman66689272018-02-14 19:24:10 -08002505 *
Janos Follathf301d232018-08-14 13:34:01 +01002506 * To generate an RSA key in a way recommended by FIPS 186-4, both primes must
2507 * be either 1024 bits or 1536 bits long, and flags must contain
2508 * MBEDTLS_MPI_GEN_PRIME_FLAG_LOW_ERR.
Paul Bakker5121ce52009-01-03 21:22:43 +00002509 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002510int mbedtls_mpi_gen_prime(mbedtls_mpi *X, size_t nbits, int flags,
2511 int (*f_rng)(void *, unsigned char *, size_t),
2512 void *p_rng)
Paul Bakker5121ce52009-01-03 21:22:43 +00002513{
Jethro Beekman66689272018-02-14 19:24:10 -08002514#ifdef MBEDTLS_HAVE_INT64
2515// ceil(2^63.5)
2516#define CEIL_MAXUINT_DIV_SQRT2 0xb504f333f9de6485ULL
2517#else
2518// ceil(2^31.5)
2519#define CEIL_MAXUINT_DIV_SQRT2 0xb504f334U
2520#endif
2521 int ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
Paul Bakker23986e52011-04-24 08:57:21 +00002522 size_t k, n;
Janos Follathda31fa12018-09-03 14:45:23 +01002523 int rounds;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002524 mbedtls_mpi_uint r;
2525 mbedtls_mpi Y;
Paul Bakker5121ce52009-01-03 21:22:43 +00002526
Gilles Peskine449bd832023-01-11 14:50:10 +01002527 MPI_VALIDATE_RET(X != NULL);
2528 MPI_VALIDATE_RET(f_rng != NULL);
Hanno Becker73d7d792018-12-11 10:35:51 +00002529
Gilles Peskine449bd832023-01-11 14:50:10 +01002530 if (nbits < 3 || nbits > MBEDTLS_MPI_MAX_BITS) {
2531 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
2532 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002533
Gilles Peskine449bd832023-01-11 14:50:10 +01002534 mbedtls_mpi_init(&Y);
Paul Bakker5121ce52009-01-03 21:22:43 +00002535
Gilles Peskine449bd832023-01-11 14:50:10 +01002536 n = BITS_TO_LIMBS(nbits);
Paul Bakker5121ce52009-01-03 21:22:43 +00002537
Gilles Peskine449bd832023-01-11 14:50:10 +01002538 if ((flags & MBEDTLS_MPI_GEN_PRIME_FLAG_LOW_ERR) == 0) {
Janos Follathda31fa12018-09-03 14:45:23 +01002539 /*
2540 * 2^-80 error probability, number of rounds chosen per HAC, table 4.4
2541 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002542 rounds = ((nbits >= 1300) ? 2 : (nbits >= 850) ? 3 :
2543 (nbits >= 650) ? 4 : (nbits >= 350) ? 8 :
2544 (nbits >= 250) ? 12 : (nbits >= 150) ? 18 : 27);
2545 } else {
Janos Follathda31fa12018-09-03 14:45:23 +01002546 /*
2547 * 2^-100 error probability, number of rounds computed based on HAC,
2548 * fact 4.48
2549 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002550 rounds = ((nbits >= 1450) ? 4 : (nbits >= 1150) ? 5 :
2551 (nbits >= 1000) ? 6 : (nbits >= 850) ? 7 :
2552 (nbits >= 750) ? 8 : (nbits >= 500) ? 13 :
2553 (nbits >= 250) ? 28 : (nbits >= 150) ? 40 : 51);
Janos Follathda31fa12018-09-03 14:45:23 +01002554 }
2555
Gilles Peskine449bd832023-01-11 14:50:10 +01002556 while (1) {
2557 MBEDTLS_MPI_CHK(mbedtls_mpi_fill_random(X, n * ciL, f_rng, p_rng));
Jethro Beekman66689272018-02-14 19:24:10 -08002558 /* 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 +01002559 if (X->p[n-1] < CEIL_MAXUINT_DIV_SQRT2) {
2560 continue;
2561 }
Jethro Beekman66689272018-02-14 19:24:10 -08002562
2563 k = n * biL;
Gilles Peskine449bd832023-01-11 14:50:10 +01002564 if (k > nbits) {
2565 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(X, k - nbits));
2566 }
Jethro Beekman66689272018-02-14 19:24:10 -08002567 X->p[0] |= 1;
2568
Gilles Peskine449bd832023-01-11 14:50:10 +01002569 if ((flags & MBEDTLS_MPI_GEN_PRIME_FLAG_DH) == 0) {
2570 ret = mbedtls_mpi_is_prime_ext(X, rounds, f_rng, p_rng);
Jethro Beekman66689272018-02-14 19:24:10 -08002571
Gilles Peskine449bd832023-01-11 14:50:10 +01002572 if (ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE) {
Paul Bakker5121ce52009-01-03 21:22:43 +00002573 goto cleanup;
Gilles Peskine449bd832023-01-11 14:50:10 +01002574 }
2575 } else {
Manuel Pégourié-Gonnardddf76152013-11-22 19:58:22 +01002576 /*
Tom Cosgrovece7f18c2022-07-28 05:50:56 +01002577 * A necessary condition for Y and X = 2Y + 1 to be prime
Jethro Beekman66689272018-02-14 19:24:10 -08002578 * is X = 2 mod 3 (which is equivalent to Y = 2 mod 3).
2579 * Make sure it is satisfied, while keeping X = 3 mod 4
Manuel Pégourié-Gonnardddf76152013-11-22 19:58:22 +01002580 */
Jethro Beekman66689272018-02-14 19:24:10 -08002581
2582 X->p[0] |= 2;
2583
Gilles Peskine449bd832023-01-11 14:50:10 +01002584 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_int(&r, X, 3));
2585 if (r == 0) {
2586 MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(X, X, 8));
2587 } else if (r == 1) {
2588 MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(X, X, 4));
2589 }
Jethro Beekman66689272018-02-14 19:24:10 -08002590
2591 /* Set Y = (X-1) / 2, which is X / 2 because X is odd */
Gilles Peskine449bd832023-01-11 14:50:10 +01002592 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&Y, X));
2593 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&Y, 1));
Jethro Beekman66689272018-02-14 19:24:10 -08002594
Gilles Peskine449bd832023-01-11 14:50:10 +01002595 while (1) {
Jethro Beekman66689272018-02-14 19:24:10 -08002596 /*
2597 * First, check small factors for X and Y
2598 * before doing Miller-Rabin on any of them
2599 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002600 if ((ret = mpi_check_small_factors(X)) == 0 &&
2601 (ret = mpi_check_small_factors(&Y)) == 0 &&
2602 (ret = mpi_miller_rabin(X, rounds, f_rng, p_rng))
2603 == 0 &&
2604 (ret = mpi_miller_rabin(&Y, rounds, f_rng, p_rng))
2605 == 0) {
Jethro Beekman66689272018-02-14 19:24:10 -08002606 goto cleanup;
Gilles Peskine449bd832023-01-11 14:50:10 +01002607 }
Jethro Beekman66689272018-02-14 19:24:10 -08002608
Gilles Peskine449bd832023-01-11 14:50:10 +01002609 if (ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE) {
Jethro Beekman66689272018-02-14 19:24:10 -08002610 goto cleanup;
Gilles Peskine449bd832023-01-11 14:50:10 +01002611 }
Jethro Beekman66689272018-02-14 19:24:10 -08002612
2613 /*
2614 * Next candidates. We want to preserve Y = (X-1) / 2 and
2615 * Y = 1 mod 2 and Y = 2 mod 3 (eq X = 3 mod 4 and X = 2 mod 3)
2616 * so up Y by 6 and X by 12.
2617 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002618 MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(X, X, 12));
2619 MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(&Y, &Y, 6));
Paul Bakker5121ce52009-01-03 21:22:43 +00002620 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002621 }
2622 }
2623
2624cleanup:
2625
Gilles Peskine449bd832023-01-11 14:50:10 +01002626 mbedtls_mpi_free(&Y);
Paul Bakker5121ce52009-01-03 21:22:43 +00002627
Gilles Peskine449bd832023-01-11 14:50:10 +01002628 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00002629}
2630
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002631#endif /* MBEDTLS_GENPRIME */
Paul Bakker5121ce52009-01-03 21:22:43 +00002632
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002633#if defined(MBEDTLS_SELF_TEST)
Paul Bakker5121ce52009-01-03 21:22:43 +00002634
Paul Bakker23986e52011-04-24 08:57:21 +00002635#define GCD_PAIR_COUNT 3
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002636
2637static const int gcd_pairs[GCD_PAIR_COUNT][3] =
2638{
2639 { 693, 609, 21 },
2640 { 1764, 868, 28 },
2641 { 768454923, 542167814, 1 }
2642};
2643
Paul Bakker5121ce52009-01-03 21:22:43 +00002644/*
2645 * Checkup routine
2646 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002647int mbedtls_mpi_self_test(int verbose)
Paul Bakker5121ce52009-01-03 21:22:43 +00002648{
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002649 int ret, i;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002650 mbedtls_mpi A, E, N, X, Y, U, V;
Paul Bakker5121ce52009-01-03 21:22:43 +00002651
Gilles Peskine449bd832023-01-11 14:50:10 +01002652 mbedtls_mpi_init(&A); mbedtls_mpi_init(&E); mbedtls_mpi_init(&N); mbedtls_mpi_init(&X);
2653 mbedtls_mpi_init(&Y); mbedtls_mpi_init(&U); mbedtls_mpi_init(&V);
Paul Bakker5121ce52009-01-03 21:22:43 +00002654
Gilles Peskine449bd832023-01-11 14:50:10 +01002655 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&A, 16,
2656 "EFE021C2645FD1DC586E69184AF4A31E" \
2657 "D5F53E93B5F123FA41680867BA110131" \
2658 "944FE7952E2517337780CB0DB80E61AA" \
2659 "E7C8DDC6C5C6AADEB34EB38A2F40D5E6"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002660
Gilles Peskine449bd832023-01-11 14:50:10 +01002661 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&E, 16,
2662 "B2E7EFD37075B9F03FF989C7C5051C20" \
2663 "34D2A323810251127E7BF8625A4F49A5" \
2664 "F3E27F4DA8BD59C47D6DAABA4C8127BD" \
2665 "5B5C25763222FEFCCFC38B832366C29E"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002666
Gilles Peskine449bd832023-01-11 14:50:10 +01002667 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&N, 16,
2668 "0066A198186C18C10B2F5ED9B522752A" \
2669 "9830B69916E535C8F047518A889A43A5" \
2670 "94B6BED27A168D31D4A52F88925AA8F5"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002671
Gilles Peskine449bd832023-01-11 14:50:10 +01002672 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&X, &A, &N));
Paul Bakker5121ce52009-01-03 21:22:43 +00002673
Gilles Peskine449bd832023-01-11 14:50:10 +01002674 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&U, 16,
2675 "602AB7ECA597A3D6B56FF9829A5E8B85" \
2676 "9E857EA95A03512E2BAE7391688D264A" \
2677 "A5663B0341DB9CCFD2C4C5F421FEC814" \
2678 "8001B72E848A38CAE1C65F78E56ABDEF" \
2679 "E12D3C039B8A02D6BE593F0BBBDA56F1" \
2680 "ECF677152EF804370C1A305CAF3B5BF1" \
2681 "30879B56C61DE584A0F53A2447A51E"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002682
Gilles Peskine449bd832023-01-11 14:50:10 +01002683 if (verbose != 0) {
2684 mbedtls_printf(" MPI test #1 (mul_mpi): ");
2685 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002686
Gilles Peskine449bd832023-01-11 14:50:10 +01002687 if (mbedtls_mpi_cmp_mpi(&X, &U) != 0) {
2688 if (verbose != 0) {
2689 mbedtls_printf("failed\n");
2690 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002691
Manuel Pégourié-Gonnard9e987ed2014-01-20 10:03:15 +01002692 ret = 1;
2693 goto cleanup;
Paul Bakker5121ce52009-01-03 21:22:43 +00002694 }
2695
Gilles Peskine449bd832023-01-11 14:50:10 +01002696 if (verbose != 0) {
2697 mbedtls_printf("passed\n");
2698 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002699
Gilles Peskine449bd832023-01-11 14:50:10 +01002700 MBEDTLS_MPI_CHK(mbedtls_mpi_div_mpi(&X, &Y, &A, &N));
Paul Bakker5121ce52009-01-03 21:22:43 +00002701
Gilles Peskine449bd832023-01-11 14:50:10 +01002702 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&U, 16,
2703 "256567336059E52CAE22925474705F39A94"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002704
Gilles Peskine449bd832023-01-11 14:50:10 +01002705 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&V, 16,
2706 "6613F26162223DF488E9CD48CC132C7A" \
2707 "0AC93C701B001B092E4E5B9F73BCD27B" \
2708 "9EE50D0657C77F374E903CDFA4C642"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002709
Gilles Peskine449bd832023-01-11 14:50:10 +01002710 if (verbose != 0) {
2711 mbedtls_printf(" MPI test #2 (div_mpi): ");
2712 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002713
Gilles Peskine449bd832023-01-11 14:50:10 +01002714 if (mbedtls_mpi_cmp_mpi(&X, &U) != 0 ||
2715 mbedtls_mpi_cmp_mpi(&Y, &V) != 0) {
2716 if (verbose != 0) {
2717 mbedtls_printf("failed\n");
2718 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002719
Manuel Pégourié-Gonnard9e987ed2014-01-20 10:03:15 +01002720 ret = 1;
2721 goto cleanup;
Paul Bakker5121ce52009-01-03 21:22:43 +00002722 }
2723
Gilles Peskine449bd832023-01-11 14:50:10 +01002724 if (verbose != 0) {
2725 mbedtls_printf("passed\n");
2726 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002727
Gilles Peskine449bd832023-01-11 14:50:10 +01002728 MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&X, &A, &E, &N, NULL));
Paul Bakker5121ce52009-01-03 21:22:43 +00002729
Gilles Peskine449bd832023-01-11 14:50:10 +01002730 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&U, 16,
2731 "36E139AEA55215609D2816998ED020BB" \
2732 "BD96C37890F65171D948E9BC7CBAA4D9" \
2733 "325D24D6A3C12710F10A09FA08AB87"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002734
Gilles Peskine449bd832023-01-11 14:50:10 +01002735 if (verbose != 0) {
2736 mbedtls_printf(" MPI test #3 (exp_mod): ");
2737 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002738
Gilles Peskine449bd832023-01-11 14:50:10 +01002739 if (mbedtls_mpi_cmp_mpi(&X, &U) != 0) {
2740 if (verbose != 0) {
2741 mbedtls_printf("failed\n");
2742 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002743
Manuel Pégourié-Gonnard9e987ed2014-01-20 10:03:15 +01002744 ret = 1;
2745 goto cleanup;
Paul Bakker5121ce52009-01-03 21:22:43 +00002746 }
2747
Gilles Peskine449bd832023-01-11 14:50:10 +01002748 if (verbose != 0) {
2749 mbedtls_printf("passed\n");
2750 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002751
Gilles Peskine449bd832023-01-11 14:50:10 +01002752 MBEDTLS_MPI_CHK(mbedtls_mpi_inv_mod(&X, &A, &N));
Paul Bakker5121ce52009-01-03 21:22:43 +00002753
Gilles Peskine449bd832023-01-11 14:50:10 +01002754 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&U, 16,
2755 "003A0AAEDD7E784FC07D8F9EC6E3BFD5" \
2756 "C3DBA76456363A10869622EAC2DD84EC" \
2757 "C5B8A74DAC4D09E03B5E0BE779F2DF61"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002758
Gilles Peskine449bd832023-01-11 14:50:10 +01002759 if (verbose != 0) {
2760 mbedtls_printf(" MPI test #4 (inv_mod): ");
2761 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002762
Gilles Peskine449bd832023-01-11 14:50:10 +01002763 if (mbedtls_mpi_cmp_mpi(&X, &U) != 0) {
2764 if (verbose != 0) {
2765 mbedtls_printf("failed\n");
2766 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002767
Manuel Pégourié-Gonnard9e987ed2014-01-20 10:03:15 +01002768 ret = 1;
2769 goto cleanup;
Paul Bakker5121ce52009-01-03 21:22:43 +00002770 }
2771
Gilles Peskine449bd832023-01-11 14:50:10 +01002772 if (verbose != 0) {
2773 mbedtls_printf("passed\n");
2774 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002775
Gilles Peskine449bd832023-01-11 14:50:10 +01002776 if (verbose != 0) {
2777 mbedtls_printf(" MPI test #5 (simple gcd): ");
2778 }
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002779
Gilles Peskine449bd832023-01-11 14:50:10 +01002780 for (i = 0; i < GCD_PAIR_COUNT; i++) {
2781 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&X, gcd_pairs[i][0]));
2782 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&Y, gcd_pairs[i][1]));
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002783
Gilles Peskine449bd832023-01-11 14:50:10 +01002784 MBEDTLS_MPI_CHK(mbedtls_mpi_gcd(&A, &X, &Y));
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002785
Gilles Peskine449bd832023-01-11 14:50:10 +01002786 if (mbedtls_mpi_cmp_int(&A, gcd_pairs[i][2]) != 0) {
2787 if (verbose != 0) {
2788 mbedtls_printf("failed at %d\n", i);
2789 }
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002790
Manuel Pégourié-Gonnard9e987ed2014-01-20 10:03:15 +01002791 ret = 1;
2792 goto cleanup;
2793 }
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002794 }
2795
Gilles Peskine449bd832023-01-11 14:50:10 +01002796 if (verbose != 0) {
2797 mbedtls_printf("passed\n");
2798 }
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002799
Paul Bakker5121ce52009-01-03 21:22:43 +00002800cleanup:
2801
Gilles Peskine449bd832023-01-11 14:50:10 +01002802 if (ret != 0 && verbose != 0) {
2803 mbedtls_printf("Unexpected error, return code = %08X\n", (unsigned int) ret);
2804 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002805
Gilles Peskine449bd832023-01-11 14:50:10 +01002806 mbedtls_mpi_free(&A); mbedtls_mpi_free(&E); mbedtls_mpi_free(&N); mbedtls_mpi_free(&X);
2807 mbedtls_mpi_free(&Y); mbedtls_mpi_free(&U); mbedtls_mpi_free(&V);
Paul Bakker5121ce52009-01-03 21:22:43 +00002808
Gilles Peskine449bd832023-01-11 14:50:10 +01002809 if (verbose != 0) {
2810 mbedtls_printf("\n");
2811 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002812
Gilles Peskine449bd832023-01-11 14:50:10 +01002813 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00002814}
2815
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002816#endif /* MBEDTLS_SELF_TEST */
Paul Bakker5121ce52009-01-03 21:22:43 +00002817
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002818#endif /* MBEDTLS_BIGNUM_C */