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"
30cb034002SJerome 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 */
mbedtls_ct_mpi_sign_if(mbedtls_ct_condition_t cond,signed short sign1,signed short sign2)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 */
mbedtls_mpi_lt_mpi_ct(const mbedtls_mpi * X,const mbedtls_mpi * Y,unsigned * ret)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
mbedtls_mpi_safe_cond_assign(mbedtls_mpi * X,const mbedtls_mpi * Y,unsigned char assign)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 */
mbedtls_mpi_safe_cond_swap(mbedtls_mpi * X,mbedtls_mpi * Y,unsigned char swap)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 */
mpi_init(mbedtls_mpi * X,short use_mempool)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
mbedtls_mpi_init(mbedtls_mpi * X)19898bd5fe3SJens Wiklander void mbedtls_mpi_init(mbedtls_mpi *X)
19998bd5fe3SJens Wiklander {
2003d3b0591SJens Wiklander mpi_init(X, 0 /*use_mempool*/);
20198bd5fe3SJens Wiklander }
20298bd5fe3SJens Wiklander
mbedtls_mpi_init_mempool(mbedtls_mpi * X)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 */
mbedtls_mpi_free(mbedtls_mpi * X)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 */
mbedtls_mpi_grow(mbedtls_mpi * X,size_t nblimbs)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 */
mbedtls_mpi_shrink(mbedtls_mpi * X,size_t nblimbs)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. */
mbedtls_mpi_resize_clear(mbedtls_mpi * X,size_t limbs)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 */
mbedtls_mpi_copy(mbedtls_mpi * X,const mbedtls_mpi * Y)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 */
mbedtls_mpi_swap(mbedtls_mpi * X,mbedtls_mpi * Y)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
mpi_sint_abs(mbedtls_mpi_sint z)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 */
mbedtls_mpi_lset(mbedtls_mpi * X,mbedtls_mpi_sint z)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 */
mbedtls_mpi_get_bit(const mbedtls_mpi * X,size_t pos)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 */
mbedtls_mpi_set_bit(mbedtls_mpi * X,size_t pos,unsigned char val)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 */
mbedtls_mpi_lsb(const mbedtls_mpi * X)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 */
mbedtls_mpi_bitlen(const mbedtls_mpi * X)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 */
mbedtls_mpi_size(const mbedtls_mpi * X)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 */
mpi_get_digit(mbedtls_mpi_uint * d,int radix,char c)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 */
mbedtls_mpi_read_string(mbedtls_mpi * X,int radix,const char * s)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 */
mpi_write_hlp(mbedtls_mpi * X,int radix,char ** p,const size_t buflen)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 */
mbedtls_mpi_write_string(const mbedtls_mpi * X,int radix,char * buf,size_t buflen,size_t * olen)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 */
mbedtls_mpi_read_file(mbedtls_mpi * X,int radix,FILE * fin)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 */
mbedtls_mpi_write_file(const char * p,const mbedtls_mpi * X,int radix,FILE * fout)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 */
mbedtls_mpi_read_binary_le(mbedtls_mpi * X,const unsigned char * buf,size_t buflen)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 */
mbedtls_mpi_read_binary(mbedtls_mpi * X,const unsigned char * buf,size_t buflen)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 */
mbedtls_mpi_write_binary_le(const mbedtls_mpi * X,unsigned char * buf,size_t buflen)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 */
mbedtls_mpi_write_binary(const mbedtls_mpi * X,unsigned char * buf,size_t buflen)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 */
mbedtls_mpi_shift_l(mbedtls_mpi * X,size_t count)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 */
mbedtls_mpi_shift_r(mbedtls_mpi * X,size_t count)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 */
mbedtls_mpi_cmp_abs(const mbedtls_mpi * X,const mbedtls_mpi * Y)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 */
mbedtls_mpi_cmp_mpi(const mbedtls_mpi * X,const mbedtls_mpi * Y)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 */
mbedtls_mpi_cmp_int(const mbedtls_mpi * X,mbedtls_mpi_sint z)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 */
mbedtls_mpi_add_abs(mbedtls_mpi * X,const mbedtls_mpi * A,const mbedtls_mpi * B)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 */
mbedtls_mpi_sub_abs(mbedtls_mpi * X,const mbedtls_mpi * A,const mbedtls_mpi * B)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 */
add_sub_mpi(mbedtls_mpi * X,const mbedtls_mpi * A,const mbedtls_mpi * B,int flip_B)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 */
mbedtls_mpi_add_mpi(mbedtls_mpi * X,const mbedtls_mpi * A,const mbedtls_mpi * B)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 */
mbedtls_mpi_sub_mpi(mbedtls_mpi * X,const mbedtls_mpi * A,const mbedtls_mpi * B)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 */
mbedtls_mpi_add_int(mbedtls_mpi * X,const mbedtls_mpi * A,mbedtls_mpi_sint b)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 */
mbedtls_mpi_sub_int(mbedtls_mpi * X,const mbedtls_mpi * A,mbedtls_mpi_sint b)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 */
mbedtls_mpi_mul_mpi(mbedtls_mpi * X,const mbedtls_mpi * A,const mbedtls_mpi * B)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 */
mbedtls_mpi_mul_int(mbedtls_mpi * X,const mbedtls_mpi * A,mbedtls_mpi_uint b)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 */
mbedtls_int_div_int(mbedtls_mpi_uint u1,mbedtls_mpi_uint u0,mbedtls_mpi_uint d,mbedtls_mpi_uint * r)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 */
mbedtls_mpi_div_mpi(mbedtls_mpi * Q,mbedtls_mpi * R,const mbedtls_mpi * A,const mbedtls_mpi * B)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 */
mbedtls_mpi_div_int(mbedtls_mpi * Q,mbedtls_mpi * R,const mbedtls_mpi * A,mbedtls_mpi_sint b)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 */
mbedtls_mpi_mod_mpi(mbedtls_mpi * R,const mbedtls_mpi * A,const mbedtls_mpi * B)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 */
mbedtls_mpi_mod_int(mbedtls_mpi_uint * r,const mbedtls_mpi * A,mbedtls_mpi_sint b)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 */
mbedtls_mpi_montg_init(mbedtls_mpi_uint * mm,const mbedtls_mpi * N)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 */
mbedtls_mpi_montmul(mbedtls_mpi * A,const mbedtls_mpi * B,const mbedtls_mpi * N,mbedtls_mpi_uint mm,mbedtls_mpi * T)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 */
mbedtls_mpi_montred(mbedtls_mpi * A,const mbedtls_mpi * N,mbedtls_mpi_uint mm,mbedtls_mpi * T)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 /*
1725cb034002SJerome Forissier * Warning! If the parameter E_public has MBEDTLS_MPI_IS_PUBLIC as its value,
1726cb034002SJerome Forissier * this function is not constant time with respect to the exponent (parameter E).
1727817466cbSJens Wiklander */
mbedtls_mpi_exp_mod_optionally_safe(mbedtls_mpi * X,const mbedtls_mpi * A,const mbedtls_mpi * E,int E_public,const mbedtls_mpi * N,mbedtls_mpi * prec_RR)1728cb034002SJerome Forissier static int mbedtls_mpi_exp_mod_optionally_safe(mbedtls_mpi *X, const mbedtls_mpi *A,
1729cb034002SJerome Forissier const mbedtls_mpi *E, int E_public,
1730cb034002SJerome 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 /*
1748cb034002SJerome Forissier * Ensure that the exponent that we are passing to the core is not NULL.
1749817466cbSJens Wiklander */
1750cb034002SJerome Forissier if (E->n == 0) {
1751cb034002SJerome Forissier ret = mbedtls_mpi_lset(X, 1);
1752cb034002SJerome Forissier return ret;
175332b31808SJens Wiklander }
1754817466cbSJens Wiklander
175532b31808SJens Wiklander /*
1756cb034002SJerome Forissier * Allocate working memory for mbedtls_mpi_core_exp_mod()
175732b31808SJens Wiklander */
1758cb034002SJerome Forissier size_t T_limbs = mbedtls_mpi_core_exp_mod_working_limbs(N->n, E->n);
17595c603566SJens Wiklander mbedtls_mpi_uint *T = mempool_calloc(mbedtls_mpi_mempool, T_limbs,
17605c603566SJens Wiklander sizeof(mbedtls_mpi_uint));
1761cb034002SJerome Forissier if (T == NULL) {
1762cb034002SJerome Forissier return MBEDTLS_ERR_MPI_ALLOC_FAILED;
176332b31808SJens Wiklander }
176432b31808SJens Wiklander
1765cb034002SJerome Forissier mbedtls_mpi RR;
1766cb034002SJerome Forissier mbedtls_mpi_init_mempool(&RR);
1767cb034002SJerome Forissier
176832b31808SJens Wiklander /*
176932b31808SJens Wiklander * If 1st call, pre-compute R^2 mod N
177032b31808SJens Wiklander */
177132b31808SJens Wiklander if (prec_RR == NULL || prec_RR->p == NULL) {
1772cb034002SJerome Forissier MBEDTLS_MPI_CHK(mbedtls_mpi_core_get_mont_r2_unsafe(&RR, N));
177332b31808SJens Wiklander
177432b31808SJens Wiklander if (prec_RR != NULL) {
1775cb034002SJerome Forissier *prec_RR = RR;
177632b31808SJens Wiklander }
177732b31808SJens Wiklander } else {
1778cb034002SJerome Forissier MBEDTLS_MPI_CHK(mbedtls_mpi_grow(prec_RR, N->n));
1779cb034002SJerome Forissier RR = *prec_RR;
178032b31808SJens Wiklander }
178132b31808SJens Wiklander
1782817466cbSJens Wiklander /*
1783cb034002SJerome Forissier * To preserve constness we need to make a copy of A. Using X for this to
1784cb034002SJerome Forissier * save memory.
1785817466cbSJens Wiklander */
1786cb034002SJerome Forissier MBEDTLS_MPI_CHK(mbedtls_mpi_copy(X, A));
1787cb034002SJerome Forissier
1788cb034002SJerome Forissier /*
1789cb034002SJerome Forissier * Compensate for negative A (and correct at the end).
1790cb034002SJerome Forissier */
1791cb034002SJerome Forissier X->s = 1;
1792cb034002SJerome Forissier
1793cb034002SJerome Forissier /*
1794cb034002SJerome Forissier * Make sure that X is in a form that is safe for consumption by
1795cb034002SJerome Forissier * the core functions.
1796cb034002SJerome Forissier *
1797cb034002SJerome Forissier * - The core functions will not touch the limbs of X above N->n. The
1798cb034002SJerome Forissier * result will be correct if those limbs are 0, which the mod call
1799cb034002SJerome Forissier * ensures.
1800cb034002SJerome Forissier * - Also, X must have at least as many limbs as N for the calls to the
1801cb034002SJerome Forissier * core functions.
1802cb034002SJerome Forissier */
1803cb034002SJerome Forissier if (mbedtls_mpi_cmp_mpi(X, N) >= 0) {
1804cb034002SJerome Forissier MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(X, X, N));
1805cb034002SJerome Forissier }
1806cb034002SJerome Forissier MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, N->n));
1807cb034002SJerome Forissier
1808cb034002SJerome Forissier /*
1809cb034002SJerome Forissier * Convert to and from Montgomery around mbedtls_mpi_core_exp_mod().
1810cb034002SJerome Forissier */
1811cb034002SJerome Forissier {
1812cb034002SJerome Forissier mbedtls_mpi_uint mm = mbedtls_mpi_core_montmul_init(N->p);
1813cb034002SJerome Forissier mbedtls_mpi_core_to_mont_rep(X->p, X->p, N->p, N->n, mm, RR.p, T);
1814cb034002SJerome Forissier if (E_public == MBEDTLS_MPI_IS_PUBLIC) {
1815cb034002SJerome Forissier mbedtls_mpi_core_exp_mod_unsafe(X->p, X->p, N->p, N->n, E->p, E->n, RR.p, T);
181632b31808SJens Wiklander } else {
1817cb034002SJerome Forissier mbedtls_mpi_core_exp_mod(X->p, X->p, N->p, N->n, E->p, E->n, RR.p, T);
181832b31808SJens Wiklander }
1819cb034002SJerome Forissier mbedtls_mpi_core_from_mont_rep(X->p, X->p, N->p, N->n, mm, T);
182032b31808SJens Wiklander }
1821817466cbSJens Wiklander
1822817466cbSJens Wiklander /*
1823cb034002SJerome Forissier * Correct for negative A.
1824817466cbSJens Wiklander */
1825cb034002SJerome Forissier if (A->s == -1 && (E->p[0] & 1) != 0) {
1826cb034002SJerome Forissier mbedtls_ct_condition_t is_x_non_zero = mbedtls_mpi_core_check_zero_ct(X->p, X->n);
1827cb034002SJerome Forissier X->s = mbedtls_ct_mpi_sign_if(is_x_non_zero, -1, 1);
1828817466cbSJens Wiklander
1829cb034002SJerome Forissier MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(X, N, X));
1830817466cbSJens Wiklander }
183132b31808SJens Wiklander
1832817466cbSJens Wiklander cleanup:
1833817466cbSJens Wiklander
18345c603566SJens Wiklander mbedtls_mpi_zeroize(T, T_limbs);
18355c603566SJens Wiklander mempool_free(mbedtls_mpi_mempool, T);
1836817466cbSJens Wiklander
183732b31808SJens Wiklander if (prec_RR == NULL || prec_RR->p == NULL) {
1838817466cbSJens Wiklander mbedtls_mpi_free(&RR);
183932b31808SJens Wiklander }
1840817466cbSJens Wiklander
184132b31808SJens Wiklander return ret;
1842817466cbSJens Wiklander }
1843817466cbSJens Wiklander
mbedtls_mpi_exp_mod(mbedtls_mpi * X,const mbedtls_mpi * A,const mbedtls_mpi * E,const mbedtls_mpi * N,mbedtls_mpi * prec_RR)1844cb034002SJerome Forissier int mbedtls_mpi_exp_mod(mbedtls_mpi *X, const mbedtls_mpi *A,
1845cb034002SJerome Forissier const mbedtls_mpi *E, const mbedtls_mpi *N,
1846cb034002SJerome Forissier mbedtls_mpi *prec_RR)
1847cb034002SJerome Forissier {
1848cb034002SJerome Forissier #if (defined(__KERNEL__) && defined(CFG_CORE_UNSAFE_MODEXP)) || \
1849*e1abe7d1SAlvin Chang (!defined(__KERNEL__) && defined(CFG_TA_MBEDTLS_UNSAFE_MODEXP))
1850cb034002SJerome Forissier return mbedtls_mpi_exp_mod_unsafe(X, A, E, N, prec_RR);
1851cb034002SJerome Forissier #else
1852cb034002SJerome Forissier return mbedtls_mpi_exp_mod_optionally_safe(X, A, E, MBEDTLS_MPI_IS_SECRET, N, prec_RR);
1853cb034002SJerome Forissier #endif
1854cb034002SJerome Forissier }
1855cb034002SJerome Forissier
1856cb034002SJerome Forissier
1857cb034002SJerome Forissier /*
1858cb034002SJerome Forissier * Sliding-window exponentiation: X = A^E mod N (HAC 14.85)
1859cb034002SJerome Forissier */
mbedtls_mpi_exp_mod_unsafe(mbedtls_mpi * X,const mbedtls_mpi * A,const mbedtls_mpi * E,const mbedtls_mpi * N,mbedtls_mpi * prec_RR)1860cb034002SJerome Forissier int mbedtls_mpi_exp_mod_unsafe(mbedtls_mpi *X, const mbedtls_mpi *A,
1861cb034002SJerome Forissier const mbedtls_mpi *E, const mbedtls_mpi *N,
1862cb034002SJerome Forissier mbedtls_mpi *prec_RR)
1863cb034002SJerome Forissier {
1864cb034002SJerome Forissier return mbedtls_mpi_exp_mod_optionally_safe(X, A, E, MBEDTLS_MPI_IS_PUBLIC, N, prec_RR);
1865cb034002SJerome Forissier }
1866cb034002SJerome Forissier
1867817466cbSJens Wiklander /*
1868817466cbSJens Wiklander * Greatest common divisor: G = gcd(A, B) (HAC 14.54)
1869817466cbSJens Wiklander */
mbedtls_mpi_gcd(mbedtls_mpi * G,const mbedtls_mpi * A,const mbedtls_mpi * B)1870817466cbSJens Wiklander int mbedtls_mpi_gcd(mbedtls_mpi *G, const mbedtls_mpi *A, const mbedtls_mpi *B)
1871817466cbSJens Wiklander {
187211fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
1873817466cbSJens Wiklander size_t lz, lzt;
187411fa71b9SJerome Forissier mbedtls_mpi TA, TB;
1875817466cbSJens Wiklander
187611fa71b9SJerome Forissier mbedtls_mpi_init_mempool(&TA); mbedtls_mpi_init_mempool(&TB);
1877817466cbSJens Wiklander
1878817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TA, A));
1879817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TB, B));
1880817466cbSJens Wiklander
1881817466cbSJens Wiklander lz = mbedtls_mpi_lsb(&TA);
1882817466cbSJens Wiklander lzt = mbedtls_mpi_lsb(&TB);
1883817466cbSJens Wiklander
18847901324dSJerome Forissier /* The loop below gives the correct result when A==0 but not when B==0.
18857901324dSJerome Forissier * So have a special case for B==0. Leverage the fact that we just
18867901324dSJerome Forissier * calculated the lsb and lsb(B)==0 iff B is odd or 0 to make the test
18877901324dSJerome Forissier * slightly more efficient than cmp_int(). */
188832b31808SJens Wiklander if (lzt == 0 && mbedtls_mpi_get_bit(&TB, 0) == 0) {
18897901324dSJerome Forissier ret = mbedtls_mpi_copy(G, A);
18907901324dSJerome Forissier goto cleanup;
18917901324dSJerome Forissier }
18927901324dSJerome Forissier
189332b31808SJens Wiklander if (lzt < lz) {
1894817466cbSJens Wiklander lz = lzt;
189532b31808SJens Wiklander }
1896817466cbSJens Wiklander
1897817466cbSJens Wiklander TA.s = TB.s = 1;
1898817466cbSJens Wiklander
18997901324dSJerome Forissier /* We mostly follow the procedure described in HAC 14.54, but with some
19007901324dSJerome Forissier * minor differences:
19017901324dSJerome Forissier * - Sequences of multiplications or divisions by 2 are grouped into a
19027901324dSJerome Forissier * single shift operation.
19037901324dSJerome Forissier * - The procedure in HAC assumes that 0 < TB <= TA.
19047901324dSJerome Forissier * - The condition TB <= TA is not actually necessary for correctness.
19057901324dSJerome Forissier * TA and TB have symmetric roles except for the loop termination
19067901324dSJerome Forissier * condition, and the shifts at the beginning of the loop body
19077901324dSJerome Forissier * remove any significance from the ordering of TA vs TB before
19087901324dSJerome Forissier * the shifts.
19097901324dSJerome Forissier * - If TA = 0, the loop goes through 0 iterations and the result is
19107901324dSJerome Forissier * correctly TB.
19117901324dSJerome Forissier * - The case TB = 0 was short-circuited above.
19127901324dSJerome Forissier *
19137901324dSJerome Forissier * For the correctness proof below, decompose the original values of
19147901324dSJerome Forissier * A and B as
19157901324dSJerome Forissier * A = sa * 2^a * A' with A'=0 or A' odd, and sa = +-1
19167901324dSJerome Forissier * B = sb * 2^b * B' with B'=0 or B' odd, and sb = +-1
19177901324dSJerome Forissier * Then gcd(A, B) = 2^{min(a,b)} * gcd(A',B'),
19187901324dSJerome Forissier * and gcd(A',B') is odd or 0.
19197901324dSJerome Forissier *
19207901324dSJerome Forissier * At the beginning, we have TA = |A| and TB = |B| so gcd(A,B) = gcd(TA,TB).
19217901324dSJerome Forissier * The code maintains the following invariant:
19227901324dSJerome Forissier * gcd(A,B) = 2^k * gcd(TA,TB) for some k (I)
19237901324dSJerome Forissier */
19247901324dSJerome Forissier
19257901324dSJerome Forissier /* Proof that the loop terminates:
19267901324dSJerome Forissier * At each iteration, either the right-shift by 1 is made on a nonzero
19277901324dSJerome Forissier * value and the nonnegative integer bitlen(TA) + bitlen(TB) decreases
19287901324dSJerome Forissier * by at least 1, or the right-shift by 1 is made on zero and then
19297901324dSJerome Forissier * TA becomes 0 which ends the loop (TB cannot be 0 if it is right-shifted
19307901324dSJerome Forissier * since in that case TB is calculated from TB-TA with the condition TB>TA).
19317901324dSJerome Forissier */
193232b31808SJens Wiklander while (mbedtls_mpi_cmp_int(&TA, 0) != 0) {
19337901324dSJerome Forissier /* Divisions by 2 preserve the invariant (I). */
1934817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TA, mbedtls_mpi_lsb(&TA)));
1935817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TB, mbedtls_mpi_lsb(&TB)));
1936817466cbSJens Wiklander
19377901324dSJerome Forissier /* Set either TA or TB to |TA-TB|/2. Since TA and TB are both odd,
19387901324dSJerome Forissier * TA-TB is even so the division by 2 has an integer result.
19397901324dSJerome Forissier * Invariant (I) is preserved since any odd divisor of both TA and TB
19407901324dSJerome Forissier * also divides |TA-TB|/2, and any odd divisor of both TA and |TA-TB|/2
1941039e02dfSJerome Forissier * also divides TB, and any odd divisor of both TB and |TA-TB|/2 also
19427901324dSJerome Forissier * divides TA.
19437901324dSJerome Forissier */
194432b31808SJens Wiklander if (mbedtls_mpi_cmp_mpi(&TA, &TB) >= 0) {
1945817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_sub_abs(&TA, &TA, &TB));
1946817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TA, 1));
194732b31808SJens Wiklander } else {
1948817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_sub_abs(&TB, &TB, &TA));
1949817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TB, 1));
1950817466cbSJens Wiklander }
19517901324dSJerome Forissier /* Note that one of TA or TB is still odd. */
1952817466cbSJens Wiklander }
1953817466cbSJens Wiklander
19547901324dSJerome Forissier /* By invariant (I), gcd(A,B) = 2^k * gcd(TA,TB) for some k.
19557901324dSJerome Forissier * At the loop exit, TA = 0, so gcd(TA,TB) = TB.
19567901324dSJerome Forissier * - If there was at least one loop iteration, then one of TA or TB is odd,
19577901324dSJerome Forissier * and TA = 0, so TB is odd and gcd(TA,TB) = gcd(A',B'). In this case,
19587901324dSJerome Forissier * lz = min(a,b) so gcd(A,B) = 2^lz * TB.
19597901324dSJerome Forissier * - If there was no loop iteration, then A was 0, and gcd(A,B) = B.
19607901324dSJerome Forissier * In this case, lz = 0 and B = TB so gcd(A,B) = B = 2^lz * TB as well.
19617901324dSJerome Forissier */
19627901324dSJerome Forissier
1963817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&TB, lz));
1964817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_copy(G, &TB));
1965817466cbSJens Wiklander
1966817466cbSJens Wiklander cleanup:
1967817466cbSJens Wiklander
196811fa71b9SJerome Forissier mbedtls_mpi_free(&TA); mbedtls_mpi_free(&TB);
1969817466cbSJens Wiklander
197032b31808SJens Wiklander return ret;
19717901324dSJerome Forissier }
19727901324dSJerome Forissier
1973817466cbSJens Wiklander /*
1974817466cbSJens Wiklander * Fill X with size bytes of random.
197532b31808SJens Wiklander * The bytes returned from the RNG are used in a specific order which
197632b31808SJens Wiklander * is suitable for deterministic ECDSA (see the specification of
197732b31808SJens Wiklander * mbedtls_mpi_random() and the implementation in mbedtls_mpi_fill_random()).
1978817466cbSJens Wiklander */
mbedtls_mpi_fill_random(mbedtls_mpi * X,size_t size,int (* f_rng)(void *,unsigned char *,size_t),void * p_rng)1979817466cbSJens Wiklander int mbedtls_mpi_fill_random(mbedtls_mpi *X, size_t size,
1980817466cbSJens Wiklander int (*f_rng)(void *, unsigned char *, size_t),
1981817466cbSJens Wiklander void *p_rng)
1982817466cbSJens Wiklander {
198311fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
198432b31808SJens Wiklander const size_t limbs = CHARS_TO_LIMBS(size);
19855b25c76aSJerome Forissier
19865b25c76aSJerome Forissier /* Ensure that target MPI has exactly the necessary number of limbs */
19877901324dSJerome Forissier MBEDTLS_MPI_CHK(mbedtls_mpi_resize_clear(X, limbs));
198832b31808SJens Wiklander if (size == 0) {
198932b31808SJens Wiklander return 0;
199032b31808SJens Wiklander }
1991817466cbSJens Wiklander
199232b31808SJens Wiklander ret = mbedtls_mpi_core_fill_random(X->p, X->n, size, f_rng, p_rng);
1993817466cbSJens Wiklander
1994817466cbSJens Wiklander cleanup:
199532b31808SJens Wiklander return ret;
1996817466cbSJens Wiklander }
1997817466cbSJens Wiklander
mbedtls_mpi_random(mbedtls_mpi * X,mbedtls_mpi_sint min,const mbedtls_mpi * N,int (* f_rng)(void *,unsigned char *,size_t),void * p_rng)19987901324dSJerome Forissier int mbedtls_mpi_random(mbedtls_mpi *X,
19997901324dSJerome Forissier mbedtls_mpi_sint min,
20007901324dSJerome Forissier const mbedtls_mpi *N,
20017901324dSJerome Forissier int (*f_rng)(void *, unsigned char *, size_t),
20027901324dSJerome Forissier void *p_rng)
20037901324dSJerome Forissier {
200432b31808SJens Wiklander if (min < 0) {
200532b31808SJens Wiklander return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
200632b31808SJens Wiklander }
200732b31808SJens Wiklander if (mbedtls_mpi_cmp_int(N, min) <= 0) {
200832b31808SJens Wiklander return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
200932b31808SJens Wiklander }
20107901324dSJerome Forissier
20117901324dSJerome Forissier /* Ensure that target MPI has exactly the same number of limbs
20127901324dSJerome Forissier * as the upper bound, even if the upper bound has leading zeros.
201332b31808SJens Wiklander * This is necessary for mbedtls_mpi_core_random. */
201432b31808SJens Wiklander int ret = mbedtls_mpi_resize_clear(X, N->n);
201532b31808SJens Wiklander if (ret != 0) {
201632b31808SJens Wiklander return ret;
20177901324dSJerome Forissier }
20187901324dSJerome Forissier
201932b31808SJens Wiklander return mbedtls_mpi_core_random(X->p, min, N->p, X->n, f_rng, p_rng);
20207901324dSJerome Forissier }
20217901324dSJerome Forissier
2022817466cbSJens Wiklander /*
2023817466cbSJens Wiklander * Modular inverse: X = A^-1 mod N (HAC 14.61 / 14.64)
2024817466cbSJens Wiklander */
mbedtls_mpi_inv_mod(mbedtls_mpi * X,const mbedtls_mpi * A,const mbedtls_mpi * N)2025817466cbSJens Wiklander int mbedtls_mpi_inv_mod(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *N)
2026817466cbSJens Wiklander {
202711fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
2028817466cbSJens Wiklander mbedtls_mpi G, TA, TU, U1, U2, TB, TV, V1, V2;
2029817466cbSJens Wiklander
203032b31808SJens Wiklander if (mbedtls_mpi_cmp_int(N, 1) <= 0) {
203132b31808SJens Wiklander return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
203232b31808SJens Wiklander }
2033817466cbSJens Wiklander
203498bd5fe3SJens Wiklander mbedtls_mpi_init_mempool(&TA); mbedtls_mpi_init_mempool(&TU);
203598bd5fe3SJens Wiklander mbedtls_mpi_init_mempool(&U1); mbedtls_mpi_init_mempool(&U2);
203698bd5fe3SJens Wiklander mbedtls_mpi_init_mempool(&G); mbedtls_mpi_init_mempool(&TB);
203798bd5fe3SJens Wiklander mbedtls_mpi_init_mempool(&TV); mbedtls_mpi_init_mempool(&V1);
203898bd5fe3SJens Wiklander mbedtls_mpi_init_mempool(&V2);
2039817466cbSJens Wiklander
2040817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_gcd(&G, A, N));
2041817466cbSJens Wiklander
204232b31808SJens Wiklander if (mbedtls_mpi_cmp_int(&G, 1) != 0) {
2043817466cbSJens Wiklander ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2044817466cbSJens Wiklander goto cleanup;
2045817466cbSJens Wiklander }
2046817466cbSJens Wiklander
2047817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&TA, A, N));
2048817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TU, &TA));
2049817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TB, N));
2050817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TV, N));
2051817466cbSJens Wiklander
2052817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&U1, 1));
2053817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&U2, 0));
2054817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&V1, 0));
2055817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&V2, 1));
2056817466cbSJens Wiklander
205732b31808SJens Wiklander do {
205832b31808SJens Wiklander while ((TU.p[0] & 1) == 0) {
2059817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TU, 1));
2060817466cbSJens Wiklander
206132b31808SJens Wiklander if ((U1.p[0] & 1) != 0 || (U2.p[0] & 1) != 0) {
2062817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&U1, &U1, &TB));
2063817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&U2, &U2, &TA));
2064817466cbSJens Wiklander }
2065817466cbSJens Wiklander
2066817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&U1, 1));
2067817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&U2, 1));
2068817466cbSJens Wiklander }
2069817466cbSJens Wiklander
207032b31808SJens Wiklander while ((TV.p[0] & 1) == 0) {
2071817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TV, 1));
2072817466cbSJens Wiklander
207332b31808SJens Wiklander if ((V1.p[0] & 1) != 0 || (V2.p[0] & 1) != 0) {
2074817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&V1, &V1, &TB));
2075817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&V2, &V2, &TA));
2076817466cbSJens Wiklander }
2077817466cbSJens Wiklander
2078817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&V1, 1));
2079817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&V2, 1));
2080817466cbSJens Wiklander }
2081817466cbSJens Wiklander
208232b31808SJens Wiklander if (mbedtls_mpi_cmp_mpi(&TU, &TV) >= 0) {
2083817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&TU, &TU, &TV));
2084817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&U1, &U1, &V1));
2085817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&U2, &U2, &V2));
208632b31808SJens Wiklander } else {
2087817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&TV, &TV, &TU));
2088817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&V1, &V1, &U1));
2089817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&V2, &V2, &U2));
2090817466cbSJens Wiklander }
209132b31808SJens Wiklander } while (mbedtls_mpi_cmp_int(&TU, 0) != 0);
2092817466cbSJens Wiklander
209332b31808SJens Wiklander while (mbedtls_mpi_cmp_int(&V1, 0) < 0) {
2094817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&V1, &V1, N));
209532b31808SJens Wiklander }
2096817466cbSJens Wiklander
209732b31808SJens Wiklander while (mbedtls_mpi_cmp_mpi(&V1, N) >= 0) {
2098817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&V1, &V1, N));
209932b31808SJens Wiklander }
2100817466cbSJens Wiklander
2101817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_copy(X, &V1));
2102817466cbSJens Wiklander
2103817466cbSJens Wiklander cleanup:
2104817466cbSJens Wiklander
2105817466cbSJens Wiklander mbedtls_mpi_free(&TA); mbedtls_mpi_free(&TU); mbedtls_mpi_free(&U1); mbedtls_mpi_free(&U2);
2106817466cbSJens Wiklander mbedtls_mpi_free(&G); mbedtls_mpi_free(&TB); mbedtls_mpi_free(&TV);
2107817466cbSJens Wiklander mbedtls_mpi_free(&V1); mbedtls_mpi_free(&V2);
2108817466cbSJens Wiklander
210932b31808SJens Wiklander return ret;
2110817466cbSJens Wiklander }
2111817466cbSJens Wiklander
2112817466cbSJens Wiklander #if defined(MBEDTLS_GENPRIME)
2113817466cbSJens Wiklander
2114b0563631STom Van Eyck /* Gaps between primes, starting at 3. https://oeis.org/A001223 */
2115b0563631STom Van Eyck static const unsigned char small_prime_gaps[] = {
2116b0563631STom Van Eyck 2, 2, 4, 2, 4, 2, 4, 6,
2117b0563631STom Van Eyck 2, 6, 4, 2, 4, 6, 6, 2,
2118b0563631STom Van Eyck 6, 4, 2, 6, 4, 6, 8, 4,
2119b0563631STom Van Eyck 2, 4, 2, 4, 14, 4, 6, 2,
2120b0563631STom Van Eyck 10, 2, 6, 6, 4, 6, 6, 2,
2121b0563631STom Van Eyck 10, 2, 4, 2, 12, 12, 4, 2,
2122b0563631STom Van Eyck 4, 6, 2, 10, 6, 6, 6, 2,
2123b0563631STom Van Eyck 6, 4, 2, 10, 14, 4, 2, 4,
2124b0563631STom Van Eyck 14, 6, 10, 2, 4, 6, 8, 6,
2125b0563631STom Van Eyck 6, 4, 6, 8, 4, 8, 10, 2,
2126b0563631STom Van Eyck 10, 2, 6, 4, 6, 8, 4, 2,
2127b0563631STom Van Eyck 4, 12, 8, 4, 8, 4, 6, 12,
2128b0563631STom Van Eyck 2, 18, 6, 10, 6, 6, 2, 6,
2129b0563631STom Van Eyck 10, 6, 6, 2, 6, 6, 4, 2,
2130b0563631STom Van Eyck 12, 10, 2, 4, 6, 6, 2, 12,
2131b0563631STom Van Eyck 4, 6, 8, 10, 8, 10, 8, 6,
2132b0563631STom Van Eyck 6, 4, 8, 6, 4, 8, 4, 14,
2133b0563631STom Van Eyck 10, 12, 2, 10, 2, 4, 2, 10,
2134b0563631STom Van Eyck 14, 4, 2, 4, 14, 4, 2, 4,
2135b0563631STom Van Eyck 20, 4, 8, 10, 8, 4, 6, 6,
2136b0563631STom Van Eyck 14, 4, 6, 6, 8, 6, /*reaches 997*/
2137b0563631STom Van Eyck 0 /* the last entry is effectively unused */
2138817466cbSJens Wiklander };
2139817466cbSJens Wiklander
2140817466cbSJens Wiklander /*
2141817466cbSJens Wiklander * Small divisors test (X must be positive)
2142817466cbSJens Wiklander *
2143817466cbSJens Wiklander * Return values:
2144817466cbSJens Wiklander * 0: no small factor (possible prime, more tests needed)
2145817466cbSJens Wiklander * 1: certain prime
2146817466cbSJens Wiklander * MBEDTLS_ERR_MPI_NOT_ACCEPTABLE: certain non-prime
2147817466cbSJens Wiklander * other negative: error
2148817466cbSJens Wiklander */
mpi_check_small_factors(const mbedtls_mpi * X)2149817466cbSJens Wiklander static int mpi_check_small_factors(const mbedtls_mpi *X)
2150817466cbSJens Wiklander {
2151817466cbSJens Wiklander int ret = 0;
2152817466cbSJens Wiklander size_t i;
2153817466cbSJens Wiklander mbedtls_mpi_uint r;
2154b0563631STom Van Eyck unsigned p = 3; /* The first odd prime */
2155817466cbSJens Wiklander
215632b31808SJens Wiklander if ((X->p[0] & 1) == 0) {
215732b31808SJens Wiklander return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
215832b31808SJens Wiklander }
2159817466cbSJens Wiklander
2160b0563631STom Van Eyck for (i = 0; i < sizeof(small_prime_gaps); p += small_prime_gaps[i], i++) {
2161b0563631STom Van Eyck MBEDTLS_MPI_CHK(mbedtls_mpi_mod_int(&r, X, p));
216232b31808SJens Wiklander if (r == 0) {
2163b0563631STom Van Eyck if (mbedtls_mpi_cmp_int(X, p) == 0) {
2164b0563631STom Van Eyck return 1;
2165b0563631STom Van Eyck } else {
216632b31808SJens Wiklander return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
216732b31808SJens Wiklander }
2168817466cbSJens Wiklander }
2169b0563631STom Van Eyck }
2170817466cbSJens Wiklander
2171817466cbSJens Wiklander cleanup:
217232b31808SJens Wiklander return ret;
2173817466cbSJens Wiklander }
2174817466cbSJens Wiklander
2175817466cbSJens Wiklander /*
2176817466cbSJens Wiklander * Miller-Rabin pseudo-primality test (HAC 4.24)
2177817466cbSJens Wiklander */
mpi_miller_rabin(const mbedtls_mpi * X,size_t rounds,int (* f_rng)(void *,unsigned char *,size_t),void * p_rng)21783d3b0591SJens Wiklander static int mpi_miller_rabin(const mbedtls_mpi *X, size_t rounds,
2179817466cbSJens Wiklander int (*f_rng)(void *, unsigned char *, size_t),
2180817466cbSJens Wiklander void *p_rng)
2181817466cbSJens Wiklander {
2182817466cbSJens Wiklander int ret, count;
21833d3b0591SJens Wiklander size_t i, j, k, s;
2184817466cbSJens Wiklander mbedtls_mpi W, R, T, A, RR;
2185817466cbSJens Wiklander
218698bd5fe3SJens Wiklander mbedtls_mpi_init_mempool(&W); mbedtls_mpi_init_mempool(&R);
218798bd5fe3SJens Wiklander mbedtls_mpi_init_mempool(&T); mbedtls_mpi_init_mempool(&A);
218898bd5fe3SJens Wiklander mbedtls_mpi_init_mempool(&RR);
2189817466cbSJens Wiklander
2190817466cbSJens Wiklander /*
2191817466cbSJens Wiklander * W = |X| - 1
2192817466cbSJens Wiklander * R = W >> lsb( W )
2193817466cbSJens Wiklander */
2194817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(&W, X, 1));
2195817466cbSJens Wiklander s = mbedtls_mpi_lsb(&W);
2196817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&R, &W));
2197817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&R, s));
2198817466cbSJens Wiklander
219932b31808SJens Wiklander for (i = 0; i < rounds; i++) {
2200817466cbSJens Wiklander /*
2201817466cbSJens Wiklander * pick a random A, 1 < A < |X| - 1
2202817466cbSJens Wiklander */
2203817466cbSJens Wiklander count = 0;
2204817466cbSJens Wiklander do {
2205817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_fill_random(&A, X->n * ciL, f_rng, p_rng));
2206817466cbSJens Wiklander
2207817466cbSJens Wiklander j = mbedtls_mpi_bitlen(&A);
2208817466cbSJens Wiklander k = mbedtls_mpi_bitlen(&W);
2209817466cbSJens Wiklander if (j > k) {
22103d3b0591SJens Wiklander A.p[A.n - 1] &= ((mbedtls_mpi_uint) 1 << (k - (A.n - 1) * biL - 1)) - 1;
2211817466cbSJens Wiklander }
2212817466cbSJens Wiklander
2213117cce93SJens Wiklander if (count++ > 300) {
2214336e3299SJens Wiklander ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2215336e3299SJens Wiklander goto cleanup;
2216817466cbSJens Wiklander }
2217817466cbSJens Wiklander
2218817466cbSJens Wiklander } while (mbedtls_mpi_cmp_mpi(&A, &W) >= 0 ||
2219817466cbSJens Wiklander mbedtls_mpi_cmp_int(&A, 1) <= 0);
2220817466cbSJens Wiklander
2221817466cbSJens Wiklander /*
2222817466cbSJens Wiklander * A = A^R mod |X|
2223817466cbSJens Wiklander */
2224817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&A, &A, &R, X, &RR));
2225817466cbSJens Wiklander
2226817466cbSJens Wiklander if (mbedtls_mpi_cmp_mpi(&A, &W) == 0 ||
222732b31808SJens Wiklander mbedtls_mpi_cmp_int(&A, 1) == 0) {
2228817466cbSJens Wiklander continue;
222932b31808SJens Wiklander }
2230817466cbSJens Wiklander
2231817466cbSJens Wiklander j = 1;
223232b31808SJens Wiklander while (j < s && mbedtls_mpi_cmp_mpi(&A, &W) != 0) {
2233817466cbSJens Wiklander /*
2234817466cbSJens Wiklander * A = A * A mod |X|
2235817466cbSJens Wiklander */
2236817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&T, &A, &A));
2237817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&A, &T, X));
2238817466cbSJens Wiklander
223932b31808SJens Wiklander if (mbedtls_mpi_cmp_int(&A, 1) == 0) {
2240817466cbSJens Wiklander break;
224132b31808SJens Wiklander }
2242817466cbSJens Wiklander
2243817466cbSJens Wiklander j++;
2244817466cbSJens Wiklander }
2245817466cbSJens Wiklander
2246817466cbSJens Wiklander /*
2247817466cbSJens Wiklander * not prime if A != |X| - 1 or A == 1
2248817466cbSJens Wiklander */
2249817466cbSJens Wiklander if (mbedtls_mpi_cmp_mpi(&A, &W) != 0 ||
225032b31808SJens Wiklander mbedtls_mpi_cmp_int(&A, 1) == 0) {
2251817466cbSJens Wiklander ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2252817466cbSJens Wiklander break;
2253817466cbSJens Wiklander }
2254817466cbSJens Wiklander }
2255817466cbSJens Wiklander
2256817466cbSJens Wiklander cleanup:
22573d3b0591SJens Wiklander mbedtls_mpi_free(&W); mbedtls_mpi_free(&R);
22583d3b0591SJens Wiklander mbedtls_mpi_free(&T); mbedtls_mpi_free(&A);
2259817466cbSJens Wiklander mbedtls_mpi_free(&RR);
2260817466cbSJens Wiklander
226132b31808SJens Wiklander return ret;
2262817466cbSJens Wiklander }
2263817466cbSJens Wiklander
2264817466cbSJens Wiklander /*
2265817466cbSJens Wiklander * Pseudo-primality test: small factors, then Miller-Rabin
2266817466cbSJens Wiklander */
mbedtls_mpi_is_prime_ext(const mbedtls_mpi * X,int rounds,int (* f_rng)(void *,unsigned char *,size_t),void * p_rng)22673d3b0591SJens Wiklander int mbedtls_mpi_is_prime_ext(const mbedtls_mpi *X, int rounds,
2268817466cbSJens Wiklander int (*f_rng)(void *, unsigned char *, size_t),
2269817466cbSJens Wiklander void *p_rng)
2270817466cbSJens Wiklander {
227111fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
2272817466cbSJens Wiklander mbedtls_mpi XX;
2273817466cbSJens Wiklander
2274817466cbSJens Wiklander XX.s = 1;
2275817466cbSJens Wiklander XX.n = X->n;
2276817466cbSJens Wiklander XX.p = X->p;
2277817466cbSJens Wiklander
2278817466cbSJens Wiklander if (mbedtls_mpi_cmp_int(&XX, 0) == 0 ||
227932b31808SJens Wiklander mbedtls_mpi_cmp_int(&XX, 1) == 0) {
228032b31808SJens Wiklander return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2281817466cbSJens Wiklander }
2282817466cbSJens Wiklander
228332b31808SJens Wiklander if (mbedtls_mpi_cmp_int(&XX, 2) == 0) {
228432b31808SJens Wiklander return 0;
2285817466cbSJens Wiklander }
2286817466cbSJens Wiklander
228732b31808SJens Wiklander if ((ret = mpi_check_small_factors(&XX)) != 0) {
228832b31808SJens Wiklander if (ret == 1) {
228932b31808SJens Wiklander return 0;
22903d3b0591SJens Wiklander }
229132b31808SJens Wiklander
229232b31808SJens Wiklander return ret;
229332b31808SJens Wiklander }
229432b31808SJens Wiklander
229532b31808SJens Wiklander return mpi_miller_rabin(&XX, rounds, f_rng, p_rng);
229632b31808SJens Wiklander }
22973d3b0591SJens Wiklander
22983d3b0591SJens Wiklander /*
22993d3b0591SJens Wiklander * Prime number generation
23003d3b0591SJens Wiklander *
23013d3b0591SJens Wiklander * To generate an RSA key in a way recommended by FIPS 186-4, both primes must
23023d3b0591SJens Wiklander * be either 1024 bits or 1536 bits long, and flags must contain
23033d3b0591SJens Wiklander * MBEDTLS_MPI_GEN_PRIME_FLAG_LOW_ERR.
23043d3b0591SJens Wiklander */
mbedtls_mpi_gen_prime(mbedtls_mpi * X,size_t nbits,int flags,int (* f_rng)(void *,unsigned char *,size_t),void * p_rng)23053d3b0591SJens Wiklander int mbedtls_mpi_gen_prime(mbedtls_mpi *X, size_t nbits, int flags,
23063d3b0591SJens Wiklander int (*f_rng)(void *, unsigned char *, size_t),
23073d3b0591SJens Wiklander void *p_rng)
23083d3b0591SJens Wiklander {
23093d3b0591SJens Wiklander #ifdef MBEDTLS_HAVE_INT64
23103d3b0591SJens Wiklander // ceil(2^63.5)
23113d3b0591SJens Wiklander #define CEIL_MAXUINT_DIV_SQRT2 0xb504f333f9de6485ULL
23123d3b0591SJens Wiklander #else
23133d3b0591SJens Wiklander // ceil(2^31.5)
23143d3b0591SJens Wiklander #define CEIL_MAXUINT_DIV_SQRT2 0xb504f334U
23153d3b0591SJens Wiklander #endif
23163d3b0591SJens Wiklander int ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2317817466cbSJens Wiklander size_t k, n;
23183d3b0591SJens Wiklander int rounds;
2319817466cbSJens Wiklander mbedtls_mpi_uint r;
2320817466cbSJens Wiklander mbedtls_mpi Y;
2321817466cbSJens Wiklander
232232b31808SJens Wiklander if (nbits < 3 || nbits > MBEDTLS_MPI_MAX_BITS) {
232332b31808SJens Wiklander return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
232432b31808SJens Wiklander }
2325817466cbSJens Wiklander
232698bd5fe3SJens Wiklander mbedtls_mpi_init_mempool(&Y);
2327817466cbSJens Wiklander
2328817466cbSJens Wiklander n = BITS_TO_LIMBS(nbits);
2329817466cbSJens Wiklander
233032b31808SJens Wiklander if ((flags & MBEDTLS_MPI_GEN_PRIME_FLAG_LOW_ERR) == 0) {
23313d3b0591SJens Wiklander /*
23323d3b0591SJens Wiklander * 2^-80 error probability, number of rounds chosen per HAC, table 4.4
23333d3b0591SJens Wiklander */
23343d3b0591SJens Wiklander rounds = ((nbits >= 1300) ? 2 : (nbits >= 850) ? 3 :
23353d3b0591SJens Wiklander (nbits >= 650) ? 4 : (nbits >= 350) ? 8 :
23363d3b0591SJens Wiklander (nbits >= 250) ? 12 : (nbits >= 150) ? 18 : 27);
233732b31808SJens Wiklander } else {
23383d3b0591SJens Wiklander /*
23393d3b0591SJens Wiklander * 2^-100 error probability, number of rounds computed based on HAC,
23403d3b0591SJens Wiklander * fact 4.48
23413d3b0591SJens Wiklander */
23423d3b0591SJens Wiklander rounds = ((nbits >= 1450) ? 4 : (nbits >= 1150) ? 5 :
23433d3b0591SJens Wiklander (nbits >= 1000) ? 6 : (nbits >= 850) ? 7 :
23443d3b0591SJens Wiklander (nbits >= 750) ? 8 : (nbits >= 500) ? 13 :
23453d3b0591SJens Wiklander (nbits >= 250) ? 28 : (nbits >= 150) ? 40 : 51);
23463d3b0591SJens Wiklander }
23473d3b0591SJens Wiklander
234832b31808SJens Wiklander while (1) {
2349817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_fill_random(X, n * ciL, f_rng, p_rng));
23503d3b0591SJens Wiklander /* make sure generated number is at least (nbits-1)+0.5 bits (FIPS 186-4 §B.3.3 steps 4.4, 5.5) */
235132b31808SJens Wiklander if (X->p[n-1] < CEIL_MAXUINT_DIV_SQRT2) {
235232b31808SJens Wiklander continue;
235332b31808SJens Wiklander }
2354817466cbSJens Wiklander
23553d3b0591SJens Wiklander k = n * biL;
235632b31808SJens Wiklander if (k > nbits) {
235732b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(X, k - nbits));
235832b31808SJens Wiklander }
2359817466cbSJens Wiklander X->p[0] |= 1;
2360817466cbSJens Wiklander
236132b31808SJens Wiklander if ((flags & MBEDTLS_MPI_GEN_PRIME_FLAG_DH) == 0) {
23623d3b0591SJens Wiklander ret = mbedtls_mpi_is_prime_ext(X, rounds, f_rng, p_rng);
23633d3b0591SJens Wiklander
236432b31808SJens Wiklander if (ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE) {
2365817466cbSJens Wiklander goto cleanup;
2366817466cbSJens Wiklander }
236732b31808SJens Wiklander } else {
2368817466cbSJens Wiklander /*
236932b31808SJens Wiklander * A necessary condition for Y and X = 2Y + 1 to be prime
2370817466cbSJens Wiklander * is X = 2 mod 3 (which is equivalent to Y = 2 mod 3).
2371817466cbSJens Wiklander * Make sure it is satisfied, while keeping X = 3 mod 4
2372817466cbSJens Wiklander */
2373817466cbSJens Wiklander
2374817466cbSJens Wiklander X->p[0] |= 2;
2375817466cbSJens Wiklander
2376817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_mod_int(&r, X, 3));
237732b31808SJens Wiklander if (r == 0) {
2378817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(X, X, 8));
237932b31808SJens Wiklander } else if (r == 1) {
2380817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(X, X, 4));
238132b31808SJens Wiklander }
2382817466cbSJens Wiklander
2383817466cbSJens Wiklander /* Set Y = (X-1) / 2, which is X / 2 because X is odd */
2384817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&Y, X));
2385817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&Y, 1));
2386817466cbSJens Wiklander
238732b31808SJens Wiklander while (1) {
2388817466cbSJens Wiklander /*
2389817466cbSJens Wiklander * First, check small factors for X and Y
2390817466cbSJens Wiklander * before doing Miller-Rabin on any of them
2391817466cbSJens Wiklander */
2392817466cbSJens Wiklander if ((ret = mpi_check_small_factors(X)) == 0 &&
2393817466cbSJens Wiklander (ret = mpi_check_small_factors(&Y)) == 0 &&
23943d3b0591SJens Wiklander (ret = mpi_miller_rabin(X, rounds, f_rng, p_rng))
23953d3b0591SJens Wiklander == 0 &&
23963d3b0591SJens Wiklander (ret = mpi_miller_rabin(&Y, rounds, f_rng, p_rng))
239732b31808SJens Wiklander == 0) {
23983d3b0591SJens Wiklander goto cleanup;
239932b31808SJens Wiklander }
2400817466cbSJens Wiklander
240132b31808SJens Wiklander if (ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE) {
2402817466cbSJens Wiklander goto cleanup;
240332b31808SJens Wiklander }
2404817466cbSJens Wiklander
2405817466cbSJens Wiklander /*
2406817466cbSJens Wiklander * Next candidates. We want to preserve Y = (X-1) / 2 and
2407817466cbSJens Wiklander * Y = 1 mod 2 and Y = 2 mod 3 (eq X = 3 mod 4 and X = 2 mod 3)
2408817466cbSJens Wiklander * so up Y by 6 and X by 12.
2409817466cbSJens Wiklander */
2410817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(X, X, 12));
2411817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(&Y, &Y, 6));
2412817466cbSJens Wiklander }
2413817466cbSJens Wiklander }
24143d3b0591SJens Wiklander }
2415817466cbSJens Wiklander
2416817466cbSJens Wiklander cleanup:
2417817466cbSJens Wiklander
2418817466cbSJens Wiklander mbedtls_mpi_free(&Y);
2419817466cbSJens Wiklander
242032b31808SJens Wiklander return ret;
2421817466cbSJens Wiklander }
2422817466cbSJens Wiklander
2423817466cbSJens Wiklander #endif /* MBEDTLS_GENPRIME */
2424817466cbSJens Wiklander
2425817466cbSJens Wiklander #if defined(MBEDTLS_SELF_TEST)
2426817466cbSJens Wiklander
2427817466cbSJens Wiklander #define GCD_PAIR_COUNT 3
2428817466cbSJens Wiklander
2429817466cbSJens Wiklander static const int gcd_pairs[GCD_PAIR_COUNT][3] =
2430817466cbSJens Wiklander {
2431817466cbSJens Wiklander { 693, 609, 21 },
2432817466cbSJens Wiklander { 1764, 868, 28 },
2433817466cbSJens Wiklander { 768454923, 542167814, 1 }
2434817466cbSJens Wiklander };
2435817466cbSJens Wiklander
2436817466cbSJens Wiklander /*
2437817466cbSJens Wiklander * Checkup routine
2438817466cbSJens Wiklander */
mbedtls_mpi_self_test(int verbose)2439817466cbSJens Wiklander int mbedtls_mpi_self_test(int verbose)
2440817466cbSJens Wiklander {
2441817466cbSJens Wiklander int ret, i;
2442817466cbSJens Wiklander mbedtls_mpi A, E, N, X, Y, U, V;
2443817466cbSJens Wiklander
244498bd5fe3SJens Wiklander mbedtls_mpi_init_mempool(&A); mbedtls_mpi_init_mempool(&E);
244598bd5fe3SJens Wiklander mbedtls_mpi_init_mempool(&N); mbedtls_mpi_init_mempool(&X);
244698bd5fe3SJens Wiklander mbedtls_mpi_init_mempool(&Y); mbedtls_mpi_init_mempool(&U);
244798bd5fe3SJens Wiklander mbedtls_mpi_init_mempool(&V);
2448817466cbSJens Wiklander
2449817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&A, 16,
2450817466cbSJens Wiklander "EFE021C2645FD1DC586E69184AF4A31E" \
2451817466cbSJens Wiklander "D5F53E93B5F123FA41680867BA110131" \
2452817466cbSJens Wiklander "944FE7952E2517337780CB0DB80E61AA" \
2453817466cbSJens Wiklander "E7C8DDC6C5C6AADEB34EB38A2F40D5E6"));
2454817466cbSJens Wiklander
2455817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&E, 16,
2456817466cbSJens Wiklander "B2E7EFD37075B9F03FF989C7C5051C20" \
2457817466cbSJens Wiklander "34D2A323810251127E7BF8625A4F49A5" \
2458817466cbSJens Wiklander "F3E27F4DA8BD59C47D6DAABA4C8127BD" \
2459817466cbSJens Wiklander "5B5C25763222FEFCCFC38B832366C29E"));
2460817466cbSJens Wiklander
2461817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&N, 16,
2462817466cbSJens Wiklander "0066A198186C18C10B2F5ED9B522752A" \
2463817466cbSJens Wiklander "9830B69916E535C8F047518A889A43A5" \
2464817466cbSJens Wiklander "94B6BED27A168D31D4A52F88925AA8F5"));
2465817466cbSJens Wiklander
2466817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&X, &A, &N));
2467817466cbSJens Wiklander
2468817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&U, 16,
2469817466cbSJens Wiklander "602AB7ECA597A3D6B56FF9829A5E8B85" \
2470817466cbSJens Wiklander "9E857EA95A03512E2BAE7391688D264A" \
2471817466cbSJens Wiklander "A5663B0341DB9CCFD2C4C5F421FEC814" \
2472817466cbSJens Wiklander "8001B72E848A38CAE1C65F78E56ABDEF" \
2473817466cbSJens Wiklander "E12D3C039B8A02D6BE593F0BBBDA56F1" \
2474817466cbSJens Wiklander "ECF677152EF804370C1A305CAF3B5BF1" \
2475817466cbSJens Wiklander "30879B56C61DE584A0F53A2447A51E"));
2476817466cbSJens Wiklander
247732b31808SJens Wiklander if (verbose != 0) {
2478817466cbSJens Wiklander mbedtls_printf(" MPI test #1 (mul_mpi): ");
247932b31808SJens Wiklander }
2480817466cbSJens Wiklander
248132b31808SJens Wiklander if (mbedtls_mpi_cmp_mpi(&X, &U) != 0) {
248232b31808SJens Wiklander if (verbose != 0) {
2483817466cbSJens Wiklander mbedtls_printf("failed\n");
248432b31808SJens Wiklander }
2485817466cbSJens Wiklander
2486817466cbSJens Wiklander ret = 1;
2487817466cbSJens Wiklander goto cleanup;
2488817466cbSJens Wiklander }
2489817466cbSJens Wiklander
249032b31808SJens Wiklander if (verbose != 0) {
2491817466cbSJens Wiklander mbedtls_printf("passed\n");
249232b31808SJens Wiklander }
2493817466cbSJens Wiklander
2494817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_div_mpi(&X, &Y, &A, &N));
2495817466cbSJens Wiklander
2496817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&U, 16,
2497817466cbSJens Wiklander "256567336059E52CAE22925474705F39A94"));
2498817466cbSJens Wiklander
2499817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&V, 16,
2500817466cbSJens Wiklander "6613F26162223DF488E9CD48CC132C7A" \
2501817466cbSJens Wiklander "0AC93C701B001B092E4E5B9F73BCD27B" \
2502817466cbSJens Wiklander "9EE50D0657C77F374E903CDFA4C642"));
2503817466cbSJens Wiklander
250432b31808SJens Wiklander if (verbose != 0) {
2505817466cbSJens Wiklander mbedtls_printf(" MPI test #2 (div_mpi): ");
250632b31808SJens Wiklander }
2507817466cbSJens Wiklander
2508817466cbSJens Wiklander if (mbedtls_mpi_cmp_mpi(&X, &U) != 0 ||
250932b31808SJens Wiklander mbedtls_mpi_cmp_mpi(&Y, &V) != 0) {
251032b31808SJens Wiklander if (verbose != 0) {
2511817466cbSJens Wiklander mbedtls_printf("failed\n");
251232b31808SJens Wiklander }
2513817466cbSJens Wiklander
2514817466cbSJens Wiklander ret = 1;
2515817466cbSJens Wiklander goto cleanup;
2516817466cbSJens Wiklander }
2517817466cbSJens Wiklander
251832b31808SJens Wiklander if (verbose != 0) {
2519817466cbSJens Wiklander mbedtls_printf("passed\n");
252032b31808SJens Wiklander }
2521817466cbSJens Wiklander
2522817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&X, &A, &E, &N, NULL));
2523817466cbSJens Wiklander
2524817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&U, 16,
2525817466cbSJens Wiklander "36E139AEA55215609D2816998ED020BB" \
2526817466cbSJens Wiklander "BD96C37890F65171D948E9BC7CBAA4D9" \
2527817466cbSJens Wiklander "325D24D6A3C12710F10A09FA08AB87"));
2528817466cbSJens Wiklander
252932b31808SJens Wiklander if (verbose != 0) {
2530817466cbSJens Wiklander mbedtls_printf(" MPI test #3 (exp_mod): ");
253132b31808SJens Wiklander }
2532817466cbSJens Wiklander
253332b31808SJens Wiklander if (mbedtls_mpi_cmp_mpi(&X, &U) != 0) {
253432b31808SJens Wiklander if (verbose != 0) {
2535817466cbSJens Wiklander mbedtls_printf("failed\n");
253632b31808SJens Wiklander }
2537817466cbSJens Wiklander
2538817466cbSJens Wiklander ret = 1;
2539817466cbSJens Wiklander goto cleanup;
2540817466cbSJens Wiklander }
2541817466cbSJens Wiklander
254232b31808SJens Wiklander if (verbose != 0) {
2543817466cbSJens Wiklander mbedtls_printf("passed\n");
254432b31808SJens Wiklander }
2545817466cbSJens Wiklander
2546817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_inv_mod(&X, &A, &N));
2547817466cbSJens Wiklander
2548817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&U, 16,
2549817466cbSJens Wiklander "003A0AAEDD7E784FC07D8F9EC6E3BFD5" \
2550817466cbSJens Wiklander "C3DBA76456363A10869622EAC2DD84EC" \
2551817466cbSJens Wiklander "C5B8A74DAC4D09E03B5E0BE779F2DF61"));
2552817466cbSJens Wiklander
255332b31808SJens Wiklander if (verbose != 0) {
2554817466cbSJens Wiklander mbedtls_printf(" MPI test #4 (inv_mod): ");
255532b31808SJens Wiklander }
2556817466cbSJens Wiklander
255732b31808SJens Wiklander if (mbedtls_mpi_cmp_mpi(&X, &U) != 0) {
255832b31808SJens Wiklander if (verbose != 0) {
2559817466cbSJens Wiklander mbedtls_printf("failed\n");
256032b31808SJens Wiklander }
2561817466cbSJens Wiklander
2562817466cbSJens Wiklander ret = 1;
2563817466cbSJens Wiklander goto cleanup;
2564817466cbSJens Wiklander }
2565817466cbSJens Wiklander
256632b31808SJens Wiklander if (verbose != 0) {
2567817466cbSJens Wiklander mbedtls_printf("passed\n");
256832b31808SJens Wiklander }
2569817466cbSJens Wiklander
257032b31808SJens Wiklander if (verbose != 0) {
2571817466cbSJens Wiklander mbedtls_printf(" MPI test #5 (simple gcd): ");
257232b31808SJens Wiklander }
2573817466cbSJens Wiklander
257432b31808SJens Wiklander for (i = 0; i < GCD_PAIR_COUNT; i++) {
2575817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&X, gcd_pairs[i][0]));
2576817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&Y, gcd_pairs[i][1]));
2577817466cbSJens Wiklander
2578817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_gcd(&A, &X, &Y));
2579817466cbSJens Wiklander
258032b31808SJens Wiklander if (mbedtls_mpi_cmp_int(&A, gcd_pairs[i][2]) != 0) {
258132b31808SJens Wiklander if (verbose != 0) {
2582817466cbSJens Wiklander mbedtls_printf("failed at %d\n", i);
258332b31808SJens Wiklander }
2584817466cbSJens Wiklander
2585817466cbSJens Wiklander ret = 1;
2586817466cbSJens Wiklander goto cleanup;
2587817466cbSJens Wiklander }
2588817466cbSJens Wiklander }
2589817466cbSJens Wiklander
259032b31808SJens Wiklander if (verbose != 0) {
2591817466cbSJens Wiklander mbedtls_printf("passed\n");
259232b31808SJens Wiklander }
2593817466cbSJens Wiklander
2594817466cbSJens Wiklander cleanup:
2595817466cbSJens Wiklander
259632b31808SJens Wiklander if (ret != 0 && verbose != 0) {
25977901324dSJerome Forissier mbedtls_printf("Unexpected error, return code = %08X\n", (unsigned int) ret);
259832b31808SJens Wiklander }
2599817466cbSJens Wiklander
2600817466cbSJens Wiklander mbedtls_mpi_free(&A); mbedtls_mpi_free(&E); mbedtls_mpi_free(&N); mbedtls_mpi_free(&X);
2601817466cbSJens Wiklander mbedtls_mpi_free(&Y); mbedtls_mpi_free(&U); mbedtls_mpi_free(&V);
2602817466cbSJens Wiklander
260332b31808SJens Wiklander if (verbose != 0) {
2604817466cbSJens Wiklander mbedtls_printf("\n");
260532b31808SJens Wiklander }
2606817466cbSJens Wiklander
260732b31808SJens Wiklander return ret;
2608817466cbSJens Wiklander }
2609817466cbSJens Wiklander
2610817466cbSJens Wiklander #endif /* MBEDTLS_SELF_TEST */
2611817466cbSJens Wiklander
2612817466cbSJens Wiklander #endif /* MBEDTLS_BIGNUM_C */
2613