xref: /optee_os/lib/libmbedtls/mbedtls/library/bignum.c (revision cb03400251f98aed22a2664509e3ed9e183800b0)
1817466cbSJens Wiklander /*
2817466cbSJens Wiklander  *  Multi-precision integer library
3817466cbSJens Wiklander  *
47901324dSJerome Forissier  *  Copyright The Mbed TLS Contributors
5b0563631STom Van Eyck  *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
6817466cbSJens Wiklander  */
7817466cbSJens Wiklander 
8817466cbSJens Wiklander /*
9817466cbSJens Wiklander  *  The following sources were referenced in the design of this Multi-precision
10817466cbSJens Wiklander  *  Integer library:
11817466cbSJens Wiklander  *
12817466cbSJens Wiklander  *  [1] Handbook of Applied Cryptography - 1997
13817466cbSJens Wiklander  *      Menezes, van Oorschot and Vanstone
14817466cbSJens Wiklander  *
15817466cbSJens Wiklander  *  [2] Multi-Precision Math
16817466cbSJens Wiklander  *      Tom St Denis
17817466cbSJens Wiklander  *      https://github.com/libtom/libtommath/blob/develop/tommath.pdf
18817466cbSJens Wiklander  *
19817466cbSJens Wiklander  *  [3] GNU Multi-Precision Arithmetic Library
20817466cbSJens Wiklander  *      https://gmplib.org/manual/index.html
21817466cbSJens Wiklander  *
22817466cbSJens Wiklander  */
23817466cbSJens Wiklander 
247901324dSJerome Forissier #include "common.h"
25817466cbSJens Wiklander 
26817466cbSJens Wiklander #if defined(MBEDTLS_BIGNUM_C)
27817466cbSJens Wiklander 
28817466cbSJens Wiklander #include "mbedtls/bignum.h"
2932b31808SJens Wiklander #include "bignum_core.h"
30*cb034002SJerome Forissier #include "bignum_internal.h"
3132b31808SJens Wiklander #include "bn_mul.h"
323d3b0591SJens Wiklander #include "mbedtls/platform_util.h"
3311fa71b9SJerome Forissier #include "mbedtls/error.h"
34039e02dfSJerome Forissier #include "constant_time_internal.h"
35817466cbSJens Wiklander 
36039e02dfSJerome Forissier #include <limits.h>
37817466cbSJens Wiklander #include <string.h>
38817466cbSJens Wiklander 
39817466cbSJens Wiklander #include "mbedtls/platform.h"
40817466cbSJens Wiklander 
4198bd5fe3SJens Wiklander #include <mempool.h>
42817466cbSJens Wiklander 
4398bd5fe3SJens Wiklander void *mbedtls_mpi_mempool;
4498bd5fe3SJens Wiklander 
45b0563631STom Van Eyck 
46b0563631STom Van Eyck /*
47b0563631STom Van Eyck  * Conditionally select an MPI sign in constant time.
48b0563631STom Van Eyck  * (MPI sign is the field s in mbedtls_mpi. It is unsigned short and only 1 and -1 are valid
49b0563631STom Van Eyck  * values.)
50b0563631STom Van Eyck  */
51b0563631STom Van Eyck static inline signed short mbedtls_ct_mpi_sign_if(mbedtls_ct_condition_t cond,
52b0563631STom Van Eyck                                                   signed short sign1, signed short sign2)
533d3b0591SJens Wiklander {
54b0563631STom Van Eyck     return (signed short) mbedtls_ct_uint_if(cond, sign1 + 1, sign2 + 1) - 1;
553d3b0591SJens Wiklander }
563d3b0591SJens Wiklander 
57817466cbSJens Wiklander /*
58b0563631STom Van Eyck  * Compare signed values in constant time
59b0563631STom Van Eyck  */
60b0563631STom Van Eyck int mbedtls_mpi_lt_mpi_ct(const mbedtls_mpi *X,
61b0563631STom Van Eyck                           const mbedtls_mpi *Y,
62b0563631STom Van Eyck                           unsigned *ret)
63b0563631STom Van Eyck {
64b0563631STom Van Eyck     mbedtls_ct_condition_t different_sign, X_is_negative, Y_is_negative, result;
65b0563631STom Van Eyck 
66b0563631STom Van Eyck     if (X->n != Y->n) {
67b0563631STom Van Eyck         return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
68b0563631STom Van Eyck     }
69b0563631STom Van Eyck 
70b0563631STom Van Eyck     /*
71b0563631STom Van Eyck      * Set N_is_negative to MBEDTLS_CT_FALSE if N >= 0, MBEDTLS_CT_TRUE if N < 0.
72b0563631STom Van Eyck      * We know that N->s == 1 if N >= 0 and N->s == -1 if N < 0.
73b0563631STom Van Eyck      */
74b0563631STom Van Eyck     X_is_negative = mbedtls_ct_bool((X->s & 2) >> 1);
75b0563631STom Van Eyck     Y_is_negative = mbedtls_ct_bool((Y->s & 2) >> 1);
76b0563631STom Van Eyck 
77b0563631STom Van Eyck     /*
78b0563631STom Van Eyck      * If the signs are different, then the positive operand is the bigger.
79b0563631STom Van Eyck      * That is if X is negative (X_is_negative == 1), then X < Y is true and it
80b0563631STom Van Eyck      * is false if X is positive (X_is_negative == 0).
81b0563631STom Van Eyck      */
82b0563631STom Van Eyck     different_sign = mbedtls_ct_bool_ne(X_is_negative, Y_is_negative); // true if different sign
83b0563631STom Van Eyck     result = mbedtls_ct_bool_and(different_sign, X_is_negative);
84b0563631STom Van Eyck 
85b0563631STom Van Eyck     /*
86b0563631STom Van Eyck      * Assuming signs are the same, compare X and Y. We switch the comparison
87b0563631STom Van Eyck      * order if they are negative so that we get the right result, regardles of
88b0563631STom Van Eyck      * sign.
89b0563631STom Van Eyck      */
90b0563631STom Van Eyck 
91b0563631STom Van Eyck     /* This array is used to conditionally swap the pointers in const time */
92b0563631STom Van Eyck     void * const p[2] = { X->p, Y->p };
93b0563631STom Van Eyck     size_t i = mbedtls_ct_size_if_else_0(X_is_negative, 1);
94b0563631STom Van Eyck     mbedtls_ct_condition_t lt = mbedtls_mpi_core_lt_ct(p[i], p[i ^ 1], X->n);
95b0563631STom Van Eyck 
96b0563631STom Van Eyck     /*
97b0563631STom Van Eyck      * Store in result iff the signs are the same (i.e., iff different_sign == false). If
98b0563631STom Van Eyck      * the signs differ, result has already been set, so we don't change it.
99b0563631STom Van Eyck      */
100b0563631STom Van Eyck     result = mbedtls_ct_bool_or(result,
101b0563631STom Van Eyck                                 mbedtls_ct_bool_and(mbedtls_ct_bool_not(different_sign), lt));
102b0563631STom Van Eyck 
103b0563631STom Van Eyck     *ret = mbedtls_ct_uint_if_else_0(result, 1);
104b0563631STom Van Eyck 
105b0563631STom Van Eyck     return 0;
106b0563631STom Van Eyck }
107b0563631STom Van Eyck 
108b0563631STom Van Eyck /*
109b0563631STom Van Eyck  * Conditionally assign X = Y, without leaking information
110b0563631STom Van Eyck  * about whether the assignment was made or not.
111b0563631STom Van Eyck  * (Leaking information about the respective sizes of X and Y is ok however.)
112b0563631STom Van Eyck  */
113b0563631STom Van Eyck #if defined(_MSC_VER) && defined(MBEDTLS_PLATFORM_IS_WINDOWS_ON_ARM64) && \
114b0563631STom Van Eyck     (_MSC_FULL_VER < 193131103)
115b0563631STom Van Eyck /*
116b0563631STom Van Eyck  * MSVC miscompiles this function if it's inlined prior to Visual Studio 2022 version 17.1. See:
117b0563631STom Van Eyck  * https://developercommunity.visualstudio.com/t/c-compiler-miscompiles-part-of-mbedtls-library-on/1646989
118b0563631STom Van Eyck  */
119b0563631STom Van Eyck __declspec(noinline)
120b0563631STom Van Eyck #endif
121b0563631STom Van Eyck int mbedtls_mpi_safe_cond_assign(mbedtls_mpi *X,
122b0563631STom Van Eyck                                  const mbedtls_mpi *Y,
123b0563631STom Van Eyck                                  unsigned char assign)
124b0563631STom Van Eyck {
125b0563631STom Van Eyck     int ret = 0;
126b0563631STom Van Eyck 
127b0563631STom Van Eyck     MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, Y->n));
128b0563631STom Van Eyck 
129b0563631STom Van Eyck     {
130b0563631STom Van Eyck         mbedtls_ct_condition_t do_assign = mbedtls_ct_bool(assign);
131b0563631STom Van Eyck 
132b0563631STom Van Eyck         X->s = mbedtls_ct_mpi_sign_if(do_assign, Y->s, X->s);
133b0563631STom Van Eyck 
134b0563631STom Van Eyck         mbedtls_mpi_core_cond_assign(X->p, Y->p, Y->n, do_assign);
135b0563631STom Van Eyck 
136b0563631STom Van Eyck         mbedtls_ct_condition_t do_not_assign = mbedtls_ct_bool_not(do_assign);
137b0563631STom Van Eyck         for (size_t i = Y->n; i < X->n; i++) {
138b0563631STom Van Eyck             X->p[i] = mbedtls_ct_mpi_uint_if_else_0(do_not_assign, X->p[i]);
139b0563631STom Van Eyck         }
140b0563631STom Van Eyck     }
141b0563631STom Van Eyck 
142b0563631STom Van Eyck cleanup:
143b0563631STom Van Eyck     return ret;
144b0563631STom Van Eyck }
145b0563631STom Van Eyck 
146b0563631STom Van Eyck /*
147b0563631STom Van Eyck  * Conditionally swap X and Y, without leaking information
148b0563631STom Van Eyck  * about whether the swap was made or not.
149b0563631STom Van Eyck  * Here it is not ok to simply swap the pointers, which would lead to
150b0563631STom Van Eyck  * different memory access patterns when X and Y are used afterwards.
151b0563631STom Van Eyck  */
152b0563631STom Van Eyck int mbedtls_mpi_safe_cond_swap(mbedtls_mpi *X,
153b0563631STom Van Eyck                                mbedtls_mpi *Y,
154b0563631STom Van Eyck                                unsigned char swap)
155b0563631STom Van Eyck {
156b0563631STom Van Eyck     int ret = 0;
157b0563631STom Van Eyck     int s;
158b0563631STom Van Eyck 
159b0563631STom Van Eyck     if (X == Y) {
160b0563631STom Van Eyck         return 0;
161b0563631STom Van Eyck     }
162b0563631STom Van Eyck 
163b0563631STom Van Eyck     mbedtls_ct_condition_t do_swap = mbedtls_ct_bool(swap);
164b0563631STom Van Eyck 
165b0563631STom Van Eyck     MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, Y->n));
166b0563631STom Van Eyck     MBEDTLS_MPI_CHK(mbedtls_mpi_grow(Y, X->n));
167b0563631STom Van Eyck 
168b0563631STom Van Eyck     s = X->s;
169b0563631STom Van Eyck     X->s = mbedtls_ct_mpi_sign_if(do_swap, Y->s, X->s);
170b0563631STom Van Eyck     Y->s = mbedtls_ct_mpi_sign_if(do_swap, s, Y->s);
171b0563631STom Van Eyck 
172b0563631STom Van Eyck     mbedtls_mpi_core_cond_swap(X->p, Y->p, X->n, do_swap);
173b0563631STom Van Eyck 
174b0563631STom Van Eyck cleanup:
175b0563631STom Van Eyck     return ret;
176b0563631STom Van Eyck }
177b0563631STom Van Eyck 
178b0563631STom Van Eyck /* Implementation that should never be optimized out by the compiler */
179b0563631STom Van Eyck #define mbedtls_mpi_zeroize_and_free(v, n) mbedtls_zeroize_and_free(v, ciL * (n))
180b0563631STom Van Eyck 
181b0563631STom Van Eyck /*
182b0563631STom Van Eyck  * Implementation that should never be optimized out by the compiler.
183b0563631STom Van Eyck  * Reintroduced to allow use of mempool.
184b0563631STom Van Eyck  */
185b0563631STom Van Eyck #define mbedtls_mpi_zeroize(v, n) mbedtls_platform_zeroize(v, ciL * (n))
186b0563631STom Van Eyck 
187b0563631STom Van Eyck /*
188817466cbSJens Wiklander  * Initialize one MPI
189817466cbSJens Wiklander  */
1903d3b0591SJens Wiklander static void mpi_init(mbedtls_mpi *X, short use_mempool)
191817466cbSJens Wiklander {
1923d3b0591SJens Wiklander     X->s = 1;
1933d3b0591SJens Wiklander     X->use_mempool = use_mempool;
1943d3b0591SJens Wiklander     X->n = 0;
1953d3b0591SJens Wiklander     X->p = NULL;
196817466cbSJens Wiklander }
197817466cbSJens Wiklander 
19898bd5fe3SJens Wiklander void mbedtls_mpi_init(mbedtls_mpi *X)
19998bd5fe3SJens Wiklander {
2003d3b0591SJens Wiklander     mpi_init(X, 0 /*use_mempool*/);
20198bd5fe3SJens Wiklander }
20298bd5fe3SJens Wiklander 
20398bd5fe3SJens Wiklander void mbedtls_mpi_init_mempool(mbedtls_mpi *X)
20498bd5fe3SJens Wiklander {
2053d3b0591SJens Wiklander     mpi_init(X, !!mbedtls_mpi_mempool /*use_mempool*/);
20698bd5fe3SJens Wiklander }
20798bd5fe3SJens Wiklander 
208817466cbSJens Wiklander /*
209817466cbSJens Wiklander  * Unallocate one MPI
210817466cbSJens Wiklander  */
211817466cbSJens Wiklander void mbedtls_mpi_free(mbedtls_mpi *X)
212817466cbSJens Wiklander {
21332b31808SJens Wiklander     if (X == NULL) {
214817466cbSJens Wiklander         return;
21532b31808SJens Wiklander     }
216817466cbSJens Wiklander 
21732b31808SJens Wiklander     if (X->p != NULL) {
218b0563631STom Van Eyck         if(X->use_mempool) {
219817466cbSJens Wiklander             mbedtls_mpi_zeroize(X->p, X->n);
22018c5148dSJens Wiklander             mempool_free(mbedtls_mpi_mempool, X->p);
221b0563631STom Van Eyck         } else {
222b0563631STom Van Eyck             mbedtls_mpi_zeroize_and_free(X->p, X->n);
223b0563631STom Van Eyck         }
224817466cbSJens Wiklander     }
225817466cbSJens Wiklander 
226817466cbSJens Wiklander     X->s = 1;
227817466cbSJens Wiklander     X->n = 0;
2283d3b0591SJens Wiklander     X->p = NULL;
229817466cbSJens Wiklander }
230817466cbSJens Wiklander 
231817466cbSJens Wiklander /*
232817466cbSJens Wiklander  * Enlarge to the specified number of limbs
233817466cbSJens Wiklander  */
234817466cbSJens Wiklander int mbedtls_mpi_grow(mbedtls_mpi *X, size_t nblimbs)
235817466cbSJens Wiklander {
236817466cbSJens Wiklander     mbedtls_mpi_uint *p;
237817466cbSJens Wiklander 
23832b31808SJens Wiklander     if (nblimbs > MBEDTLS_MPI_MAX_LIMBS) {
23932b31808SJens Wiklander         return MBEDTLS_ERR_MPI_ALLOC_FAILED;
24032b31808SJens Wiklander     }
241817466cbSJens Wiklander 
24232b31808SJens Wiklander     if (X->n < nblimbs) {
24332b31808SJens Wiklander         if(X->use_mempool) {
2443d3b0591SJens Wiklander             p = mempool_alloc(mbedtls_mpi_mempool, nblimbs * ciL);
24518c5148dSJens Wiklander             if(p == NULL)
24632b31808SJens Wiklander                 return MBEDTLS_ERR_MPI_ALLOC_FAILED;
2473d3b0591SJens Wiklander             memset(p, 0, nblimbs * ciL);
24832b31808SJens Wiklander         } else {
2493d3b0591SJens Wiklander                 p = (mbedtls_mpi_uint *) mbedtls_calloc(nblimbs, ciL);
2503d3b0591SJens Wiklander                 if (p == NULL)
25132b31808SJens Wiklander                     return MBEDTLS_ERR_MPI_ALLOC_FAILED;
252817466cbSJens Wiklander         }
253817466cbSJens Wiklander 
25432b31808SJens Wiklander         if (X->p != NULL) {
2553d3b0591SJens Wiklander             memcpy(p, X->p, X->n * ciL);
256b0563631STom Van Eyck 
257b0563631STom Van Eyck             if (X->use_mempool) {
2583d3b0591SJens Wiklander                 mbedtls_mpi_zeroize(X->p, X->n);
25918c5148dSJens Wiklander                 mempool_free(mbedtls_mpi_mempool, X->p);
260b0563631STom Van Eyck             } else {
261b0563631STom Van Eyck                 mbedtls_mpi_zeroize_and_free(X->p, X->n);
262b0563631STom Van Eyck             }
2633d3b0591SJens Wiklander         }
26418c5148dSJens Wiklander 
265b0563631STom Van Eyck         /* nblimbs fits in n because we ensure that MBEDTLS_MPI_MAX_LIMBS
266b0563631STom Van Eyck          * fits, and we've checked that nblimbs <= MBEDTLS_MPI_MAX_LIMBS. */
267b0563631STom Van Eyck         X->n = (unsigned short) nblimbs;
2683d3b0591SJens Wiklander         X->p = p;
2693d3b0591SJens Wiklander     }
270817466cbSJens Wiklander 
27132b31808SJens Wiklander     return 0;
272817466cbSJens Wiklander }
273817466cbSJens Wiklander 
274817466cbSJens Wiklander /*
275817466cbSJens Wiklander  * Resize down as much as possible,
276817466cbSJens Wiklander  * while keeping at least the specified number of limbs
277817466cbSJens Wiklander  */
278817466cbSJens Wiklander int mbedtls_mpi_shrink(mbedtls_mpi *X, size_t nblimbs)
279817466cbSJens Wiklander {
280817466cbSJens Wiklander     mbedtls_mpi_uint *p;
281817466cbSJens Wiklander     size_t i;
2823d3b0591SJens Wiklander 
28332b31808SJens Wiklander     if (nblimbs > MBEDTLS_MPI_MAX_LIMBS) {
28432b31808SJens Wiklander         return MBEDTLS_ERR_MPI_ALLOC_FAILED;
28532b31808SJens Wiklander     }
286817466cbSJens Wiklander 
2875b25c76aSJerome Forissier     /* Actually resize up if there are currently fewer than nblimbs limbs. */
28832b31808SJens Wiklander     if (X->n <= nblimbs) {
28932b31808SJens Wiklander         return mbedtls_mpi_grow(X, nblimbs);
29032b31808SJens Wiklander     }
2915b25c76aSJerome Forissier     /* After this point, then X->n > nblimbs and in particular X->n > 0. */
292817466cbSJens Wiklander 
29332b31808SJens Wiklander     for (i = X->n - 1; i > 0; i--) {
29432b31808SJens Wiklander         if (X->p[i] != 0) {
295817466cbSJens Wiklander             break;
29632b31808SJens Wiklander         }
29732b31808SJens Wiklander     }
298817466cbSJens Wiklander     i++;
299817466cbSJens Wiklander 
30032b31808SJens Wiklander     if (i < nblimbs) {
301817466cbSJens Wiklander         i = nblimbs;
30232b31808SJens Wiklander     }
303817466cbSJens Wiklander 
30432b31808SJens Wiklander     if (X->use_mempool) {
305ed3fa831SJerome Forissier         p = mempool_alloc(mbedtls_mpi_mempool, i * ciL);
3063d3b0591SJens Wiklander         if (p == NULL)
30732b31808SJens Wiklander             return MBEDTLS_ERR_MPI_ALLOC_FAILED;
308ed3fa831SJerome Forissier         memset(p, 0, i * ciL);
30932b31808SJens Wiklander     } else {
31032b31808SJens Wiklander         if ((p = (mbedtls_mpi_uint *) mbedtls_calloc(i, ciL)) == NULL)
31132b31808SJens Wiklander             return MBEDTLS_ERR_MPI_ALLOC_FAILED;
3123d3b0591SJens Wiklander     }
31318c5148dSJens Wiklander 
31432b31808SJens Wiklander     if (X->p != NULL) {
315817466cbSJens Wiklander         memcpy(p, X->p, i * ciL);
316b0563631STom Van Eyck 
317b0563631STom Van Eyck         if (X->use_mempool) {
318817466cbSJens Wiklander             mbedtls_mpi_zeroize(X->p, X->n);
31918c5148dSJens Wiklander             mempool_free(mbedtls_mpi_mempool, X->p);
320b0563631STom Van Eyck         }
321b0563631STom Van Eyck         else {
322b0563631STom Van Eyck             mbedtls_mpi_zeroize_and_free(X->p, X->n);
323b0563631STom Van Eyck         }
324817466cbSJens Wiklander     }
325817466cbSJens Wiklander 
326b0563631STom Van Eyck     /* i fits in n because we ensure that MBEDTLS_MPI_MAX_LIMBS
327b0563631STom Van Eyck      * fits, and we've checked that i <= nblimbs <= MBEDTLS_MPI_MAX_LIMBS. */
328b0563631STom Van Eyck     X->n = (unsigned short) i;
3293d3b0591SJens Wiklander     X->p = p;
330817466cbSJens Wiklander 
33132b31808SJens Wiklander     return 0;
332817466cbSJens Wiklander }
333817466cbSJens Wiklander 
3347901324dSJerome Forissier /* Resize X to have exactly n limbs and set it to 0. */
3357901324dSJerome Forissier static int mbedtls_mpi_resize_clear(mbedtls_mpi *X, size_t limbs)
3367901324dSJerome Forissier {
33732b31808SJens Wiklander     if (limbs == 0) {
3387901324dSJerome Forissier         mbedtls_mpi_free(X);
33932b31808SJens Wiklander         return 0;
34032b31808SJens Wiklander     } else if (X->n == limbs) {
3417901324dSJerome Forissier         memset(X->p, 0, limbs * ciL);
3427901324dSJerome Forissier         X->s = 1;
34332b31808SJens Wiklander         return 0;
34432b31808SJens Wiklander     } else {
3457901324dSJerome Forissier         mbedtls_mpi_free(X);
34632b31808SJens Wiklander         return mbedtls_mpi_grow(X, limbs);
3477901324dSJerome Forissier     }
3487901324dSJerome Forissier }
3497901324dSJerome Forissier 
350817466cbSJens Wiklander /*
3517901324dSJerome Forissier  * Copy the contents of Y into X.
3527901324dSJerome Forissier  *
3537901324dSJerome Forissier  * This function is not constant-time. Leading zeros in Y may be removed.
3547901324dSJerome Forissier  *
3557901324dSJerome Forissier  * Ensure that X does not shrink. This is not guaranteed by the public API,
356b0563631STom Van Eyck  * but some code in the bignum module might still rely on this property.
357817466cbSJens Wiklander  */
358817466cbSJens Wiklander int mbedtls_mpi_copy(mbedtls_mpi *X, const mbedtls_mpi *Y)
359817466cbSJens Wiklander {
3603d3b0591SJens Wiklander     int ret = 0;
361817466cbSJens Wiklander     size_t i;
362817466cbSJens Wiklander 
36332b31808SJens Wiklander     if (X == Y) {
36432b31808SJens Wiklander         return 0;
36532b31808SJens Wiklander     }
366817466cbSJens Wiklander 
36732b31808SJens Wiklander     if (Y->n == 0) {
36832b31808SJens Wiklander         if (X->n != 0) {
3697901324dSJerome Forissier             X->s = 1;
3707901324dSJerome Forissier             memset(X->p, 0, X->n * ciL);
3717901324dSJerome Forissier         }
37232b31808SJens Wiklander         return 0;
373817466cbSJens Wiklander     }
374817466cbSJens Wiklander 
37532b31808SJens Wiklander     for (i = Y->n - 1; i > 0; i--) {
37632b31808SJens Wiklander         if (Y->p[i] != 0) {
377817466cbSJens Wiklander             break;
37832b31808SJens Wiklander         }
37932b31808SJens Wiklander     }
380817466cbSJens Wiklander     i++;
381817466cbSJens Wiklander 
382817466cbSJens Wiklander     X->s = Y->s;
383817466cbSJens Wiklander 
38432b31808SJens Wiklander     if (X->n < i) {
385817466cbSJens Wiklander         MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, i));
38632b31808SJens Wiklander     } else {
3873d3b0591SJens Wiklander         memset(X->p + i, 0, (X->n - i) * ciL);
3883d3b0591SJens Wiklander     }
389817466cbSJens Wiklander 
390817466cbSJens Wiklander     memcpy(X->p, Y->p, i * ciL);
391817466cbSJens Wiklander 
392817466cbSJens Wiklander cleanup:
393817466cbSJens Wiklander 
39432b31808SJens Wiklander     return ret;
395817466cbSJens Wiklander }
396817466cbSJens Wiklander 
397817466cbSJens Wiklander /*
398817466cbSJens Wiklander  * Swap the contents of X and Y
399817466cbSJens Wiklander  */
400817466cbSJens Wiklander void mbedtls_mpi_swap(mbedtls_mpi *X, mbedtls_mpi *Y)
401817466cbSJens Wiklander {
402817466cbSJens Wiklander     mbedtls_mpi T;
403817466cbSJens Wiklander 
404817466cbSJens Wiklander     memcpy(&T,  X, sizeof(mbedtls_mpi));
405817466cbSJens Wiklander     memcpy(X,  Y, sizeof(mbedtls_mpi));
406817466cbSJens Wiklander     memcpy(Y, &T, sizeof(mbedtls_mpi));
407817466cbSJens Wiklander }
408817466cbSJens Wiklander 
40932b31808SJens Wiklander static inline mbedtls_mpi_uint mpi_sint_abs(mbedtls_mpi_sint z)
41032b31808SJens Wiklander {
41132b31808SJens Wiklander     if (z >= 0) {
41232b31808SJens Wiklander         return z;
41332b31808SJens Wiklander     }
41432b31808SJens Wiklander     /* Take care to handle the most negative value (-2^(biL-1)) correctly.
41532b31808SJens Wiklander      * A naive -z would have undefined behavior.
41632b31808SJens Wiklander      * Write this in a way that makes popular compilers happy (GCC, Clang,
41732b31808SJens Wiklander      * MSVC). */
41832b31808SJens Wiklander     return (mbedtls_mpi_uint) 0 - (mbedtls_mpi_uint) z;
41932b31808SJens Wiklander }
42032b31808SJens Wiklander 
421b0563631STom Van Eyck /* Convert x to a sign, i.e. to 1, if x is positive, or -1, if x is negative.
422b0563631STom Van Eyck  * This looks awkward but generates smaller code than (x < 0 ? -1 : 1) */
423b0563631STom Van Eyck #define TO_SIGN(x) ((mbedtls_mpi_sint) (((mbedtls_mpi_uint) x) >> (biL - 1)) * -2 + 1)
424b0563631STom Van Eyck 
425817466cbSJens Wiklander /*
426817466cbSJens Wiklander  * Set value from integer
427817466cbSJens Wiklander  */
428817466cbSJens Wiklander int mbedtls_mpi_lset(mbedtls_mpi *X, mbedtls_mpi_sint z)
429817466cbSJens Wiklander {
43011fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
431817466cbSJens Wiklander 
432817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, 1));
433817466cbSJens Wiklander     memset(X->p, 0, X->n * ciL);
434817466cbSJens Wiklander 
43532b31808SJens Wiklander     X->p[0] = mpi_sint_abs(z);
436b0563631STom Van Eyck     X->s    = TO_SIGN(z);
437817466cbSJens Wiklander 
438817466cbSJens Wiklander cleanup:
439817466cbSJens Wiklander 
44032b31808SJens Wiklander     return ret;
441817466cbSJens Wiklander }
442817466cbSJens Wiklander 
443817466cbSJens Wiklander /*
444817466cbSJens Wiklander  * Get a specific bit
445817466cbSJens Wiklander  */
446817466cbSJens Wiklander int mbedtls_mpi_get_bit(const mbedtls_mpi *X, size_t pos)
447817466cbSJens Wiklander {
44832b31808SJens Wiklander     if (X->n * biL <= pos) {
44932b31808SJens Wiklander         return 0;
450817466cbSJens Wiklander     }
451817466cbSJens Wiklander 
45232b31808SJens Wiklander     return (X->p[pos / biL] >> (pos % biL)) & 0x01;
45332b31808SJens Wiklander }
4543d3b0591SJens Wiklander 
455817466cbSJens Wiklander /*
456817466cbSJens Wiklander  * Set a bit to a specific value of 0 or 1
457817466cbSJens Wiklander  */
458817466cbSJens Wiklander int mbedtls_mpi_set_bit(mbedtls_mpi *X, size_t pos, unsigned char val)
459817466cbSJens Wiklander {
460817466cbSJens Wiklander     int ret = 0;
461817466cbSJens Wiklander     size_t off = pos / biL;
462817466cbSJens Wiklander     size_t idx = pos % biL;
463817466cbSJens Wiklander 
46432b31808SJens Wiklander     if (val != 0 && val != 1) {
46532b31808SJens Wiklander         return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
46632b31808SJens Wiklander     }
467817466cbSJens Wiklander 
46832b31808SJens Wiklander     if (X->n * biL <= pos) {
46932b31808SJens Wiklander         if (val == 0) {
47032b31808SJens Wiklander             return 0;
47132b31808SJens Wiklander         }
472817466cbSJens Wiklander 
473817466cbSJens Wiklander         MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, off + 1));
474817466cbSJens Wiklander     }
475817466cbSJens Wiklander 
476817466cbSJens Wiklander     X->p[off] &= ~((mbedtls_mpi_uint) 0x01 << idx);
477817466cbSJens Wiklander     X->p[off] |= (mbedtls_mpi_uint) val << idx;
478817466cbSJens Wiklander 
479817466cbSJens Wiklander cleanup:
480817466cbSJens Wiklander 
48132b31808SJens Wiklander     return ret;
482817466cbSJens Wiklander }
483817466cbSJens Wiklander 
484817466cbSJens Wiklander /*
485817466cbSJens Wiklander  * Return the number of less significant zero-bits
486817466cbSJens Wiklander  */
487817466cbSJens Wiklander size_t mbedtls_mpi_lsb(const mbedtls_mpi *X)
488817466cbSJens Wiklander {
489b0563631STom Van Eyck     size_t i;
490817466cbSJens Wiklander 
491b0563631STom Van Eyck #if defined(__has_builtin)
492b0563631STom Van Eyck #if (MBEDTLS_MPI_UINT_MAX == UINT_MAX) && __has_builtin(__builtin_ctz)
493b0563631STom Van Eyck     #define mbedtls_mpi_uint_ctz __builtin_ctz
494b0563631STom Van Eyck #elif (MBEDTLS_MPI_UINT_MAX == ULONG_MAX) && __has_builtin(__builtin_ctzl)
495b0563631STom Van Eyck     #define mbedtls_mpi_uint_ctz __builtin_ctzl
496b0563631STom Van Eyck #elif (MBEDTLS_MPI_UINT_MAX == ULLONG_MAX) && __has_builtin(__builtin_ctzll)
497b0563631STom Van Eyck     #define mbedtls_mpi_uint_ctz __builtin_ctzll
498b0563631STom Van Eyck #endif
499b0563631STom Van Eyck #endif
500b0563631STom Van Eyck 
501b0563631STom Van Eyck #if defined(mbedtls_mpi_uint_ctz)
50232b31808SJens Wiklander     for (i = 0; i < X->n; i++) {
503b0563631STom Van Eyck         if (X->p[i] != 0) {
504b0563631STom Van Eyck             return i * biL + mbedtls_mpi_uint_ctz(X->p[i]);
505b0563631STom Van Eyck         }
506b0563631STom Van Eyck     }
507b0563631STom Van Eyck #else
508b0563631STom Van Eyck     size_t count = 0;
509b0563631STom Van Eyck     for (i = 0; i < X->n; i++) {
510b0563631STom Van Eyck         for (size_t j = 0; j < biL; j++, count++) {
51132b31808SJens Wiklander             if (((X->p[i] >> j) & 1) != 0) {
51232b31808SJens Wiklander                 return count;
51332b31808SJens Wiklander             }
51432b31808SJens Wiklander         }
515817466cbSJens Wiklander     }
516b0563631STom Van Eyck #endif
517817466cbSJens Wiklander 
51832b31808SJens Wiklander     return 0;
519817466cbSJens Wiklander }
520817466cbSJens Wiklander 
521817466cbSJens Wiklander /*
522817466cbSJens Wiklander  * Return the number of bits
523817466cbSJens Wiklander  */
524817466cbSJens Wiklander size_t mbedtls_mpi_bitlen(const mbedtls_mpi *X)
525817466cbSJens Wiklander {
52632b31808SJens Wiklander     return mbedtls_mpi_core_bitlen(X->p, X->n);
527817466cbSJens Wiklander }
528817466cbSJens Wiklander 
529817466cbSJens Wiklander /*
530817466cbSJens Wiklander  * Return the total size in bytes
531817466cbSJens Wiklander  */
532817466cbSJens Wiklander size_t mbedtls_mpi_size(const mbedtls_mpi *X)
533817466cbSJens Wiklander {
53432b31808SJens Wiklander     return (mbedtls_mpi_bitlen(X) + 7) >> 3;
535817466cbSJens Wiklander }
536817466cbSJens Wiklander 
537817466cbSJens Wiklander /*
538817466cbSJens Wiklander  * Convert an ASCII character to digit value
539817466cbSJens Wiklander  */
540817466cbSJens Wiklander static int mpi_get_digit(mbedtls_mpi_uint *d, int radix, char c)
541817466cbSJens Wiklander {
542817466cbSJens Wiklander     *d = 255;
543817466cbSJens Wiklander 
54432b31808SJens Wiklander     if (c >= 0x30 && c <= 0x39) {
54532b31808SJens Wiklander         *d = c - 0x30;
54632b31808SJens Wiklander     }
54732b31808SJens Wiklander     if (c >= 0x41 && c <= 0x46) {
54832b31808SJens Wiklander         *d = c - 0x37;
54932b31808SJens Wiklander     }
55032b31808SJens Wiklander     if (c >= 0x61 && c <= 0x66) {
55132b31808SJens Wiklander         *d = c - 0x57;
55232b31808SJens Wiklander     }
553817466cbSJens Wiklander 
55432b31808SJens Wiklander     if (*d >= (mbedtls_mpi_uint) radix) {
55532b31808SJens Wiklander         return MBEDTLS_ERR_MPI_INVALID_CHARACTER;
55632b31808SJens Wiklander     }
557817466cbSJens Wiklander 
55832b31808SJens Wiklander     return 0;
559817466cbSJens Wiklander }
560817466cbSJens Wiklander 
561817466cbSJens Wiklander /*
562817466cbSJens Wiklander  * Import from an ASCII string
563817466cbSJens Wiklander  */
564817466cbSJens Wiklander int mbedtls_mpi_read_string(mbedtls_mpi *X, int radix, const char *s)
565817466cbSJens Wiklander {
56611fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
567817466cbSJens Wiklander     size_t i, j, slen, n;
5687901324dSJerome Forissier     int sign = 1;
569817466cbSJens Wiklander     mbedtls_mpi_uint d;
570817466cbSJens Wiklander     mbedtls_mpi T;
571817466cbSJens Wiklander 
57232b31808SJens Wiklander     if (radix < 2 || radix > 16) {
57332b31808SJens Wiklander         return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
57432b31808SJens Wiklander     }
575817466cbSJens Wiklander 
57698bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool(&T);
577817466cbSJens Wiklander 
57832b31808SJens Wiklander     if (s[0] == 0) {
5797901324dSJerome Forissier         mbedtls_mpi_free(X);
58032b31808SJens Wiklander         return 0;
5817901324dSJerome Forissier     }
5827901324dSJerome Forissier 
58332b31808SJens Wiklander     if (s[0] == '-') {
5847901324dSJerome Forissier         ++s;
5857901324dSJerome Forissier         sign = -1;
5867901324dSJerome Forissier     }
5877901324dSJerome Forissier 
588817466cbSJens Wiklander     slen = strlen(s);
589817466cbSJens Wiklander 
59032b31808SJens Wiklander     if (radix == 16) {
591b0563631STom Van Eyck         if (slen > SIZE_MAX >> 2) {
59232b31808SJens Wiklander             return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
59332b31808SJens Wiklander         }
594817466cbSJens Wiklander 
595817466cbSJens Wiklander         n = BITS_TO_LIMBS(slen << 2);
596817466cbSJens Wiklander 
597817466cbSJens Wiklander         MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, n));
598817466cbSJens Wiklander         MBEDTLS_MPI_CHK(mbedtls_mpi_lset(X, 0));
599817466cbSJens Wiklander 
60032b31808SJens Wiklander         for (i = slen, j = 0; i > 0; i--, j++) {
601817466cbSJens Wiklander             MBEDTLS_MPI_CHK(mpi_get_digit(&d, radix, s[i - 1]));
602817466cbSJens Wiklander             X->p[j / (2 * ciL)] |= d << ((j % (2 * ciL)) << 2);
603817466cbSJens Wiklander         }
60432b31808SJens Wiklander     } else {
605817466cbSJens Wiklander         MBEDTLS_MPI_CHK(mbedtls_mpi_lset(X, 0));
606817466cbSJens Wiklander 
60732b31808SJens Wiklander         for (i = 0; i < slen; i++) {
608817466cbSJens Wiklander             MBEDTLS_MPI_CHK(mpi_get_digit(&d, radix, s[i]));
609817466cbSJens Wiklander             MBEDTLS_MPI_CHK(mbedtls_mpi_mul_int(&T, X, radix));
610817466cbSJens Wiklander             MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(X, &T, d));
611817466cbSJens Wiklander         }
612817466cbSJens Wiklander     }
6137901324dSJerome Forissier 
61432b31808SJens Wiklander     if (sign < 0 && mbedtls_mpi_bitlen(X) != 0) {
6157901324dSJerome Forissier         X->s = -1;
61632b31808SJens Wiklander     }
617817466cbSJens Wiklander 
618817466cbSJens Wiklander cleanup:
619817466cbSJens Wiklander 
620817466cbSJens Wiklander     mbedtls_mpi_free(&T);
621817466cbSJens Wiklander 
62232b31808SJens Wiklander     return ret;
623817466cbSJens Wiklander }
624817466cbSJens Wiklander 
625817466cbSJens Wiklander /*
6265b25c76aSJerome Forissier  * Helper to write the digits high-order first.
627817466cbSJens Wiklander  */
6285b25c76aSJerome Forissier static int mpi_write_hlp(mbedtls_mpi *X, int radix,
6295b25c76aSJerome Forissier                          char **p, const size_t buflen)
630817466cbSJens Wiklander {
63111fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
632817466cbSJens Wiklander     mbedtls_mpi_uint r;
6335b25c76aSJerome Forissier     size_t length = 0;
6345b25c76aSJerome Forissier     char *p_end = *p + buflen;
635817466cbSJens Wiklander 
63632b31808SJens Wiklander     do {
63732b31808SJens Wiklander         if (length >= buflen) {
63832b31808SJens Wiklander             return MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL;
6395b25c76aSJerome Forissier         }
640817466cbSJens Wiklander 
641817466cbSJens Wiklander         MBEDTLS_MPI_CHK(mbedtls_mpi_mod_int(&r, X, radix));
642817466cbSJens Wiklander         MBEDTLS_MPI_CHK(mbedtls_mpi_div_int(X, NULL, X, radix));
6435b25c76aSJerome Forissier         /*
6445b25c76aSJerome Forissier          * Write the residue in the current position, as an ASCII character.
6455b25c76aSJerome Forissier          */
64632b31808SJens Wiklander         if (r < 0xA) {
6475b25c76aSJerome Forissier             *(--p_end) = (char) ('0' + r);
64832b31808SJens Wiklander         } else {
6495b25c76aSJerome Forissier             *(--p_end) = (char) ('A' + (r - 0xA));
65032b31808SJens Wiklander         }
6515b25c76aSJerome Forissier 
6525b25c76aSJerome Forissier         length++;
6535b25c76aSJerome Forissier     } while (mbedtls_mpi_cmp_int(X, 0) != 0);
6545b25c76aSJerome Forissier 
6555b25c76aSJerome Forissier     memmove(*p, p_end, length);
6565b25c76aSJerome Forissier     *p += length;
657817466cbSJens Wiklander 
658817466cbSJens Wiklander cleanup:
659817466cbSJens Wiklander 
66032b31808SJens Wiklander     return ret;
661817466cbSJens Wiklander }
662817466cbSJens Wiklander 
663817466cbSJens Wiklander /*
664817466cbSJens Wiklander  * Export into an ASCII string
665817466cbSJens Wiklander  */
666817466cbSJens Wiklander int mbedtls_mpi_write_string(const mbedtls_mpi *X, int radix,
667817466cbSJens Wiklander                              char *buf, size_t buflen, size_t *olen)
668817466cbSJens Wiklander {
669817466cbSJens Wiklander     int ret = 0;
670817466cbSJens Wiklander     size_t n;
671817466cbSJens Wiklander     char *p;
672817466cbSJens Wiklander     mbedtls_mpi T;
673817466cbSJens Wiklander 
67432b31808SJens Wiklander     if (radix < 2 || radix > 16) {
67532b31808SJens Wiklander         return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
67632b31808SJens Wiklander     }
677817466cbSJens Wiklander 
6785b25c76aSJerome Forissier     n = mbedtls_mpi_bitlen(X);   /* Number of bits necessary to present `n`. */
67932b31808SJens Wiklander     if (radix >=  4) {
68032b31808SJens Wiklander         n >>= 1;                 /* Number of 4-adic digits necessary to present
6815b25c76aSJerome Forissier                                   * `n`. If radix > 4, this might be a strict
6825b25c76aSJerome Forissier                                   * overapproximation of the number of
6835b25c76aSJerome Forissier                                   * radix-adic digits needed to present `n`. */
68432b31808SJens Wiklander     }
68532b31808SJens Wiklander     if (radix >= 16) {
68632b31808SJens Wiklander         n >>= 1;                 /* Number of hexadecimal digits necessary to
6875b25c76aSJerome Forissier                                   * present `n`. */
6885b25c76aSJerome Forissier 
68932b31808SJens Wiklander     }
6905b25c76aSJerome Forissier     n += 1; /* Terminating null byte */
6915b25c76aSJerome Forissier     n += 1; /* Compensate for the divisions above, which round down `n`
6925b25c76aSJerome Forissier              * in case it's not even. */
6935b25c76aSJerome Forissier     n += 1; /* Potential '-'-sign. */
6945b25c76aSJerome Forissier     n += (n & 1);   /* Make n even to have enough space for hexadecimal writing,
6955b25c76aSJerome Forissier                      * which always uses an even number of hex-digits. */
696817466cbSJens Wiklander 
69732b31808SJens Wiklander     if (buflen < n) {
698817466cbSJens Wiklander         *olen = n;
69932b31808SJens Wiklander         return MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL;
700817466cbSJens Wiklander     }
701817466cbSJens Wiklander 
702817466cbSJens Wiklander     p = buf;
70398bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool(&T);
704817466cbSJens Wiklander 
70532b31808SJens Wiklander     if (X->s == -1) {
706817466cbSJens Wiklander         *p++ = '-';
7075b25c76aSJerome Forissier         buflen--;
7085b25c76aSJerome Forissier     }
709817466cbSJens Wiklander 
71032b31808SJens Wiklander     if (radix == 16) {
711817466cbSJens Wiklander         int c;
712817466cbSJens Wiklander         size_t i, j, k;
713817466cbSJens Wiklander 
71432b31808SJens Wiklander         for (i = X->n, k = 0; i > 0; i--) {
71532b31808SJens Wiklander             for (j = ciL; j > 0; j--) {
716817466cbSJens Wiklander                 c = (X->p[i - 1] >> ((j - 1) << 3)) & 0xFF;
717817466cbSJens Wiklander 
71832b31808SJens Wiklander                 if (c == 0 && k == 0 && (i + j) != 2) {
719817466cbSJens Wiklander                     continue;
72032b31808SJens Wiklander                 }
721817466cbSJens Wiklander 
722817466cbSJens Wiklander                 *(p++) = "0123456789ABCDEF" [c / 16];
723817466cbSJens Wiklander                 *(p++) = "0123456789ABCDEF" [c % 16];
724817466cbSJens Wiklander                 k = 1;
725817466cbSJens Wiklander             }
726817466cbSJens Wiklander         }
72732b31808SJens Wiklander     } else {
728817466cbSJens Wiklander         MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&T, X));
729817466cbSJens Wiklander 
73032b31808SJens Wiklander         if (T.s == -1) {
731817466cbSJens Wiklander             T.s = 1;
73232b31808SJens Wiklander         }
733817466cbSJens Wiklander 
7345b25c76aSJerome Forissier         MBEDTLS_MPI_CHK(mpi_write_hlp(&T, radix, &p, buflen));
735817466cbSJens Wiklander     }
736817466cbSJens Wiklander 
737817466cbSJens Wiklander     *p++ = '\0';
738b0563631STom Van Eyck     *olen = (size_t) (p - buf);
739817466cbSJens Wiklander 
740817466cbSJens Wiklander cleanup:
741817466cbSJens Wiklander 
742817466cbSJens Wiklander     mbedtls_mpi_free(&T);
743817466cbSJens Wiklander 
74432b31808SJens Wiklander     return ret;
745817466cbSJens Wiklander }
746817466cbSJens Wiklander 
747817466cbSJens Wiklander #if defined(MBEDTLS_FS_IO)
748817466cbSJens Wiklander /*
749817466cbSJens Wiklander  * Read X from an opened file
750817466cbSJens Wiklander  */
751817466cbSJens Wiklander int mbedtls_mpi_read_file(mbedtls_mpi *X, int radix, FILE *fin)
752817466cbSJens Wiklander {
753817466cbSJens Wiklander     mbedtls_mpi_uint d;
754817466cbSJens Wiklander     size_t slen;
755817466cbSJens Wiklander     char *p;
756817466cbSJens Wiklander     /*
757817466cbSJens Wiklander      * Buffer should have space for (short) label and decimal formatted MPI,
758817466cbSJens Wiklander      * newline characters and '\0'
759817466cbSJens Wiklander      */
760817466cbSJens Wiklander     char s[MBEDTLS_MPI_RW_BUFFER_SIZE];
761817466cbSJens Wiklander 
76232b31808SJens Wiklander     if (radix < 2 || radix > 16) {
76332b31808SJens Wiklander         return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
76432b31808SJens Wiklander     }
7653d3b0591SJens Wiklander 
766817466cbSJens Wiklander     memset(s, 0, sizeof(s));
76732b31808SJens Wiklander     if (fgets(s, sizeof(s) - 1, fin) == NULL) {
76832b31808SJens Wiklander         return MBEDTLS_ERR_MPI_FILE_IO_ERROR;
76932b31808SJens Wiklander     }
770817466cbSJens Wiklander 
771817466cbSJens Wiklander     slen = strlen(s);
77232b31808SJens Wiklander     if (slen == sizeof(s) - 2) {
77332b31808SJens Wiklander         return MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL;
77432b31808SJens Wiklander     }
775817466cbSJens Wiklander 
77632b31808SJens Wiklander     if (slen > 0 && s[slen - 1] == '\n') {
77732b31808SJens Wiklander         slen--; s[slen] = '\0';
77832b31808SJens Wiklander     }
77932b31808SJens Wiklander     if (slen > 0 && s[slen - 1] == '\r') {
78032b31808SJens Wiklander         slen--; s[slen] = '\0';
78132b31808SJens Wiklander     }
782817466cbSJens Wiklander 
783817466cbSJens Wiklander     p = s + slen;
78432b31808SJens Wiklander     while (p-- > s) {
78532b31808SJens Wiklander         if (mpi_get_digit(&d, radix, *p) != 0) {
786817466cbSJens Wiklander             break;
78732b31808SJens Wiklander         }
78832b31808SJens Wiklander     }
789817466cbSJens Wiklander 
79032b31808SJens Wiklander     return mbedtls_mpi_read_string(X, radix, p + 1);
791817466cbSJens Wiklander }
792817466cbSJens Wiklander 
793817466cbSJens Wiklander /*
794817466cbSJens Wiklander  * Write X into an opened file (or stdout if fout == NULL)
795817466cbSJens Wiklander  */
796817466cbSJens Wiklander int mbedtls_mpi_write_file(const char *p, const mbedtls_mpi *X, int radix, FILE *fout)
797817466cbSJens Wiklander {
79811fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
799817466cbSJens Wiklander     size_t n, slen, plen;
800817466cbSJens Wiklander     /*
801817466cbSJens Wiklander      * Buffer should have space for (short) label and decimal formatted MPI,
802817466cbSJens Wiklander      * newline characters and '\0'
803817466cbSJens Wiklander      */
804817466cbSJens Wiklander     char s[MBEDTLS_MPI_RW_BUFFER_SIZE];
8053d3b0591SJens Wiklander 
80632b31808SJens Wiklander     if (radix < 2 || radix > 16) {
80732b31808SJens Wiklander         return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
80832b31808SJens Wiklander     }
809817466cbSJens Wiklander 
810817466cbSJens Wiklander     memset(s, 0, sizeof(s));
811817466cbSJens Wiklander 
812817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_write_string(X, radix, s, sizeof(s) - 2, &n));
813817466cbSJens Wiklander 
81432b31808SJens Wiklander     if (p == NULL) {
81532b31808SJens Wiklander         p = "";
81632b31808SJens Wiklander     }
817817466cbSJens Wiklander 
818817466cbSJens Wiklander     plen = strlen(p);
819817466cbSJens Wiklander     slen = strlen(s);
820817466cbSJens Wiklander     s[slen++] = '\r';
821817466cbSJens Wiklander     s[slen++] = '\n';
822817466cbSJens Wiklander 
82332b31808SJens Wiklander     if (fout != NULL) {
824817466cbSJens Wiklander         if (fwrite(p, 1, plen, fout) != plen ||
82532b31808SJens Wiklander             fwrite(s, 1, slen, fout) != slen) {
82632b31808SJens Wiklander             return MBEDTLS_ERR_MPI_FILE_IO_ERROR;
827817466cbSJens Wiklander         }
82832b31808SJens Wiklander     } else {
829817466cbSJens Wiklander         mbedtls_printf("%s%s", p, s);
83032b31808SJens Wiklander     }
831817466cbSJens Wiklander 
832817466cbSJens Wiklander cleanup:
833817466cbSJens Wiklander 
83432b31808SJens Wiklander     return ret;
835817466cbSJens Wiklander }
836817466cbSJens Wiklander #endif /* MBEDTLS_FS_IO */
837817466cbSJens Wiklander 
838817466cbSJens Wiklander /*
83911fa71b9SJerome Forissier  * Import X from unsigned binary data, little endian
84032b31808SJens Wiklander  *
84132b31808SJens Wiklander  * This function is guaranteed to return an MPI with exactly the necessary
84232b31808SJens Wiklander  * number of limbs (in particular, it does not skip 0s in the input).
84311fa71b9SJerome Forissier  */
84411fa71b9SJerome Forissier int mbedtls_mpi_read_binary_le(mbedtls_mpi *X,
84511fa71b9SJerome Forissier                                const unsigned char *buf, size_t buflen)
84611fa71b9SJerome Forissier {
84711fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
84832b31808SJens Wiklander     const size_t limbs = CHARS_TO_LIMBS(buflen);
84911fa71b9SJerome Forissier 
85011fa71b9SJerome Forissier     /* Ensure that target MPI has exactly the necessary number of limbs */
8517901324dSJerome Forissier     MBEDTLS_MPI_CHK(mbedtls_mpi_resize_clear(X, limbs));
85211fa71b9SJerome Forissier 
85332b31808SJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_core_read_le(X->p, X->n, buf, buflen));
85411fa71b9SJerome Forissier 
85511fa71b9SJerome Forissier cleanup:
85611fa71b9SJerome Forissier 
85711fa71b9SJerome Forissier     /*
85811fa71b9SJerome Forissier      * This function is also used to import keys. However, wiping the buffers
85911fa71b9SJerome Forissier      * upon failure is not necessary because failure only can happen before any
86011fa71b9SJerome Forissier      * input is copied.
86111fa71b9SJerome Forissier      */
86232b31808SJens Wiklander     return ret;
86311fa71b9SJerome Forissier }
86411fa71b9SJerome Forissier 
86511fa71b9SJerome Forissier /*
866817466cbSJens Wiklander  * Import X from unsigned binary data, big endian
86732b31808SJens Wiklander  *
86832b31808SJens Wiklander  * This function is guaranteed to return an MPI with exactly the necessary
86932b31808SJens Wiklander  * number of limbs (in particular, it does not skip 0s in the input).
870817466cbSJens Wiklander  */
871817466cbSJens Wiklander int mbedtls_mpi_read_binary(mbedtls_mpi *X, const unsigned char *buf, size_t buflen)
872817466cbSJens Wiklander {
87311fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
87432b31808SJens Wiklander     const size_t limbs = CHARS_TO_LIMBS(buflen);
875817466cbSJens Wiklander 
8763d3b0591SJens Wiklander     /* Ensure that target MPI has exactly the necessary number of limbs */
8777901324dSJerome Forissier     MBEDTLS_MPI_CHK(mbedtls_mpi_resize_clear(X, limbs));
8782976273fSJens Wiklander 
87932b31808SJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_core_read_be(X->p, X->n, buf, buflen));
880817466cbSJens Wiklander 
881817466cbSJens Wiklander cleanup:
882817466cbSJens Wiklander 
88311fa71b9SJerome Forissier     /*
88411fa71b9SJerome Forissier      * This function is also used to import keys. However, wiping the buffers
88511fa71b9SJerome Forissier      * upon failure is not necessary because failure only can happen before any
88611fa71b9SJerome Forissier      * input is copied.
88711fa71b9SJerome Forissier      */
88832b31808SJens Wiklander     return ret;
889817466cbSJens Wiklander }
890817466cbSJens Wiklander 
891817466cbSJens Wiklander /*
89211fa71b9SJerome Forissier  * Export X into unsigned binary data, little endian
89311fa71b9SJerome Forissier  */
89411fa71b9SJerome Forissier int mbedtls_mpi_write_binary_le(const mbedtls_mpi *X,
89511fa71b9SJerome Forissier                                 unsigned char *buf, size_t buflen)
89611fa71b9SJerome Forissier {
89732b31808SJens Wiklander     return mbedtls_mpi_core_write_le(X->p, X->n, buf, buflen);
89811fa71b9SJerome Forissier }
89911fa71b9SJerome Forissier 
90011fa71b9SJerome Forissier /*
901817466cbSJens Wiklander  * Export X into unsigned binary data, big endian
902817466cbSJens Wiklander  */
9033d3b0591SJens Wiklander int mbedtls_mpi_write_binary(const mbedtls_mpi *X,
9043d3b0591SJens Wiklander                              unsigned char *buf, size_t buflen)
905817466cbSJens Wiklander {
90632b31808SJens Wiklander     return mbedtls_mpi_core_write_be(X->p, X->n, buf, buflen);
907817466cbSJens Wiklander }
908817466cbSJens Wiklander 
909817466cbSJens Wiklander /*
910817466cbSJens Wiklander  * Left-shift: X <<= count
911817466cbSJens Wiklander  */
912817466cbSJens Wiklander int mbedtls_mpi_shift_l(mbedtls_mpi *X, size_t count)
913817466cbSJens Wiklander {
91411fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
915b0563631STom Van Eyck     size_t i;
916817466cbSJens Wiklander 
917817466cbSJens Wiklander     i = mbedtls_mpi_bitlen(X) + count;
918817466cbSJens Wiklander 
91932b31808SJens Wiklander     if (X->n * biL < i) {
920817466cbSJens Wiklander         MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, BITS_TO_LIMBS(i)));
92132b31808SJens Wiklander     }
922817466cbSJens Wiklander 
923817466cbSJens Wiklander     ret = 0;
924817466cbSJens Wiklander 
925b0563631STom Van Eyck     mbedtls_mpi_core_shift_l(X->p, X->n, count);
926817466cbSJens Wiklander cleanup:
927817466cbSJens Wiklander 
92832b31808SJens Wiklander     return ret;
929817466cbSJens Wiklander }
930817466cbSJens Wiklander 
931817466cbSJens Wiklander /*
932817466cbSJens Wiklander  * Right-shift: X >>= count
933817466cbSJens Wiklander  */
934817466cbSJens Wiklander int mbedtls_mpi_shift_r(mbedtls_mpi *X, size_t count)
935817466cbSJens Wiklander {
93632b31808SJens Wiklander     if (X->n != 0) {
93732b31808SJens Wiklander         mbedtls_mpi_core_shift_r(X->p, X->n, count);
938817466cbSJens Wiklander     }
93932b31808SJens Wiklander     return 0;
940817466cbSJens Wiklander }
941817466cbSJens Wiklander 
942817466cbSJens Wiklander /*
943817466cbSJens Wiklander  * Compare unsigned values
944817466cbSJens Wiklander  */
945817466cbSJens Wiklander int mbedtls_mpi_cmp_abs(const mbedtls_mpi *X, const mbedtls_mpi *Y)
946817466cbSJens Wiklander {
947817466cbSJens Wiklander     size_t i, j;
948817466cbSJens Wiklander 
94932b31808SJens Wiklander     for (i = X->n; i > 0; i--) {
95032b31808SJens Wiklander         if (X->p[i - 1] != 0) {
951817466cbSJens Wiklander             break;
95232b31808SJens Wiklander         }
953817466cbSJens Wiklander     }
954817466cbSJens Wiklander 
95532b31808SJens Wiklander     for (j = Y->n; j > 0; j--) {
95632b31808SJens Wiklander         if (Y->p[j - 1] != 0) {
95732b31808SJens Wiklander             break;
95832b31808SJens Wiklander         }
95932b31808SJens Wiklander     }
96032b31808SJens Wiklander 
961b0563631STom Van Eyck     /* If i == j == 0, i.e. abs(X) == abs(Y),
962b0563631STom Van Eyck      * we end up returning 0 at the end of the function. */
96332b31808SJens Wiklander 
96432b31808SJens Wiklander     if (i > j) {
96532b31808SJens Wiklander         return 1;
96632b31808SJens Wiklander     }
96732b31808SJens Wiklander     if (j > i) {
96832b31808SJens Wiklander         return -1;
96932b31808SJens Wiklander     }
97032b31808SJens Wiklander 
97132b31808SJens Wiklander     for (; i > 0; i--) {
97232b31808SJens Wiklander         if (X->p[i - 1] > Y->p[i - 1]) {
97332b31808SJens Wiklander             return 1;
97432b31808SJens Wiklander         }
97532b31808SJens Wiklander         if (X->p[i - 1] < Y->p[i - 1]) {
97632b31808SJens Wiklander             return -1;
97732b31808SJens Wiklander         }
97832b31808SJens Wiklander     }
97932b31808SJens Wiklander 
98032b31808SJens Wiklander     return 0;
981817466cbSJens Wiklander }
982817466cbSJens Wiklander 
983817466cbSJens Wiklander /*
984817466cbSJens Wiklander  * Compare signed values
985817466cbSJens Wiklander  */
986817466cbSJens Wiklander int mbedtls_mpi_cmp_mpi(const mbedtls_mpi *X, const mbedtls_mpi *Y)
987817466cbSJens Wiklander {
988817466cbSJens Wiklander     size_t i, j;
989817466cbSJens Wiklander 
99032b31808SJens Wiklander     for (i = X->n; i > 0; i--) {
99132b31808SJens Wiklander         if (X->p[i - 1] != 0) {
992817466cbSJens Wiklander             break;
99332b31808SJens Wiklander         }
994817466cbSJens Wiklander     }
995817466cbSJens Wiklander 
99632b31808SJens Wiklander     for (j = Y->n; j > 0; j--) {
99732b31808SJens Wiklander         if (Y->p[j - 1] != 0) {
99832b31808SJens Wiklander             break;
99932b31808SJens Wiklander         }
100032b31808SJens Wiklander     }
100132b31808SJens Wiklander 
100232b31808SJens Wiklander     if (i == 0 && j == 0) {
100332b31808SJens Wiklander         return 0;
100432b31808SJens Wiklander     }
100532b31808SJens Wiklander 
100632b31808SJens Wiklander     if (i > j) {
100732b31808SJens Wiklander         return X->s;
100832b31808SJens Wiklander     }
100932b31808SJens Wiklander     if (j > i) {
101032b31808SJens Wiklander         return -Y->s;
101132b31808SJens Wiklander     }
101232b31808SJens Wiklander 
101332b31808SJens Wiklander     if (X->s > 0 && Y->s < 0) {
101432b31808SJens Wiklander         return 1;
101532b31808SJens Wiklander     }
101632b31808SJens Wiklander     if (Y->s > 0 && X->s < 0) {
101732b31808SJens Wiklander         return -1;
101832b31808SJens Wiklander     }
101932b31808SJens Wiklander 
102032b31808SJens Wiklander     for (; i > 0; i--) {
102132b31808SJens Wiklander         if (X->p[i - 1] > Y->p[i - 1]) {
102232b31808SJens Wiklander             return X->s;
102332b31808SJens Wiklander         }
102432b31808SJens Wiklander         if (X->p[i - 1] < Y->p[i - 1]) {
102532b31808SJens Wiklander             return -X->s;
102632b31808SJens Wiklander         }
102732b31808SJens Wiklander     }
102832b31808SJens Wiklander 
102932b31808SJens Wiklander     return 0;
1030817466cbSJens Wiklander }
1031817466cbSJens Wiklander 
1032817466cbSJens Wiklander /*
1033817466cbSJens Wiklander  * Compare signed values
1034817466cbSJens Wiklander  */
1035817466cbSJens Wiklander int mbedtls_mpi_cmp_int(const mbedtls_mpi *X, mbedtls_mpi_sint z)
1036817466cbSJens Wiklander {
1037817466cbSJens Wiklander     mbedtls_mpi Y;
1038817466cbSJens Wiklander     mbedtls_mpi_uint p[1];
1039817466cbSJens Wiklander 
104032b31808SJens Wiklander     *p  = mpi_sint_abs(z);
1041b0563631STom Van Eyck     Y.s = TO_SIGN(z);
1042817466cbSJens Wiklander     Y.n = 1;
1043817466cbSJens Wiklander     Y.p = p;
1044817466cbSJens Wiklander 
104532b31808SJens Wiklander     return mbedtls_mpi_cmp_mpi(X, &Y);
1046817466cbSJens Wiklander }
1047817466cbSJens Wiklander 
1048817466cbSJens Wiklander /*
1049817466cbSJens Wiklander  * Unsigned addition: X = |A| + |B|  (HAC 14.7)
1050817466cbSJens Wiklander  */
1051817466cbSJens Wiklander int mbedtls_mpi_add_abs(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B)
1052817466cbSJens Wiklander {
105311fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
105432b31808SJens Wiklander     size_t j;
1055b0563631STom Van Eyck     mbedtls_mpi_uint *p;
1056b0563631STom Van Eyck     mbedtls_mpi_uint c;
1057817466cbSJens Wiklander 
105832b31808SJens Wiklander     if (X == B) {
1059817466cbSJens Wiklander         const mbedtls_mpi *T = A; A = X; B = T;
1060817466cbSJens Wiklander     }
1061817466cbSJens Wiklander 
106232b31808SJens Wiklander     if (X != A) {
1063817466cbSJens Wiklander         MBEDTLS_MPI_CHK(mbedtls_mpi_copy(X, A));
106432b31808SJens Wiklander     }
1065817466cbSJens Wiklander 
1066817466cbSJens Wiklander     /*
106732b31808SJens Wiklander      * X must always be positive as a result of unsigned additions.
1068817466cbSJens Wiklander      */
1069817466cbSJens Wiklander     X->s = 1;
1070817466cbSJens Wiklander 
107132b31808SJens Wiklander     for (j = B->n; j > 0; j--) {
107232b31808SJens Wiklander         if (B->p[j - 1] != 0) {
1073817466cbSJens Wiklander             break;
107432b31808SJens Wiklander         }
107532b31808SJens Wiklander     }
107632b31808SJens Wiklander 
107732b31808SJens Wiklander     /* Exit early to avoid undefined behavior on NULL+0 when X->n == 0
107832b31808SJens Wiklander      * and B is 0 (of any size). */
107932b31808SJens Wiklander     if (j == 0) {
108032b31808SJens Wiklander         return 0;
108132b31808SJens Wiklander     }
1082817466cbSJens Wiklander 
1083817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, j));
1084817466cbSJens Wiklander 
108532b31808SJens Wiklander     /* j is the number of non-zero limbs of B. Add those to X. */
1086817466cbSJens Wiklander 
1087b0563631STom Van Eyck     p = X->p;
108832b31808SJens Wiklander 
1089b0563631STom Van Eyck     c = mbedtls_mpi_core_add(p, p, B->p, j);
109032b31808SJens Wiklander 
109132b31808SJens Wiklander     p += j;
109232b31808SJens Wiklander 
109332b31808SJens Wiklander     /* Now propagate any carry */
109432b31808SJens Wiklander 
109532b31808SJens Wiklander     while (c != 0) {
109632b31808SJens Wiklander         if (j >= X->n) {
109732b31808SJens Wiklander             MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, j + 1));
109832b31808SJens Wiklander             p = X->p + j;
1099817466cbSJens Wiklander         }
1100817466cbSJens Wiklander 
110132b31808SJens Wiklander         *p += c; c = (*p < c); j++; p++;
1102817466cbSJens Wiklander     }
1103817466cbSJens Wiklander 
1104817466cbSJens Wiklander cleanup:
1105817466cbSJens Wiklander 
110632b31808SJens Wiklander     return ret;
1107817466cbSJens Wiklander }
1108817466cbSJens Wiklander 
1109817466cbSJens Wiklander /*
11107901324dSJerome Forissier  * Unsigned subtraction: X = |A| - |B|  (HAC 14.9, 14.10)
1111817466cbSJens Wiklander  */
1112817466cbSJens Wiklander int mbedtls_mpi_sub_abs(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B)
1113817466cbSJens Wiklander {
111411fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
1115817466cbSJens Wiklander     size_t n;
11167901324dSJerome Forissier     mbedtls_mpi_uint carry;
1117817466cbSJens Wiklander 
111832b31808SJens Wiklander     for (n = B->n; n > 0; n--) {
111932b31808SJens Wiklander         if (B->p[n - 1] != 0) {
1120817466cbSJens Wiklander             break;
112132b31808SJens Wiklander         }
112232b31808SJens Wiklander     }
112332b31808SJens Wiklander     if (n > A->n) {
11247901324dSJerome Forissier         /* B >= (2^ciL)^n > A */
11257901324dSJerome Forissier         ret = MBEDTLS_ERR_MPI_NEGATIVE_VALUE;
11267901324dSJerome Forissier         goto cleanup;
11277901324dSJerome Forissier     }
1128817466cbSJens Wiklander 
11297901324dSJerome Forissier     MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, A->n));
11307901324dSJerome Forissier 
11317901324dSJerome Forissier     /* Set the high limbs of X to match A. Don't touch the lower limbs
11327901324dSJerome Forissier      * because X might be aliased to B, and we must not overwrite the
11337901324dSJerome Forissier      * significant digits of B. */
113432b31808SJens Wiklander     if (A->n > n && A != X) {
11357901324dSJerome Forissier         memcpy(X->p + n, A->p + n, (A->n - n) * ciL);
113632b31808SJens Wiklander     }
113732b31808SJens Wiklander     if (X->n > A->n) {
11387901324dSJerome Forissier         memset(X->p + A->n, 0, (X->n - A->n) * ciL);
113932b31808SJens Wiklander     }
11407901324dSJerome Forissier 
114132b31808SJens Wiklander     carry = mbedtls_mpi_core_sub(X->p, A->p, B->p, n);
114232b31808SJens Wiklander     if (carry != 0) {
114332b31808SJens Wiklander         /* Propagate the carry through the rest of X. */
114432b31808SJens Wiklander         carry = mbedtls_mpi_core_sub_int(X->p + n, X->p + n, carry, X->n - n);
114532b31808SJens Wiklander 
114632b31808SJens Wiklander         /* If we have further carry/borrow, the result is negative. */
114732b31808SJens Wiklander         if (carry != 0) {
11487901324dSJerome Forissier             ret = MBEDTLS_ERR_MPI_NEGATIVE_VALUE;
11497901324dSJerome Forissier             goto cleanup;
11507901324dSJerome Forissier         }
11517901324dSJerome Forissier     }
11527901324dSJerome Forissier 
11537901324dSJerome Forissier     /* X should always be positive as a result of unsigned subtractions. */
11547901324dSJerome Forissier     X->s = 1;
1155817466cbSJens Wiklander 
1156817466cbSJens Wiklander cleanup:
115732b31808SJens Wiklander     return ret;
115832b31808SJens Wiklander }
115932b31808SJens Wiklander 
116032b31808SJens Wiklander /* Common function for signed addition and subtraction.
116132b31808SJens Wiklander  * Calculate A + B * flip_B where flip_B is 1 or -1.
116232b31808SJens Wiklander  */
116332b31808SJens Wiklander static int add_sub_mpi(mbedtls_mpi *X,
116432b31808SJens Wiklander                        const mbedtls_mpi *A, const mbedtls_mpi *B,
116532b31808SJens Wiklander                        int flip_B)
116632b31808SJens Wiklander {
116732b31808SJens Wiklander     int ret, s;
116832b31808SJens Wiklander 
116932b31808SJens Wiklander     s = A->s;
117032b31808SJens Wiklander     if (A->s * B->s * flip_B < 0) {
117132b31808SJens Wiklander         int cmp = mbedtls_mpi_cmp_abs(A, B);
117232b31808SJens Wiklander         if (cmp >= 0) {
117332b31808SJens Wiklander             MBEDTLS_MPI_CHK(mbedtls_mpi_sub_abs(X, A, B));
117432b31808SJens Wiklander             /* If |A| = |B|, the result is 0 and we must set the sign bit
117532b31808SJens Wiklander              * to +1 regardless of which of A or B was negative. Otherwise,
117632b31808SJens Wiklander              * since |A| > |B|, the sign is the sign of A. */
117732b31808SJens Wiklander             X->s = cmp == 0 ? 1 : s;
117832b31808SJens Wiklander         } else {
117932b31808SJens Wiklander             MBEDTLS_MPI_CHK(mbedtls_mpi_sub_abs(X, B, A));
118032b31808SJens Wiklander             /* Since |A| < |B|, the sign is the opposite of A. */
118132b31808SJens Wiklander             X->s = -s;
118232b31808SJens Wiklander         }
118332b31808SJens Wiklander     } else {
118432b31808SJens Wiklander         MBEDTLS_MPI_CHK(mbedtls_mpi_add_abs(X, A, B));
118532b31808SJens Wiklander         X->s = s;
118632b31808SJens Wiklander     }
118732b31808SJens Wiklander 
118832b31808SJens Wiklander cleanup:
118932b31808SJens Wiklander 
119032b31808SJens Wiklander     return ret;
1191817466cbSJens Wiklander }
1192817466cbSJens Wiklander 
1193817466cbSJens Wiklander /*
1194817466cbSJens Wiklander  * Signed addition: X = A + B
1195817466cbSJens Wiklander  */
1196817466cbSJens Wiklander int mbedtls_mpi_add_mpi(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B)
1197817466cbSJens Wiklander {
119832b31808SJens Wiklander     return add_sub_mpi(X, A, B, 1);
1199817466cbSJens Wiklander }
1200817466cbSJens Wiklander 
1201817466cbSJens Wiklander /*
1202817466cbSJens Wiklander  * Signed subtraction: X = A - B
1203817466cbSJens Wiklander  */
1204817466cbSJens Wiklander int mbedtls_mpi_sub_mpi(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B)
1205817466cbSJens Wiklander {
120632b31808SJens Wiklander     return add_sub_mpi(X, A, B, -1);
1207817466cbSJens Wiklander }
1208817466cbSJens Wiklander 
1209817466cbSJens Wiklander /*
1210817466cbSJens Wiklander  * Signed addition: X = A + b
1211817466cbSJens Wiklander  */
1212817466cbSJens Wiklander int mbedtls_mpi_add_int(mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b)
1213817466cbSJens Wiklander {
1214039e02dfSJerome Forissier     mbedtls_mpi B;
1215817466cbSJens Wiklander     mbedtls_mpi_uint p[1];
1216817466cbSJens Wiklander 
121732b31808SJens Wiklander     p[0] = mpi_sint_abs(b);
1218b0563631STom Van Eyck     B.s = TO_SIGN(b);
1219039e02dfSJerome Forissier     B.n = 1;
1220039e02dfSJerome Forissier     B.p = p;
1221817466cbSJens Wiklander 
122232b31808SJens Wiklander     return mbedtls_mpi_add_mpi(X, A, &B);
1223817466cbSJens Wiklander }
1224817466cbSJens Wiklander 
1225817466cbSJens Wiklander /*
1226817466cbSJens Wiklander  * Signed subtraction: X = A - b
1227817466cbSJens Wiklander  */
1228817466cbSJens Wiklander int mbedtls_mpi_sub_int(mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b)
1229817466cbSJens Wiklander {
1230039e02dfSJerome Forissier     mbedtls_mpi B;
1231817466cbSJens Wiklander     mbedtls_mpi_uint p[1];
1232817466cbSJens Wiklander 
123332b31808SJens Wiklander     p[0] = mpi_sint_abs(b);
1234b0563631STom Van Eyck     B.s = TO_SIGN(b);
1235039e02dfSJerome Forissier     B.n = 1;
1236039e02dfSJerome Forissier     B.p = p;
1237817466cbSJens Wiklander 
123832b31808SJens Wiklander     return mbedtls_mpi_sub_mpi(X, A, &B);
1239817466cbSJens Wiklander }
1240817466cbSJens Wiklander 
1241817466cbSJens Wiklander /*
1242817466cbSJens Wiklander  * Baseline multiplication: X = A * B  (HAC 14.12)
1243817466cbSJens Wiklander  */
1244817466cbSJens Wiklander int mbedtls_mpi_mul_mpi(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B)
1245817466cbSJens Wiklander {
124611fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
1247817466cbSJens Wiklander     size_t i, j;
1248817466cbSJens Wiklander     mbedtls_mpi TA, TB;
12497901324dSJerome Forissier     int result_is_zero = 0;
1250817466cbSJens Wiklander 
1251b0563631STom Van Eyck     mbedtls_mpi_init_mempool(&TA);
1252b0563631STom Van Eyck     mbedtls_mpi_init_mempool(&TB);
1253817466cbSJens Wiklander 
125432b31808SJens Wiklander     if (X == A) {
125532b31808SJens Wiklander         MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TA, A)); A = &TA;
125632b31808SJens Wiklander     }
125732b31808SJens Wiklander     if (X == B) {
125832b31808SJens Wiklander         MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TB, B)); B = &TB;
125932b31808SJens Wiklander     }
1260817466cbSJens Wiklander 
126132b31808SJens Wiklander     for (i = A->n; i > 0; i--) {
126232b31808SJens Wiklander         if (A->p[i - 1] != 0) {
1263817466cbSJens Wiklander             break;
126432b31808SJens Wiklander         }
126532b31808SJens Wiklander     }
126632b31808SJens Wiklander     if (i == 0) {
12677901324dSJerome Forissier         result_is_zero = 1;
126832b31808SJens Wiklander     }
1269817466cbSJens Wiklander 
127032b31808SJens Wiklander     for (j = B->n; j > 0; j--) {
127132b31808SJens Wiklander         if (B->p[j - 1] != 0) {
1272817466cbSJens Wiklander             break;
127332b31808SJens Wiklander         }
127432b31808SJens Wiklander     }
127532b31808SJens Wiklander     if (j == 0) {
12767901324dSJerome Forissier         result_is_zero = 1;
127732b31808SJens Wiklander     }
1278817466cbSJens Wiklander 
1279817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, i + j));
1280817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_lset(X, 0));
1281817466cbSJens Wiklander 
1282b0563631STom Van Eyck     mbedtls_mpi_core_mul(X->p, A->p, i, B->p, j);
1283817466cbSJens Wiklander 
12847901324dSJerome Forissier     /* If the result is 0, we don't shortcut the operation, which reduces
12857901324dSJerome Forissier      * but does not eliminate side channels leaking the zero-ness. We do
12867901324dSJerome Forissier      * need to take care to set the sign bit properly since the library does
12877901324dSJerome Forissier      * not fully support an MPI object with a value of 0 and s == -1. */
128832b31808SJens Wiklander     if (result_is_zero) {
12897901324dSJerome Forissier         X->s = 1;
129032b31808SJens Wiklander     } else {
1291817466cbSJens Wiklander         X->s = A->s * B->s;
129232b31808SJens Wiklander     }
1293817466cbSJens Wiklander 
1294817466cbSJens Wiklander cleanup:
1295817466cbSJens Wiklander 
1296817466cbSJens Wiklander     mbedtls_mpi_free(&TB); mbedtls_mpi_free(&TA);
1297817466cbSJens Wiklander 
129832b31808SJens Wiklander     return ret;
1299817466cbSJens Wiklander }
1300817466cbSJens Wiklander 
1301817466cbSJens Wiklander /*
1302817466cbSJens Wiklander  * Baseline multiplication: X = A * b
1303817466cbSJens Wiklander  */
1304817466cbSJens Wiklander int mbedtls_mpi_mul_int(mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_uint b)
1305817466cbSJens Wiklander {
13067901324dSJerome Forissier     size_t n = A->n;
130732b31808SJens Wiklander     while (n > 0 && A->p[n - 1] == 0) {
13087901324dSJerome Forissier         --n;
13097901324dSJerome Forissier     }
13107901324dSJerome Forissier 
131132b31808SJens Wiklander     /* The general method below doesn't work if b==0. */
131232b31808SJens Wiklander     if (b == 0 || n == 0) {
131332b31808SJens Wiklander         return mbedtls_mpi_lset(X, 0);
131432b31808SJens Wiklander     }
131532b31808SJens Wiklander 
131632b31808SJens Wiklander     /* Calculate A*b as A + A*(b-1) to take advantage of mbedtls_mpi_core_mla */
13177901324dSJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
13187901324dSJerome Forissier     /* In general, A * b requires 1 limb more than b. If
13197901324dSJerome Forissier      * A->p[n - 1] * b / b == A->p[n - 1], then A * b fits in the same
13207901324dSJerome Forissier      * number of limbs as A and the call to grow() is not required since
13217901324dSJerome Forissier      * copy() will take care of the growth if needed. However, experimentally,
13227901324dSJerome Forissier      * making the call to grow() unconditional causes slightly fewer
13237901324dSJerome Forissier      * calls to calloc() in ECP code, presumably because it reuses the
13247901324dSJerome Forissier      * same mpi for a while and this way the mpi is more likely to directly
132532b31808SJens Wiklander      * grow to its final size.
132632b31808SJens Wiklander      *
132732b31808SJens Wiklander      * Note that calculating A*b as 0 + A*b doesn't work as-is because
132832b31808SJens Wiklander      * A,X can be the same. */
13297901324dSJerome Forissier     MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, n + 1));
13307901324dSJerome Forissier     MBEDTLS_MPI_CHK(mbedtls_mpi_copy(X, A));
133132b31808SJens Wiklander     mbedtls_mpi_core_mla(X->p, X->n, A->p, n, b - 1);
13327901324dSJerome Forissier 
13337901324dSJerome Forissier cleanup:
133432b31808SJens Wiklander     return ret;
1335817466cbSJens Wiklander }
1336817466cbSJens Wiklander 
1337817466cbSJens Wiklander /*
1338817466cbSJens Wiklander  * Unsigned integer divide - double mbedtls_mpi_uint dividend, u1/u0, and
1339817466cbSJens Wiklander  * mbedtls_mpi_uint divisor, d
1340817466cbSJens Wiklander  */
1341817466cbSJens Wiklander static mbedtls_mpi_uint mbedtls_int_div_int(mbedtls_mpi_uint u1,
134232b31808SJens Wiklander                                             mbedtls_mpi_uint u0,
134332b31808SJens Wiklander                                             mbedtls_mpi_uint d,
134432b31808SJens Wiklander                                             mbedtls_mpi_uint *r)
1345817466cbSJens Wiklander {
1346817466cbSJens Wiklander #if defined(MBEDTLS_HAVE_UDBL)
1347817466cbSJens Wiklander     mbedtls_t_udbl dividend, quotient;
1348817466cbSJens Wiklander #else
1349817466cbSJens Wiklander     const mbedtls_mpi_uint radix = (mbedtls_mpi_uint) 1 << biH;
1350817466cbSJens Wiklander     const mbedtls_mpi_uint uint_halfword_mask = ((mbedtls_mpi_uint) 1 << biH) - 1;
1351817466cbSJens Wiklander     mbedtls_mpi_uint d0, d1, q0, q1, rAX, r0, quotient;
1352817466cbSJens Wiklander     mbedtls_mpi_uint u0_msw, u0_lsw;
1353817466cbSJens Wiklander     size_t s;
1354817466cbSJens Wiklander #endif
1355817466cbSJens Wiklander 
1356817466cbSJens Wiklander     /*
1357817466cbSJens Wiklander      * Check for overflow
1358817466cbSJens Wiklander      */
135932b31808SJens Wiklander     if (0 == d || u1 >= d) {
136032b31808SJens Wiklander         if (r != NULL) {
136132b31808SJens Wiklander             *r = ~(mbedtls_mpi_uint) 0u;
136232b31808SJens Wiklander         }
1363817466cbSJens Wiklander 
136432b31808SJens Wiklander         return ~(mbedtls_mpi_uint) 0u;
1365817466cbSJens Wiklander     }
1366817466cbSJens Wiklander 
1367817466cbSJens Wiklander #if defined(MBEDTLS_HAVE_UDBL)
1368817466cbSJens Wiklander     dividend  = (mbedtls_t_udbl) u1 << biL;
1369817466cbSJens Wiklander     dividend |= (mbedtls_t_udbl) u0;
1370817466cbSJens Wiklander     quotient = dividend / d;
137132b31808SJens Wiklander     if (quotient > ((mbedtls_t_udbl) 1 << biL) - 1) {
1372817466cbSJens Wiklander         quotient = ((mbedtls_t_udbl) 1 << biL) - 1;
137332b31808SJens Wiklander     }
1374817466cbSJens Wiklander 
137532b31808SJens Wiklander     if (r != NULL) {
1376817466cbSJens Wiklander         *r = (mbedtls_mpi_uint) (dividend - (quotient * d));
137732b31808SJens Wiklander     }
1378817466cbSJens Wiklander 
1379817466cbSJens Wiklander     return (mbedtls_mpi_uint) quotient;
1380817466cbSJens Wiklander #else
1381817466cbSJens Wiklander 
1382817466cbSJens Wiklander     /*
1383817466cbSJens Wiklander      * Algorithm D, Section 4.3.1 - The Art of Computer Programming
1384817466cbSJens Wiklander      *   Vol. 2 - Seminumerical Algorithms, Knuth
1385817466cbSJens Wiklander      */
1386817466cbSJens Wiklander 
1387817466cbSJens Wiklander     /*
1388817466cbSJens Wiklander      * Normalize the divisor, d, and dividend, u0, u1
1389817466cbSJens Wiklander      */
139032b31808SJens Wiklander     s = mbedtls_mpi_core_clz(d);
1391817466cbSJens Wiklander     d = d << s;
1392817466cbSJens Wiklander 
1393817466cbSJens Wiklander     u1 = u1 << s;
1394817466cbSJens Wiklander     u1 |= (u0 >> (biL - s)) & (-(mbedtls_mpi_sint) s >> (biL - 1));
1395817466cbSJens Wiklander     u0 =  u0 << s;
1396817466cbSJens Wiklander 
1397817466cbSJens Wiklander     d1 = d >> biH;
1398817466cbSJens Wiklander     d0 = d & uint_halfword_mask;
1399817466cbSJens Wiklander 
1400817466cbSJens Wiklander     u0_msw = u0 >> biH;
1401817466cbSJens Wiklander     u0_lsw = u0 & uint_halfword_mask;
1402817466cbSJens Wiklander 
1403817466cbSJens Wiklander     /*
1404817466cbSJens Wiklander      * Find the first quotient and remainder
1405817466cbSJens Wiklander      */
1406817466cbSJens Wiklander     q1 = u1 / d1;
1407817466cbSJens Wiklander     r0 = u1 - d1 * q1;
1408817466cbSJens Wiklander 
140932b31808SJens Wiklander     while (q1 >= radix || (q1 * d0 > radix * r0 + u0_msw)) {
1410817466cbSJens Wiklander         q1 -= 1;
1411817466cbSJens Wiklander         r0 += d1;
1412817466cbSJens Wiklander 
141332b31808SJens Wiklander         if (r0 >= radix) {
141432b31808SJens Wiklander             break;
141532b31808SJens Wiklander         }
1416817466cbSJens Wiklander     }
1417817466cbSJens Wiklander 
1418817466cbSJens Wiklander     rAX = (u1 * radix) + (u0_msw - q1 * d);
1419817466cbSJens Wiklander     q0 = rAX / d1;
1420817466cbSJens Wiklander     r0 = rAX - q0 * d1;
1421817466cbSJens Wiklander 
142232b31808SJens Wiklander     while (q0 >= radix || (q0 * d0 > radix * r0 + u0_lsw)) {
1423817466cbSJens Wiklander         q0 -= 1;
1424817466cbSJens Wiklander         r0 += d1;
1425817466cbSJens Wiklander 
142632b31808SJens Wiklander         if (r0 >= radix) {
142732b31808SJens Wiklander             break;
142832b31808SJens Wiklander         }
1429817466cbSJens Wiklander     }
1430817466cbSJens Wiklander 
143132b31808SJens Wiklander     if (r != NULL) {
1432817466cbSJens Wiklander         *r = (rAX * radix + u0_lsw - q0 * d) >> s;
143332b31808SJens Wiklander     }
1434817466cbSJens Wiklander 
1435817466cbSJens Wiklander     quotient = q1 * radix + q0;
1436817466cbSJens Wiklander 
1437817466cbSJens Wiklander     return quotient;
1438817466cbSJens Wiklander #endif
1439817466cbSJens Wiklander }
1440817466cbSJens Wiklander 
1441817466cbSJens Wiklander /*
1442817466cbSJens Wiklander  * Division by mbedtls_mpi: A = Q * B + R  (HAC 14.20)
1443817466cbSJens Wiklander  */
14443d3b0591SJens Wiklander int mbedtls_mpi_div_mpi(mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A,
14453d3b0591SJens Wiklander                         const mbedtls_mpi *B)
1446817466cbSJens Wiklander {
144711fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
1448817466cbSJens Wiklander     size_t i, n, t, k;
1449817466cbSJens Wiklander     mbedtls_mpi X, Y, Z, T1, T2;
145011fa71b9SJerome Forissier     mbedtls_mpi_uint TP2[3];
1451817466cbSJens Wiklander 
145232b31808SJens Wiklander     if (mbedtls_mpi_cmp_int(B, 0) == 0) {
145332b31808SJens Wiklander         return MBEDTLS_ERR_MPI_DIVISION_BY_ZERO;
145432b31808SJens Wiklander     }
1455817466cbSJens Wiklander 
145698bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool(&X); mbedtls_mpi_init_mempool(&Y);
145798bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool(&Z); mbedtls_mpi_init_mempool(&T1);
145811fa71b9SJerome Forissier     /*
145911fa71b9SJerome Forissier      * Avoid dynamic memory allocations for constant-size T2.
146011fa71b9SJerome Forissier      *
146111fa71b9SJerome Forissier      * T2 is used for comparison only and the 3 limbs are assigned explicitly,
146211fa71b9SJerome Forissier      * so nobody increase the size of the MPI and we're safe to use an on-stack
146311fa71b9SJerome Forissier      * buffer.
146411fa71b9SJerome Forissier      */
146511fa71b9SJerome Forissier     T2.s = 1;
146611fa71b9SJerome Forissier     T2.n = sizeof(TP2) / sizeof(*TP2);
146711fa71b9SJerome Forissier     T2.p = TP2;
1468817466cbSJens Wiklander 
146932b31808SJens Wiklander     if (mbedtls_mpi_cmp_abs(A, B) < 0) {
147032b31808SJens Wiklander         if (Q != NULL) {
147132b31808SJens Wiklander             MBEDTLS_MPI_CHK(mbedtls_mpi_lset(Q, 0));
147232b31808SJens Wiklander         }
147332b31808SJens Wiklander         if (R != NULL) {
147432b31808SJens Wiklander             MBEDTLS_MPI_CHK(mbedtls_mpi_copy(R, A));
147532b31808SJens Wiklander         }
147632b31808SJens Wiklander         return 0;
1477817466cbSJens Wiklander     }
1478817466cbSJens Wiklander 
1479817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&X, A));
1480817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&Y, B));
1481817466cbSJens Wiklander     X.s = Y.s = 1;
1482817466cbSJens Wiklander 
1483817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_grow(&Z, A->n + 2));
1484817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&Z,  0));
14857901324dSJerome Forissier     MBEDTLS_MPI_CHK(mbedtls_mpi_grow(&T1, A->n + 2));
1486817466cbSJens Wiklander 
1487817466cbSJens Wiklander     k = mbedtls_mpi_bitlen(&Y) % biL;
148832b31808SJens Wiklander     if (k < biL - 1) {
1489817466cbSJens Wiklander         k = biL - 1 - k;
1490817466cbSJens Wiklander         MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&X, k));
1491817466cbSJens Wiklander         MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&Y, k));
149232b31808SJens Wiklander     } else {
149332b31808SJens Wiklander         k = 0;
1494817466cbSJens Wiklander     }
1495817466cbSJens Wiklander 
1496817466cbSJens Wiklander     n = X.n - 1;
1497817466cbSJens Wiklander     t = Y.n - 1;
1498817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&Y, biL * (n - t)));
1499817466cbSJens Wiklander 
150032b31808SJens Wiklander     while (mbedtls_mpi_cmp_mpi(&X, &Y) >= 0) {
1501817466cbSJens Wiklander         Z.p[n - t]++;
1502817466cbSJens Wiklander         MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&X, &X, &Y));
1503817466cbSJens Wiklander     }
1504817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&Y, biL * (n - t)));
1505817466cbSJens Wiklander 
150632b31808SJens Wiklander     for (i = n; i > t; i--) {
150732b31808SJens Wiklander         if (X.p[i] >= Y.p[t]) {
150832b31808SJens Wiklander             Z.p[i - t - 1] = ~(mbedtls_mpi_uint) 0u;
150932b31808SJens Wiklander         } else {
1510817466cbSJens Wiklander             Z.p[i - t - 1] = mbedtls_int_div_int(X.p[i], X.p[i - 1],
1511817466cbSJens Wiklander                                                  Y.p[t], NULL);
1512817466cbSJens Wiklander         }
1513817466cbSJens Wiklander 
151411fa71b9SJerome Forissier         T2.p[0] = (i < 2) ? 0 : X.p[i - 2];
151511fa71b9SJerome Forissier         T2.p[1] = (i < 1) ? 0 : X.p[i - 1];
151611fa71b9SJerome Forissier         T2.p[2] = X.p[i];
151711fa71b9SJerome Forissier 
1518817466cbSJens Wiklander         Z.p[i - t - 1]++;
151932b31808SJens Wiklander         do {
1520817466cbSJens Wiklander             Z.p[i - t - 1]--;
1521817466cbSJens Wiklander 
1522817466cbSJens Wiklander             MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&T1, 0));
1523817466cbSJens Wiklander             T1.p[0] = (t < 1) ? 0 : Y.p[t - 1];
1524817466cbSJens Wiklander             T1.p[1] = Y.p[t];
1525817466cbSJens Wiklander             MBEDTLS_MPI_CHK(mbedtls_mpi_mul_int(&T1, &T1, Z.p[i - t - 1]));
152632b31808SJens Wiklander         } while (mbedtls_mpi_cmp_mpi(&T1, &T2) > 0);
1527817466cbSJens Wiklander 
1528817466cbSJens Wiklander         MBEDTLS_MPI_CHK(mbedtls_mpi_mul_int(&T1, &Y, Z.p[i - t - 1]));
1529817466cbSJens Wiklander         MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&T1,  biL * (i - t - 1)));
1530817466cbSJens Wiklander         MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&X, &X, &T1));
1531817466cbSJens Wiklander 
153232b31808SJens Wiklander         if (mbedtls_mpi_cmp_int(&X, 0) < 0) {
1533817466cbSJens Wiklander             MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&T1, &Y));
1534817466cbSJens Wiklander             MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&T1, biL * (i - t - 1)));
1535817466cbSJens Wiklander             MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&X, &X, &T1));
1536817466cbSJens Wiklander             Z.p[i - t - 1]--;
1537817466cbSJens Wiklander         }
1538817466cbSJens Wiklander     }
1539817466cbSJens Wiklander 
154032b31808SJens Wiklander     if (Q != NULL) {
1541817466cbSJens Wiklander         MBEDTLS_MPI_CHK(mbedtls_mpi_copy(Q, &Z));
1542817466cbSJens Wiklander         Q->s = A->s * B->s;
1543817466cbSJens Wiklander     }
1544817466cbSJens Wiklander 
154532b31808SJens Wiklander     if (R != NULL) {
1546817466cbSJens Wiklander         MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&X, k));
1547817466cbSJens Wiklander         X.s = A->s;
1548817466cbSJens Wiklander         MBEDTLS_MPI_CHK(mbedtls_mpi_copy(R, &X));
1549817466cbSJens Wiklander 
155032b31808SJens Wiklander         if (mbedtls_mpi_cmp_int(R, 0) == 0) {
1551817466cbSJens Wiklander             R->s = 1;
1552817466cbSJens Wiklander         }
155332b31808SJens Wiklander     }
1554817466cbSJens Wiklander 
1555817466cbSJens Wiklander cleanup:
1556817466cbSJens Wiklander 
1557817466cbSJens Wiklander     mbedtls_mpi_free(&X); mbedtls_mpi_free(&Y); mbedtls_mpi_free(&Z);
155811fa71b9SJerome Forissier     mbedtls_mpi_free(&T1);
155911fa71b9SJerome Forissier     mbedtls_platform_zeroize(TP2, sizeof(TP2));
1560817466cbSJens Wiklander 
156132b31808SJens Wiklander     return ret;
1562817466cbSJens Wiklander }
1563817466cbSJens Wiklander 
1564817466cbSJens Wiklander /*
1565817466cbSJens Wiklander  * Division by int: A = Q * b + R
1566817466cbSJens Wiklander  */
15673d3b0591SJens Wiklander int mbedtls_mpi_div_int(mbedtls_mpi *Q, mbedtls_mpi *R,
15683d3b0591SJens Wiklander                         const mbedtls_mpi *A,
15693d3b0591SJens Wiklander                         mbedtls_mpi_sint b)
1570817466cbSJens Wiklander {
1571039e02dfSJerome Forissier     mbedtls_mpi B;
1572817466cbSJens Wiklander     mbedtls_mpi_uint p[1];
1573817466cbSJens Wiklander 
157432b31808SJens Wiklander     p[0] = mpi_sint_abs(b);
1575b0563631STom Van Eyck     B.s = TO_SIGN(b);
1576039e02dfSJerome Forissier     B.n = 1;
1577039e02dfSJerome Forissier     B.p = p;
1578817466cbSJens Wiklander 
157932b31808SJens Wiklander     return mbedtls_mpi_div_mpi(Q, R, A, &B);
1580817466cbSJens Wiklander }
1581817466cbSJens Wiklander 
1582817466cbSJens Wiklander /*
1583817466cbSJens Wiklander  * Modulo: R = A mod B
1584817466cbSJens Wiklander  */
1585817466cbSJens Wiklander int mbedtls_mpi_mod_mpi(mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B)
1586817466cbSJens Wiklander {
158711fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
1588817466cbSJens Wiklander 
158932b31808SJens Wiklander     if (mbedtls_mpi_cmp_int(B, 0) < 0) {
159032b31808SJens Wiklander         return MBEDTLS_ERR_MPI_NEGATIVE_VALUE;
159132b31808SJens Wiklander     }
1592817466cbSJens Wiklander 
1593817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_div_mpi(NULL, R, A, B));
1594817466cbSJens Wiklander 
159532b31808SJens Wiklander     while (mbedtls_mpi_cmp_int(R, 0) < 0) {
1596817466cbSJens Wiklander         MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(R, R, B));
159732b31808SJens Wiklander     }
1598817466cbSJens Wiklander 
159932b31808SJens Wiklander     while (mbedtls_mpi_cmp_mpi(R, B) >= 0) {
1600817466cbSJens Wiklander         MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(R, R, B));
160132b31808SJens Wiklander     }
1602817466cbSJens Wiklander 
1603817466cbSJens Wiklander cleanup:
1604817466cbSJens Wiklander 
160532b31808SJens Wiklander     return ret;
1606817466cbSJens Wiklander }
1607817466cbSJens Wiklander 
1608817466cbSJens Wiklander /*
1609817466cbSJens Wiklander  * Modulo: r = A mod b
1610817466cbSJens Wiklander  */
1611817466cbSJens Wiklander int mbedtls_mpi_mod_int(mbedtls_mpi_uint *r, const mbedtls_mpi *A, mbedtls_mpi_sint b)
1612817466cbSJens Wiklander {
1613817466cbSJens Wiklander     size_t i;
1614817466cbSJens Wiklander     mbedtls_mpi_uint x, y, z;
1615817466cbSJens Wiklander 
161632b31808SJens Wiklander     if (b == 0) {
161732b31808SJens Wiklander         return MBEDTLS_ERR_MPI_DIVISION_BY_ZERO;
161832b31808SJens Wiklander     }
1619817466cbSJens Wiklander 
162032b31808SJens Wiklander     if (b < 0) {
162132b31808SJens Wiklander         return MBEDTLS_ERR_MPI_NEGATIVE_VALUE;
162232b31808SJens Wiklander     }
1623817466cbSJens Wiklander 
1624817466cbSJens Wiklander     /*
1625817466cbSJens Wiklander      * handle trivial cases
1626817466cbSJens Wiklander      */
162732b31808SJens Wiklander     if (b == 1 || A->n == 0) {
1628817466cbSJens Wiklander         *r = 0;
162932b31808SJens Wiklander         return 0;
1630817466cbSJens Wiklander     }
1631817466cbSJens Wiklander 
163232b31808SJens Wiklander     if (b == 2) {
1633817466cbSJens Wiklander         *r = A->p[0] & 1;
163432b31808SJens Wiklander         return 0;
1635817466cbSJens Wiklander     }
1636817466cbSJens Wiklander 
1637817466cbSJens Wiklander     /*
1638817466cbSJens Wiklander      * general case
1639817466cbSJens Wiklander      */
164032b31808SJens Wiklander     for (i = A->n, y = 0; i > 0; i--) {
1641817466cbSJens Wiklander         x  = A->p[i - 1];
1642817466cbSJens Wiklander         y  = (y << biH) | (x >> biH);
1643817466cbSJens Wiklander         z  = y / b;
1644817466cbSJens Wiklander         y -= z * b;
1645817466cbSJens Wiklander 
1646817466cbSJens Wiklander         x <<= biH;
1647817466cbSJens Wiklander         y  = (y << biH) | (x >> biH);
1648817466cbSJens Wiklander         z  = y / b;
1649817466cbSJens Wiklander         y -= z * b;
1650817466cbSJens Wiklander     }
1651817466cbSJens Wiklander 
1652817466cbSJens Wiklander     /*
1653817466cbSJens Wiklander      * If A is negative, then the current y represents a negative value.
1654817466cbSJens Wiklander      * Flipping it to the positive side.
1655817466cbSJens Wiklander      */
165632b31808SJens Wiklander     if (A->s < 0 && y != 0) {
1657817466cbSJens Wiklander         y = b - y;
165832b31808SJens Wiklander     }
1659817466cbSJens Wiklander 
1660817466cbSJens Wiklander     *r = y;
1661817466cbSJens Wiklander 
166232b31808SJens Wiklander     return 0;
1663817466cbSJens Wiklander }
1664817466cbSJens Wiklander 
1665b0563631STom Van Eyck /**
1666b0563631STom Van Eyck  * \remark Replaced by our own because the original has been removed since
1667b0563631STom Van Eyck  *         mbedtls v3.6.0.
1668b0563631STom Van Eyck */
16697901324dSJerome Forissier void mbedtls_mpi_montg_init(mbedtls_mpi_uint *mm, const mbedtls_mpi *N)
16707901324dSJerome Forissier {
1671b0563631STom Van Eyck     *mm = mbedtls_mpi_core_montmul_init(N->p);
16727901324dSJerome Forissier }
16737901324dSJerome Forissier 
16747901324dSJerome Forissier /** Montgomery multiplication: A = A * B * R^-1 mod N  (HAC 14.36)
16757901324dSJerome Forissier  *
16767901324dSJerome Forissier  * \param[in,out]   A   One of the numbers to multiply.
16777901324dSJerome Forissier  *                      It must have at least as many limbs as N
16787901324dSJerome Forissier  *                      (A->n >= N->n), and any limbs beyond n are ignored.
16797901324dSJerome Forissier  *                      On successful completion, A contains the result of
16807901324dSJerome Forissier  *                      the multiplication A * B * R^-1 mod N where
16817901324dSJerome Forissier  *                      R = (2^ciL)^n.
16827901324dSJerome Forissier  * \param[in]       B   One of the numbers to multiply.
16837901324dSJerome Forissier  *                      It must be nonzero and must not have more limbs than N
16847901324dSJerome Forissier  *                      (B->n <= N->n).
168532b31808SJens Wiklander  * \param[in]       N   The modulus. \p N must be odd.
16867901324dSJerome Forissier  * \param           mm  The value calculated by `mpi_montg_init(&mm, N)`.
16877901324dSJerome Forissier  *                      This is -N^-1 mod 2^ciL.
16887901324dSJerome Forissier  * \param[in,out]   T   A bignum for temporary storage.
168932b31808SJens Wiklander  *                      It must be at least twice the limb size of N plus 1
169032b31808SJens Wiklander  *                      (T->n >= 2 * N->n + 1).
16917901324dSJerome Forissier  *                      Its initial content is unused and
16927901324dSJerome Forissier  *                      its final content is indeterminate.
169332b31808SJens Wiklander  *                      It does not get reallocated.
1694b0563631STom Van Eyck  * \remark Replaced by our own because the original has been removed since
1695b0563631STom Van Eyck  *         mbedtls v3.6.0.
1696817466cbSJens Wiklander  */
1697b0563631STom Van Eyck void mbedtls_mpi_montmul(mbedtls_mpi *A, const mbedtls_mpi *B,
169832b31808SJens Wiklander                         const mbedtls_mpi *N, mbedtls_mpi_uint mm,
169932b31808SJens Wiklander                         mbedtls_mpi *T)
1700817466cbSJens Wiklander {
170132b31808SJens Wiklander     mbedtls_mpi_core_montmul(A->p, A->p, B->p, B->n, N->p, N->n, mm, T->p);
1702817466cbSJens Wiklander }
1703817466cbSJens Wiklander 
1704b0563631STom Van Eyck /**
1705817466cbSJens Wiklander  * Montgomery reduction: A = A * R^-1 mod N
17067901324dSJerome Forissier  *
1707b0563631STom Van Eyck  * See mbedtls_mpi_montmul() regarding constraints and guarantees on the parameters.
1708b0563631STom Van Eyck  *
1709b0563631STom Van Eyck  * \remark Replaced by our own because the original has been removed since
1710b0563631STom Van Eyck  *         mbedtls v3.6.0.
1711817466cbSJens Wiklander  */
1712b0563631STom Van Eyck void mbedtls_mpi_montred(mbedtls_mpi *A, const mbedtls_mpi *N,
171332b31808SJens Wiklander                         mbedtls_mpi_uint mm, mbedtls_mpi *T)
1714817466cbSJens Wiklander {
1715817466cbSJens Wiklander     mbedtls_mpi_uint z = 1;
1716817466cbSJens Wiklander     mbedtls_mpi U;
1717817466cbSJens Wiklander 
1718817466cbSJens Wiklander     U.n = U.s = (int) z;
1719817466cbSJens Wiklander     U.p = &z;
1720817466cbSJens Wiklander 
1721b0563631STom Van Eyck     mbedtls_mpi_montmul(A, &U, N, mm, T);
17227901324dSJerome Forissier }
17237901324dSJerome Forissier 
1724817466cbSJens Wiklander /*
1725*cb034002SJerome Forissier  * Warning! If the parameter E_public has MBEDTLS_MPI_IS_PUBLIC as its value,
1726*cb034002SJerome Forissier  * this function is not constant time with respect to the exponent (parameter E).
1727817466cbSJens Wiklander  */
1728*cb034002SJerome Forissier static int mbedtls_mpi_exp_mod_optionally_safe(mbedtls_mpi *X, const mbedtls_mpi *A,
1729*cb034002SJerome Forissier                                                const mbedtls_mpi *E, int E_public,
1730*cb034002SJerome Forissier                                                const mbedtls_mpi *N, mbedtls_mpi *prec_RR)
1731817466cbSJens Wiklander {
173211fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
1733817466cbSJens Wiklander 
173432b31808SJens Wiklander     if (mbedtls_mpi_cmp_int(N, 0) <= 0 || (N->p[0] & 1) == 0) {
173532b31808SJens Wiklander         return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
173632b31808SJens Wiklander     }
1737817466cbSJens Wiklander 
173832b31808SJens Wiklander     if (mbedtls_mpi_cmp_int(E, 0) < 0) {
173932b31808SJens Wiklander         return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
174032b31808SJens Wiklander     }
1741817466cbSJens Wiklander 
17427901324dSJerome Forissier     if (mbedtls_mpi_bitlen(E) > MBEDTLS_MPI_MAX_BITS ||
174332b31808SJens Wiklander         mbedtls_mpi_bitlen(N) > MBEDTLS_MPI_MAX_BITS) {
174432b31808SJens Wiklander         return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
174532b31808SJens Wiklander     }
17467901324dSJerome Forissier 
1747817466cbSJens Wiklander     /*
1748*cb034002SJerome Forissier      * Ensure that the exponent that we are passing to the core is not NULL.
1749817466cbSJens Wiklander      */
1750*cb034002SJerome Forissier     if (E->n == 0) {
1751*cb034002SJerome Forissier         ret = mbedtls_mpi_lset(X, 1);
1752*cb034002SJerome Forissier         return ret;
175332b31808SJens Wiklander     }
1754817466cbSJens Wiklander 
175532b31808SJens Wiklander     /*
1756*cb034002SJerome Forissier      * Allocate working memory for mbedtls_mpi_core_exp_mod()
175732b31808SJens Wiklander      */
1758*cb034002SJerome Forissier     size_t T_limbs = mbedtls_mpi_core_exp_mod_working_limbs(N->n, E->n);
1759*cb034002SJerome Forissier     mbedtls_mpi_uint *T = (mbedtls_mpi_uint *) mbedtls_calloc(T_limbs, sizeof(mbedtls_mpi_uint));
1760*cb034002SJerome Forissier     if (T == NULL) {
1761*cb034002SJerome Forissier         return MBEDTLS_ERR_MPI_ALLOC_FAILED;
176232b31808SJens Wiklander     }
176332b31808SJens Wiklander 
1764*cb034002SJerome Forissier     mbedtls_mpi RR;
1765*cb034002SJerome Forissier     mbedtls_mpi_init_mempool(&RR);
1766*cb034002SJerome Forissier 
176732b31808SJens Wiklander     /*
176832b31808SJens Wiklander      * If 1st call, pre-compute R^2 mod N
176932b31808SJens Wiklander      */
177032b31808SJens Wiklander     if (prec_RR == NULL || prec_RR->p == NULL) {
1771*cb034002SJerome Forissier         MBEDTLS_MPI_CHK(mbedtls_mpi_core_get_mont_r2_unsafe(&RR, N));
177232b31808SJens Wiklander 
177332b31808SJens Wiklander         if (prec_RR != NULL) {
1774*cb034002SJerome Forissier             *prec_RR = RR;
177532b31808SJens Wiklander         }
177632b31808SJens Wiklander     } else {
1777*cb034002SJerome Forissier         MBEDTLS_MPI_CHK(mbedtls_mpi_grow(prec_RR, N->n));
1778*cb034002SJerome Forissier         RR = *prec_RR;
177932b31808SJens Wiklander     }
178032b31808SJens Wiklander 
1781817466cbSJens Wiklander     /*
1782*cb034002SJerome Forissier      * To preserve constness we need to make a copy of A. Using X for this to
1783*cb034002SJerome Forissier      * save memory.
1784817466cbSJens Wiklander      */
1785*cb034002SJerome Forissier     MBEDTLS_MPI_CHK(mbedtls_mpi_copy(X, A));
1786*cb034002SJerome Forissier 
1787*cb034002SJerome Forissier     /*
1788*cb034002SJerome Forissier      * Compensate for negative A (and correct at the end).
1789*cb034002SJerome Forissier      */
1790*cb034002SJerome Forissier     X->s = 1;
1791*cb034002SJerome Forissier 
1792*cb034002SJerome Forissier     /*
1793*cb034002SJerome Forissier      * Make sure that X is in a form that is safe for consumption by
1794*cb034002SJerome Forissier      * the core functions.
1795*cb034002SJerome Forissier      *
1796*cb034002SJerome Forissier      * - The core functions will not touch the limbs of X above N->n. The
1797*cb034002SJerome Forissier      *   result will be correct if those limbs are 0, which the mod call
1798*cb034002SJerome Forissier      *   ensures.
1799*cb034002SJerome Forissier      * - Also, X must have at least as many limbs as N for the calls to the
1800*cb034002SJerome Forissier      *   core functions.
1801*cb034002SJerome Forissier      */
1802*cb034002SJerome Forissier     if (mbedtls_mpi_cmp_mpi(X, N) >= 0) {
1803*cb034002SJerome Forissier         MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(X, X, N));
1804*cb034002SJerome Forissier     }
1805*cb034002SJerome Forissier     MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, N->n));
1806*cb034002SJerome Forissier 
1807*cb034002SJerome Forissier     /*
1808*cb034002SJerome Forissier      * Convert to and from Montgomery around mbedtls_mpi_core_exp_mod().
1809*cb034002SJerome Forissier      */
1810*cb034002SJerome Forissier     {
1811*cb034002SJerome Forissier         mbedtls_mpi_uint mm = mbedtls_mpi_core_montmul_init(N->p);
1812*cb034002SJerome Forissier         mbedtls_mpi_core_to_mont_rep(X->p, X->p, N->p, N->n, mm, RR.p, T);
1813*cb034002SJerome Forissier         if (E_public == MBEDTLS_MPI_IS_PUBLIC) {
1814*cb034002SJerome Forissier             mbedtls_mpi_core_exp_mod_unsafe(X->p, X->p, N->p, N->n, E->p, E->n, RR.p, T);
181532b31808SJens Wiklander         } else {
1816*cb034002SJerome Forissier             mbedtls_mpi_core_exp_mod(X->p, X->p, N->p, N->n, E->p, E->n, RR.p, T);
181732b31808SJens Wiklander         }
1818*cb034002SJerome Forissier         mbedtls_mpi_core_from_mont_rep(X->p, X->p, N->p, N->n, mm, T);
181932b31808SJens Wiklander     }
1820817466cbSJens Wiklander 
1821817466cbSJens Wiklander     /*
1822*cb034002SJerome Forissier      * Correct for negative A.
1823817466cbSJens Wiklander      */
1824*cb034002SJerome Forissier     if (A->s == -1 && (E->p[0] & 1) != 0) {
1825*cb034002SJerome Forissier         mbedtls_ct_condition_t is_x_non_zero = mbedtls_mpi_core_check_zero_ct(X->p, X->n);
1826*cb034002SJerome Forissier         X->s = mbedtls_ct_mpi_sign_if(is_x_non_zero, -1, 1);
1827817466cbSJens Wiklander 
1828*cb034002SJerome Forissier         MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(X, N, X));
1829817466cbSJens Wiklander     }
183032b31808SJens Wiklander 
1831817466cbSJens Wiklander cleanup:
1832817466cbSJens Wiklander 
1833*cb034002SJerome Forissier     mbedtls_mpi_zeroize_and_free(T, T_limbs);
1834817466cbSJens Wiklander 
183532b31808SJens Wiklander     if (prec_RR == NULL || prec_RR->p == NULL) {
1836817466cbSJens Wiklander         mbedtls_mpi_free(&RR);
183732b31808SJens Wiklander     }
1838817466cbSJens Wiklander 
183932b31808SJens Wiklander     return ret;
1840817466cbSJens Wiklander }
1841817466cbSJens Wiklander 
1842*cb034002SJerome Forissier int mbedtls_mpi_exp_mod(mbedtls_mpi *X, const mbedtls_mpi *A,
1843*cb034002SJerome Forissier                         const mbedtls_mpi *E, const mbedtls_mpi *N,
1844*cb034002SJerome Forissier                         mbedtls_mpi *prec_RR)
1845*cb034002SJerome Forissier {
1846*cb034002SJerome Forissier #if (defined(__KERNEL__) && defined(CFG_CORE_UNSAFE_MODEXP)) || \
1847*cb034002SJerome Forissier     (!defined(__KERNEL__) && defined(CFG_TA_MEBDTLS_UNSAFE_MODEXP))
1848*cb034002SJerome Forissier     return mbedtls_mpi_exp_mod_unsafe(X, A, E, N, prec_RR);
1849*cb034002SJerome Forissier #else
1850*cb034002SJerome Forissier     return mbedtls_mpi_exp_mod_optionally_safe(X, A, E, MBEDTLS_MPI_IS_SECRET, N, prec_RR);
1851*cb034002SJerome Forissier #endif
1852*cb034002SJerome Forissier }
1853*cb034002SJerome Forissier 
1854*cb034002SJerome Forissier 
1855*cb034002SJerome Forissier /*
1856*cb034002SJerome Forissier  * Sliding-window exponentiation: X = A^E mod N  (HAC 14.85)
1857*cb034002SJerome Forissier  */
1858*cb034002SJerome Forissier int mbedtls_mpi_exp_mod_unsafe(mbedtls_mpi *X, const mbedtls_mpi *A,
1859*cb034002SJerome Forissier                                const mbedtls_mpi *E, const mbedtls_mpi *N,
1860*cb034002SJerome Forissier                                mbedtls_mpi *prec_RR)
1861*cb034002SJerome Forissier {
1862*cb034002SJerome Forissier     return mbedtls_mpi_exp_mod_optionally_safe(X, A, E, MBEDTLS_MPI_IS_PUBLIC, N, prec_RR);
1863*cb034002SJerome Forissier }
1864*cb034002SJerome Forissier 
1865817466cbSJens Wiklander /*
1866817466cbSJens Wiklander  * Greatest common divisor: G = gcd(A, B)  (HAC 14.54)
1867817466cbSJens Wiklander  */
1868817466cbSJens Wiklander int mbedtls_mpi_gcd(mbedtls_mpi *G, const mbedtls_mpi *A, const mbedtls_mpi *B)
1869817466cbSJens Wiklander {
187011fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
1871817466cbSJens Wiklander     size_t lz, lzt;
187211fa71b9SJerome Forissier     mbedtls_mpi TA, TB;
1873817466cbSJens Wiklander 
187411fa71b9SJerome Forissier     mbedtls_mpi_init_mempool(&TA); mbedtls_mpi_init_mempool(&TB);
1875817466cbSJens Wiklander 
1876817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TA, A));
1877817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TB, B));
1878817466cbSJens Wiklander 
1879817466cbSJens Wiklander     lz = mbedtls_mpi_lsb(&TA);
1880817466cbSJens Wiklander     lzt = mbedtls_mpi_lsb(&TB);
1881817466cbSJens Wiklander 
18827901324dSJerome Forissier     /* The loop below gives the correct result when A==0 but not when B==0.
18837901324dSJerome Forissier      * So have a special case for B==0. Leverage the fact that we just
18847901324dSJerome Forissier      * calculated the lsb and lsb(B)==0 iff B is odd or 0 to make the test
18857901324dSJerome Forissier      * slightly more efficient than cmp_int(). */
188632b31808SJens Wiklander     if (lzt == 0 && mbedtls_mpi_get_bit(&TB, 0) == 0) {
18877901324dSJerome Forissier         ret = mbedtls_mpi_copy(G, A);
18887901324dSJerome Forissier         goto cleanup;
18897901324dSJerome Forissier     }
18907901324dSJerome Forissier 
189132b31808SJens Wiklander     if (lzt < lz) {
1892817466cbSJens Wiklander         lz = lzt;
189332b31808SJens Wiklander     }
1894817466cbSJens Wiklander 
1895817466cbSJens Wiklander     TA.s = TB.s = 1;
1896817466cbSJens Wiklander 
18977901324dSJerome Forissier     /* We mostly follow the procedure described in HAC 14.54, but with some
18987901324dSJerome Forissier      * minor differences:
18997901324dSJerome Forissier      * - Sequences of multiplications or divisions by 2 are grouped into a
19007901324dSJerome Forissier      *   single shift operation.
19017901324dSJerome Forissier      * - The procedure in HAC assumes that 0 < TB <= TA.
19027901324dSJerome Forissier      *     - The condition TB <= TA is not actually necessary for correctness.
19037901324dSJerome Forissier      *       TA and TB have symmetric roles except for the loop termination
19047901324dSJerome Forissier      *       condition, and the shifts at the beginning of the loop body
19057901324dSJerome Forissier      *       remove any significance from the ordering of TA vs TB before
19067901324dSJerome Forissier      *       the shifts.
19077901324dSJerome Forissier      *     - If TA = 0, the loop goes through 0 iterations and the result is
19087901324dSJerome Forissier      *       correctly TB.
19097901324dSJerome Forissier      *     - The case TB = 0 was short-circuited above.
19107901324dSJerome Forissier      *
19117901324dSJerome Forissier      * For the correctness proof below, decompose the original values of
19127901324dSJerome Forissier      * A and B as
19137901324dSJerome Forissier      *   A = sa * 2^a * A' with A'=0 or A' odd, and sa = +-1
19147901324dSJerome Forissier      *   B = sb * 2^b * B' with B'=0 or B' odd, and sb = +-1
19157901324dSJerome Forissier      * Then gcd(A, B) = 2^{min(a,b)} * gcd(A',B'),
19167901324dSJerome Forissier      * and gcd(A',B') is odd or 0.
19177901324dSJerome Forissier      *
19187901324dSJerome Forissier      * At the beginning, we have TA = |A| and TB = |B| so gcd(A,B) = gcd(TA,TB).
19197901324dSJerome Forissier      * The code maintains the following invariant:
19207901324dSJerome Forissier      *     gcd(A,B) = 2^k * gcd(TA,TB) for some k   (I)
19217901324dSJerome Forissier      */
19227901324dSJerome Forissier 
19237901324dSJerome Forissier     /* Proof that the loop terminates:
19247901324dSJerome Forissier      * At each iteration, either the right-shift by 1 is made on a nonzero
19257901324dSJerome Forissier      * value and the nonnegative integer bitlen(TA) + bitlen(TB) decreases
19267901324dSJerome Forissier      * by at least 1, or the right-shift by 1 is made on zero and then
19277901324dSJerome Forissier      * TA becomes 0 which ends the loop (TB cannot be 0 if it is right-shifted
19287901324dSJerome Forissier      * since in that case TB is calculated from TB-TA with the condition TB>TA).
19297901324dSJerome Forissier      */
193032b31808SJens Wiklander     while (mbedtls_mpi_cmp_int(&TA, 0) != 0) {
19317901324dSJerome Forissier         /* Divisions by 2 preserve the invariant (I). */
1932817466cbSJens Wiklander         MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TA, mbedtls_mpi_lsb(&TA)));
1933817466cbSJens Wiklander         MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TB, mbedtls_mpi_lsb(&TB)));
1934817466cbSJens Wiklander 
19357901324dSJerome Forissier         /* Set either TA or TB to |TA-TB|/2. Since TA and TB are both odd,
19367901324dSJerome Forissier          * TA-TB is even so the division by 2 has an integer result.
19377901324dSJerome Forissier          * Invariant (I) is preserved since any odd divisor of both TA and TB
19387901324dSJerome Forissier          * also divides |TA-TB|/2, and any odd divisor of both TA and |TA-TB|/2
1939039e02dfSJerome Forissier          * also divides TB, and any odd divisor of both TB and |TA-TB|/2 also
19407901324dSJerome Forissier          * divides TA.
19417901324dSJerome Forissier          */
194232b31808SJens Wiklander         if (mbedtls_mpi_cmp_mpi(&TA, &TB) >= 0) {
1943817466cbSJens Wiklander             MBEDTLS_MPI_CHK(mbedtls_mpi_sub_abs(&TA, &TA, &TB));
1944817466cbSJens Wiklander             MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TA, 1));
194532b31808SJens Wiklander         } else {
1946817466cbSJens Wiklander             MBEDTLS_MPI_CHK(mbedtls_mpi_sub_abs(&TB, &TB, &TA));
1947817466cbSJens Wiklander             MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TB, 1));
1948817466cbSJens Wiklander         }
19497901324dSJerome Forissier         /* Note that one of TA or TB is still odd. */
1950817466cbSJens Wiklander     }
1951817466cbSJens Wiklander 
19527901324dSJerome Forissier     /* By invariant (I), gcd(A,B) = 2^k * gcd(TA,TB) for some k.
19537901324dSJerome Forissier      * At the loop exit, TA = 0, so gcd(TA,TB) = TB.
19547901324dSJerome Forissier      * - If there was at least one loop iteration, then one of TA or TB is odd,
19557901324dSJerome Forissier      *   and TA = 0, so TB is odd and gcd(TA,TB) = gcd(A',B'). In this case,
19567901324dSJerome Forissier      *   lz = min(a,b) so gcd(A,B) = 2^lz * TB.
19577901324dSJerome Forissier      * - If there was no loop iteration, then A was 0, and gcd(A,B) = B.
19587901324dSJerome Forissier      *   In this case, lz = 0 and B = TB so gcd(A,B) = B = 2^lz * TB as well.
19597901324dSJerome Forissier      */
19607901324dSJerome Forissier 
1961817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&TB, lz));
1962817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_copy(G, &TB));
1963817466cbSJens Wiklander 
1964817466cbSJens Wiklander cleanup:
1965817466cbSJens Wiklander 
196611fa71b9SJerome Forissier     mbedtls_mpi_free(&TA); mbedtls_mpi_free(&TB);
1967817466cbSJens Wiklander 
196832b31808SJens Wiklander     return ret;
19697901324dSJerome Forissier }
19707901324dSJerome Forissier 
1971817466cbSJens Wiklander /*
1972817466cbSJens Wiklander  * Fill X with size bytes of random.
197332b31808SJens Wiklander  * The bytes returned from the RNG are used in a specific order which
197432b31808SJens Wiklander  * is suitable for deterministic ECDSA (see the specification of
197532b31808SJens Wiklander  * mbedtls_mpi_random() and the implementation in mbedtls_mpi_fill_random()).
1976817466cbSJens Wiklander  */
1977817466cbSJens Wiklander int mbedtls_mpi_fill_random(mbedtls_mpi *X, size_t size,
1978817466cbSJens Wiklander                             int (*f_rng)(void *, unsigned char *, size_t),
1979817466cbSJens Wiklander                             void *p_rng)
1980817466cbSJens Wiklander {
198111fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
198232b31808SJens Wiklander     const size_t limbs = CHARS_TO_LIMBS(size);
19835b25c76aSJerome Forissier 
19845b25c76aSJerome Forissier     /* Ensure that target MPI has exactly the necessary number of limbs */
19857901324dSJerome Forissier     MBEDTLS_MPI_CHK(mbedtls_mpi_resize_clear(X, limbs));
198632b31808SJens Wiklander     if (size == 0) {
198732b31808SJens Wiklander         return 0;
198832b31808SJens Wiklander     }
1989817466cbSJens Wiklander 
199032b31808SJens Wiklander     ret = mbedtls_mpi_core_fill_random(X->p, X->n, size, f_rng, p_rng);
1991817466cbSJens Wiklander 
1992817466cbSJens Wiklander cleanup:
199332b31808SJens Wiklander     return ret;
1994817466cbSJens Wiklander }
1995817466cbSJens Wiklander 
19967901324dSJerome Forissier int mbedtls_mpi_random(mbedtls_mpi *X,
19977901324dSJerome Forissier                        mbedtls_mpi_sint min,
19987901324dSJerome Forissier                        const mbedtls_mpi *N,
19997901324dSJerome Forissier                        int (*f_rng)(void *, unsigned char *, size_t),
20007901324dSJerome Forissier                        void *p_rng)
20017901324dSJerome Forissier {
200232b31808SJens Wiklander     if (min < 0) {
200332b31808SJens Wiklander         return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
200432b31808SJens Wiklander     }
200532b31808SJens Wiklander     if (mbedtls_mpi_cmp_int(N, min) <= 0) {
200632b31808SJens Wiklander         return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
200732b31808SJens Wiklander     }
20087901324dSJerome Forissier 
20097901324dSJerome Forissier     /* Ensure that target MPI has exactly the same number of limbs
20107901324dSJerome Forissier      * as the upper bound, even if the upper bound has leading zeros.
201132b31808SJens Wiklander      * This is necessary for mbedtls_mpi_core_random. */
201232b31808SJens Wiklander     int ret = mbedtls_mpi_resize_clear(X, N->n);
201332b31808SJens Wiklander     if (ret != 0) {
201432b31808SJens Wiklander         return ret;
20157901324dSJerome Forissier     }
20167901324dSJerome Forissier 
201732b31808SJens Wiklander     return mbedtls_mpi_core_random(X->p, min, N->p, X->n, f_rng, p_rng);
20187901324dSJerome Forissier }
20197901324dSJerome Forissier 
2020817466cbSJens Wiklander /*
2021817466cbSJens Wiklander  * Modular inverse: X = A^-1 mod N  (HAC 14.61 / 14.64)
2022817466cbSJens Wiklander  */
2023817466cbSJens Wiklander int mbedtls_mpi_inv_mod(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *N)
2024817466cbSJens Wiklander {
202511fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
2026817466cbSJens Wiklander     mbedtls_mpi G, TA, TU, U1, U2, TB, TV, V1, V2;
2027817466cbSJens Wiklander 
202832b31808SJens Wiklander     if (mbedtls_mpi_cmp_int(N, 1) <= 0) {
202932b31808SJens Wiklander         return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
203032b31808SJens Wiklander     }
2031817466cbSJens Wiklander 
203298bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool(&TA); mbedtls_mpi_init_mempool(&TU);
203398bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool(&U1); mbedtls_mpi_init_mempool(&U2);
203498bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool(&G); mbedtls_mpi_init_mempool(&TB);
203598bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool(&TV); mbedtls_mpi_init_mempool(&V1);
203698bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool(&V2);
2037817466cbSJens Wiklander 
2038817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_gcd(&G, A, N));
2039817466cbSJens Wiklander 
204032b31808SJens Wiklander     if (mbedtls_mpi_cmp_int(&G, 1) != 0) {
2041817466cbSJens Wiklander         ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2042817466cbSJens Wiklander         goto cleanup;
2043817466cbSJens Wiklander     }
2044817466cbSJens Wiklander 
2045817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&TA, A, N));
2046817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TU, &TA));
2047817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TB, N));
2048817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TV, N));
2049817466cbSJens Wiklander 
2050817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&U1, 1));
2051817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&U2, 0));
2052817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&V1, 0));
2053817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&V2, 1));
2054817466cbSJens Wiklander 
205532b31808SJens Wiklander     do {
205632b31808SJens Wiklander         while ((TU.p[0] & 1) == 0) {
2057817466cbSJens Wiklander             MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TU, 1));
2058817466cbSJens Wiklander 
205932b31808SJens Wiklander             if ((U1.p[0] & 1) != 0 || (U2.p[0] & 1) != 0) {
2060817466cbSJens Wiklander                 MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&U1, &U1, &TB));
2061817466cbSJens Wiklander                 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&U2, &U2, &TA));
2062817466cbSJens Wiklander             }
2063817466cbSJens Wiklander 
2064817466cbSJens Wiklander             MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&U1, 1));
2065817466cbSJens Wiklander             MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&U2, 1));
2066817466cbSJens Wiklander         }
2067817466cbSJens Wiklander 
206832b31808SJens Wiklander         while ((TV.p[0] & 1) == 0) {
2069817466cbSJens Wiklander             MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TV, 1));
2070817466cbSJens Wiklander 
207132b31808SJens Wiklander             if ((V1.p[0] & 1) != 0 || (V2.p[0] & 1) != 0) {
2072817466cbSJens Wiklander                 MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&V1, &V1, &TB));
2073817466cbSJens Wiklander                 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&V2, &V2, &TA));
2074817466cbSJens Wiklander             }
2075817466cbSJens Wiklander 
2076817466cbSJens Wiklander             MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&V1, 1));
2077817466cbSJens Wiklander             MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&V2, 1));
2078817466cbSJens Wiklander         }
2079817466cbSJens Wiklander 
208032b31808SJens Wiklander         if (mbedtls_mpi_cmp_mpi(&TU, &TV) >= 0) {
2081817466cbSJens Wiklander             MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&TU, &TU, &TV));
2082817466cbSJens Wiklander             MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&U1, &U1, &V1));
2083817466cbSJens Wiklander             MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&U2, &U2, &V2));
208432b31808SJens Wiklander         } else {
2085817466cbSJens Wiklander             MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&TV, &TV, &TU));
2086817466cbSJens Wiklander             MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&V1, &V1, &U1));
2087817466cbSJens Wiklander             MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&V2, &V2, &U2));
2088817466cbSJens Wiklander         }
208932b31808SJens Wiklander     } while (mbedtls_mpi_cmp_int(&TU, 0) != 0);
2090817466cbSJens Wiklander 
209132b31808SJens Wiklander     while (mbedtls_mpi_cmp_int(&V1, 0) < 0) {
2092817466cbSJens Wiklander         MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&V1, &V1, N));
209332b31808SJens Wiklander     }
2094817466cbSJens Wiklander 
209532b31808SJens Wiklander     while (mbedtls_mpi_cmp_mpi(&V1, N) >= 0) {
2096817466cbSJens Wiklander         MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&V1, &V1, N));
209732b31808SJens Wiklander     }
2098817466cbSJens Wiklander 
2099817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_copy(X, &V1));
2100817466cbSJens Wiklander 
2101817466cbSJens Wiklander cleanup:
2102817466cbSJens Wiklander 
2103817466cbSJens Wiklander     mbedtls_mpi_free(&TA); mbedtls_mpi_free(&TU); mbedtls_mpi_free(&U1); mbedtls_mpi_free(&U2);
2104817466cbSJens Wiklander     mbedtls_mpi_free(&G); mbedtls_mpi_free(&TB); mbedtls_mpi_free(&TV);
2105817466cbSJens Wiklander     mbedtls_mpi_free(&V1); mbedtls_mpi_free(&V2);
2106817466cbSJens Wiklander 
210732b31808SJens Wiklander     return ret;
2108817466cbSJens Wiklander }
2109817466cbSJens Wiklander 
2110817466cbSJens Wiklander #if defined(MBEDTLS_GENPRIME)
2111817466cbSJens Wiklander 
2112b0563631STom Van Eyck /* Gaps between primes, starting at 3. https://oeis.org/A001223 */
2113b0563631STom Van Eyck static const unsigned char small_prime_gaps[] = {
2114b0563631STom Van Eyck     2, 2, 4, 2, 4, 2, 4, 6,
2115b0563631STom Van Eyck     2, 6, 4, 2, 4, 6, 6, 2,
2116b0563631STom Van Eyck     6, 4, 2, 6, 4, 6, 8, 4,
2117b0563631STom Van Eyck     2, 4, 2, 4, 14, 4, 6, 2,
2118b0563631STom Van Eyck     10, 2, 6, 6, 4, 6, 6, 2,
2119b0563631STom Van Eyck     10, 2, 4, 2, 12, 12, 4, 2,
2120b0563631STom Van Eyck     4, 6, 2, 10, 6, 6, 6, 2,
2121b0563631STom Van Eyck     6, 4, 2, 10, 14, 4, 2, 4,
2122b0563631STom Van Eyck     14, 6, 10, 2, 4, 6, 8, 6,
2123b0563631STom Van Eyck     6, 4, 6, 8, 4, 8, 10, 2,
2124b0563631STom Van Eyck     10, 2, 6, 4, 6, 8, 4, 2,
2125b0563631STom Van Eyck     4, 12, 8, 4, 8, 4, 6, 12,
2126b0563631STom Van Eyck     2, 18, 6, 10, 6, 6, 2, 6,
2127b0563631STom Van Eyck     10, 6, 6, 2, 6, 6, 4, 2,
2128b0563631STom Van Eyck     12, 10, 2, 4, 6, 6, 2, 12,
2129b0563631STom Van Eyck     4, 6, 8, 10, 8, 10, 8, 6,
2130b0563631STom Van Eyck     6, 4, 8, 6, 4, 8, 4, 14,
2131b0563631STom Van Eyck     10, 12, 2, 10, 2, 4, 2, 10,
2132b0563631STom Van Eyck     14, 4, 2, 4, 14, 4, 2, 4,
2133b0563631STom Van Eyck     20, 4, 8, 10, 8, 4, 6, 6,
2134b0563631STom Van Eyck     14, 4, 6, 6, 8, 6, /*reaches 997*/
2135b0563631STom Van Eyck     0 /* the last entry is effectively unused */
2136817466cbSJens Wiklander };
2137817466cbSJens Wiklander 
2138817466cbSJens Wiklander /*
2139817466cbSJens Wiklander  * Small divisors test (X must be positive)
2140817466cbSJens Wiklander  *
2141817466cbSJens Wiklander  * Return values:
2142817466cbSJens Wiklander  * 0: no small factor (possible prime, more tests needed)
2143817466cbSJens Wiklander  * 1: certain prime
2144817466cbSJens Wiklander  * MBEDTLS_ERR_MPI_NOT_ACCEPTABLE: certain non-prime
2145817466cbSJens Wiklander  * other negative: error
2146817466cbSJens Wiklander  */
2147817466cbSJens Wiklander static int mpi_check_small_factors(const mbedtls_mpi *X)
2148817466cbSJens Wiklander {
2149817466cbSJens Wiklander     int ret = 0;
2150817466cbSJens Wiklander     size_t i;
2151817466cbSJens Wiklander     mbedtls_mpi_uint r;
2152b0563631STom Van Eyck     unsigned p = 3; /* The first odd prime */
2153817466cbSJens Wiklander 
215432b31808SJens Wiklander     if ((X->p[0] & 1) == 0) {
215532b31808SJens Wiklander         return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
215632b31808SJens Wiklander     }
2157817466cbSJens Wiklander 
2158b0563631STom Van Eyck     for (i = 0; i < sizeof(small_prime_gaps); p += small_prime_gaps[i], i++) {
2159b0563631STom Van Eyck         MBEDTLS_MPI_CHK(mbedtls_mpi_mod_int(&r, X, p));
216032b31808SJens Wiklander         if (r == 0) {
2161b0563631STom Van Eyck             if (mbedtls_mpi_cmp_int(X, p) == 0) {
2162b0563631STom Van Eyck                 return 1;
2163b0563631STom Van Eyck             } else {
216432b31808SJens Wiklander                 return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
216532b31808SJens Wiklander             }
2166817466cbSJens Wiklander         }
2167b0563631STom Van Eyck     }
2168817466cbSJens Wiklander 
2169817466cbSJens Wiklander cleanup:
217032b31808SJens Wiklander     return ret;
2171817466cbSJens Wiklander }
2172817466cbSJens Wiklander 
2173817466cbSJens Wiklander /*
2174817466cbSJens Wiklander  * Miller-Rabin pseudo-primality test  (HAC 4.24)
2175817466cbSJens Wiklander  */
21763d3b0591SJens Wiklander static int mpi_miller_rabin(const mbedtls_mpi *X, size_t rounds,
2177817466cbSJens Wiklander                             int (*f_rng)(void *, unsigned char *, size_t),
2178817466cbSJens Wiklander                             void *p_rng)
2179817466cbSJens Wiklander {
2180817466cbSJens Wiklander     int ret, count;
21813d3b0591SJens Wiklander     size_t i, j, k, s;
2182817466cbSJens Wiklander     mbedtls_mpi W, R, T, A, RR;
2183817466cbSJens Wiklander 
218498bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool(&W); mbedtls_mpi_init_mempool(&R);
218598bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool(&T); mbedtls_mpi_init_mempool(&A);
218698bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool(&RR);
2187817466cbSJens Wiklander 
2188817466cbSJens Wiklander     /*
2189817466cbSJens Wiklander      * W = |X| - 1
2190817466cbSJens Wiklander      * R = W >> lsb( W )
2191817466cbSJens Wiklander      */
2192817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(&W, X, 1));
2193817466cbSJens Wiklander     s = mbedtls_mpi_lsb(&W);
2194817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&R, &W));
2195817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&R, s));
2196817466cbSJens Wiklander 
219732b31808SJens Wiklander     for (i = 0; i < rounds; i++) {
2198817466cbSJens Wiklander         /*
2199817466cbSJens Wiklander          * pick a random A, 1 < A < |X| - 1
2200817466cbSJens Wiklander          */
2201817466cbSJens Wiklander         count = 0;
2202817466cbSJens Wiklander         do {
2203817466cbSJens Wiklander             MBEDTLS_MPI_CHK(mbedtls_mpi_fill_random(&A, X->n * ciL, f_rng, p_rng));
2204817466cbSJens Wiklander 
2205817466cbSJens Wiklander             j = mbedtls_mpi_bitlen(&A);
2206817466cbSJens Wiklander             k = mbedtls_mpi_bitlen(&W);
2207817466cbSJens Wiklander             if (j > k) {
22083d3b0591SJens Wiklander                 A.p[A.n - 1] &= ((mbedtls_mpi_uint) 1 << (k - (A.n - 1) * biL - 1)) - 1;
2209817466cbSJens Wiklander             }
2210817466cbSJens Wiklander 
2211117cce93SJens Wiklander             if (count++ > 300) {
2212336e3299SJens Wiklander                 ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2213336e3299SJens Wiklander                 goto cleanup;
2214817466cbSJens Wiklander             }
2215817466cbSJens Wiklander 
2216817466cbSJens Wiklander         } while (mbedtls_mpi_cmp_mpi(&A, &W) >= 0 ||
2217817466cbSJens Wiklander                  mbedtls_mpi_cmp_int(&A, 1)  <= 0);
2218817466cbSJens Wiklander 
2219817466cbSJens Wiklander         /*
2220817466cbSJens Wiklander          * A = A^R mod |X|
2221817466cbSJens Wiklander          */
2222817466cbSJens Wiklander         MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&A, &A, &R, X, &RR));
2223817466cbSJens Wiklander 
2224817466cbSJens Wiklander         if (mbedtls_mpi_cmp_mpi(&A, &W) == 0 ||
222532b31808SJens Wiklander             mbedtls_mpi_cmp_int(&A,  1) == 0) {
2226817466cbSJens Wiklander             continue;
222732b31808SJens Wiklander         }
2228817466cbSJens Wiklander 
2229817466cbSJens Wiklander         j = 1;
223032b31808SJens Wiklander         while (j < s && mbedtls_mpi_cmp_mpi(&A, &W) != 0) {
2231817466cbSJens Wiklander             /*
2232817466cbSJens Wiklander              * A = A * A mod |X|
2233817466cbSJens Wiklander              */
2234817466cbSJens Wiklander             MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&T, &A, &A));
2235817466cbSJens Wiklander             MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&A, &T, X));
2236817466cbSJens Wiklander 
223732b31808SJens Wiklander             if (mbedtls_mpi_cmp_int(&A, 1) == 0) {
2238817466cbSJens Wiklander                 break;
223932b31808SJens Wiklander             }
2240817466cbSJens Wiklander 
2241817466cbSJens Wiklander             j++;
2242817466cbSJens Wiklander         }
2243817466cbSJens Wiklander 
2244817466cbSJens Wiklander         /*
2245817466cbSJens Wiklander          * not prime if A != |X| - 1 or A == 1
2246817466cbSJens Wiklander          */
2247817466cbSJens Wiklander         if (mbedtls_mpi_cmp_mpi(&A, &W) != 0 ||
224832b31808SJens Wiklander             mbedtls_mpi_cmp_int(&A,  1) == 0) {
2249817466cbSJens Wiklander             ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2250817466cbSJens Wiklander             break;
2251817466cbSJens Wiklander         }
2252817466cbSJens Wiklander     }
2253817466cbSJens Wiklander 
2254817466cbSJens Wiklander cleanup:
22553d3b0591SJens Wiklander     mbedtls_mpi_free(&W); mbedtls_mpi_free(&R);
22563d3b0591SJens Wiklander     mbedtls_mpi_free(&T); mbedtls_mpi_free(&A);
2257817466cbSJens Wiklander     mbedtls_mpi_free(&RR);
2258817466cbSJens Wiklander 
225932b31808SJens Wiklander     return ret;
2260817466cbSJens Wiklander }
2261817466cbSJens Wiklander 
2262817466cbSJens Wiklander /*
2263817466cbSJens Wiklander  * Pseudo-primality test: small factors, then Miller-Rabin
2264817466cbSJens Wiklander  */
22653d3b0591SJens Wiklander int mbedtls_mpi_is_prime_ext(const mbedtls_mpi *X, int rounds,
2266817466cbSJens Wiklander                              int (*f_rng)(void *, unsigned char *, size_t),
2267817466cbSJens Wiklander                              void *p_rng)
2268817466cbSJens Wiklander {
226911fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
2270817466cbSJens Wiklander     mbedtls_mpi XX;
2271817466cbSJens Wiklander 
2272817466cbSJens Wiklander     XX.s = 1;
2273817466cbSJens Wiklander     XX.n = X->n;
2274817466cbSJens Wiklander     XX.p = X->p;
2275817466cbSJens Wiklander 
2276817466cbSJens Wiklander     if (mbedtls_mpi_cmp_int(&XX, 0) == 0 ||
227732b31808SJens Wiklander         mbedtls_mpi_cmp_int(&XX, 1) == 0) {
227832b31808SJens Wiklander         return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2279817466cbSJens Wiklander     }
2280817466cbSJens Wiklander 
228132b31808SJens Wiklander     if (mbedtls_mpi_cmp_int(&XX, 2) == 0) {
228232b31808SJens Wiklander         return 0;
2283817466cbSJens Wiklander     }
2284817466cbSJens Wiklander 
228532b31808SJens Wiklander     if ((ret = mpi_check_small_factors(&XX)) != 0) {
228632b31808SJens Wiklander         if (ret == 1) {
228732b31808SJens Wiklander             return 0;
22883d3b0591SJens Wiklander         }
228932b31808SJens Wiklander 
229032b31808SJens Wiklander         return ret;
229132b31808SJens Wiklander     }
229232b31808SJens Wiklander 
229332b31808SJens Wiklander     return mpi_miller_rabin(&XX, rounds, f_rng, p_rng);
229432b31808SJens Wiklander }
22953d3b0591SJens Wiklander 
22963d3b0591SJens Wiklander /*
22973d3b0591SJens Wiklander  * Prime number generation
22983d3b0591SJens Wiklander  *
22993d3b0591SJens Wiklander  * To generate an RSA key in a way recommended by FIPS 186-4, both primes must
23003d3b0591SJens Wiklander  * be either 1024 bits or 1536 bits long, and flags must contain
23013d3b0591SJens Wiklander  * MBEDTLS_MPI_GEN_PRIME_FLAG_LOW_ERR.
23023d3b0591SJens Wiklander  */
23033d3b0591SJens Wiklander int mbedtls_mpi_gen_prime(mbedtls_mpi *X, size_t nbits, int flags,
23043d3b0591SJens Wiklander                           int (*f_rng)(void *, unsigned char *, size_t),
23053d3b0591SJens Wiklander                           void *p_rng)
23063d3b0591SJens Wiklander {
23073d3b0591SJens Wiklander #ifdef MBEDTLS_HAVE_INT64
23083d3b0591SJens Wiklander // ceil(2^63.5)
23093d3b0591SJens Wiklander #define CEIL_MAXUINT_DIV_SQRT2 0xb504f333f9de6485ULL
23103d3b0591SJens Wiklander #else
23113d3b0591SJens Wiklander // ceil(2^31.5)
23123d3b0591SJens Wiklander #define CEIL_MAXUINT_DIV_SQRT2 0xb504f334U
23133d3b0591SJens Wiklander #endif
23143d3b0591SJens Wiklander     int ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2315817466cbSJens Wiklander     size_t k, n;
23163d3b0591SJens Wiklander     int rounds;
2317817466cbSJens Wiklander     mbedtls_mpi_uint r;
2318817466cbSJens Wiklander     mbedtls_mpi Y;
2319817466cbSJens Wiklander 
232032b31808SJens Wiklander     if (nbits < 3 || nbits > MBEDTLS_MPI_MAX_BITS) {
232132b31808SJens Wiklander         return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
232232b31808SJens Wiklander     }
2323817466cbSJens Wiklander 
232498bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool(&Y);
2325817466cbSJens Wiklander 
2326817466cbSJens Wiklander     n = BITS_TO_LIMBS(nbits);
2327817466cbSJens Wiklander 
232832b31808SJens Wiklander     if ((flags & MBEDTLS_MPI_GEN_PRIME_FLAG_LOW_ERR) == 0) {
23293d3b0591SJens Wiklander         /*
23303d3b0591SJens Wiklander          * 2^-80 error probability, number of rounds chosen per HAC, table 4.4
23313d3b0591SJens Wiklander          */
23323d3b0591SJens Wiklander         rounds = ((nbits >= 1300) ?  2 : (nbits >=  850) ?  3 :
23333d3b0591SJens Wiklander                   (nbits >=  650) ?  4 : (nbits >=  350) ?  8 :
23343d3b0591SJens Wiklander                   (nbits >=  250) ? 12 : (nbits >=  150) ? 18 : 27);
233532b31808SJens Wiklander     } else {
23363d3b0591SJens Wiklander         /*
23373d3b0591SJens Wiklander          * 2^-100 error probability, number of rounds computed based on HAC,
23383d3b0591SJens Wiklander          * fact 4.48
23393d3b0591SJens Wiklander          */
23403d3b0591SJens Wiklander         rounds = ((nbits >= 1450) ?  4 : (nbits >=  1150) ?  5 :
23413d3b0591SJens Wiklander                   (nbits >= 1000) ?  6 : (nbits >=   850) ?  7 :
23423d3b0591SJens Wiklander                   (nbits >=  750) ?  8 : (nbits >=   500) ? 13 :
23433d3b0591SJens Wiklander                   (nbits >=  250) ? 28 : (nbits >=   150) ? 40 : 51);
23443d3b0591SJens Wiklander     }
23453d3b0591SJens Wiklander 
234632b31808SJens Wiklander     while (1) {
2347817466cbSJens Wiklander         MBEDTLS_MPI_CHK(mbedtls_mpi_fill_random(X, n * ciL, f_rng, p_rng));
23483d3b0591SJens Wiklander         /* make sure generated number is at least (nbits-1)+0.5 bits (FIPS 186-4 §B.3.3 steps 4.4, 5.5) */
234932b31808SJens Wiklander         if (X->p[n-1] < CEIL_MAXUINT_DIV_SQRT2) {
235032b31808SJens Wiklander             continue;
235132b31808SJens Wiklander         }
2352817466cbSJens Wiklander 
23533d3b0591SJens Wiklander         k = n * biL;
235432b31808SJens Wiklander         if (k > nbits) {
235532b31808SJens Wiklander             MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(X, k - nbits));
235632b31808SJens Wiklander         }
2357817466cbSJens Wiklander         X->p[0] |= 1;
2358817466cbSJens Wiklander 
235932b31808SJens Wiklander         if ((flags & MBEDTLS_MPI_GEN_PRIME_FLAG_DH) == 0) {
23603d3b0591SJens Wiklander             ret = mbedtls_mpi_is_prime_ext(X, rounds, f_rng, p_rng);
23613d3b0591SJens Wiklander 
236232b31808SJens Wiklander             if (ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE) {
2363817466cbSJens Wiklander                 goto cleanup;
2364817466cbSJens Wiklander             }
236532b31808SJens Wiklander         } else {
2366817466cbSJens Wiklander             /*
236732b31808SJens Wiklander              * A necessary condition for Y and X = 2Y + 1 to be prime
2368817466cbSJens Wiklander              * is X = 2 mod 3 (which is equivalent to Y = 2 mod 3).
2369817466cbSJens Wiklander              * Make sure it is satisfied, while keeping X = 3 mod 4
2370817466cbSJens Wiklander              */
2371817466cbSJens Wiklander 
2372817466cbSJens Wiklander             X->p[0] |= 2;
2373817466cbSJens Wiklander 
2374817466cbSJens Wiklander             MBEDTLS_MPI_CHK(mbedtls_mpi_mod_int(&r, X, 3));
237532b31808SJens Wiklander             if (r == 0) {
2376817466cbSJens Wiklander                 MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(X, X, 8));
237732b31808SJens Wiklander             } else if (r == 1) {
2378817466cbSJens Wiklander                 MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(X, X, 4));
237932b31808SJens Wiklander             }
2380817466cbSJens Wiklander 
2381817466cbSJens Wiklander             /* Set Y = (X-1) / 2, which is X / 2 because X is odd */
2382817466cbSJens Wiklander             MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&Y, X));
2383817466cbSJens Wiklander             MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&Y, 1));
2384817466cbSJens Wiklander 
238532b31808SJens Wiklander             while (1) {
2386817466cbSJens Wiklander                 /*
2387817466cbSJens Wiklander                  * First, check small factors for X and Y
2388817466cbSJens Wiklander                  * before doing Miller-Rabin on any of them
2389817466cbSJens Wiklander                  */
2390817466cbSJens Wiklander                 if ((ret = mpi_check_small_factors(X)) == 0 &&
2391817466cbSJens Wiklander                     (ret = mpi_check_small_factors(&Y)) == 0 &&
23923d3b0591SJens Wiklander                     (ret = mpi_miller_rabin(X, rounds, f_rng, p_rng))
23933d3b0591SJens Wiklander                     == 0 &&
23943d3b0591SJens Wiklander                     (ret = mpi_miller_rabin(&Y, rounds, f_rng, p_rng))
239532b31808SJens Wiklander                     == 0) {
23963d3b0591SJens Wiklander                     goto cleanup;
239732b31808SJens Wiklander                 }
2398817466cbSJens Wiklander 
239932b31808SJens Wiklander                 if (ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE) {
2400817466cbSJens Wiklander                     goto cleanup;
240132b31808SJens Wiklander                 }
2402817466cbSJens Wiklander 
2403817466cbSJens Wiklander                 /*
2404817466cbSJens Wiklander                  * Next candidates. We want to preserve Y = (X-1) / 2 and
2405817466cbSJens Wiklander                  * Y = 1 mod 2 and Y = 2 mod 3 (eq X = 3 mod 4 and X = 2 mod 3)
2406817466cbSJens Wiklander                  * so up Y by 6 and X by 12.
2407817466cbSJens Wiklander                  */
2408817466cbSJens Wiklander                 MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(X,  X, 12));
2409817466cbSJens Wiklander                 MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(&Y, &Y, 6));
2410817466cbSJens Wiklander             }
2411817466cbSJens Wiklander         }
24123d3b0591SJens Wiklander     }
2413817466cbSJens Wiklander 
2414817466cbSJens Wiklander cleanup:
2415817466cbSJens Wiklander 
2416817466cbSJens Wiklander     mbedtls_mpi_free(&Y);
2417817466cbSJens Wiklander 
241832b31808SJens Wiklander     return ret;
2419817466cbSJens Wiklander }
2420817466cbSJens Wiklander 
2421817466cbSJens Wiklander #endif /* MBEDTLS_GENPRIME */
2422817466cbSJens Wiklander 
2423817466cbSJens Wiklander #if defined(MBEDTLS_SELF_TEST)
2424817466cbSJens Wiklander 
2425817466cbSJens Wiklander #define GCD_PAIR_COUNT  3
2426817466cbSJens Wiklander 
2427817466cbSJens Wiklander static const int gcd_pairs[GCD_PAIR_COUNT][3] =
2428817466cbSJens Wiklander {
2429817466cbSJens Wiklander     { 693, 609, 21 },
2430817466cbSJens Wiklander     { 1764, 868, 28 },
2431817466cbSJens Wiklander     { 768454923, 542167814, 1 }
2432817466cbSJens Wiklander };
2433817466cbSJens Wiklander 
2434817466cbSJens Wiklander /*
2435817466cbSJens Wiklander  * Checkup routine
2436817466cbSJens Wiklander  */
2437817466cbSJens Wiklander int mbedtls_mpi_self_test(int verbose)
2438817466cbSJens Wiklander {
2439817466cbSJens Wiklander     int ret, i;
2440817466cbSJens Wiklander     mbedtls_mpi A, E, N, X, Y, U, V;
2441817466cbSJens Wiklander 
244298bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool(&A); mbedtls_mpi_init_mempool(&E);
244398bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool(&N); mbedtls_mpi_init_mempool(&X);
244498bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool(&Y); mbedtls_mpi_init_mempool(&U);
244598bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool(&V);
2446817466cbSJens Wiklander 
2447817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&A, 16,
2448817466cbSJens Wiklander                                             "EFE021C2645FD1DC586E69184AF4A31E" \
2449817466cbSJens Wiklander                                             "D5F53E93B5F123FA41680867BA110131" \
2450817466cbSJens Wiklander                                             "944FE7952E2517337780CB0DB80E61AA" \
2451817466cbSJens Wiklander                                             "E7C8DDC6C5C6AADEB34EB38A2F40D5E6"));
2452817466cbSJens Wiklander 
2453817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&E, 16,
2454817466cbSJens Wiklander                                             "B2E7EFD37075B9F03FF989C7C5051C20" \
2455817466cbSJens Wiklander                                             "34D2A323810251127E7BF8625A4F49A5" \
2456817466cbSJens Wiklander                                             "F3E27F4DA8BD59C47D6DAABA4C8127BD" \
2457817466cbSJens Wiklander                                             "5B5C25763222FEFCCFC38B832366C29E"));
2458817466cbSJens Wiklander 
2459817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&N, 16,
2460817466cbSJens Wiklander                                             "0066A198186C18C10B2F5ED9B522752A" \
2461817466cbSJens Wiklander                                             "9830B69916E535C8F047518A889A43A5" \
2462817466cbSJens Wiklander                                             "94B6BED27A168D31D4A52F88925AA8F5"));
2463817466cbSJens Wiklander 
2464817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&X, &A, &N));
2465817466cbSJens Wiklander 
2466817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&U, 16,
2467817466cbSJens Wiklander                                             "602AB7ECA597A3D6B56FF9829A5E8B85" \
2468817466cbSJens Wiklander                                             "9E857EA95A03512E2BAE7391688D264A" \
2469817466cbSJens Wiklander                                             "A5663B0341DB9CCFD2C4C5F421FEC814" \
2470817466cbSJens Wiklander                                             "8001B72E848A38CAE1C65F78E56ABDEF" \
2471817466cbSJens Wiklander                                             "E12D3C039B8A02D6BE593F0BBBDA56F1" \
2472817466cbSJens Wiklander                                             "ECF677152EF804370C1A305CAF3B5BF1" \
2473817466cbSJens Wiklander                                             "30879B56C61DE584A0F53A2447A51E"));
2474817466cbSJens Wiklander 
247532b31808SJens Wiklander     if (verbose != 0) {
2476817466cbSJens Wiklander         mbedtls_printf("  MPI test #1 (mul_mpi): ");
247732b31808SJens Wiklander     }
2478817466cbSJens Wiklander 
247932b31808SJens Wiklander     if (mbedtls_mpi_cmp_mpi(&X, &U) != 0) {
248032b31808SJens Wiklander         if (verbose != 0) {
2481817466cbSJens Wiklander             mbedtls_printf("failed\n");
248232b31808SJens Wiklander         }
2483817466cbSJens Wiklander 
2484817466cbSJens Wiklander         ret = 1;
2485817466cbSJens Wiklander         goto cleanup;
2486817466cbSJens Wiklander     }
2487817466cbSJens Wiklander 
248832b31808SJens Wiklander     if (verbose != 0) {
2489817466cbSJens Wiklander         mbedtls_printf("passed\n");
249032b31808SJens Wiklander     }
2491817466cbSJens Wiklander 
2492817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_div_mpi(&X, &Y, &A, &N));
2493817466cbSJens Wiklander 
2494817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&U, 16,
2495817466cbSJens Wiklander                                             "256567336059E52CAE22925474705F39A94"));
2496817466cbSJens Wiklander 
2497817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&V, 16,
2498817466cbSJens Wiklander                                             "6613F26162223DF488E9CD48CC132C7A" \
2499817466cbSJens Wiklander                                             "0AC93C701B001B092E4E5B9F73BCD27B" \
2500817466cbSJens Wiklander                                             "9EE50D0657C77F374E903CDFA4C642"));
2501817466cbSJens Wiklander 
250232b31808SJens Wiklander     if (verbose != 0) {
2503817466cbSJens Wiklander         mbedtls_printf("  MPI test #2 (div_mpi): ");
250432b31808SJens Wiklander     }
2505817466cbSJens Wiklander 
2506817466cbSJens Wiklander     if (mbedtls_mpi_cmp_mpi(&X, &U) != 0 ||
250732b31808SJens Wiklander         mbedtls_mpi_cmp_mpi(&Y, &V) != 0) {
250832b31808SJens Wiklander         if (verbose != 0) {
2509817466cbSJens Wiklander             mbedtls_printf("failed\n");
251032b31808SJens Wiklander         }
2511817466cbSJens Wiklander 
2512817466cbSJens Wiklander         ret = 1;
2513817466cbSJens Wiklander         goto cleanup;
2514817466cbSJens Wiklander     }
2515817466cbSJens Wiklander 
251632b31808SJens Wiklander     if (verbose != 0) {
2517817466cbSJens Wiklander         mbedtls_printf("passed\n");
251832b31808SJens Wiklander     }
2519817466cbSJens Wiklander 
2520817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&X, &A, &E, &N, NULL));
2521817466cbSJens Wiklander 
2522817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&U, 16,
2523817466cbSJens Wiklander                                             "36E139AEA55215609D2816998ED020BB" \
2524817466cbSJens Wiklander                                             "BD96C37890F65171D948E9BC7CBAA4D9" \
2525817466cbSJens Wiklander                                             "325D24D6A3C12710F10A09FA08AB87"));
2526817466cbSJens Wiklander 
252732b31808SJens Wiklander     if (verbose != 0) {
2528817466cbSJens Wiklander         mbedtls_printf("  MPI test #3 (exp_mod): ");
252932b31808SJens Wiklander     }
2530817466cbSJens Wiklander 
253132b31808SJens Wiklander     if (mbedtls_mpi_cmp_mpi(&X, &U) != 0) {
253232b31808SJens Wiklander         if (verbose != 0) {
2533817466cbSJens Wiklander             mbedtls_printf("failed\n");
253432b31808SJens Wiklander         }
2535817466cbSJens Wiklander 
2536817466cbSJens Wiklander         ret = 1;
2537817466cbSJens Wiklander         goto cleanup;
2538817466cbSJens Wiklander     }
2539817466cbSJens Wiklander 
254032b31808SJens Wiklander     if (verbose != 0) {
2541817466cbSJens Wiklander         mbedtls_printf("passed\n");
254232b31808SJens Wiklander     }
2543817466cbSJens Wiklander 
2544817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_inv_mod(&X, &A, &N));
2545817466cbSJens Wiklander 
2546817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&U, 16,
2547817466cbSJens Wiklander                                             "003A0AAEDD7E784FC07D8F9EC6E3BFD5" \
2548817466cbSJens Wiklander                                             "C3DBA76456363A10869622EAC2DD84EC" \
2549817466cbSJens Wiklander                                             "C5B8A74DAC4D09E03B5E0BE779F2DF61"));
2550817466cbSJens Wiklander 
255132b31808SJens Wiklander     if (verbose != 0) {
2552817466cbSJens Wiklander         mbedtls_printf("  MPI test #4 (inv_mod): ");
255332b31808SJens Wiklander     }
2554817466cbSJens Wiklander 
255532b31808SJens Wiklander     if (mbedtls_mpi_cmp_mpi(&X, &U) != 0) {
255632b31808SJens Wiklander         if (verbose != 0) {
2557817466cbSJens Wiklander             mbedtls_printf("failed\n");
255832b31808SJens Wiklander         }
2559817466cbSJens Wiklander 
2560817466cbSJens Wiklander         ret = 1;
2561817466cbSJens Wiklander         goto cleanup;
2562817466cbSJens Wiklander     }
2563817466cbSJens Wiklander 
256432b31808SJens Wiklander     if (verbose != 0) {
2565817466cbSJens Wiklander         mbedtls_printf("passed\n");
256632b31808SJens Wiklander     }
2567817466cbSJens Wiklander 
256832b31808SJens Wiklander     if (verbose != 0) {
2569817466cbSJens Wiklander         mbedtls_printf("  MPI test #5 (simple gcd): ");
257032b31808SJens Wiklander     }
2571817466cbSJens Wiklander 
257232b31808SJens Wiklander     for (i = 0; i < GCD_PAIR_COUNT; i++) {
2573817466cbSJens Wiklander         MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&X, gcd_pairs[i][0]));
2574817466cbSJens Wiklander         MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&Y, gcd_pairs[i][1]));
2575817466cbSJens Wiklander 
2576817466cbSJens Wiklander         MBEDTLS_MPI_CHK(mbedtls_mpi_gcd(&A, &X, &Y));
2577817466cbSJens Wiklander 
257832b31808SJens Wiklander         if (mbedtls_mpi_cmp_int(&A, gcd_pairs[i][2]) != 0) {
257932b31808SJens Wiklander             if (verbose != 0) {
2580817466cbSJens Wiklander                 mbedtls_printf("failed at %d\n", i);
258132b31808SJens Wiklander             }
2582817466cbSJens Wiklander 
2583817466cbSJens Wiklander             ret = 1;
2584817466cbSJens Wiklander             goto cleanup;
2585817466cbSJens Wiklander         }
2586817466cbSJens Wiklander     }
2587817466cbSJens Wiklander 
258832b31808SJens Wiklander     if (verbose != 0) {
2589817466cbSJens Wiklander         mbedtls_printf("passed\n");
259032b31808SJens Wiklander     }
2591817466cbSJens Wiklander 
2592817466cbSJens Wiklander cleanup:
2593817466cbSJens Wiklander 
259432b31808SJens Wiklander     if (ret != 0 && verbose != 0) {
25957901324dSJerome Forissier         mbedtls_printf("Unexpected error, return code = %08X\n", (unsigned int) ret);
259632b31808SJens Wiklander     }
2597817466cbSJens Wiklander 
2598817466cbSJens Wiklander     mbedtls_mpi_free(&A); mbedtls_mpi_free(&E); mbedtls_mpi_free(&N); mbedtls_mpi_free(&X);
2599817466cbSJens Wiklander     mbedtls_mpi_free(&Y); mbedtls_mpi_free(&U); mbedtls_mpi_free(&V);
2600817466cbSJens Wiklander 
260132b31808SJens Wiklander     if (verbose != 0) {
2602817466cbSJens Wiklander         mbedtls_printf("\n");
260332b31808SJens Wiklander     }
2604817466cbSJens Wiklander 
260532b31808SJens Wiklander     return ret;
2606817466cbSJens Wiklander }
2607817466cbSJens Wiklander 
2608817466cbSJens Wiklander #endif /* MBEDTLS_SELF_TEST */
2609817466cbSJens Wiklander 
2610817466cbSJens Wiklander #endif /* MBEDTLS_BIGNUM_C */
2611