1a8e1175bSopenharmony_ci/*
2a8e1175bSopenharmony_ci *  Multi-precision integer library
3a8e1175bSopenharmony_ci *
4a8e1175bSopenharmony_ci *  Copyright The Mbed TLS Contributors
5a8e1175bSopenharmony_ci *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
6a8e1175bSopenharmony_ci */
7a8e1175bSopenharmony_ci
8a8e1175bSopenharmony_ci/*
9a8e1175bSopenharmony_ci *  The following sources were referenced in the design of this Multi-precision
10a8e1175bSopenharmony_ci *  Integer library:
11a8e1175bSopenharmony_ci *
12a8e1175bSopenharmony_ci *  [1] Handbook of Applied Cryptography - 1997
13a8e1175bSopenharmony_ci *      Menezes, van Oorschot and Vanstone
14a8e1175bSopenharmony_ci *
15a8e1175bSopenharmony_ci *  [2] Multi-Precision Math
16a8e1175bSopenharmony_ci *      Tom St Denis
17a8e1175bSopenharmony_ci *      https://github.com/libtom/libtommath/blob/develop/tommath.pdf
18a8e1175bSopenharmony_ci *
19a8e1175bSopenharmony_ci *  [3] GNU Multi-Precision Arithmetic Library
20a8e1175bSopenharmony_ci *      https://gmplib.org/manual/index.html
21a8e1175bSopenharmony_ci *
22a8e1175bSopenharmony_ci */
23a8e1175bSopenharmony_ci
24a8e1175bSopenharmony_ci#include "common.h"
25a8e1175bSopenharmony_ci
26a8e1175bSopenharmony_ci#if defined(MBEDTLS_BIGNUM_C)
27a8e1175bSopenharmony_ci
28a8e1175bSopenharmony_ci#include "mbedtls/bignum.h"
29a8e1175bSopenharmony_ci#include "bignum_core.h"
30a8e1175bSopenharmony_ci#include "bn_mul.h"
31a8e1175bSopenharmony_ci#include "mbedtls/platform_util.h"
32a8e1175bSopenharmony_ci#include "mbedtls/error.h"
33a8e1175bSopenharmony_ci#include "constant_time_internal.h"
34a8e1175bSopenharmony_ci
35a8e1175bSopenharmony_ci#include <limits.h>
36a8e1175bSopenharmony_ci#include <string.h>
37a8e1175bSopenharmony_ci
38a8e1175bSopenharmony_ci#include "mbedtls/platform.h"
39a8e1175bSopenharmony_ci
40a8e1175bSopenharmony_ci
41a8e1175bSopenharmony_ci
42a8e1175bSopenharmony_ci/*
43a8e1175bSopenharmony_ci * Conditionally select an MPI sign in constant time.
44a8e1175bSopenharmony_ci * (MPI sign is the field s in mbedtls_mpi. It is unsigned short and only 1 and -1 are valid
45a8e1175bSopenharmony_ci * values.)
46a8e1175bSopenharmony_ci */
47a8e1175bSopenharmony_cistatic inline signed short mbedtls_ct_mpi_sign_if(mbedtls_ct_condition_t cond,
48a8e1175bSopenharmony_ci                                                  signed short sign1, signed short sign2)
49a8e1175bSopenharmony_ci{
50a8e1175bSopenharmony_ci    return (signed short) mbedtls_ct_uint_if(cond, sign1 + 1, sign2 + 1) - 1;
51a8e1175bSopenharmony_ci}
52a8e1175bSopenharmony_ci
53a8e1175bSopenharmony_ci/*
54a8e1175bSopenharmony_ci * Compare signed values in constant time
55a8e1175bSopenharmony_ci */
56a8e1175bSopenharmony_ciint mbedtls_mpi_lt_mpi_ct(const mbedtls_mpi *X,
57a8e1175bSopenharmony_ci                          const mbedtls_mpi *Y,
58a8e1175bSopenharmony_ci                          unsigned *ret)
59a8e1175bSopenharmony_ci{
60a8e1175bSopenharmony_ci    mbedtls_ct_condition_t different_sign, X_is_negative, Y_is_negative, result;
61a8e1175bSopenharmony_ci
62a8e1175bSopenharmony_ci    if (X->n != Y->n) {
63a8e1175bSopenharmony_ci        return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
64a8e1175bSopenharmony_ci    }
65a8e1175bSopenharmony_ci
66a8e1175bSopenharmony_ci    /*
67a8e1175bSopenharmony_ci     * Set N_is_negative to MBEDTLS_CT_FALSE if N >= 0, MBEDTLS_CT_TRUE if N < 0.
68a8e1175bSopenharmony_ci     * We know that N->s == 1 if N >= 0 and N->s == -1 if N < 0.
69a8e1175bSopenharmony_ci     */
70a8e1175bSopenharmony_ci    X_is_negative = mbedtls_ct_bool((X->s & 2) >> 1);
71a8e1175bSopenharmony_ci    Y_is_negative = mbedtls_ct_bool((Y->s & 2) >> 1);
72a8e1175bSopenharmony_ci
73a8e1175bSopenharmony_ci    /*
74a8e1175bSopenharmony_ci     * If the signs are different, then the positive operand is the bigger.
75a8e1175bSopenharmony_ci     * That is if X is negative (X_is_negative == 1), then X < Y is true and it
76a8e1175bSopenharmony_ci     * is false if X is positive (X_is_negative == 0).
77a8e1175bSopenharmony_ci     */
78a8e1175bSopenharmony_ci    different_sign = mbedtls_ct_bool_ne(X_is_negative, Y_is_negative); // true if different sign
79a8e1175bSopenharmony_ci    result = mbedtls_ct_bool_and(different_sign, X_is_negative);
80a8e1175bSopenharmony_ci
81a8e1175bSopenharmony_ci    /*
82a8e1175bSopenharmony_ci     * Assuming signs are the same, compare X and Y. We switch the comparison
83a8e1175bSopenharmony_ci     * order if they are negative so that we get the right result, regardles of
84a8e1175bSopenharmony_ci     * sign.
85a8e1175bSopenharmony_ci     */
86a8e1175bSopenharmony_ci
87a8e1175bSopenharmony_ci    /* This array is used to conditionally swap the pointers in const time */
88a8e1175bSopenharmony_ci    void * const p[2] = { X->p, Y->p };
89a8e1175bSopenharmony_ci    size_t i = mbedtls_ct_size_if_else_0(X_is_negative, 1);
90a8e1175bSopenharmony_ci    mbedtls_ct_condition_t lt = mbedtls_mpi_core_lt_ct(p[i], p[i ^ 1], X->n);
91a8e1175bSopenharmony_ci
92a8e1175bSopenharmony_ci    /*
93a8e1175bSopenharmony_ci     * Store in result iff the signs are the same (i.e., iff different_sign == false). If
94a8e1175bSopenharmony_ci     * the signs differ, result has already been set, so we don't change it.
95a8e1175bSopenharmony_ci     */
96a8e1175bSopenharmony_ci    result = mbedtls_ct_bool_or(result,
97a8e1175bSopenharmony_ci                                mbedtls_ct_bool_and(mbedtls_ct_bool_not(different_sign), lt));
98a8e1175bSopenharmony_ci
99a8e1175bSopenharmony_ci    *ret = mbedtls_ct_uint_if_else_0(result, 1);
100a8e1175bSopenharmony_ci
101a8e1175bSopenharmony_ci    return 0;
102a8e1175bSopenharmony_ci}
103a8e1175bSopenharmony_ci
104a8e1175bSopenharmony_ci/*
105a8e1175bSopenharmony_ci * Conditionally assign X = Y, without leaking information
106a8e1175bSopenharmony_ci * about whether the assignment was made or not.
107a8e1175bSopenharmony_ci * (Leaking information about the respective sizes of X and Y is ok however.)
108a8e1175bSopenharmony_ci */
109a8e1175bSopenharmony_ci#if defined(_MSC_VER) && defined(MBEDTLS_PLATFORM_IS_WINDOWS_ON_ARM64) && \
110a8e1175bSopenharmony_ci    (_MSC_FULL_VER < 193131103)
111a8e1175bSopenharmony_ci/*
112a8e1175bSopenharmony_ci * MSVC miscompiles this function if it's inlined prior to Visual Studio 2022 version 17.1. See:
113a8e1175bSopenharmony_ci * https://developercommunity.visualstudio.com/t/c-compiler-miscompiles-part-of-mbedtls-library-on/1646989
114a8e1175bSopenharmony_ci */
115a8e1175bSopenharmony_ci__declspec(noinline)
116a8e1175bSopenharmony_ci#endif
117a8e1175bSopenharmony_ciint mbedtls_mpi_safe_cond_assign(mbedtls_mpi *X,
118a8e1175bSopenharmony_ci                                 const mbedtls_mpi *Y,
119a8e1175bSopenharmony_ci                                 unsigned char assign)
120a8e1175bSopenharmony_ci{
121a8e1175bSopenharmony_ci    int ret = 0;
122a8e1175bSopenharmony_ci
123a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, Y->n));
124a8e1175bSopenharmony_ci
125a8e1175bSopenharmony_ci    {
126a8e1175bSopenharmony_ci        mbedtls_ct_condition_t do_assign = mbedtls_ct_bool(assign);
127a8e1175bSopenharmony_ci
128a8e1175bSopenharmony_ci        X->s = mbedtls_ct_mpi_sign_if(do_assign, Y->s, X->s);
129a8e1175bSopenharmony_ci
130a8e1175bSopenharmony_ci        mbedtls_mpi_core_cond_assign(X->p, Y->p, Y->n, do_assign);
131a8e1175bSopenharmony_ci
132a8e1175bSopenharmony_ci        mbedtls_ct_condition_t do_not_assign = mbedtls_ct_bool_not(do_assign);
133a8e1175bSopenharmony_ci        for (size_t i = Y->n; i < X->n; i++) {
134a8e1175bSopenharmony_ci            X->p[i] = mbedtls_ct_mpi_uint_if_else_0(do_not_assign, X->p[i]);
135a8e1175bSopenharmony_ci        }
136a8e1175bSopenharmony_ci    }
137a8e1175bSopenharmony_ci
138a8e1175bSopenharmony_cicleanup:
139a8e1175bSopenharmony_ci    return ret;
140a8e1175bSopenharmony_ci}
141a8e1175bSopenharmony_ci
142a8e1175bSopenharmony_ci/*
143a8e1175bSopenharmony_ci * Conditionally swap X and Y, without leaking information
144a8e1175bSopenharmony_ci * about whether the swap was made or not.
145a8e1175bSopenharmony_ci * Here it is not ok to simply swap the pointers, which would lead to
146a8e1175bSopenharmony_ci * different memory access patterns when X and Y are used afterwards.
147a8e1175bSopenharmony_ci */
148a8e1175bSopenharmony_ciint mbedtls_mpi_safe_cond_swap(mbedtls_mpi *X,
149a8e1175bSopenharmony_ci                               mbedtls_mpi *Y,
150a8e1175bSopenharmony_ci                               unsigned char swap)
151a8e1175bSopenharmony_ci{
152a8e1175bSopenharmony_ci    int ret = 0;
153a8e1175bSopenharmony_ci    int s;
154a8e1175bSopenharmony_ci
155a8e1175bSopenharmony_ci    if (X == Y) {
156a8e1175bSopenharmony_ci        return 0;
157a8e1175bSopenharmony_ci    }
158a8e1175bSopenharmony_ci
159a8e1175bSopenharmony_ci    mbedtls_ct_condition_t do_swap = mbedtls_ct_bool(swap);
160a8e1175bSopenharmony_ci
161a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, Y->n));
162a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_grow(Y, X->n));
163a8e1175bSopenharmony_ci
164a8e1175bSopenharmony_ci    s = X->s;
165a8e1175bSopenharmony_ci    X->s = mbedtls_ct_mpi_sign_if(do_swap, Y->s, X->s);
166a8e1175bSopenharmony_ci    Y->s = mbedtls_ct_mpi_sign_if(do_swap, s, Y->s);
167a8e1175bSopenharmony_ci
168a8e1175bSopenharmony_ci    mbedtls_mpi_core_cond_swap(X->p, Y->p, X->n, do_swap);
169a8e1175bSopenharmony_ci
170a8e1175bSopenharmony_cicleanup:
171a8e1175bSopenharmony_ci    return ret;
172a8e1175bSopenharmony_ci}
173a8e1175bSopenharmony_ci
174a8e1175bSopenharmony_ci/* Implementation that should never be optimized out by the compiler */
175a8e1175bSopenharmony_ci#define mbedtls_mpi_zeroize_and_free(v, n) mbedtls_zeroize_and_free(v, ciL * (n))
176a8e1175bSopenharmony_ci
177a8e1175bSopenharmony_ci/*
178a8e1175bSopenharmony_ci * Initialize one MPI
179a8e1175bSopenharmony_ci */
180a8e1175bSopenharmony_civoid mbedtls_mpi_init(mbedtls_mpi *X)
181a8e1175bSopenharmony_ci{
182a8e1175bSopenharmony_ci    X->s = 1;
183a8e1175bSopenharmony_ci    X->n = 0;
184a8e1175bSopenharmony_ci    X->p = NULL;
185a8e1175bSopenharmony_ci}
186a8e1175bSopenharmony_ci
187a8e1175bSopenharmony_ci/*
188a8e1175bSopenharmony_ci * Unallocate one MPI
189a8e1175bSopenharmony_ci */
190a8e1175bSopenharmony_civoid mbedtls_mpi_free(mbedtls_mpi *X)
191a8e1175bSopenharmony_ci{
192a8e1175bSopenharmony_ci    if (X == NULL) {
193a8e1175bSopenharmony_ci        return;
194a8e1175bSopenharmony_ci    }
195a8e1175bSopenharmony_ci
196a8e1175bSopenharmony_ci    if (X->p != NULL) {
197a8e1175bSopenharmony_ci        mbedtls_mpi_zeroize_and_free(X->p, X->n);
198a8e1175bSopenharmony_ci    }
199a8e1175bSopenharmony_ci
200a8e1175bSopenharmony_ci    X->s = 1;
201a8e1175bSopenharmony_ci    X->n = 0;
202a8e1175bSopenharmony_ci    X->p = NULL;
203a8e1175bSopenharmony_ci}
204a8e1175bSopenharmony_ci
205a8e1175bSopenharmony_ci/*
206a8e1175bSopenharmony_ci * Enlarge to the specified number of limbs
207a8e1175bSopenharmony_ci */
208a8e1175bSopenharmony_ciint mbedtls_mpi_grow(mbedtls_mpi *X, size_t nblimbs)
209a8e1175bSopenharmony_ci{
210a8e1175bSopenharmony_ci    mbedtls_mpi_uint *p;
211a8e1175bSopenharmony_ci
212a8e1175bSopenharmony_ci    if (nblimbs > MBEDTLS_MPI_MAX_LIMBS) {
213a8e1175bSopenharmony_ci        return MBEDTLS_ERR_MPI_ALLOC_FAILED;
214a8e1175bSopenharmony_ci    }
215a8e1175bSopenharmony_ci
216a8e1175bSopenharmony_ci    if (X->n < nblimbs) {
217a8e1175bSopenharmony_ci        if ((p = (mbedtls_mpi_uint *) mbedtls_calloc(nblimbs, ciL)) == NULL) {
218a8e1175bSopenharmony_ci            return MBEDTLS_ERR_MPI_ALLOC_FAILED;
219a8e1175bSopenharmony_ci        }
220a8e1175bSopenharmony_ci
221a8e1175bSopenharmony_ci        if (X->p != NULL) {
222a8e1175bSopenharmony_ci            memcpy(p, X->p, X->n * ciL);
223a8e1175bSopenharmony_ci            mbedtls_mpi_zeroize_and_free(X->p, X->n);
224a8e1175bSopenharmony_ci        }
225a8e1175bSopenharmony_ci
226a8e1175bSopenharmony_ci        /* nblimbs fits in n because we ensure that MBEDTLS_MPI_MAX_LIMBS
227a8e1175bSopenharmony_ci         * fits, and we've checked that nblimbs <= MBEDTLS_MPI_MAX_LIMBS. */
228a8e1175bSopenharmony_ci        X->n = (unsigned short) nblimbs;
229a8e1175bSopenharmony_ci        X->p = p;
230a8e1175bSopenharmony_ci    }
231a8e1175bSopenharmony_ci
232a8e1175bSopenharmony_ci    return 0;
233a8e1175bSopenharmony_ci}
234a8e1175bSopenharmony_ci
235a8e1175bSopenharmony_ci/*
236a8e1175bSopenharmony_ci * Resize down as much as possible,
237a8e1175bSopenharmony_ci * while keeping at least the specified number of limbs
238a8e1175bSopenharmony_ci */
239a8e1175bSopenharmony_ciint mbedtls_mpi_shrink(mbedtls_mpi *X, size_t nblimbs)
240a8e1175bSopenharmony_ci{
241a8e1175bSopenharmony_ci    mbedtls_mpi_uint *p;
242a8e1175bSopenharmony_ci    size_t i;
243a8e1175bSopenharmony_ci
244a8e1175bSopenharmony_ci    if (nblimbs > MBEDTLS_MPI_MAX_LIMBS) {
245a8e1175bSopenharmony_ci        return MBEDTLS_ERR_MPI_ALLOC_FAILED;
246a8e1175bSopenharmony_ci    }
247a8e1175bSopenharmony_ci
248a8e1175bSopenharmony_ci    /* Actually resize up if there are currently fewer than nblimbs limbs. */
249a8e1175bSopenharmony_ci    if (X->n <= nblimbs) {
250a8e1175bSopenharmony_ci        return mbedtls_mpi_grow(X, nblimbs);
251a8e1175bSopenharmony_ci    }
252a8e1175bSopenharmony_ci    /* After this point, then X->n > nblimbs and in particular X->n > 0. */
253a8e1175bSopenharmony_ci
254a8e1175bSopenharmony_ci    for (i = X->n - 1; i > 0; i--) {
255a8e1175bSopenharmony_ci        if (X->p[i] != 0) {
256a8e1175bSopenharmony_ci            break;
257a8e1175bSopenharmony_ci        }
258a8e1175bSopenharmony_ci    }
259a8e1175bSopenharmony_ci    i++;
260a8e1175bSopenharmony_ci
261a8e1175bSopenharmony_ci    if (i < nblimbs) {
262a8e1175bSopenharmony_ci        i = nblimbs;
263a8e1175bSopenharmony_ci    }
264a8e1175bSopenharmony_ci
265a8e1175bSopenharmony_ci    if ((p = (mbedtls_mpi_uint *) mbedtls_calloc(i, ciL)) == NULL) {
266a8e1175bSopenharmony_ci        return MBEDTLS_ERR_MPI_ALLOC_FAILED;
267a8e1175bSopenharmony_ci    }
268a8e1175bSopenharmony_ci
269a8e1175bSopenharmony_ci    if (X->p != NULL) {
270a8e1175bSopenharmony_ci        memcpy(p, X->p, i * ciL);
271a8e1175bSopenharmony_ci        mbedtls_mpi_zeroize_and_free(X->p, X->n);
272a8e1175bSopenharmony_ci    }
273a8e1175bSopenharmony_ci
274a8e1175bSopenharmony_ci    /* i fits in n because we ensure that MBEDTLS_MPI_MAX_LIMBS
275a8e1175bSopenharmony_ci     * fits, and we've checked that i <= nblimbs <= MBEDTLS_MPI_MAX_LIMBS. */
276a8e1175bSopenharmony_ci    X->n = (unsigned short) i;
277a8e1175bSopenharmony_ci    X->p = p;
278a8e1175bSopenharmony_ci
279a8e1175bSopenharmony_ci    return 0;
280a8e1175bSopenharmony_ci}
281a8e1175bSopenharmony_ci
282a8e1175bSopenharmony_ci/* Resize X to have exactly n limbs and set it to 0. */
283a8e1175bSopenharmony_cistatic int mbedtls_mpi_resize_clear(mbedtls_mpi *X, size_t limbs)
284a8e1175bSopenharmony_ci{
285a8e1175bSopenharmony_ci    if (limbs == 0) {
286a8e1175bSopenharmony_ci        mbedtls_mpi_free(X);
287a8e1175bSopenharmony_ci        return 0;
288a8e1175bSopenharmony_ci    } else if (X->n == limbs) {
289a8e1175bSopenharmony_ci        memset(X->p, 0, limbs * ciL);
290a8e1175bSopenharmony_ci        X->s = 1;
291a8e1175bSopenharmony_ci        return 0;
292a8e1175bSopenharmony_ci    } else {
293a8e1175bSopenharmony_ci        mbedtls_mpi_free(X);
294a8e1175bSopenharmony_ci        return mbedtls_mpi_grow(X, limbs);
295a8e1175bSopenharmony_ci    }
296a8e1175bSopenharmony_ci}
297a8e1175bSopenharmony_ci
298a8e1175bSopenharmony_ci/*
299a8e1175bSopenharmony_ci * Copy the contents of Y into X.
300a8e1175bSopenharmony_ci *
301a8e1175bSopenharmony_ci * This function is not constant-time. Leading zeros in Y may be removed.
302a8e1175bSopenharmony_ci *
303a8e1175bSopenharmony_ci * Ensure that X does not shrink. This is not guaranteed by the public API,
304a8e1175bSopenharmony_ci * but some code in the bignum module might still rely on this property.
305a8e1175bSopenharmony_ci */
306a8e1175bSopenharmony_ciint mbedtls_mpi_copy(mbedtls_mpi *X, const mbedtls_mpi *Y)
307a8e1175bSopenharmony_ci{
308a8e1175bSopenharmony_ci    int ret = 0;
309a8e1175bSopenharmony_ci    size_t i;
310a8e1175bSopenharmony_ci
311a8e1175bSopenharmony_ci    if (X == Y) {
312a8e1175bSopenharmony_ci        return 0;
313a8e1175bSopenharmony_ci    }
314a8e1175bSopenharmony_ci
315a8e1175bSopenharmony_ci    if (Y->n == 0) {
316a8e1175bSopenharmony_ci        if (X->n != 0) {
317a8e1175bSopenharmony_ci            X->s = 1;
318a8e1175bSopenharmony_ci            memset(X->p, 0, X->n * ciL);
319a8e1175bSopenharmony_ci        }
320a8e1175bSopenharmony_ci        return 0;
321a8e1175bSopenharmony_ci    }
322a8e1175bSopenharmony_ci
323a8e1175bSopenharmony_ci    for (i = Y->n - 1; i > 0; i--) {
324a8e1175bSopenharmony_ci        if (Y->p[i] != 0) {
325a8e1175bSopenharmony_ci            break;
326a8e1175bSopenharmony_ci        }
327a8e1175bSopenharmony_ci    }
328a8e1175bSopenharmony_ci    i++;
329a8e1175bSopenharmony_ci
330a8e1175bSopenharmony_ci    X->s = Y->s;
331a8e1175bSopenharmony_ci
332a8e1175bSopenharmony_ci    if (X->n < i) {
333a8e1175bSopenharmony_ci        MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, i));
334a8e1175bSopenharmony_ci    } else {
335a8e1175bSopenharmony_ci        memset(X->p + i, 0, (X->n - i) * ciL);
336a8e1175bSopenharmony_ci    }
337a8e1175bSopenharmony_ci
338a8e1175bSopenharmony_ci    memcpy(X->p, Y->p, i * ciL);
339a8e1175bSopenharmony_ci
340a8e1175bSopenharmony_cicleanup:
341a8e1175bSopenharmony_ci
342a8e1175bSopenharmony_ci    return ret;
343a8e1175bSopenharmony_ci}
344a8e1175bSopenharmony_ci
345a8e1175bSopenharmony_ci/*
346a8e1175bSopenharmony_ci * Swap the contents of X and Y
347a8e1175bSopenharmony_ci */
348a8e1175bSopenharmony_civoid mbedtls_mpi_swap(mbedtls_mpi *X, mbedtls_mpi *Y)
349a8e1175bSopenharmony_ci{
350a8e1175bSopenharmony_ci    mbedtls_mpi T;
351a8e1175bSopenharmony_ci
352a8e1175bSopenharmony_ci    memcpy(&T,  X, sizeof(mbedtls_mpi));
353a8e1175bSopenharmony_ci    memcpy(X,  Y, sizeof(mbedtls_mpi));
354a8e1175bSopenharmony_ci    memcpy(Y, &T, sizeof(mbedtls_mpi));
355a8e1175bSopenharmony_ci}
356a8e1175bSopenharmony_ci
357a8e1175bSopenharmony_cistatic inline mbedtls_mpi_uint mpi_sint_abs(mbedtls_mpi_sint z)
358a8e1175bSopenharmony_ci{
359a8e1175bSopenharmony_ci    if (z >= 0) {
360a8e1175bSopenharmony_ci        return z;
361a8e1175bSopenharmony_ci    }
362a8e1175bSopenharmony_ci    /* Take care to handle the most negative value (-2^(biL-1)) correctly.
363a8e1175bSopenharmony_ci     * A naive -z would have undefined behavior.
364a8e1175bSopenharmony_ci     * Write this in a way that makes popular compilers happy (GCC, Clang,
365a8e1175bSopenharmony_ci     * MSVC). */
366a8e1175bSopenharmony_ci    return (mbedtls_mpi_uint) 0 - (mbedtls_mpi_uint) z;
367a8e1175bSopenharmony_ci}
368a8e1175bSopenharmony_ci
369a8e1175bSopenharmony_ci/* Convert x to a sign, i.e. to 1, if x is positive, or -1, if x is negative.
370a8e1175bSopenharmony_ci * This looks awkward but generates smaller code than (x < 0 ? -1 : 1) */
371a8e1175bSopenharmony_ci#define TO_SIGN(x) ((mbedtls_mpi_sint) (((mbedtls_mpi_uint) x) >> (biL - 1)) * -2 + 1)
372a8e1175bSopenharmony_ci
373a8e1175bSopenharmony_ci/*
374a8e1175bSopenharmony_ci * Set value from integer
375a8e1175bSopenharmony_ci */
376a8e1175bSopenharmony_ciint mbedtls_mpi_lset(mbedtls_mpi *X, mbedtls_mpi_sint z)
377a8e1175bSopenharmony_ci{
378a8e1175bSopenharmony_ci    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
379a8e1175bSopenharmony_ci
380a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, 1));
381a8e1175bSopenharmony_ci    memset(X->p, 0, X->n * ciL);
382a8e1175bSopenharmony_ci
383a8e1175bSopenharmony_ci    X->p[0] = mpi_sint_abs(z);
384a8e1175bSopenharmony_ci    X->s    = TO_SIGN(z);
385a8e1175bSopenharmony_ci
386a8e1175bSopenharmony_cicleanup:
387a8e1175bSopenharmony_ci
388a8e1175bSopenharmony_ci    return ret;
389a8e1175bSopenharmony_ci}
390a8e1175bSopenharmony_ci
391a8e1175bSopenharmony_ci/*
392a8e1175bSopenharmony_ci * Get a specific bit
393a8e1175bSopenharmony_ci */
394a8e1175bSopenharmony_ciint mbedtls_mpi_get_bit(const mbedtls_mpi *X, size_t pos)
395a8e1175bSopenharmony_ci{
396a8e1175bSopenharmony_ci    if (X->n * biL <= pos) {
397a8e1175bSopenharmony_ci        return 0;
398a8e1175bSopenharmony_ci    }
399a8e1175bSopenharmony_ci
400a8e1175bSopenharmony_ci    return (X->p[pos / biL] >> (pos % biL)) & 0x01;
401a8e1175bSopenharmony_ci}
402a8e1175bSopenharmony_ci
403a8e1175bSopenharmony_ci/*
404a8e1175bSopenharmony_ci * Set a bit to a specific value of 0 or 1
405a8e1175bSopenharmony_ci */
406a8e1175bSopenharmony_ciint mbedtls_mpi_set_bit(mbedtls_mpi *X, size_t pos, unsigned char val)
407a8e1175bSopenharmony_ci{
408a8e1175bSopenharmony_ci    int ret = 0;
409a8e1175bSopenharmony_ci    size_t off = pos / biL;
410a8e1175bSopenharmony_ci    size_t idx = pos % biL;
411a8e1175bSopenharmony_ci
412a8e1175bSopenharmony_ci    if (val != 0 && val != 1) {
413a8e1175bSopenharmony_ci        return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
414a8e1175bSopenharmony_ci    }
415a8e1175bSopenharmony_ci
416a8e1175bSopenharmony_ci    if (X->n * biL <= pos) {
417a8e1175bSopenharmony_ci        if (val == 0) {
418a8e1175bSopenharmony_ci            return 0;
419a8e1175bSopenharmony_ci        }
420a8e1175bSopenharmony_ci
421a8e1175bSopenharmony_ci        MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, off + 1));
422a8e1175bSopenharmony_ci    }
423a8e1175bSopenharmony_ci
424a8e1175bSopenharmony_ci    X->p[off] &= ~((mbedtls_mpi_uint) 0x01 << idx);
425a8e1175bSopenharmony_ci    X->p[off] |= (mbedtls_mpi_uint) val << idx;
426a8e1175bSopenharmony_ci
427a8e1175bSopenharmony_cicleanup:
428a8e1175bSopenharmony_ci
429a8e1175bSopenharmony_ci    return ret;
430a8e1175bSopenharmony_ci}
431a8e1175bSopenharmony_ci
432a8e1175bSopenharmony_ci/*
433a8e1175bSopenharmony_ci * Return the number of less significant zero-bits
434a8e1175bSopenharmony_ci */
435a8e1175bSopenharmony_cisize_t mbedtls_mpi_lsb(const mbedtls_mpi *X)
436a8e1175bSopenharmony_ci{
437a8e1175bSopenharmony_ci    size_t i;
438a8e1175bSopenharmony_ci
439a8e1175bSopenharmony_ci#if defined(__has_builtin)
440a8e1175bSopenharmony_ci#if (MBEDTLS_MPI_UINT_MAX == UINT_MAX) && __has_builtin(__builtin_ctz)
441a8e1175bSopenharmony_ci    #define mbedtls_mpi_uint_ctz __builtin_ctz
442a8e1175bSopenharmony_ci#elif (MBEDTLS_MPI_UINT_MAX == ULONG_MAX) && __has_builtin(__builtin_ctzl)
443a8e1175bSopenharmony_ci    #define mbedtls_mpi_uint_ctz __builtin_ctzl
444a8e1175bSopenharmony_ci#elif (MBEDTLS_MPI_UINT_MAX == ULLONG_MAX) && __has_builtin(__builtin_ctzll)
445a8e1175bSopenharmony_ci    #define mbedtls_mpi_uint_ctz __builtin_ctzll
446a8e1175bSopenharmony_ci#endif
447a8e1175bSopenharmony_ci#endif
448a8e1175bSopenharmony_ci
449a8e1175bSopenharmony_ci#if defined(mbedtls_mpi_uint_ctz)
450a8e1175bSopenharmony_ci    for (i = 0; i < X->n; i++) {
451a8e1175bSopenharmony_ci        if (X->p[i] != 0) {
452a8e1175bSopenharmony_ci            return i * biL + mbedtls_mpi_uint_ctz(X->p[i]);
453a8e1175bSopenharmony_ci        }
454a8e1175bSopenharmony_ci    }
455a8e1175bSopenharmony_ci#else
456a8e1175bSopenharmony_ci    size_t count = 0;
457a8e1175bSopenharmony_ci    for (i = 0; i < X->n; i++) {
458a8e1175bSopenharmony_ci        for (size_t j = 0; j < biL; j++, count++) {
459a8e1175bSopenharmony_ci            if (((X->p[i] >> j) & 1) != 0) {
460a8e1175bSopenharmony_ci                return count;
461a8e1175bSopenharmony_ci            }
462a8e1175bSopenharmony_ci        }
463a8e1175bSopenharmony_ci    }
464a8e1175bSopenharmony_ci#endif
465a8e1175bSopenharmony_ci
466a8e1175bSopenharmony_ci    return 0;
467a8e1175bSopenharmony_ci}
468a8e1175bSopenharmony_ci
469a8e1175bSopenharmony_ci/*
470a8e1175bSopenharmony_ci * Return the number of bits
471a8e1175bSopenharmony_ci */
472a8e1175bSopenharmony_cisize_t mbedtls_mpi_bitlen(const mbedtls_mpi *X)
473a8e1175bSopenharmony_ci{
474a8e1175bSopenharmony_ci    return mbedtls_mpi_core_bitlen(X->p, X->n);
475a8e1175bSopenharmony_ci}
476a8e1175bSopenharmony_ci
477a8e1175bSopenharmony_ci/*
478a8e1175bSopenharmony_ci * Return the total size in bytes
479a8e1175bSopenharmony_ci */
480a8e1175bSopenharmony_cisize_t mbedtls_mpi_size(const mbedtls_mpi *X)
481a8e1175bSopenharmony_ci{
482a8e1175bSopenharmony_ci    return (mbedtls_mpi_bitlen(X) + 7) >> 3;
483a8e1175bSopenharmony_ci}
484a8e1175bSopenharmony_ci
485a8e1175bSopenharmony_ci/*
486a8e1175bSopenharmony_ci * Convert an ASCII character to digit value
487a8e1175bSopenharmony_ci */
488a8e1175bSopenharmony_cistatic int mpi_get_digit(mbedtls_mpi_uint *d, int radix, char c)
489a8e1175bSopenharmony_ci{
490a8e1175bSopenharmony_ci    *d = 255;
491a8e1175bSopenharmony_ci
492a8e1175bSopenharmony_ci    if (c >= 0x30 && c <= 0x39) {
493a8e1175bSopenharmony_ci        *d = c - 0x30;
494a8e1175bSopenharmony_ci    }
495a8e1175bSopenharmony_ci    if (c >= 0x41 && c <= 0x46) {
496a8e1175bSopenharmony_ci        *d = c - 0x37;
497a8e1175bSopenharmony_ci    }
498a8e1175bSopenharmony_ci    if (c >= 0x61 && c <= 0x66) {
499a8e1175bSopenharmony_ci        *d = c - 0x57;
500a8e1175bSopenharmony_ci    }
501a8e1175bSopenharmony_ci
502a8e1175bSopenharmony_ci    if (*d >= (mbedtls_mpi_uint) radix) {
503a8e1175bSopenharmony_ci        return MBEDTLS_ERR_MPI_INVALID_CHARACTER;
504a8e1175bSopenharmony_ci    }
505a8e1175bSopenharmony_ci
506a8e1175bSopenharmony_ci    return 0;
507a8e1175bSopenharmony_ci}
508a8e1175bSopenharmony_ci
509a8e1175bSopenharmony_ci/*
510a8e1175bSopenharmony_ci * Import from an ASCII string
511a8e1175bSopenharmony_ci */
512a8e1175bSopenharmony_ciint mbedtls_mpi_read_string(mbedtls_mpi *X, int radix, const char *s)
513a8e1175bSopenharmony_ci{
514a8e1175bSopenharmony_ci    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
515a8e1175bSopenharmony_ci    size_t i, j, slen, n;
516a8e1175bSopenharmony_ci    int sign = 1;
517a8e1175bSopenharmony_ci    mbedtls_mpi_uint d;
518a8e1175bSopenharmony_ci    mbedtls_mpi T;
519a8e1175bSopenharmony_ci
520a8e1175bSopenharmony_ci    if (radix < 2 || radix > 16) {
521a8e1175bSopenharmony_ci        return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
522a8e1175bSopenharmony_ci    }
523a8e1175bSopenharmony_ci
524a8e1175bSopenharmony_ci    mbedtls_mpi_init(&T);
525a8e1175bSopenharmony_ci
526a8e1175bSopenharmony_ci    if (s[0] == 0) {
527a8e1175bSopenharmony_ci        mbedtls_mpi_free(X);
528a8e1175bSopenharmony_ci        return 0;
529a8e1175bSopenharmony_ci    }
530a8e1175bSopenharmony_ci
531a8e1175bSopenharmony_ci    if (s[0] == '-') {
532a8e1175bSopenharmony_ci        ++s;
533a8e1175bSopenharmony_ci        sign = -1;
534a8e1175bSopenharmony_ci    }
535a8e1175bSopenharmony_ci
536a8e1175bSopenharmony_ci    slen = strlen(s);
537a8e1175bSopenharmony_ci
538a8e1175bSopenharmony_ci    if (radix == 16) {
539a8e1175bSopenharmony_ci        if (slen > SIZE_MAX >> 2) {
540a8e1175bSopenharmony_ci            return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
541a8e1175bSopenharmony_ci        }
542a8e1175bSopenharmony_ci
543a8e1175bSopenharmony_ci        n = BITS_TO_LIMBS(slen << 2);
544a8e1175bSopenharmony_ci
545a8e1175bSopenharmony_ci        MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, n));
546a8e1175bSopenharmony_ci        MBEDTLS_MPI_CHK(mbedtls_mpi_lset(X, 0));
547a8e1175bSopenharmony_ci
548a8e1175bSopenharmony_ci        for (i = slen, j = 0; i > 0; i--, j++) {
549a8e1175bSopenharmony_ci            MBEDTLS_MPI_CHK(mpi_get_digit(&d, radix, s[i - 1]));
550a8e1175bSopenharmony_ci            X->p[j / (2 * ciL)] |= d << ((j % (2 * ciL)) << 2);
551a8e1175bSopenharmony_ci        }
552a8e1175bSopenharmony_ci    } else {
553a8e1175bSopenharmony_ci        MBEDTLS_MPI_CHK(mbedtls_mpi_lset(X, 0));
554a8e1175bSopenharmony_ci
555a8e1175bSopenharmony_ci        for (i = 0; i < slen; i++) {
556a8e1175bSopenharmony_ci            MBEDTLS_MPI_CHK(mpi_get_digit(&d, radix, s[i]));
557a8e1175bSopenharmony_ci            MBEDTLS_MPI_CHK(mbedtls_mpi_mul_int(&T, X, radix));
558a8e1175bSopenharmony_ci            MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(X, &T, d));
559a8e1175bSopenharmony_ci        }
560a8e1175bSopenharmony_ci    }
561a8e1175bSopenharmony_ci
562a8e1175bSopenharmony_ci    if (sign < 0 && mbedtls_mpi_bitlen(X) != 0) {
563a8e1175bSopenharmony_ci        X->s = -1;
564a8e1175bSopenharmony_ci    }
565a8e1175bSopenharmony_ci
566a8e1175bSopenharmony_cicleanup:
567a8e1175bSopenharmony_ci
568a8e1175bSopenharmony_ci    mbedtls_mpi_free(&T);
569a8e1175bSopenharmony_ci
570a8e1175bSopenharmony_ci    return ret;
571a8e1175bSopenharmony_ci}
572a8e1175bSopenharmony_ci
573a8e1175bSopenharmony_ci/*
574a8e1175bSopenharmony_ci * Helper to write the digits high-order first.
575a8e1175bSopenharmony_ci */
576a8e1175bSopenharmony_cistatic int mpi_write_hlp(mbedtls_mpi *X, int radix,
577a8e1175bSopenharmony_ci                         char **p, const size_t buflen)
578a8e1175bSopenharmony_ci{
579a8e1175bSopenharmony_ci    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
580a8e1175bSopenharmony_ci    mbedtls_mpi_uint r;
581a8e1175bSopenharmony_ci    size_t length = 0;
582a8e1175bSopenharmony_ci    char *p_end = *p + buflen;
583a8e1175bSopenharmony_ci
584a8e1175bSopenharmony_ci    do {
585a8e1175bSopenharmony_ci        if (length >= buflen) {
586a8e1175bSopenharmony_ci            return MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL;
587a8e1175bSopenharmony_ci        }
588a8e1175bSopenharmony_ci
589a8e1175bSopenharmony_ci        MBEDTLS_MPI_CHK(mbedtls_mpi_mod_int(&r, X, radix));
590a8e1175bSopenharmony_ci        MBEDTLS_MPI_CHK(mbedtls_mpi_div_int(X, NULL, X, radix));
591a8e1175bSopenharmony_ci        /*
592a8e1175bSopenharmony_ci         * Write the residue in the current position, as an ASCII character.
593a8e1175bSopenharmony_ci         */
594a8e1175bSopenharmony_ci        if (r < 0xA) {
595a8e1175bSopenharmony_ci            *(--p_end) = (char) ('0' + r);
596a8e1175bSopenharmony_ci        } else {
597a8e1175bSopenharmony_ci            *(--p_end) = (char) ('A' + (r - 0xA));
598a8e1175bSopenharmony_ci        }
599a8e1175bSopenharmony_ci
600a8e1175bSopenharmony_ci        length++;
601a8e1175bSopenharmony_ci    } while (mbedtls_mpi_cmp_int(X, 0) != 0);
602a8e1175bSopenharmony_ci
603a8e1175bSopenharmony_ci    memmove(*p, p_end, length);
604a8e1175bSopenharmony_ci    *p += length;
605a8e1175bSopenharmony_ci
606a8e1175bSopenharmony_cicleanup:
607a8e1175bSopenharmony_ci
608a8e1175bSopenharmony_ci    return ret;
609a8e1175bSopenharmony_ci}
610a8e1175bSopenharmony_ci
611a8e1175bSopenharmony_ci/*
612a8e1175bSopenharmony_ci * Export into an ASCII string
613a8e1175bSopenharmony_ci */
614a8e1175bSopenharmony_ciint mbedtls_mpi_write_string(const mbedtls_mpi *X, int radix,
615a8e1175bSopenharmony_ci                             char *buf, size_t buflen, size_t *olen)
616a8e1175bSopenharmony_ci{
617a8e1175bSopenharmony_ci    int ret = 0;
618a8e1175bSopenharmony_ci    size_t n;
619a8e1175bSopenharmony_ci    char *p;
620a8e1175bSopenharmony_ci    mbedtls_mpi T;
621a8e1175bSopenharmony_ci
622a8e1175bSopenharmony_ci    if (radix < 2 || radix > 16) {
623a8e1175bSopenharmony_ci        return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
624a8e1175bSopenharmony_ci    }
625a8e1175bSopenharmony_ci
626a8e1175bSopenharmony_ci    n = mbedtls_mpi_bitlen(X);   /* Number of bits necessary to present `n`. */
627a8e1175bSopenharmony_ci    if (radix >=  4) {
628a8e1175bSopenharmony_ci        n >>= 1;                 /* Number of 4-adic digits necessary to present
629a8e1175bSopenharmony_ci                                  * `n`. If radix > 4, this might be a strict
630a8e1175bSopenharmony_ci                                  * overapproximation of the number of
631a8e1175bSopenharmony_ci                                  * radix-adic digits needed to present `n`. */
632a8e1175bSopenharmony_ci    }
633a8e1175bSopenharmony_ci    if (radix >= 16) {
634a8e1175bSopenharmony_ci        n >>= 1;                 /* Number of hexadecimal digits necessary to
635a8e1175bSopenharmony_ci                                  * present `n`. */
636a8e1175bSopenharmony_ci
637a8e1175bSopenharmony_ci    }
638a8e1175bSopenharmony_ci    n += 1; /* Terminating null byte */
639a8e1175bSopenharmony_ci    n += 1; /* Compensate for the divisions above, which round down `n`
640a8e1175bSopenharmony_ci             * in case it's not even. */
641a8e1175bSopenharmony_ci    n += 1; /* Potential '-'-sign. */
642a8e1175bSopenharmony_ci    n += (n & 1);   /* Make n even to have enough space for hexadecimal writing,
643a8e1175bSopenharmony_ci                     * which always uses an even number of hex-digits. */
644a8e1175bSopenharmony_ci
645a8e1175bSopenharmony_ci    if (buflen < n) {
646a8e1175bSopenharmony_ci        *olen = n;
647a8e1175bSopenharmony_ci        return MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL;
648a8e1175bSopenharmony_ci    }
649a8e1175bSopenharmony_ci
650a8e1175bSopenharmony_ci    p = buf;
651a8e1175bSopenharmony_ci    mbedtls_mpi_init(&T);
652a8e1175bSopenharmony_ci
653a8e1175bSopenharmony_ci    if (X->s == -1) {
654a8e1175bSopenharmony_ci        *p++ = '-';
655a8e1175bSopenharmony_ci        buflen--;
656a8e1175bSopenharmony_ci    }
657a8e1175bSopenharmony_ci
658a8e1175bSopenharmony_ci    if (radix == 16) {
659a8e1175bSopenharmony_ci        int c;
660a8e1175bSopenharmony_ci        size_t i, j, k;
661a8e1175bSopenharmony_ci
662a8e1175bSopenharmony_ci        for (i = X->n, k = 0; i > 0; i--) {
663a8e1175bSopenharmony_ci            for (j = ciL; j > 0; j--) {
664a8e1175bSopenharmony_ci                c = (X->p[i - 1] >> ((j - 1) << 3)) & 0xFF;
665a8e1175bSopenharmony_ci
666a8e1175bSopenharmony_ci                if (c == 0 && k == 0 && (i + j) != 2) {
667a8e1175bSopenharmony_ci                    continue;
668a8e1175bSopenharmony_ci                }
669a8e1175bSopenharmony_ci
670a8e1175bSopenharmony_ci                *(p++) = "0123456789ABCDEF" [c / 16];
671a8e1175bSopenharmony_ci                *(p++) = "0123456789ABCDEF" [c % 16];
672a8e1175bSopenharmony_ci                k = 1;
673a8e1175bSopenharmony_ci            }
674a8e1175bSopenharmony_ci        }
675a8e1175bSopenharmony_ci    } else {
676a8e1175bSopenharmony_ci        MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&T, X));
677a8e1175bSopenharmony_ci
678a8e1175bSopenharmony_ci        if (T.s == -1) {
679a8e1175bSopenharmony_ci            T.s = 1;
680a8e1175bSopenharmony_ci        }
681a8e1175bSopenharmony_ci
682a8e1175bSopenharmony_ci        MBEDTLS_MPI_CHK(mpi_write_hlp(&T, radix, &p, buflen));
683a8e1175bSopenharmony_ci    }
684a8e1175bSopenharmony_ci
685a8e1175bSopenharmony_ci    *p++ = '\0';
686a8e1175bSopenharmony_ci    *olen = (size_t) (p - buf);
687a8e1175bSopenharmony_ci
688a8e1175bSopenharmony_cicleanup:
689a8e1175bSopenharmony_ci
690a8e1175bSopenharmony_ci    mbedtls_mpi_free(&T);
691a8e1175bSopenharmony_ci
692a8e1175bSopenharmony_ci    return ret;
693a8e1175bSopenharmony_ci}
694a8e1175bSopenharmony_ci
695a8e1175bSopenharmony_ci#if defined(MBEDTLS_FS_IO)
696a8e1175bSopenharmony_ci/*
697a8e1175bSopenharmony_ci * Read X from an opened file
698a8e1175bSopenharmony_ci */
699a8e1175bSopenharmony_ciint mbedtls_mpi_read_file(mbedtls_mpi *X, int radix, FILE *fin)
700a8e1175bSopenharmony_ci{
701a8e1175bSopenharmony_ci    mbedtls_mpi_uint d;
702a8e1175bSopenharmony_ci    size_t slen;
703a8e1175bSopenharmony_ci    char *p;
704a8e1175bSopenharmony_ci    /*
705a8e1175bSopenharmony_ci     * Buffer should have space for (short) label and decimal formatted MPI,
706a8e1175bSopenharmony_ci     * newline characters and '\0'
707a8e1175bSopenharmony_ci     */
708a8e1175bSopenharmony_ci    char s[MBEDTLS_MPI_RW_BUFFER_SIZE];
709a8e1175bSopenharmony_ci
710a8e1175bSopenharmony_ci    if (radix < 2 || radix > 16) {
711a8e1175bSopenharmony_ci        return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
712a8e1175bSopenharmony_ci    }
713a8e1175bSopenharmony_ci
714a8e1175bSopenharmony_ci    memset(s, 0, sizeof(s));
715a8e1175bSopenharmony_ci    if (fgets(s, sizeof(s) - 1, fin) == NULL) {
716a8e1175bSopenharmony_ci        return MBEDTLS_ERR_MPI_FILE_IO_ERROR;
717a8e1175bSopenharmony_ci    }
718a8e1175bSopenharmony_ci
719a8e1175bSopenharmony_ci    slen = strlen(s);
720a8e1175bSopenharmony_ci    if (slen == sizeof(s) - 2) {
721a8e1175bSopenharmony_ci        return MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL;
722a8e1175bSopenharmony_ci    }
723a8e1175bSopenharmony_ci
724a8e1175bSopenharmony_ci    if (slen > 0 && s[slen - 1] == '\n') {
725a8e1175bSopenharmony_ci        slen--; s[slen] = '\0';
726a8e1175bSopenharmony_ci    }
727a8e1175bSopenharmony_ci    if (slen > 0 && s[slen - 1] == '\r') {
728a8e1175bSopenharmony_ci        slen--; s[slen] = '\0';
729a8e1175bSopenharmony_ci    }
730a8e1175bSopenharmony_ci
731a8e1175bSopenharmony_ci    p = s + slen;
732a8e1175bSopenharmony_ci    while (p-- > s) {
733a8e1175bSopenharmony_ci        if (mpi_get_digit(&d, radix, *p) != 0) {
734a8e1175bSopenharmony_ci            break;
735a8e1175bSopenharmony_ci        }
736a8e1175bSopenharmony_ci    }
737a8e1175bSopenharmony_ci
738a8e1175bSopenharmony_ci    return mbedtls_mpi_read_string(X, radix, p + 1);
739a8e1175bSopenharmony_ci}
740a8e1175bSopenharmony_ci
741a8e1175bSopenharmony_ci/*
742a8e1175bSopenharmony_ci * Write X into an opened file (or stdout if fout == NULL)
743a8e1175bSopenharmony_ci */
744a8e1175bSopenharmony_ciint mbedtls_mpi_write_file(const char *p, const mbedtls_mpi *X, int radix, FILE *fout)
745a8e1175bSopenharmony_ci{
746a8e1175bSopenharmony_ci    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
747a8e1175bSopenharmony_ci    size_t n, slen, plen;
748a8e1175bSopenharmony_ci    /*
749a8e1175bSopenharmony_ci     * Buffer should have space for (short) label and decimal formatted MPI,
750a8e1175bSopenharmony_ci     * newline characters and '\0'
751a8e1175bSopenharmony_ci     */
752a8e1175bSopenharmony_ci    char s[MBEDTLS_MPI_RW_BUFFER_SIZE];
753a8e1175bSopenharmony_ci
754a8e1175bSopenharmony_ci    if (radix < 2 || radix > 16) {
755a8e1175bSopenharmony_ci        return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
756a8e1175bSopenharmony_ci    }
757a8e1175bSopenharmony_ci
758a8e1175bSopenharmony_ci    memset(s, 0, sizeof(s));
759a8e1175bSopenharmony_ci
760a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_write_string(X, radix, s, sizeof(s) - 2, &n));
761a8e1175bSopenharmony_ci
762a8e1175bSopenharmony_ci    if (p == NULL) {
763a8e1175bSopenharmony_ci        p = "";
764a8e1175bSopenharmony_ci    }
765a8e1175bSopenharmony_ci
766a8e1175bSopenharmony_ci    plen = strlen(p);
767a8e1175bSopenharmony_ci    slen = strlen(s);
768a8e1175bSopenharmony_ci    s[slen++] = '\r';
769a8e1175bSopenharmony_ci    s[slen++] = '\n';
770a8e1175bSopenharmony_ci
771a8e1175bSopenharmony_ci    if (fout != NULL) {
772a8e1175bSopenharmony_ci        if (fwrite(p, 1, plen, fout) != plen ||
773a8e1175bSopenharmony_ci            fwrite(s, 1, slen, fout) != slen) {
774a8e1175bSopenharmony_ci            return MBEDTLS_ERR_MPI_FILE_IO_ERROR;
775a8e1175bSopenharmony_ci        }
776a8e1175bSopenharmony_ci    } else {
777a8e1175bSopenharmony_ci        mbedtls_printf("%s%s", p, s);
778a8e1175bSopenharmony_ci    }
779a8e1175bSopenharmony_ci
780a8e1175bSopenharmony_cicleanup:
781a8e1175bSopenharmony_ci
782a8e1175bSopenharmony_ci    return ret;
783a8e1175bSopenharmony_ci}
784a8e1175bSopenharmony_ci#endif /* MBEDTLS_FS_IO */
785a8e1175bSopenharmony_ci
786a8e1175bSopenharmony_ci/*
787a8e1175bSopenharmony_ci * Import X from unsigned binary data, little endian
788a8e1175bSopenharmony_ci *
789a8e1175bSopenharmony_ci * This function is guaranteed to return an MPI with exactly the necessary
790a8e1175bSopenharmony_ci * number of limbs (in particular, it does not skip 0s in the input).
791a8e1175bSopenharmony_ci */
792a8e1175bSopenharmony_ciint mbedtls_mpi_read_binary_le(mbedtls_mpi *X,
793a8e1175bSopenharmony_ci                               const unsigned char *buf, size_t buflen)
794a8e1175bSopenharmony_ci{
795a8e1175bSopenharmony_ci    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
796a8e1175bSopenharmony_ci    const size_t limbs = CHARS_TO_LIMBS(buflen);
797a8e1175bSopenharmony_ci
798a8e1175bSopenharmony_ci    /* Ensure that target MPI has exactly the necessary number of limbs */
799a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_resize_clear(X, limbs));
800a8e1175bSopenharmony_ci
801a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_core_read_le(X->p, X->n, buf, buflen));
802a8e1175bSopenharmony_ci
803a8e1175bSopenharmony_cicleanup:
804a8e1175bSopenharmony_ci
805a8e1175bSopenharmony_ci    /*
806a8e1175bSopenharmony_ci     * This function is also used to import keys. However, wiping the buffers
807a8e1175bSopenharmony_ci     * upon failure is not necessary because failure only can happen before any
808a8e1175bSopenharmony_ci     * input is copied.
809a8e1175bSopenharmony_ci     */
810a8e1175bSopenharmony_ci    return ret;
811a8e1175bSopenharmony_ci}
812a8e1175bSopenharmony_ci
813a8e1175bSopenharmony_ci/*
814a8e1175bSopenharmony_ci * Import X from unsigned binary data, big endian
815a8e1175bSopenharmony_ci *
816a8e1175bSopenharmony_ci * This function is guaranteed to return an MPI with exactly the necessary
817a8e1175bSopenharmony_ci * number of limbs (in particular, it does not skip 0s in the input).
818a8e1175bSopenharmony_ci */
819a8e1175bSopenharmony_ciint mbedtls_mpi_read_binary(mbedtls_mpi *X, const unsigned char *buf, size_t buflen)
820a8e1175bSopenharmony_ci{
821a8e1175bSopenharmony_ci    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
822a8e1175bSopenharmony_ci    const size_t limbs = CHARS_TO_LIMBS(buflen);
823a8e1175bSopenharmony_ci
824a8e1175bSopenharmony_ci    /* Ensure that target MPI has exactly the necessary number of limbs */
825a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_resize_clear(X, limbs));
826a8e1175bSopenharmony_ci
827a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_core_read_be(X->p, X->n, buf, buflen));
828a8e1175bSopenharmony_ci
829a8e1175bSopenharmony_cicleanup:
830a8e1175bSopenharmony_ci
831a8e1175bSopenharmony_ci    /*
832a8e1175bSopenharmony_ci     * This function is also used to import keys. However, wiping the buffers
833a8e1175bSopenharmony_ci     * upon failure is not necessary because failure only can happen before any
834a8e1175bSopenharmony_ci     * input is copied.
835a8e1175bSopenharmony_ci     */
836a8e1175bSopenharmony_ci    return ret;
837a8e1175bSopenharmony_ci}
838a8e1175bSopenharmony_ci
839a8e1175bSopenharmony_ci/*
840a8e1175bSopenharmony_ci * Export X into unsigned binary data, little endian
841a8e1175bSopenharmony_ci */
842a8e1175bSopenharmony_ciint mbedtls_mpi_write_binary_le(const mbedtls_mpi *X,
843a8e1175bSopenharmony_ci                                unsigned char *buf, size_t buflen)
844a8e1175bSopenharmony_ci{
845a8e1175bSopenharmony_ci    return mbedtls_mpi_core_write_le(X->p, X->n, buf, buflen);
846a8e1175bSopenharmony_ci}
847a8e1175bSopenharmony_ci
848a8e1175bSopenharmony_ci/*
849a8e1175bSopenharmony_ci * Export X into unsigned binary data, big endian
850a8e1175bSopenharmony_ci */
851a8e1175bSopenharmony_ciint mbedtls_mpi_write_binary(const mbedtls_mpi *X,
852a8e1175bSopenharmony_ci                             unsigned char *buf, size_t buflen)
853a8e1175bSopenharmony_ci{
854a8e1175bSopenharmony_ci    return mbedtls_mpi_core_write_be(X->p, X->n, buf, buflen);
855a8e1175bSopenharmony_ci}
856a8e1175bSopenharmony_ci
857a8e1175bSopenharmony_ci/*
858a8e1175bSopenharmony_ci * Left-shift: X <<= count
859a8e1175bSopenharmony_ci */
860a8e1175bSopenharmony_ciint mbedtls_mpi_shift_l(mbedtls_mpi *X, size_t count)
861a8e1175bSopenharmony_ci{
862a8e1175bSopenharmony_ci    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
863a8e1175bSopenharmony_ci    size_t i;
864a8e1175bSopenharmony_ci
865a8e1175bSopenharmony_ci    i = mbedtls_mpi_bitlen(X) + count;
866a8e1175bSopenharmony_ci
867a8e1175bSopenharmony_ci    if (X->n * biL < i) {
868a8e1175bSopenharmony_ci        MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, BITS_TO_LIMBS(i)));
869a8e1175bSopenharmony_ci    }
870a8e1175bSopenharmony_ci
871a8e1175bSopenharmony_ci    ret = 0;
872a8e1175bSopenharmony_ci
873a8e1175bSopenharmony_ci    mbedtls_mpi_core_shift_l(X->p, X->n, count);
874a8e1175bSopenharmony_cicleanup:
875a8e1175bSopenharmony_ci
876a8e1175bSopenharmony_ci    return ret;
877a8e1175bSopenharmony_ci}
878a8e1175bSopenharmony_ci
879a8e1175bSopenharmony_ci/*
880a8e1175bSopenharmony_ci * Right-shift: X >>= count
881a8e1175bSopenharmony_ci */
882a8e1175bSopenharmony_ciint mbedtls_mpi_shift_r(mbedtls_mpi *X, size_t count)
883a8e1175bSopenharmony_ci{
884a8e1175bSopenharmony_ci    if (X->n != 0) {
885a8e1175bSopenharmony_ci        mbedtls_mpi_core_shift_r(X->p, X->n, count);
886a8e1175bSopenharmony_ci    }
887a8e1175bSopenharmony_ci    return 0;
888a8e1175bSopenharmony_ci}
889a8e1175bSopenharmony_ci
890a8e1175bSopenharmony_ci/*
891a8e1175bSopenharmony_ci * Compare unsigned values
892a8e1175bSopenharmony_ci */
893a8e1175bSopenharmony_ciint mbedtls_mpi_cmp_abs(const mbedtls_mpi *X, const mbedtls_mpi *Y)
894a8e1175bSopenharmony_ci{
895a8e1175bSopenharmony_ci    size_t i, j;
896a8e1175bSopenharmony_ci
897a8e1175bSopenharmony_ci    for (i = X->n; i > 0; i--) {
898a8e1175bSopenharmony_ci        if (X->p[i - 1] != 0) {
899a8e1175bSopenharmony_ci            break;
900a8e1175bSopenharmony_ci        }
901a8e1175bSopenharmony_ci    }
902a8e1175bSopenharmony_ci
903a8e1175bSopenharmony_ci    for (j = Y->n; j > 0; j--) {
904a8e1175bSopenharmony_ci        if (Y->p[j - 1] != 0) {
905a8e1175bSopenharmony_ci            break;
906a8e1175bSopenharmony_ci        }
907a8e1175bSopenharmony_ci    }
908a8e1175bSopenharmony_ci
909a8e1175bSopenharmony_ci    /* If i == j == 0, i.e. abs(X) == abs(Y),
910a8e1175bSopenharmony_ci     * we end up returning 0 at the end of the function. */
911a8e1175bSopenharmony_ci
912a8e1175bSopenharmony_ci    if (i > j) {
913a8e1175bSopenharmony_ci        return 1;
914a8e1175bSopenharmony_ci    }
915a8e1175bSopenharmony_ci    if (j > i) {
916a8e1175bSopenharmony_ci        return -1;
917a8e1175bSopenharmony_ci    }
918a8e1175bSopenharmony_ci
919a8e1175bSopenharmony_ci    for (; i > 0; i--) {
920a8e1175bSopenharmony_ci        if (X->p[i - 1] > Y->p[i - 1]) {
921a8e1175bSopenharmony_ci            return 1;
922a8e1175bSopenharmony_ci        }
923a8e1175bSopenharmony_ci        if (X->p[i - 1] < Y->p[i - 1]) {
924a8e1175bSopenharmony_ci            return -1;
925a8e1175bSopenharmony_ci        }
926a8e1175bSopenharmony_ci    }
927a8e1175bSopenharmony_ci
928a8e1175bSopenharmony_ci    return 0;
929a8e1175bSopenharmony_ci}
930a8e1175bSopenharmony_ci
931a8e1175bSopenharmony_ci/*
932a8e1175bSopenharmony_ci * Compare signed values
933a8e1175bSopenharmony_ci */
934a8e1175bSopenharmony_ciint mbedtls_mpi_cmp_mpi(const mbedtls_mpi *X, const mbedtls_mpi *Y)
935a8e1175bSopenharmony_ci{
936a8e1175bSopenharmony_ci    size_t i, j;
937a8e1175bSopenharmony_ci
938a8e1175bSopenharmony_ci    for (i = X->n; i > 0; i--) {
939a8e1175bSopenharmony_ci        if (X->p[i - 1] != 0) {
940a8e1175bSopenharmony_ci            break;
941a8e1175bSopenharmony_ci        }
942a8e1175bSopenharmony_ci    }
943a8e1175bSopenharmony_ci
944a8e1175bSopenharmony_ci    for (j = Y->n; j > 0; j--) {
945a8e1175bSopenharmony_ci        if (Y->p[j - 1] != 0) {
946a8e1175bSopenharmony_ci            break;
947a8e1175bSopenharmony_ci        }
948a8e1175bSopenharmony_ci    }
949a8e1175bSopenharmony_ci
950a8e1175bSopenharmony_ci    if (i == 0 && j == 0) {
951a8e1175bSopenharmony_ci        return 0;
952a8e1175bSopenharmony_ci    }
953a8e1175bSopenharmony_ci
954a8e1175bSopenharmony_ci    if (i > j) {
955a8e1175bSopenharmony_ci        return X->s;
956a8e1175bSopenharmony_ci    }
957a8e1175bSopenharmony_ci    if (j > i) {
958a8e1175bSopenharmony_ci        return -Y->s;
959a8e1175bSopenharmony_ci    }
960a8e1175bSopenharmony_ci
961a8e1175bSopenharmony_ci    if (X->s > 0 && Y->s < 0) {
962a8e1175bSopenharmony_ci        return 1;
963a8e1175bSopenharmony_ci    }
964a8e1175bSopenharmony_ci    if (Y->s > 0 && X->s < 0) {
965a8e1175bSopenharmony_ci        return -1;
966a8e1175bSopenharmony_ci    }
967a8e1175bSopenharmony_ci
968a8e1175bSopenharmony_ci    for (; i > 0; i--) {
969a8e1175bSopenharmony_ci        if (X->p[i - 1] > Y->p[i - 1]) {
970a8e1175bSopenharmony_ci            return X->s;
971a8e1175bSopenharmony_ci        }
972a8e1175bSopenharmony_ci        if (X->p[i - 1] < Y->p[i - 1]) {
973a8e1175bSopenharmony_ci            return -X->s;
974a8e1175bSopenharmony_ci        }
975a8e1175bSopenharmony_ci    }
976a8e1175bSopenharmony_ci
977a8e1175bSopenharmony_ci    return 0;
978a8e1175bSopenharmony_ci}
979a8e1175bSopenharmony_ci
980a8e1175bSopenharmony_ci/*
981a8e1175bSopenharmony_ci * Compare signed values
982a8e1175bSopenharmony_ci */
983a8e1175bSopenharmony_ciint mbedtls_mpi_cmp_int(const mbedtls_mpi *X, mbedtls_mpi_sint z)
984a8e1175bSopenharmony_ci{
985a8e1175bSopenharmony_ci    mbedtls_mpi Y;
986a8e1175bSopenharmony_ci    mbedtls_mpi_uint p[1];
987a8e1175bSopenharmony_ci
988a8e1175bSopenharmony_ci    *p  = mpi_sint_abs(z);
989a8e1175bSopenharmony_ci    Y.s = TO_SIGN(z);
990a8e1175bSopenharmony_ci    Y.n = 1;
991a8e1175bSopenharmony_ci    Y.p = p;
992a8e1175bSopenharmony_ci
993a8e1175bSopenharmony_ci    return mbedtls_mpi_cmp_mpi(X, &Y);
994a8e1175bSopenharmony_ci}
995a8e1175bSopenharmony_ci
996a8e1175bSopenharmony_ci/*
997a8e1175bSopenharmony_ci * Unsigned addition: X = |A| + |B|  (HAC 14.7)
998a8e1175bSopenharmony_ci */
999a8e1175bSopenharmony_ciint mbedtls_mpi_add_abs(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B)
1000a8e1175bSopenharmony_ci{
1001a8e1175bSopenharmony_ci    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
1002a8e1175bSopenharmony_ci    size_t j;
1003a8e1175bSopenharmony_ci    mbedtls_mpi_uint *p;
1004a8e1175bSopenharmony_ci    mbedtls_mpi_uint c;
1005a8e1175bSopenharmony_ci
1006a8e1175bSopenharmony_ci    if (X == B) {
1007a8e1175bSopenharmony_ci        const mbedtls_mpi *T = A; A = X; B = T;
1008a8e1175bSopenharmony_ci    }
1009a8e1175bSopenharmony_ci
1010a8e1175bSopenharmony_ci    if (X != A) {
1011a8e1175bSopenharmony_ci        MBEDTLS_MPI_CHK(mbedtls_mpi_copy(X, A));
1012a8e1175bSopenharmony_ci    }
1013a8e1175bSopenharmony_ci
1014a8e1175bSopenharmony_ci    /*
1015a8e1175bSopenharmony_ci     * X must always be positive as a result of unsigned additions.
1016a8e1175bSopenharmony_ci     */
1017a8e1175bSopenharmony_ci    X->s = 1;
1018a8e1175bSopenharmony_ci
1019a8e1175bSopenharmony_ci    for (j = B->n; j > 0; j--) {
1020a8e1175bSopenharmony_ci        if (B->p[j - 1] != 0) {
1021a8e1175bSopenharmony_ci            break;
1022a8e1175bSopenharmony_ci        }
1023a8e1175bSopenharmony_ci    }
1024a8e1175bSopenharmony_ci
1025a8e1175bSopenharmony_ci    /* Exit early to avoid undefined behavior on NULL+0 when X->n == 0
1026a8e1175bSopenharmony_ci     * and B is 0 (of any size). */
1027a8e1175bSopenharmony_ci    if (j == 0) {
1028a8e1175bSopenharmony_ci        return 0;
1029a8e1175bSopenharmony_ci    }
1030a8e1175bSopenharmony_ci
1031a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, j));
1032a8e1175bSopenharmony_ci
1033a8e1175bSopenharmony_ci    /* j is the number of non-zero limbs of B. Add those to X. */
1034a8e1175bSopenharmony_ci
1035a8e1175bSopenharmony_ci    p = X->p;
1036a8e1175bSopenharmony_ci
1037a8e1175bSopenharmony_ci    c = mbedtls_mpi_core_add(p, p, B->p, j);
1038a8e1175bSopenharmony_ci
1039a8e1175bSopenharmony_ci    p += j;
1040a8e1175bSopenharmony_ci
1041a8e1175bSopenharmony_ci    /* Now propagate any carry */
1042a8e1175bSopenharmony_ci
1043a8e1175bSopenharmony_ci    while (c != 0) {
1044a8e1175bSopenharmony_ci        if (j >= X->n) {
1045a8e1175bSopenharmony_ci            MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, j + 1));
1046a8e1175bSopenharmony_ci            p = X->p + j;
1047a8e1175bSopenharmony_ci        }
1048a8e1175bSopenharmony_ci
1049a8e1175bSopenharmony_ci        *p += c; c = (*p < c); j++; p++;
1050a8e1175bSopenharmony_ci    }
1051a8e1175bSopenharmony_ci
1052a8e1175bSopenharmony_cicleanup:
1053a8e1175bSopenharmony_ci
1054a8e1175bSopenharmony_ci    return ret;
1055a8e1175bSopenharmony_ci}
1056a8e1175bSopenharmony_ci
1057a8e1175bSopenharmony_ci/*
1058a8e1175bSopenharmony_ci * Unsigned subtraction: X = |A| - |B|  (HAC 14.9, 14.10)
1059a8e1175bSopenharmony_ci */
1060a8e1175bSopenharmony_ciint mbedtls_mpi_sub_abs(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B)
1061a8e1175bSopenharmony_ci{
1062a8e1175bSopenharmony_ci    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
1063a8e1175bSopenharmony_ci    size_t n;
1064a8e1175bSopenharmony_ci    mbedtls_mpi_uint carry;
1065a8e1175bSopenharmony_ci
1066a8e1175bSopenharmony_ci    for (n = B->n; n > 0; n--) {
1067a8e1175bSopenharmony_ci        if (B->p[n - 1] != 0) {
1068a8e1175bSopenharmony_ci            break;
1069a8e1175bSopenharmony_ci        }
1070a8e1175bSopenharmony_ci    }
1071a8e1175bSopenharmony_ci    if (n > A->n) {
1072a8e1175bSopenharmony_ci        /* B >= (2^ciL)^n > A */
1073a8e1175bSopenharmony_ci        ret = MBEDTLS_ERR_MPI_NEGATIVE_VALUE;
1074a8e1175bSopenharmony_ci        goto cleanup;
1075a8e1175bSopenharmony_ci    }
1076a8e1175bSopenharmony_ci
1077a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, A->n));
1078a8e1175bSopenharmony_ci
1079a8e1175bSopenharmony_ci    /* Set the high limbs of X to match A. Don't touch the lower limbs
1080a8e1175bSopenharmony_ci     * because X might be aliased to B, and we must not overwrite the
1081a8e1175bSopenharmony_ci     * significant digits of B. */
1082a8e1175bSopenharmony_ci    if (A->n > n && A != X) {
1083a8e1175bSopenharmony_ci        memcpy(X->p + n, A->p + n, (A->n - n) * ciL);
1084a8e1175bSopenharmony_ci    }
1085a8e1175bSopenharmony_ci    if (X->n > A->n) {
1086a8e1175bSopenharmony_ci        memset(X->p + A->n, 0, (X->n - A->n) * ciL);
1087a8e1175bSopenharmony_ci    }
1088a8e1175bSopenharmony_ci
1089a8e1175bSopenharmony_ci    carry = mbedtls_mpi_core_sub(X->p, A->p, B->p, n);
1090a8e1175bSopenharmony_ci    if (carry != 0) {
1091a8e1175bSopenharmony_ci        /* Propagate the carry through the rest of X. */
1092a8e1175bSopenharmony_ci        carry = mbedtls_mpi_core_sub_int(X->p + n, X->p + n, carry, X->n - n);
1093a8e1175bSopenharmony_ci
1094a8e1175bSopenharmony_ci        /* If we have further carry/borrow, the result is negative. */
1095a8e1175bSopenharmony_ci        if (carry != 0) {
1096a8e1175bSopenharmony_ci            ret = MBEDTLS_ERR_MPI_NEGATIVE_VALUE;
1097a8e1175bSopenharmony_ci            goto cleanup;
1098a8e1175bSopenharmony_ci        }
1099a8e1175bSopenharmony_ci    }
1100a8e1175bSopenharmony_ci
1101a8e1175bSopenharmony_ci    /* X should always be positive as a result of unsigned subtractions. */
1102a8e1175bSopenharmony_ci    X->s = 1;
1103a8e1175bSopenharmony_ci
1104a8e1175bSopenharmony_cicleanup:
1105a8e1175bSopenharmony_ci    return ret;
1106a8e1175bSopenharmony_ci}
1107a8e1175bSopenharmony_ci
1108a8e1175bSopenharmony_ci/* Common function for signed addition and subtraction.
1109a8e1175bSopenharmony_ci * Calculate A + B * flip_B where flip_B is 1 or -1.
1110a8e1175bSopenharmony_ci */
1111a8e1175bSopenharmony_cistatic int add_sub_mpi(mbedtls_mpi *X,
1112a8e1175bSopenharmony_ci                       const mbedtls_mpi *A, const mbedtls_mpi *B,
1113a8e1175bSopenharmony_ci                       int flip_B)
1114a8e1175bSopenharmony_ci{
1115a8e1175bSopenharmony_ci    int ret, s;
1116a8e1175bSopenharmony_ci
1117a8e1175bSopenharmony_ci    s = A->s;
1118a8e1175bSopenharmony_ci    if (A->s * B->s * flip_B < 0) {
1119a8e1175bSopenharmony_ci        int cmp = mbedtls_mpi_cmp_abs(A, B);
1120a8e1175bSopenharmony_ci        if (cmp >= 0) {
1121a8e1175bSopenharmony_ci            MBEDTLS_MPI_CHK(mbedtls_mpi_sub_abs(X, A, B));
1122a8e1175bSopenharmony_ci            /* If |A| = |B|, the result is 0 and we must set the sign bit
1123a8e1175bSopenharmony_ci             * to +1 regardless of which of A or B was negative. Otherwise,
1124a8e1175bSopenharmony_ci             * since |A| > |B|, the sign is the sign of A. */
1125a8e1175bSopenharmony_ci            X->s = cmp == 0 ? 1 : s;
1126a8e1175bSopenharmony_ci        } else {
1127a8e1175bSopenharmony_ci            MBEDTLS_MPI_CHK(mbedtls_mpi_sub_abs(X, B, A));
1128a8e1175bSopenharmony_ci            /* Since |A| < |B|, the sign is the opposite of A. */
1129a8e1175bSopenharmony_ci            X->s = -s;
1130a8e1175bSopenharmony_ci        }
1131a8e1175bSopenharmony_ci    } else {
1132a8e1175bSopenharmony_ci        MBEDTLS_MPI_CHK(mbedtls_mpi_add_abs(X, A, B));
1133a8e1175bSopenharmony_ci        X->s = s;
1134a8e1175bSopenharmony_ci    }
1135a8e1175bSopenharmony_ci
1136a8e1175bSopenharmony_cicleanup:
1137a8e1175bSopenharmony_ci
1138a8e1175bSopenharmony_ci    return ret;
1139a8e1175bSopenharmony_ci}
1140a8e1175bSopenharmony_ci
1141a8e1175bSopenharmony_ci/*
1142a8e1175bSopenharmony_ci * Signed addition: X = A + B
1143a8e1175bSopenharmony_ci */
1144a8e1175bSopenharmony_ciint mbedtls_mpi_add_mpi(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B)
1145a8e1175bSopenharmony_ci{
1146a8e1175bSopenharmony_ci    return add_sub_mpi(X, A, B, 1);
1147a8e1175bSopenharmony_ci}
1148a8e1175bSopenharmony_ci
1149a8e1175bSopenharmony_ci/*
1150a8e1175bSopenharmony_ci * Signed subtraction: X = A - B
1151a8e1175bSopenharmony_ci */
1152a8e1175bSopenharmony_ciint mbedtls_mpi_sub_mpi(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B)
1153a8e1175bSopenharmony_ci{
1154a8e1175bSopenharmony_ci    return add_sub_mpi(X, A, B, -1);
1155a8e1175bSopenharmony_ci}
1156a8e1175bSopenharmony_ci
1157a8e1175bSopenharmony_ci/*
1158a8e1175bSopenharmony_ci * Signed addition: X = A + b
1159a8e1175bSopenharmony_ci */
1160a8e1175bSopenharmony_ciint mbedtls_mpi_add_int(mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b)
1161a8e1175bSopenharmony_ci{
1162a8e1175bSopenharmony_ci    mbedtls_mpi B;
1163a8e1175bSopenharmony_ci    mbedtls_mpi_uint p[1];
1164a8e1175bSopenharmony_ci
1165a8e1175bSopenharmony_ci    p[0] = mpi_sint_abs(b);
1166a8e1175bSopenharmony_ci    B.s = TO_SIGN(b);
1167a8e1175bSopenharmony_ci    B.n = 1;
1168a8e1175bSopenharmony_ci    B.p = p;
1169a8e1175bSopenharmony_ci
1170a8e1175bSopenharmony_ci    return mbedtls_mpi_add_mpi(X, A, &B);
1171a8e1175bSopenharmony_ci}
1172a8e1175bSopenharmony_ci
1173a8e1175bSopenharmony_ci/*
1174a8e1175bSopenharmony_ci * Signed subtraction: X = A - b
1175a8e1175bSopenharmony_ci */
1176a8e1175bSopenharmony_ciint mbedtls_mpi_sub_int(mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b)
1177a8e1175bSopenharmony_ci{
1178a8e1175bSopenharmony_ci    mbedtls_mpi B;
1179a8e1175bSopenharmony_ci    mbedtls_mpi_uint p[1];
1180a8e1175bSopenharmony_ci
1181a8e1175bSopenharmony_ci    p[0] = mpi_sint_abs(b);
1182a8e1175bSopenharmony_ci    B.s = TO_SIGN(b);
1183a8e1175bSopenharmony_ci    B.n = 1;
1184a8e1175bSopenharmony_ci    B.p = p;
1185a8e1175bSopenharmony_ci
1186a8e1175bSopenharmony_ci    return mbedtls_mpi_sub_mpi(X, A, &B);
1187a8e1175bSopenharmony_ci}
1188a8e1175bSopenharmony_ci
1189a8e1175bSopenharmony_ci/*
1190a8e1175bSopenharmony_ci * Baseline multiplication: X = A * B  (HAC 14.12)
1191a8e1175bSopenharmony_ci */
1192a8e1175bSopenharmony_ciint mbedtls_mpi_mul_mpi(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B)
1193a8e1175bSopenharmony_ci{
1194a8e1175bSopenharmony_ci    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
1195a8e1175bSopenharmony_ci    size_t i, j;
1196a8e1175bSopenharmony_ci    mbedtls_mpi TA, TB;
1197a8e1175bSopenharmony_ci    int result_is_zero = 0;
1198a8e1175bSopenharmony_ci
1199a8e1175bSopenharmony_ci    mbedtls_mpi_init(&TA);
1200a8e1175bSopenharmony_ci    mbedtls_mpi_init(&TB);
1201a8e1175bSopenharmony_ci
1202a8e1175bSopenharmony_ci    if (X == A) {
1203a8e1175bSopenharmony_ci        MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TA, A)); A = &TA;
1204a8e1175bSopenharmony_ci    }
1205a8e1175bSopenharmony_ci    if (X == B) {
1206a8e1175bSopenharmony_ci        MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TB, B)); B = &TB;
1207a8e1175bSopenharmony_ci    }
1208a8e1175bSopenharmony_ci
1209a8e1175bSopenharmony_ci    for (i = A->n; i > 0; i--) {
1210a8e1175bSopenharmony_ci        if (A->p[i - 1] != 0) {
1211a8e1175bSopenharmony_ci            break;
1212a8e1175bSopenharmony_ci        }
1213a8e1175bSopenharmony_ci    }
1214a8e1175bSopenharmony_ci    if (i == 0) {
1215a8e1175bSopenharmony_ci        result_is_zero = 1;
1216a8e1175bSopenharmony_ci    }
1217a8e1175bSopenharmony_ci
1218a8e1175bSopenharmony_ci    for (j = B->n; j > 0; j--) {
1219a8e1175bSopenharmony_ci        if (B->p[j - 1] != 0) {
1220a8e1175bSopenharmony_ci            break;
1221a8e1175bSopenharmony_ci        }
1222a8e1175bSopenharmony_ci    }
1223a8e1175bSopenharmony_ci    if (j == 0) {
1224a8e1175bSopenharmony_ci        result_is_zero = 1;
1225a8e1175bSopenharmony_ci    }
1226a8e1175bSopenharmony_ci
1227a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, i + j));
1228a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_lset(X, 0));
1229a8e1175bSopenharmony_ci
1230a8e1175bSopenharmony_ci    mbedtls_mpi_core_mul(X->p, A->p, i, B->p, j);
1231a8e1175bSopenharmony_ci
1232a8e1175bSopenharmony_ci    /* If the result is 0, we don't shortcut the operation, which reduces
1233a8e1175bSopenharmony_ci     * but does not eliminate side channels leaking the zero-ness. We do
1234a8e1175bSopenharmony_ci     * need to take care to set the sign bit properly since the library does
1235a8e1175bSopenharmony_ci     * not fully support an MPI object with a value of 0 and s == -1. */
1236a8e1175bSopenharmony_ci    if (result_is_zero) {
1237a8e1175bSopenharmony_ci        X->s = 1;
1238a8e1175bSopenharmony_ci    } else {
1239a8e1175bSopenharmony_ci        X->s = A->s * B->s;
1240a8e1175bSopenharmony_ci    }
1241a8e1175bSopenharmony_ci
1242a8e1175bSopenharmony_cicleanup:
1243a8e1175bSopenharmony_ci
1244a8e1175bSopenharmony_ci    mbedtls_mpi_free(&TB); mbedtls_mpi_free(&TA);
1245a8e1175bSopenharmony_ci
1246a8e1175bSopenharmony_ci    return ret;
1247a8e1175bSopenharmony_ci}
1248a8e1175bSopenharmony_ci
1249a8e1175bSopenharmony_ci/*
1250a8e1175bSopenharmony_ci * Baseline multiplication: X = A * b
1251a8e1175bSopenharmony_ci */
1252a8e1175bSopenharmony_ciint mbedtls_mpi_mul_int(mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_uint b)
1253a8e1175bSopenharmony_ci{
1254a8e1175bSopenharmony_ci    size_t n = A->n;
1255a8e1175bSopenharmony_ci    while (n > 0 && A->p[n - 1] == 0) {
1256a8e1175bSopenharmony_ci        --n;
1257a8e1175bSopenharmony_ci    }
1258a8e1175bSopenharmony_ci
1259a8e1175bSopenharmony_ci    /* The general method below doesn't work if b==0. */
1260a8e1175bSopenharmony_ci    if (b == 0 || n == 0) {
1261a8e1175bSopenharmony_ci        return mbedtls_mpi_lset(X, 0);
1262a8e1175bSopenharmony_ci    }
1263a8e1175bSopenharmony_ci
1264a8e1175bSopenharmony_ci    /* Calculate A*b as A + A*(b-1) to take advantage of mbedtls_mpi_core_mla */
1265a8e1175bSopenharmony_ci    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
1266a8e1175bSopenharmony_ci    /* In general, A * b requires 1 limb more than b. If
1267a8e1175bSopenharmony_ci     * A->p[n - 1] * b / b == A->p[n - 1], then A * b fits in the same
1268a8e1175bSopenharmony_ci     * number of limbs as A and the call to grow() is not required since
1269a8e1175bSopenharmony_ci     * copy() will take care of the growth if needed. However, experimentally,
1270a8e1175bSopenharmony_ci     * making the call to grow() unconditional causes slightly fewer
1271a8e1175bSopenharmony_ci     * calls to calloc() in ECP code, presumably because it reuses the
1272a8e1175bSopenharmony_ci     * same mpi for a while and this way the mpi is more likely to directly
1273a8e1175bSopenharmony_ci     * grow to its final size.
1274a8e1175bSopenharmony_ci     *
1275a8e1175bSopenharmony_ci     * Note that calculating A*b as 0 + A*b doesn't work as-is because
1276a8e1175bSopenharmony_ci     * A,X can be the same. */
1277a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, n + 1));
1278a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_copy(X, A));
1279a8e1175bSopenharmony_ci    mbedtls_mpi_core_mla(X->p, X->n, A->p, n, b - 1);
1280a8e1175bSopenharmony_ci
1281a8e1175bSopenharmony_cicleanup:
1282a8e1175bSopenharmony_ci    return ret;
1283a8e1175bSopenharmony_ci}
1284a8e1175bSopenharmony_ci
1285a8e1175bSopenharmony_ci/*
1286a8e1175bSopenharmony_ci * Unsigned integer divide - double mbedtls_mpi_uint dividend, u1/u0, and
1287a8e1175bSopenharmony_ci * mbedtls_mpi_uint divisor, d
1288a8e1175bSopenharmony_ci */
1289a8e1175bSopenharmony_cistatic mbedtls_mpi_uint mbedtls_int_div_int(mbedtls_mpi_uint u1,
1290a8e1175bSopenharmony_ci                                            mbedtls_mpi_uint u0,
1291a8e1175bSopenharmony_ci                                            mbedtls_mpi_uint d,
1292a8e1175bSopenharmony_ci                                            mbedtls_mpi_uint *r)
1293a8e1175bSopenharmony_ci{
1294a8e1175bSopenharmony_ci#if defined(MBEDTLS_HAVE_UDBL)
1295a8e1175bSopenharmony_ci    mbedtls_t_udbl dividend, quotient;
1296a8e1175bSopenharmony_ci#else
1297a8e1175bSopenharmony_ci    const mbedtls_mpi_uint radix = (mbedtls_mpi_uint) 1 << biH;
1298a8e1175bSopenharmony_ci    const mbedtls_mpi_uint uint_halfword_mask = ((mbedtls_mpi_uint) 1 << biH) - 1;
1299a8e1175bSopenharmony_ci    mbedtls_mpi_uint d0, d1, q0, q1, rAX, r0, quotient;
1300a8e1175bSopenharmony_ci    mbedtls_mpi_uint u0_msw, u0_lsw;
1301a8e1175bSopenharmony_ci    size_t s;
1302a8e1175bSopenharmony_ci#endif
1303a8e1175bSopenharmony_ci
1304a8e1175bSopenharmony_ci    /*
1305a8e1175bSopenharmony_ci     * Check for overflow
1306a8e1175bSopenharmony_ci     */
1307a8e1175bSopenharmony_ci    if (0 == d || u1 >= d) {
1308a8e1175bSopenharmony_ci        if (r != NULL) {
1309a8e1175bSopenharmony_ci            *r = ~(mbedtls_mpi_uint) 0u;
1310a8e1175bSopenharmony_ci        }
1311a8e1175bSopenharmony_ci
1312a8e1175bSopenharmony_ci        return ~(mbedtls_mpi_uint) 0u;
1313a8e1175bSopenharmony_ci    }
1314a8e1175bSopenharmony_ci
1315a8e1175bSopenharmony_ci#if defined(MBEDTLS_HAVE_UDBL)
1316a8e1175bSopenharmony_ci    dividend  = (mbedtls_t_udbl) u1 << biL;
1317a8e1175bSopenharmony_ci    dividend |= (mbedtls_t_udbl) u0;
1318a8e1175bSopenharmony_ci    quotient = dividend / d;
1319a8e1175bSopenharmony_ci    if (quotient > ((mbedtls_t_udbl) 1 << biL) - 1) {
1320a8e1175bSopenharmony_ci        quotient = ((mbedtls_t_udbl) 1 << biL) - 1;
1321a8e1175bSopenharmony_ci    }
1322a8e1175bSopenharmony_ci
1323a8e1175bSopenharmony_ci    if (r != NULL) {
1324a8e1175bSopenharmony_ci        *r = (mbedtls_mpi_uint) (dividend - (quotient * d));
1325a8e1175bSopenharmony_ci    }
1326a8e1175bSopenharmony_ci
1327a8e1175bSopenharmony_ci    return (mbedtls_mpi_uint) quotient;
1328a8e1175bSopenharmony_ci#else
1329a8e1175bSopenharmony_ci
1330a8e1175bSopenharmony_ci    /*
1331a8e1175bSopenharmony_ci     * Algorithm D, Section 4.3.1 - The Art of Computer Programming
1332a8e1175bSopenharmony_ci     *   Vol. 2 - Seminumerical Algorithms, Knuth
1333a8e1175bSopenharmony_ci     */
1334a8e1175bSopenharmony_ci
1335a8e1175bSopenharmony_ci    /*
1336a8e1175bSopenharmony_ci     * Normalize the divisor, d, and dividend, u0, u1
1337a8e1175bSopenharmony_ci     */
1338a8e1175bSopenharmony_ci    s = mbedtls_mpi_core_clz(d);
1339a8e1175bSopenharmony_ci    d = d << s;
1340a8e1175bSopenharmony_ci
1341a8e1175bSopenharmony_ci    u1 = u1 << s;
1342a8e1175bSopenharmony_ci    u1 |= (u0 >> (biL - s)) & (-(mbedtls_mpi_sint) s >> (biL - 1));
1343a8e1175bSopenharmony_ci    u0 =  u0 << s;
1344a8e1175bSopenharmony_ci
1345a8e1175bSopenharmony_ci    d1 = d >> biH;
1346a8e1175bSopenharmony_ci    d0 = d & uint_halfword_mask;
1347a8e1175bSopenharmony_ci
1348a8e1175bSopenharmony_ci    u0_msw = u0 >> biH;
1349a8e1175bSopenharmony_ci    u0_lsw = u0 & uint_halfword_mask;
1350a8e1175bSopenharmony_ci
1351a8e1175bSopenharmony_ci    /*
1352a8e1175bSopenharmony_ci     * Find the first quotient and remainder
1353a8e1175bSopenharmony_ci     */
1354a8e1175bSopenharmony_ci    q1 = u1 / d1;
1355a8e1175bSopenharmony_ci    r0 = u1 - d1 * q1;
1356a8e1175bSopenharmony_ci
1357a8e1175bSopenharmony_ci    while (q1 >= radix || (q1 * d0 > radix * r0 + u0_msw)) {
1358a8e1175bSopenharmony_ci        q1 -= 1;
1359a8e1175bSopenharmony_ci        r0 += d1;
1360a8e1175bSopenharmony_ci
1361a8e1175bSopenharmony_ci        if (r0 >= radix) {
1362a8e1175bSopenharmony_ci            break;
1363a8e1175bSopenharmony_ci        }
1364a8e1175bSopenharmony_ci    }
1365a8e1175bSopenharmony_ci
1366a8e1175bSopenharmony_ci    rAX = (u1 * radix) + (u0_msw - q1 * d);
1367a8e1175bSopenharmony_ci    q0 = rAX / d1;
1368a8e1175bSopenharmony_ci    r0 = rAX - q0 * d1;
1369a8e1175bSopenharmony_ci
1370a8e1175bSopenharmony_ci    while (q0 >= radix || (q0 * d0 > radix * r0 + u0_lsw)) {
1371a8e1175bSopenharmony_ci        q0 -= 1;
1372a8e1175bSopenharmony_ci        r0 += d1;
1373a8e1175bSopenharmony_ci
1374a8e1175bSopenharmony_ci        if (r0 >= radix) {
1375a8e1175bSopenharmony_ci            break;
1376a8e1175bSopenharmony_ci        }
1377a8e1175bSopenharmony_ci    }
1378a8e1175bSopenharmony_ci
1379a8e1175bSopenharmony_ci    if (r != NULL) {
1380a8e1175bSopenharmony_ci        *r = (rAX * radix + u0_lsw - q0 * d) >> s;
1381a8e1175bSopenharmony_ci    }
1382a8e1175bSopenharmony_ci
1383a8e1175bSopenharmony_ci    quotient = q1 * radix + q0;
1384a8e1175bSopenharmony_ci
1385a8e1175bSopenharmony_ci    return quotient;
1386a8e1175bSopenharmony_ci#endif
1387a8e1175bSopenharmony_ci}
1388a8e1175bSopenharmony_ci
1389a8e1175bSopenharmony_ci/*
1390a8e1175bSopenharmony_ci * Division by mbedtls_mpi: A = Q * B + R  (HAC 14.20)
1391a8e1175bSopenharmony_ci */
1392a8e1175bSopenharmony_ciint mbedtls_mpi_div_mpi(mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A,
1393a8e1175bSopenharmony_ci                        const mbedtls_mpi *B)
1394a8e1175bSopenharmony_ci{
1395a8e1175bSopenharmony_ci    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
1396a8e1175bSopenharmony_ci    size_t i, n, t, k;
1397a8e1175bSopenharmony_ci    mbedtls_mpi X, Y, Z, T1, T2;
1398a8e1175bSopenharmony_ci    mbedtls_mpi_uint TP2[3];
1399a8e1175bSopenharmony_ci
1400a8e1175bSopenharmony_ci    if (mbedtls_mpi_cmp_int(B, 0) == 0) {
1401a8e1175bSopenharmony_ci        return MBEDTLS_ERR_MPI_DIVISION_BY_ZERO;
1402a8e1175bSopenharmony_ci    }
1403a8e1175bSopenharmony_ci
1404a8e1175bSopenharmony_ci    mbedtls_mpi_init(&X); mbedtls_mpi_init(&Y); mbedtls_mpi_init(&Z);
1405a8e1175bSopenharmony_ci    mbedtls_mpi_init(&T1);
1406a8e1175bSopenharmony_ci    /*
1407a8e1175bSopenharmony_ci     * Avoid dynamic memory allocations for constant-size T2.
1408a8e1175bSopenharmony_ci     *
1409a8e1175bSopenharmony_ci     * T2 is used for comparison only and the 3 limbs are assigned explicitly,
1410a8e1175bSopenharmony_ci     * so nobody increase the size of the MPI and we're safe to use an on-stack
1411a8e1175bSopenharmony_ci     * buffer.
1412a8e1175bSopenharmony_ci     */
1413a8e1175bSopenharmony_ci    T2.s = 1;
1414a8e1175bSopenharmony_ci    T2.n = sizeof(TP2) / sizeof(*TP2);
1415a8e1175bSopenharmony_ci    T2.p = TP2;
1416a8e1175bSopenharmony_ci
1417a8e1175bSopenharmony_ci    if (mbedtls_mpi_cmp_abs(A, B) < 0) {
1418a8e1175bSopenharmony_ci        if (Q != NULL) {
1419a8e1175bSopenharmony_ci            MBEDTLS_MPI_CHK(mbedtls_mpi_lset(Q, 0));
1420a8e1175bSopenharmony_ci        }
1421a8e1175bSopenharmony_ci        if (R != NULL) {
1422a8e1175bSopenharmony_ci            MBEDTLS_MPI_CHK(mbedtls_mpi_copy(R, A));
1423a8e1175bSopenharmony_ci        }
1424a8e1175bSopenharmony_ci        return 0;
1425a8e1175bSopenharmony_ci    }
1426a8e1175bSopenharmony_ci
1427a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&X, A));
1428a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&Y, B));
1429a8e1175bSopenharmony_ci    X.s = Y.s = 1;
1430a8e1175bSopenharmony_ci
1431a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_grow(&Z, A->n + 2));
1432a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&Z,  0));
1433a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_grow(&T1, A->n + 2));
1434a8e1175bSopenharmony_ci
1435a8e1175bSopenharmony_ci    k = mbedtls_mpi_bitlen(&Y) % biL;
1436a8e1175bSopenharmony_ci    if (k < biL - 1) {
1437a8e1175bSopenharmony_ci        k = biL - 1 - k;
1438a8e1175bSopenharmony_ci        MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&X, k));
1439a8e1175bSopenharmony_ci        MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&Y, k));
1440a8e1175bSopenharmony_ci    } else {
1441a8e1175bSopenharmony_ci        k = 0;
1442a8e1175bSopenharmony_ci    }
1443a8e1175bSopenharmony_ci
1444a8e1175bSopenharmony_ci    n = X.n - 1;
1445a8e1175bSopenharmony_ci    t = Y.n - 1;
1446a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&Y, biL * (n - t)));
1447a8e1175bSopenharmony_ci
1448a8e1175bSopenharmony_ci    while (mbedtls_mpi_cmp_mpi(&X, &Y) >= 0) {
1449a8e1175bSopenharmony_ci        Z.p[n - t]++;
1450a8e1175bSopenharmony_ci        MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&X, &X, &Y));
1451a8e1175bSopenharmony_ci    }
1452a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&Y, biL * (n - t)));
1453a8e1175bSopenharmony_ci
1454a8e1175bSopenharmony_ci    for (i = n; i > t; i--) {
1455a8e1175bSopenharmony_ci        if (X.p[i] >= Y.p[t]) {
1456a8e1175bSopenharmony_ci            Z.p[i - t - 1] = ~(mbedtls_mpi_uint) 0u;
1457a8e1175bSopenharmony_ci        } else {
1458a8e1175bSopenharmony_ci            Z.p[i - t - 1] = mbedtls_int_div_int(X.p[i], X.p[i - 1],
1459a8e1175bSopenharmony_ci                                                 Y.p[t], NULL);
1460a8e1175bSopenharmony_ci        }
1461a8e1175bSopenharmony_ci
1462a8e1175bSopenharmony_ci        T2.p[0] = (i < 2) ? 0 : X.p[i - 2];
1463a8e1175bSopenharmony_ci        T2.p[1] = (i < 1) ? 0 : X.p[i - 1];
1464a8e1175bSopenharmony_ci        T2.p[2] = X.p[i];
1465a8e1175bSopenharmony_ci
1466a8e1175bSopenharmony_ci        Z.p[i - t - 1]++;
1467a8e1175bSopenharmony_ci        do {
1468a8e1175bSopenharmony_ci            Z.p[i - t - 1]--;
1469a8e1175bSopenharmony_ci
1470a8e1175bSopenharmony_ci            MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&T1, 0));
1471a8e1175bSopenharmony_ci            T1.p[0] = (t < 1) ? 0 : Y.p[t - 1];
1472a8e1175bSopenharmony_ci            T1.p[1] = Y.p[t];
1473a8e1175bSopenharmony_ci            MBEDTLS_MPI_CHK(mbedtls_mpi_mul_int(&T1, &T1, Z.p[i - t - 1]));
1474a8e1175bSopenharmony_ci        } while (mbedtls_mpi_cmp_mpi(&T1, &T2) > 0);
1475a8e1175bSopenharmony_ci
1476a8e1175bSopenharmony_ci        MBEDTLS_MPI_CHK(mbedtls_mpi_mul_int(&T1, &Y, Z.p[i - t - 1]));
1477a8e1175bSopenharmony_ci        MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&T1,  biL * (i - t - 1)));
1478a8e1175bSopenharmony_ci        MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&X, &X, &T1));
1479a8e1175bSopenharmony_ci
1480a8e1175bSopenharmony_ci        if (mbedtls_mpi_cmp_int(&X, 0) < 0) {
1481a8e1175bSopenharmony_ci            MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&T1, &Y));
1482a8e1175bSopenharmony_ci            MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&T1, biL * (i - t - 1)));
1483a8e1175bSopenharmony_ci            MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&X, &X, &T1));
1484a8e1175bSopenharmony_ci            Z.p[i - t - 1]--;
1485a8e1175bSopenharmony_ci        }
1486a8e1175bSopenharmony_ci    }
1487a8e1175bSopenharmony_ci
1488a8e1175bSopenharmony_ci    if (Q != NULL) {
1489a8e1175bSopenharmony_ci        MBEDTLS_MPI_CHK(mbedtls_mpi_copy(Q, &Z));
1490a8e1175bSopenharmony_ci        Q->s = A->s * B->s;
1491a8e1175bSopenharmony_ci    }
1492a8e1175bSopenharmony_ci
1493a8e1175bSopenharmony_ci    if (R != NULL) {
1494a8e1175bSopenharmony_ci        MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&X, k));
1495a8e1175bSopenharmony_ci        X.s = A->s;
1496a8e1175bSopenharmony_ci        MBEDTLS_MPI_CHK(mbedtls_mpi_copy(R, &X));
1497a8e1175bSopenharmony_ci
1498a8e1175bSopenharmony_ci        if (mbedtls_mpi_cmp_int(R, 0) == 0) {
1499a8e1175bSopenharmony_ci            R->s = 1;
1500a8e1175bSopenharmony_ci        }
1501a8e1175bSopenharmony_ci    }
1502a8e1175bSopenharmony_ci
1503a8e1175bSopenharmony_cicleanup:
1504a8e1175bSopenharmony_ci
1505a8e1175bSopenharmony_ci    mbedtls_mpi_free(&X); mbedtls_mpi_free(&Y); mbedtls_mpi_free(&Z);
1506a8e1175bSopenharmony_ci    mbedtls_mpi_free(&T1);
1507a8e1175bSopenharmony_ci    mbedtls_platform_zeroize(TP2, sizeof(TP2));
1508a8e1175bSopenharmony_ci
1509a8e1175bSopenharmony_ci    return ret;
1510a8e1175bSopenharmony_ci}
1511a8e1175bSopenharmony_ci
1512a8e1175bSopenharmony_ci/*
1513a8e1175bSopenharmony_ci * Division by int: A = Q * b + R
1514a8e1175bSopenharmony_ci */
1515a8e1175bSopenharmony_ciint mbedtls_mpi_div_int(mbedtls_mpi *Q, mbedtls_mpi *R,
1516a8e1175bSopenharmony_ci                        const mbedtls_mpi *A,
1517a8e1175bSopenharmony_ci                        mbedtls_mpi_sint b)
1518a8e1175bSopenharmony_ci{
1519a8e1175bSopenharmony_ci    mbedtls_mpi B;
1520a8e1175bSopenharmony_ci    mbedtls_mpi_uint p[1];
1521a8e1175bSopenharmony_ci
1522a8e1175bSopenharmony_ci    p[0] = mpi_sint_abs(b);
1523a8e1175bSopenharmony_ci    B.s = TO_SIGN(b);
1524a8e1175bSopenharmony_ci    B.n = 1;
1525a8e1175bSopenharmony_ci    B.p = p;
1526a8e1175bSopenharmony_ci
1527a8e1175bSopenharmony_ci    return mbedtls_mpi_div_mpi(Q, R, A, &B);
1528a8e1175bSopenharmony_ci}
1529a8e1175bSopenharmony_ci
1530a8e1175bSopenharmony_ci/*
1531a8e1175bSopenharmony_ci * Modulo: R = A mod B
1532a8e1175bSopenharmony_ci */
1533a8e1175bSopenharmony_ciint mbedtls_mpi_mod_mpi(mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B)
1534a8e1175bSopenharmony_ci{
1535a8e1175bSopenharmony_ci    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
1536a8e1175bSopenharmony_ci
1537a8e1175bSopenharmony_ci    if (mbedtls_mpi_cmp_int(B, 0) < 0) {
1538a8e1175bSopenharmony_ci        return MBEDTLS_ERR_MPI_NEGATIVE_VALUE;
1539a8e1175bSopenharmony_ci    }
1540a8e1175bSopenharmony_ci
1541a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_div_mpi(NULL, R, A, B));
1542a8e1175bSopenharmony_ci
1543a8e1175bSopenharmony_ci    while (mbedtls_mpi_cmp_int(R, 0) < 0) {
1544a8e1175bSopenharmony_ci        MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(R, R, B));
1545a8e1175bSopenharmony_ci    }
1546a8e1175bSopenharmony_ci
1547a8e1175bSopenharmony_ci    while (mbedtls_mpi_cmp_mpi(R, B) >= 0) {
1548a8e1175bSopenharmony_ci        MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(R, R, B));
1549a8e1175bSopenharmony_ci    }
1550a8e1175bSopenharmony_ci
1551a8e1175bSopenharmony_cicleanup:
1552a8e1175bSopenharmony_ci
1553a8e1175bSopenharmony_ci    return ret;
1554a8e1175bSopenharmony_ci}
1555a8e1175bSopenharmony_ci
1556a8e1175bSopenharmony_ci/*
1557a8e1175bSopenharmony_ci * Modulo: r = A mod b
1558a8e1175bSopenharmony_ci */
1559a8e1175bSopenharmony_ciint mbedtls_mpi_mod_int(mbedtls_mpi_uint *r, const mbedtls_mpi *A, mbedtls_mpi_sint b)
1560a8e1175bSopenharmony_ci{
1561a8e1175bSopenharmony_ci    size_t i;
1562a8e1175bSopenharmony_ci    mbedtls_mpi_uint x, y, z;
1563a8e1175bSopenharmony_ci
1564a8e1175bSopenharmony_ci    if (b == 0) {
1565a8e1175bSopenharmony_ci        return MBEDTLS_ERR_MPI_DIVISION_BY_ZERO;
1566a8e1175bSopenharmony_ci    }
1567a8e1175bSopenharmony_ci
1568a8e1175bSopenharmony_ci    if (b < 0) {
1569a8e1175bSopenharmony_ci        return MBEDTLS_ERR_MPI_NEGATIVE_VALUE;
1570a8e1175bSopenharmony_ci    }
1571a8e1175bSopenharmony_ci
1572a8e1175bSopenharmony_ci    /*
1573a8e1175bSopenharmony_ci     * handle trivial cases
1574a8e1175bSopenharmony_ci     */
1575a8e1175bSopenharmony_ci    if (b == 1 || A->n == 0) {
1576a8e1175bSopenharmony_ci        *r = 0;
1577a8e1175bSopenharmony_ci        return 0;
1578a8e1175bSopenharmony_ci    }
1579a8e1175bSopenharmony_ci
1580a8e1175bSopenharmony_ci    if (b == 2) {
1581a8e1175bSopenharmony_ci        *r = A->p[0] & 1;
1582a8e1175bSopenharmony_ci        return 0;
1583a8e1175bSopenharmony_ci    }
1584a8e1175bSopenharmony_ci
1585a8e1175bSopenharmony_ci    /*
1586a8e1175bSopenharmony_ci     * general case
1587a8e1175bSopenharmony_ci     */
1588a8e1175bSopenharmony_ci    for (i = A->n, y = 0; i > 0; i--) {
1589a8e1175bSopenharmony_ci        x  = A->p[i - 1];
1590a8e1175bSopenharmony_ci        y  = (y << biH) | (x >> biH);
1591a8e1175bSopenharmony_ci        z  = y / b;
1592a8e1175bSopenharmony_ci        y -= z * b;
1593a8e1175bSopenharmony_ci
1594a8e1175bSopenharmony_ci        x <<= biH;
1595a8e1175bSopenharmony_ci        y  = (y << biH) | (x >> biH);
1596a8e1175bSopenharmony_ci        z  = y / b;
1597a8e1175bSopenharmony_ci        y -= z * b;
1598a8e1175bSopenharmony_ci    }
1599a8e1175bSopenharmony_ci
1600a8e1175bSopenharmony_ci    /*
1601a8e1175bSopenharmony_ci     * If A is negative, then the current y represents a negative value.
1602a8e1175bSopenharmony_ci     * Flipping it to the positive side.
1603a8e1175bSopenharmony_ci     */
1604a8e1175bSopenharmony_ci    if (A->s < 0 && y != 0) {
1605a8e1175bSopenharmony_ci        y = b - y;
1606a8e1175bSopenharmony_ci    }
1607a8e1175bSopenharmony_ci
1608a8e1175bSopenharmony_ci    *r = y;
1609a8e1175bSopenharmony_ci
1610a8e1175bSopenharmony_ci    return 0;
1611a8e1175bSopenharmony_ci}
1612a8e1175bSopenharmony_ci
1613a8e1175bSopenharmony_ciint mbedtls_mpi_exp_mod(mbedtls_mpi *X, const mbedtls_mpi *A,
1614a8e1175bSopenharmony_ci                        const mbedtls_mpi *E, const mbedtls_mpi *N,
1615a8e1175bSopenharmony_ci                        mbedtls_mpi *prec_RR)
1616a8e1175bSopenharmony_ci{
1617a8e1175bSopenharmony_ci    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
1618a8e1175bSopenharmony_ci
1619a8e1175bSopenharmony_ci    if (mbedtls_mpi_cmp_int(N, 0) <= 0 || (N->p[0] & 1) == 0) {
1620a8e1175bSopenharmony_ci        return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
1621a8e1175bSopenharmony_ci    }
1622a8e1175bSopenharmony_ci
1623a8e1175bSopenharmony_ci    if (mbedtls_mpi_cmp_int(E, 0) < 0) {
1624a8e1175bSopenharmony_ci        return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
1625a8e1175bSopenharmony_ci    }
1626a8e1175bSopenharmony_ci
1627a8e1175bSopenharmony_ci    if (mbedtls_mpi_bitlen(E) > MBEDTLS_MPI_MAX_BITS ||
1628a8e1175bSopenharmony_ci        mbedtls_mpi_bitlen(N) > MBEDTLS_MPI_MAX_BITS) {
1629a8e1175bSopenharmony_ci        return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
1630a8e1175bSopenharmony_ci    }
1631a8e1175bSopenharmony_ci
1632a8e1175bSopenharmony_ci    /*
1633a8e1175bSopenharmony_ci     * Ensure that the exponent that we are passing to the core is not NULL.
1634a8e1175bSopenharmony_ci     */
1635a8e1175bSopenharmony_ci    if (E->n == 0) {
1636a8e1175bSopenharmony_ci        ret = mbedtls_mpi_lset(X, 1);
1637a8e1175bSopenharmony_ci        return ret;
1638a8e1175bSopenharmony_ci    }
1639a8e1175bSopenharmony_ci
1640a8e1175bSopenharmony_ci    /*
1641a8e1175bSopenharmony_ci     * Allocate working memory for mbedtls_mpi_core_exp_mod()
1642a8e1175bSopenharmony_ci     */
1643a8e1175bSopenharmony_ci    size_t T_limbs = mbedtls_mpi_core_exp_mod_working_limbs(N->n, E->n);
1644a8e1175bSopenharmony_ci    mbedtls_mpi_uint *T = (mbedtls_mpi_uint *) mbedtls_calloc(T_limbs, sizeof(mbedtls_mpi_uint));
1645a8e1175bSopenharmony_ci    if (T == NULL) {
1646a8e1175bSopenharmony_ci        return MBEDTLS_ERR_MPI_ALLOC_FAILED;
1647a8e1175bSopenharmony_ci    }
1648a8e1175bSopenharmony_ci
1649a8e1175bSopenharmony_ci    mbedtls_mpi RR;
1650a8e1175bSopenharmony_ci    mbedtls_mpi_init(&RR);
1651a8e1175bSopenharmony_ci
1652a8e1175bSopenharmony_ci    /*
1653a8e1175bSopenharmony_ci     * If 1st call, pre-compute R^2 mod N
1654a8e1175bSopenharmony_ci     */
1655a8e1175bSopenharmony_ci    if (prec_RR == NULL || prec_RR->p == NULL) {
1656a8e1175bSopenharmony_ci        MBEDTLS_MPI_CHK(mbedtls_mpi_core_get_mont_r2_unsafe(&RR, N));
1657a8e1175bSopenharmony_ci
1658a8e1175bSopenharmony_ci        if (prec_RR != NULL) {
1659a8e1175bSopenharmony_ci            *prec_RR = RR;
1660a8e1175bSopenharmony_ci        }
1661a8e1175bSopenharmony_ci    } else {
1662a8e1175bSopenharmony_ci        MBEDTLS_MPI_CHK(mbedtls_mpi_grow(prec_RR, N->n));
1663a8e1175bSopenharmony_ci        RR = *prec_RR;
1664a8e1175bSopenharmony_ci    }
1665a8e1175bSopenharmony_ci
1666a8e1175bSopenharmony_ci    /*
1667a8e1175bSopenharmony_ci     * To preserve constness we need to make a copy of A. Using X for this to
1668a8e1175bSopenharmony_ci     * save memory.
1669a8e1175bSopenharmony_ci     */
1670a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_copy(X, A));
1671a8e1175bSopenharmony_ci
1672a8e1175bSopenharmony_ci    /*
1673a8e1175bSopenharmony_ci     * Compensate for negative A (and correct at the end).
1674a8e1175bSopenharmony_ci     */
1675a8e1175bSopenharmony_ci    X->s = 1;
1676a8e1175bSopenharmony_ci
1677a8e1175bSopenharmony_ci    /*
1678a8e1175bSopenharmony_ci     * Make sure that X is in a form that is safe for consumption by
1679a8e1175bSopenharmony_ci     * the core functions.
1680a8e1175bSopenharmony_ci     *
1681a8e1175bSopenharmony_ci     * - The core functions will not touch the limbs of X above N->n. The
1682a8e1175bSopenharmony_ci     *   result will be correct if those limbs are 0, which the mod call
1683a8e1175bSopenharmony_ci     *   ensures.
1684a8e1175bSopenharmony_ci     * - Also, X must have at least as many limbs as N for the calls to the
1685a8e1175bSopenharmony_ci     *   core functions.
1686a8e1175bSopenharmony_ci     */
1687a8e1175bSopenharmony_ci    if (mbedtls_mpi_cmp_mpi(X, N) >= 0) {
1688a8e1175bSopenharmony_ci        MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(X, X, N));
1689a8e1175bSopenharmony_ci    }
1690a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, N->n));
1691a8e1175bSopenharmony_ci
1692a8e1175bSopenharmony_ci    /*
1693a8e1175bSopenharmony_ci     * Convert to and from Montgomery around mbedtls_mpi_core_exp_mod().
1694a8e1175bSopenharmony_ci     */
1695a8e1175bSopenharmony_ci    {
1696a8e1175bSopenharmony_ci        mbedtls_mpi_uint mm = mbedtls_mpi_core_montmul_init(N->p);
1697a8e1175bSopenharmony_ci        mbedtls_mpi_core_to_mont_rep(X->p, X->p, N->p, N->n, mm, RR.p, T);
1698a8e1175bSopenharmony_ci        mbedtls_mpi_core_exp_mod(X->p, X->p, N->p, N->n, E->p, E->n, RR.p, T);
1699a8e1175bSopenharmony_ci        mbedtls_mpi_core_from_mont_rep(X->p, X->p, N->p, N->n, mm, T);
1700a8e1175bSopenharmony_ci    }
1701a8e1175bSopenharmony_ci
1702a8e1175bSopenharmony_ci    /*
1703a8e1175bSopenharmony_ci     * Correct for negative A.
1704a8e1175bSopenharmony_ci     */
1705a8e1175bSopenharmony_ci    if (A->s == -1 && (E->p[0] & 1) != 0) {
1706a8e1175bSopenharmony_ci        mbedtls_ct_condition_t is_x_non_zero = mbedtls_mpi_core_check_zero_ct(X->p, X->n);
1707a8e1175bSopenharmony_ci        X->s = mbedtls_ct_mpi_sign_if(is_x_non_zero, -1, 1);
1708a8e1175bSopenharmony_ci
1709a8e1175bSopenharmony_ci        MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(X, N, X));
1710a8e1175bSopenharmony_ci    }
1711a8e1175bSopenharmony_ci
1712a8e1175bSopenharmony_cicleanup:
1713a8e1175bSopenharmony_ci
1714a8e1175bSopenharmony_ci    mbedtls_mpi_zeroize_and_free(T, T_limbs);
1715a8e1175bSopenharmony_ci
1716a8e1175bSopenharmony_ci    if (prec_RR == NULL || prec_RR->p == NULL) {
1717a8e1175bSopenharmony_ci        mbedtls_mpi_free(&RR);
1718a8e1175bSopenharmony_ci    }
1719a8e1175bSopenharmony_ci
1720a8e1175bSopenharmony_ci    return ret;
1721a8e1175bSopenharmony_ci}
1722a8e1175bSopenharmony_ci
1723a8e1175bSopenharmony_ci/*
1724a8e1175bSopenharmony_ci * Greatest common divisor: G = gcd(A, B)  (HAC 14.54)
1725a8e1175bSopenharmony_ci */
1726a8e1175bSopenharmony_ciint mbedtls_mpi_gcd(mbedtls_mpi *G, const mbedtls_mpi *A, const mbedtls_mpi *B)
1727a8e1175bSopenharmony_ci{
1728a8e1175bSopenharmony_ci    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
1729a8e1175bSopenharmony_ci    size_t lz, lzt;
1730a8e1175bSopenharmony_ci    mbedtls_mpi TA, TB;
1731a8e1175bSopenharmony_ci
1732a8e1175bSopenharmony_ci    mbedtls_mpi_init(&TA); mbedtls_mpi_init(&TB);
1733a8e1175bSopenharmony_ci
1734a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TA, A));
1735a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TB, B));
1736a8e1175bSopenharmony_ci
1737a8e1175bSopenharmony_ci    lz = mbedtls_mpi_lsb(&TA);
1738a8e1175bSopenharmony_ci    lzt = mbedtls_mpi_lsb(&TB);
1739a8e1175bSopenharmony_ci
1740a8e1175bSopenharmony_ci    /* The loop below gives the correct result when A==0 but not when B==0.
1741a8e1175bSopenharmony_ci     * So have a special case for B==0. Leverage the fact that we just
1742a8e1175bSopenharmony_ci     * calculated the lsb and lsb(B)==0 iff B is odd or 0 to make the test
1743a8e1175bSopenharmony_ci     * slightly more efficient than cmp_int(). */
1744a8e1175bSopenharmony_ci    if (lzt == 0 && mbedtls_mpi_get_bit(&TB, 0) == 0) {
1745a8e1175bSopenharmony_ci        ret = mbedtls_mpi_copy(G, A);
1746a8e1175bSopenharmony_ci        goto cleanup;
1747a8e1175bSopenharmony_ci    }
1748a8e1175bSopenharmony_ci
1749a8e1175bSopenharmony_ci    if (lzt < lz) {
1750a8e1175bSopenharmony_ci        lz = lzt;
1751a8e1175bSopenharmony_ci    }
1752a8e1175bSopenharmony_ci
1753a8e1175bSopenharmony_ci    TA.s = TB.s = 1;
1754a8e1175bSopenharmony_ci
1755a8e1175bSopenharmony_ci    /* We mostly follow the procedure described in HAC 14.54, but with some
1756a8e1175bSopenharmony_ci     * minor differences:
1757a8e1175bSopenharmony_ci     * - Sequences of multiplications or divisions by 2 are grouped into a
1758a8e1175bSopenharmony_ci     *   single shift operation.
1759a8e1175bSopenharmony_ci     * - The procedure in HAC assumes that 0 < TB <= TA.
1760a8e1175bSopenharmony_ci     *     - The condition TB <= TA is not actually necessary for correctness.
1761a8e1175bSopenharmony_ci     *       TA and TB have symmetric roles except for the loop termination
1762a8e1175bSopenharmony_ci     *       condition, and the shifts at the beginning of the loop body
1763a8e1175bSopenharmony_ci     *       remove any significance from the ordering of TA vs TB before
1764a8e1175bSopenharmony_ci     *       the shifts.
1765a8e1175bSopenharmony_ci     *     - If TA = 0, the loop goes through 0 iterations and the result is
1766a8e1175bSopenharmony_ci     *       correctly TB.
1767a8e1175bSopenharmony_ci     *     - The case TB = 0 was short-circuited above.
1768a8e1175bSopenharmony_ci     *
1769a8e1175bSopenharmony_ci     * For the correctness proof below, decompose the original values of
1770a8e1175bSopenharmony_ci     * A and B as
1771a8e1175bSopenharmony_ci     *   A = sa * 2^a * A' with A'=0 or A' odd, and sa = +-1
1772a8e1175bSopenharmony_ci     *   B = sb * 2^b * B' with B'=0 or B' odd, and sb = +-1
1773a8e1175bSopenharmony_ci     * Then gcd(A, B) = 2^{min(a,b)} * gcd(A',B'),
1774a8e1175bSopenharmony_ci     * and gcd(A',B') is odd or 0.
1775a8e1175bSopenharmony_ci     *
1776a8e1175bSopenharmony_ci     * At the beginning, we have TA = |A| and TB = |B| so gcd(A,B) = gcd(TA,TB).
1777a8e1175bSopenharmony_ci     * The code maintains the following invariant:
1778a8e1175bSopenharmony_ci     *     gcd(A,B) = 2^k * gcd(TA,TB) for some k   (I)
1779a8e1175bSopenharmony_ci     */
1780a8e1175bSopenharmony_ci
1781a8e1175bSopenharmony_ci    /* Proof that the loop terminates:
1782a8e1175bSopenharmony_ci     * At each iteration, either the right-shift by 1 is made on a nonzero
1783a8e1175bSopenharmony_ci     * value and the nonnegative integer bitlen(TA) + bitlen(TB) decreases
1784a8e1175bSopenharmony_ci     * by at least 1, or the right-shift by 1 is made on zero and then
1785a8e1175bSopenharmony_ci     * TA becomes 0 which ends the loop (TB cannot be 0 if it is right-shifted
1786a8e1175bSopenharmony_ci     * since in that case TB is calculated from TB-TA with the condition TB>TA).
1787a8e1175bSopenharmony_ci     */
1788a8e1175bSopenharmony_ci    while (mbedtls_mpi_cmp_int(&TA, 0) != 0) {
1789a8e1175bSopenharmony_ci        /* Divisions by 2 preserve the invariant (I). */
1790a8e1175bSopenharmony_ci        MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TA, mbedtls_mpi_lsb(&TA)));
1791a8e1175bSopenharmony_ci        MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TB, mbedtls_mpi_lsb(&TB)));
1792a8e1175bSopenharmony_ci
1793a8e1175bSopenharmony_ci        /* Set either TA or TB to |TA-TB|/2. Since TA and TB are both odd,
1794a8e1175bSopenharmony_ci         * TA-TB is even so the division by 2 has an integer result.
1795a8e1175bSopenharmony_ci         * Invariant (I) is preserved since any odd divisor of both TA and TB
1796a8e1175bSopenharmony_ci         * also divides |TA-TB|/2, and any odd divisor of both TA and |TA-TB|/2
1797a8e1175bSopenharmony_ci         * also divides TB, and any odd divisor of both TB and |TA-TB|/2 also
1798a8e1175bSopenharmony_ci         * divides TA.
1799a8e1175bSopenharmony_ci         */
1800a8e1175bSopenharmony_ci        if (mbedtls_mpi_cmp_mpi(&TA, &TB) >= 0) {
1801a8e1175bSopenharmony_ci            MBEDTLS_MPI_CHK(mbedtls_mpi_sub_abs(&TA, &TA, &TB));
1802a8e1175bSopenharmony_ci            MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TA, 1));
1803a8e1175bSopenharmony_ci        } else {
1804a8e1175bSopenharmony_ci            MBEDTLS_MPI_CHK(mbedtls_mpi_sub_abs(&TB, &TB, &TA));
1805a8e1175bSopenharmony_ci            MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TB, 1));
1806a8e1175bSopenharmony_ci        }
1807a8e1175bSopenharmony_ci        /* Note that one of TA or TB is still odd. */
1808a8e1175bSopenharmony_ci    }
1809a8e1175bSopenharmony_ci
1810a8e1175bSopenharmony_ci    /* By invariant (I), gcd(A,B) = 2^k * gcd(TA,TB) for some k.
1811a8e1175bSopenharmony_ci     * At the loop exit, TA = 0, so gcd(TA,TB) = TB.
1812a8e1175bSopenharmony_ci     * - If there was at least one loop iteration, then one of TA or TB is odd,
1813a8e1175bSopenharmony_ci     *   and TA = 0, so TB is odd and gcd(TA,TB) = gcd(A',B'). In this case,
1814a8e1175bSopenharmony_ci     *   lz = min(a,b) so gcd(A,B) = 2^lz * TB.
1815a8e1175bSopenharmony_ci     * - If there was no loop iteration, then A was 0, and gcd(A,B) = B.
1816a8e1175bSopenharmony_ci     *   In this case, lz = 0 and B = TB so gcd(A,B) = B = 2^lz * TB as well.
1817a8e1175bSopenharmony_ci     */
1818a8e1175bSopenharmony_ci
1819a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&TB, lz));
1820a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_copy(G, &TB));
1821a8e1175bSopenharmony_ci
1822a8e1175bSopenharmony_cicleanup:
1823a8e1175bSopenharmony_ci
1824a8e1175bSopenharmony_ci    mbedtls_mpi_free(&TA); mbedtls_mpi_free(&TB);
1825a8e1175bSopenharmony_ci
1826a8e1175bSopenharmony_ci    return ret;
1827a8e1175bSopenharmony_ci}
1828a8e1175bSopenharmony_ci
1829a8e1175bSopenharmony_ci/*
1830a8e1175bSopenharmony_ci * Fill X with size bytes of random.
1831a8e1175bSopenharmony_ci * The bytes returned from the RNG are used in a specific order which
1832a8e1175bSopenharmony_ci * is suitable for deterministic ECDSA (see the specification of
1833a8e1175bSopenharmony_ci * mbedtls_mpi_random() and the implementation in mbedtls_mpi_fill_random()).
1834a8e1175bSopenharmony_ci */
1835a8e1175bSopenharmony_ciint mbedtls_mpi_fill_random(mbedtls_mpi *X, size_t size,
1836a8e1175bSopenharmony_ci                            int (*f_rng)(void *, unsigned char *, size_t),
1837a8e1175bSopenharmony_ci                            void *p_rng)
1838a8e1175bSopenharmony_ci{
1839a8e1175bSopenharmony_ci    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
1840a8e1175bSopenharmony_ci    const size_t limbs = CHARS_TO_LIMBS(size);
1841a8e1175bSopenharmony_ci
1842a8e1175bSopenharmony_ci    /* Ensure that target MPI has exactly the necessary number of limbs */
1843a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_resize_clear(X, limbs));
1844a8e1175bSopenharmony_ci    if (size == 0) {
1845a8e1175bSopenharmony_ci        return 0;
1846a8e1175bSopenharmony_ci    }
1847a8e1175bSopenharmony_ci
1848a8e1175bSopenharmony_ci    ret = mbedtls_mpi_core_fill_random(X->p, X->n, size, f_rng, p_rng);
1849a8e1175bSopenharmony_ci
1850a8e1175bSopenharmony_cicleanup:
1851a8e1175bSopenharmony_ci    return ret;
1852a8e1175bSopenharmony_ci}
1853a8e1175bSopenharmony_ci
1854a8e1175bSopenharmony_ciint mbedtls_mpi_random(mbedtls_mpi *X,
1855a8e1175bSopenharmony_ci                       mbedtls_mpi_sint min,
1856a8e1175bSopenharmony_ci                       const mbedtls_mpi *N,
1857a8e1175bSopenharmony_ci                       int (*f_rng)(void *, unsigned char *, size_t),
1858a8e1175bSopenharmony_ci                       void *p_rng)
1859a8e1175bSopenharmony_ci{
1860a8e1175bSopenharmony_ci    if (min < 0) {
1861a8e1175bSopenharmony_ci        return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
1862a8e1175bSopenharmony_ci    }
1863a8e1175bSopenharmony_ci    if (mbedtls_mpi_cmp_int(N, min) <= 0) {
1864a8e1175bSopenharmony_ci        return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
1865a8e1175bSopenharmony_ci    }
1866a8e1175bSopenharmony_ci
1867a8e1175bSopenharmony_ci    /* Ensure that target MPI has exactly the same number of limbs
1868a8e1175bSopenharmony_ci     * as the upper bound, even if the upper bound has leading zeros.
1869a8e1175bSopenharmony_ci     * This is necessary for mbedtls_mpi_core_random. */
1870a8e1175bSopenharmony_ci    int ret = mbedtls_mpi_resize_clear(X, N->n);
1871a8e1175bSopenharmony_ci    if (ret != 0) {
1872a8e1175bSopenharmony_ci        return ret;
1873a8e1175bSopenharmony_ci    }
1874a8e1175bSopenharmony_ci
1875a8e1175bSopenharmony_ci    return mbedtls_mpi_core_random(X->p, min, N->p, X->n, f_rng, p_rng);
1876a8e1175bSopenharmony_ci}
1877a8e1175bSopenharmony_ci
1878a8e1175bSopenharmony_ci/*
1879a8e1175bSopenharmony_ci * Modular inverse: X = A^-1 mod N  (HAC 14.61 / 14.64)
1880a8e1175bSopenharmony_ci */
1881a8e1175bSopenharmony_ciint mbedtls_mpi_inv_mod(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *N)
1882a8e1175bSopenharmony_ci{
1883a8e1175bSopenharmony_ci    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
1884a8e1175bSopenharmony_ci    mbedtls_mpi G, TA, TU, U1, U2, TB, TV, V1, V2;
1885a8e1175bSopenharmony_ci
1886a8e1175bSopenharmony_ci    if (mbedtls_mpi_cmp_int(N, 1) <= 0) {
1887a8e1175bSopenharmony_ci        return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
1888a8e1175bSopenharmony_ci    }
1889a8e1175bSopenharmony_ci
1890a8e1175bSopenharmony_ci    mbedtls_mpi_init(&TA); mbedtls_mpi_init(&TU); mbedtls_mpi_init(&U1); mbedtls_mpi_init(&U2);
1891a8e1175bSopenharmony_ci    mbedtls_mpi_init(&G); mbedtls_mpi_init(&TB); mbedtls_mpi_init(&TV);
1892a8e1175bSopenharmony_ci    mbedtls_mpi_init(&V1); mbedtls_mpi_init(&V2);
1893a8e1175bSopenharmony_ci
1894a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_gcd(&G, A, N));
1895a8e1175bSopenharmony_ci
1896a8e1175bSopenharmony_ci    if (mbedtls_mpi_cmp_int(&G, 1) != 0) {
1897a8e1175bSopenharmony_ci        ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
1898a8e1175bSopenharmony_ci        goto cleanup;
1899a8e1175bSopenharmony_ci    }
1900a8e1175bSopenharmony_ci
1901a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&TA, A, N));
1902a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TU, &TA));
1903a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TB, N));
1904a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TV, N));
1905a8e1175bSopenharmony_ci
1906a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&U1, 1));
1907a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&U2, 0));
1908a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&V1, 0));
1909a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&V2, 1));
1910a8e1175bSopenharmony_ci
1911a8e1175bSopenharmony_ci    do {
1912a8e1175bSopenharmony_ci        while ((TU.p[0] & 1) == 0) {
1913a8e1175bSopenharmony_ci            MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TU, 1));
1914a8e1175bSopenharmony_ci
1915a8e1175bSopenharmony_ci            if ((U1.p[0] & 1) != 0 || (U2.p[0] & 1) != 0) {
1916a8e1175bSopenharmony_ci                MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&U1, &U1, &TB));
1917a8e1175bSopenharmony_ci                MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&U2, &U2, &TA));
1918a8e1175bSopenharmony_ci            }
1919a8e1175bSopenharmony_ci
1920a8e1175bSopenharmony_ci            MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&U1, 1));
1921a8e1175bSopenharmony_ci            MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&U2, 1));
1922a8e1175bSopenharmony_ci        }
1923a8e1175bSopenharmony_ci
1924a8e1175bSopenharmony_ci        while ((TV.p[0] & 1) == 0) {
1925a8e1175bSopenharmony_ci            MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TV, 1));
1926a8e1175bSopenharmony_ci
1927a8e1175bSopenharmony_ci            if ((V1.p[0] & 1) != 0 || (V2.p[0] & 1) != 0) {
1928a8e1175bSopenharmony_ci                MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&V1, &V1, &TB));
1929a8e1175bSopenharmony_ci                MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&V2, &V2, &TA));
1930a8e1175bSopenharmony_ci            }
1931a8e1175bSopenharmony_ci
1932a8e1175bSopenharmony_ci            MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&V1, 1));
1933a8e1175bSopenharmony_ci            MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&V2, 1));
1934a8e1175bSopenharmony_ci        }
1935a8e1175bSopenharmony_ci
1936a8e1175bSopenharmony_ci        if (mbedtls_mpi_cmp_mpi(&TU, &TV) >= 0) {
1937a8e1175bSopenharmony_ci            MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&TU, &TU, &TV));
1938a8e1175bSopenharmony_ci            MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&U1, &U1, &V1));
1939a8e1175bSopenharmony_ci            MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&U2, &U2, &V2));
1940a8e1175bSopenharmony_ci        } else {
1941a8e1175bSopenharmony_ci            MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&TV, &TV, &TU));
1942a8e1175bSopenharmony_ci            MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&V1, &V1, &U1));
1943a8e1175bSopenharmony_ci            MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&V2, &V2, &U2));
1944a8e1175bSopenharmony_ci        }
1945a8e1175bSopenharmony_ci    } while (mbedtls_mpi_cmp_int(&TU, 0) != 0);
1946a8e1175bSopenharmony_ci
1947a8e1175bSopenharmony_ci    while (mbedtls_mpi_cmp_int(&V1, 0) < 0) {
1948a8e1175bSopenharmony_ci        MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&V1, &V1, N));
1949a8e1175bSopenharmony_ci    }
1950a8e1175bSopenharmony_ci
1951a8e1175bSopenharmony_ci    while (mbedtls_mpi_cmp_mpi(&V1, N) >= 0) {
1952a8e1175bSopenharmony_ci        MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&V1, &V1, N));
1953a8e1175bSopenharmony_ci    }
1954a8e1175bSopenharmony_ci
1955a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_copy(X, &V1));
1956a8e1175bSopenharmony_ci
1957a8e1175bSopenharmony_cicleanup:
1958a8e1175bSopenharmony_ci
1959a8e1175bSopenharmony_ci    mbedtls_mpi_free(&TA); mbedtls_mpi_free(&TU); mbedtls_mpi_free(&U1); mbedtls_mpi_free(&U2);
1960a8e1175bSopenharmony_ci    mbedtls_mpi_free(&G); mbedtls_mpi_free(&TB); mbedtls_mpi_free(&TV);
1961a8e1175bSopenharmony_ci    mbedtls_mpi_free(&V1); mbedtls_mpi_free(&V2);
1962a8e1175bSopenharmony_ci
1963a8e1175bSopenharmony_ci    return ret;
1964a8e1175bSopenharmony_ci}
1965a8e1175bSopenharmony_ci
1966a8e1175bSopenharmony_ci#if defined(MBEDTLS_GENPRIME)
1967a8e1175bSopenharmony_ci
1968a8e1175bSopenharmony_ci/* Gaps between primes, starting at 3. https://oeis.org/A001223 */
1969a8e1175bSopenharmony_cistatic const unsigned char small_prime_gaps[] = {
1970a8e1175bSopenharmony_ci    2, 2, 4, 2, 4, 2, 4, 6,
1971a8e1175bSopenharmony_ci    2, 6, 4, 2, 4, 6, 6, 2,
1972a8e1175bSopenharmony_ci    6, 4, 2, 6, 4, 6, 8, 4,
1973a8e1175bSopenharmony_ci    2, 4, 2, 4, 14, 4, 6, 2,
1974a8e1175bSopenharmony_ci    10, 2, 6, 6, 4, 6, 6, 2,
1975a8e1175bSopenharmony_ci    10, 2, 4, 2, 12, 12, 4, 2,
1976a8e1175bSopenharmony_ci    4, 6, 2, 10, 6, 6, 6, 2,
1977a8e1175bSopenharmony_ci    6, 4, 2, 10, 14, 4, 2, 4,
1978a8e1175bSopenharmony_ci    14, 6, 10, 2, 4, 6, 8, 6,
1979a8e1175bSopenharmony_ci    6, 4, 6, 8, 4, 8, 10, 2,
1980a8e1175bSopenharmony_ci    10, 2, 6, 4, 6, 8, 4, 2,
1981a8e1175bSopenharmony_ci    4, 12, 8, 4, 8, 4, 6, 12,
1982a8e1175bSopenharmony_ci    2, 18, 6, 10, 6, 6, 2, 6,
1983a8e1175bSopenharmony_ci    10, 6, 6, 2, 6, 6, 4, 2,
1984a8e1175bSopenharmony_ci    12, 10, 2, 4, 6, 6, 2, 12,
1985a8e1175bSopenharmony_ci    4, 6, 8, 10, 8, 10, 8, 6,
1986a8e1175bSopenharmony_ci    6, 4, 8, 6, 4, 8, 4, 14,
1987a8e1175bSopenharmony_ci    10, 12, 2, 10, 2, 4, 2, 10,
1988a8e1175bSopenharmony_ci    14, 4, 2, 4, 14, 4, 2, 4,
1989a8e1175bSopenharmony_ci    20, 4, 8, 10, 8, 4, 6, 6,
1990a8e1175bSopenharmony_ci    14, 4, 6, 6, 8, 6, /*reaches 997*/
1991a8e1175bSopenharmony_ci    0 /* the last entry is effectively unused */
1992a8e1175bSopenharmony_ci};
1993a8e1175bSopenharmony_ci
1994a8e1175bSopenharmony_ci/*
1995a8e1175bSopenharmony_ci * Small divisors test (X must be positive)
1996a8e1175bSopenharmony_ci *
1997a8e1175bSopenharmony_ci * Return values:
1998a8e1175bSopenharmony_ci * 0: no small factor (possible prime, more tests needed)
1999a8e1175bSopenharmony_ci * 1: certain prime
2000a8e1175bSopenharmony_ci * MBEDTLS_ERR_MPI_NOT_ACCEPTABLE: certain non-prime
2001a8e1175bSopenharmony_ci * other negative: error
2002a8e1175bSopenharmony_ci */
2003a8e1175bSopenharmony_cistatic int mpi_check_small_factors(const mbedtls_mpi *X)
2004a8e1175bSopenharmony_ci{
2005a8e1175bSopenharmony_ci    int ret = 0;
2006a8e1175bSopenharmony_ci    size_t i;
2007a8e1175bSopenharmony_ci    mbedtls_mpi_uint r;
2008a8e1175bSopenharmony_ci    unsigned p = 3; /* The first odd prime */
2009a8e1175bSopenharmony_ci
2010a8e1175bSopenharmony_ci    if ((X->p[0] & 1) == 0) {
2011a8e1175bSopenharmony_ci        return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2012a8e1175bSopenharmony_ci    }
2013a8e1175bSopenharmony_ci
2014a8e1175bSopenharmony_ci    for (i = 0; i < sizeof(small_prime_gaps); p += small_prime_gaps[i], i++) {
2015a8e1175bSopenharmony_ci        MBEDTLS_MPI_CHK(mbedtls_mpi_mod_int(&r, X, p));
2016a8e1175bSopenharmony_ci        if (r == 0) {
2017a8e1175bSopenharmony_ci            if (mbedtls_mpi_cmp_int(X, p) == 0) {
2018a8e1175bSopenharmony_ci                return 1;
2019a8e1175bSopenharmony_ci            } else {
2020a8e1175bSopenharmony_ci                return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2021a8e1175bSopenharmony_ci            }
2022a8e1175bSopenharmony_ci        }
2023a8e1175bSopenharmony_ci    }
2024a8e1175bSopenharmony_ci
2025a8e1175bSopenharmony_cicleanup:
2026a8e1175bSopenharmony_ci    return ret;
2027a8e1175bSopenharmony_ci}
2028a8e1175bSopenharmony_ci
2029a8e1175bSopenharmony_ci/*
2030a8e1175bSopenharmony_ci * Miller-Rabin pseudo-primality test  (HAC 4.24)
2031a8e1175bSopenharmony_ci */
2032a8e1175bSopenharmony_cistatic int mpi_miller_rabin(const mbedtls_mpi *X, size_t rounds,
2033a8e1175bSopenharmony_ci                            int (*f_rng)(void *, unsigned char *, size_t),
2034a8e1175bSopenharmony_ci                            void *p_rng)
2035a8e1175bSopenharmony_ci{
2036a8e1175bSopenharmony_ci    int ret, count;
2037a8e1175bSopenharmony_ci    size_t i, j, k, s;
2038a8e1175bSopenharmony_ci    mbedtls_mpi W, R, T, A, RR;
2039a8e1175bSopenharmony_ci
2040a8e1175bSopenharmony_ci    mbedtls_mpi_init(&W); mbedtls_mpi_init(&R);
2041a8e1175bSopenharmony_ci    mbedtls_mpi_init(&T); mbedtls_mpi_init(&A);
2042a8e1175bSopenharmony_ci    mbedtls_mpi_init(&RR);
2043a8e1175bSopenharmony_ci
2044a8e1175bSopenharmony_ci    /*
2045a8e1175bSopenharmony_ci     * W = |X| - 1
2046a8e1175bSopenharmony_ci     * R = W >> lsb( W )
2047a8e1175bSopenharmony_ci     */
2048a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(&W, X, 1));
2049a8e1175bSopenharmony_ci    s = mbedtls_mpi_lsb(&W);
2050a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&R, &W));
2051a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&R, s));
2052a8e1175bSopenharmony_ci
2053a8e1175bSopenharmony_ci    for (i = 0; i < rounds; i++) {
2054a8e1175bSopenharmony_ci        /*
2055a8e1175bSopenharmony_ci         * pick a random A, 1 < A < |X| - 1
2056a8e1175bSopenharmony_ci         */
2057a8e1175bSopenharmony_ci        count = 0;
2058a8e1175bSopenharmony_ci        do {
2059a8e1175bSopenharmony_ci            MBEDTLS_MPI_CHK(mbedtls_mpi_fill_random(&A, X->n * ciL, f_rng, p_rng));
2060a8e1175bSopenharmony_ci
2061a8e1175bSopenharmony_ci            j = mbedtls_mpi_bitlen(&A);
2062a8e1175bSopenharmony_ci            k = mbedtls_mpi_bitlen(&W);
2063a8e1175bSopenharmony_ci            if (j > k) {
2064a8e1175bSopenharmony_ci                A.p[A.n - 1] &= ((mbedtls_mpi_uint) 1 << (k - (A.n - 1) * biL - 1)) - 1;
2065a8e1175bSopenharmony_ci            }
2066a8e1175bSopenharmony_ci
2067a8e1175bSopenharmony_ci            if (count++ > 30) {
2068a8e1175bSopenharmony_ci                ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2069a8e1175bSopenharmony_ci                goto cleanup;
2070a8e1175bSopenharmony_ci            }
2071a8e1175bSopenharmony_ci
2072a8e1175bSopenharmony_ci        } while (mbedtls_mpi_cmp_mpi(&A, &W) >= 0 ||
2073a8e1175bSopenharmony_ci                 mbedtls_mpi_cmp_int(&A, 1)  <= 0);
2074a8e1175bSopenharmony_ci
2075a8e1175bSopenharmony_ci        /*
2076a8e1175bSopenharmony_ci         * A = A^R mod |X|
2077a8e1175bSopenharmony_ci         */
2078a8e1175bSopenharmony_ci        MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&A, &A, &R, X, &RR));
2079a8e1175bSopenharmony_ci
2080a8e1175bSopenharmony_ci        if (mbedtls_mpi_cmp_mpi(&A, &W) == 0 ||
2081a8e1175bSopenharmony_ci            mbedtls_mpi_cmp_int(&A,  1) == 0) {
2082a8e1175bSopenharmony_ci            continue;
2083a8e1175bSopenharmony_ci        }
2084a8e1175bSopenharmony_ci
2085a8e1175bSopenharmony_ci        j = 1;
2086a8e1175bSopenharmony_ci        while (j < s && mbedtls_mpi_cmp_mpi(&A, &W) != 0) {
2087a8e1175bSopenharmony_ci            /*
2088a8e1175bSopenharmony_ci             * A = A * A mod |X|
2089a8e1175bSopenharmony_ci             */
2090a8e1175bSopenharmony_ci            MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&T, &A, &A));
2091a8e1175bSopenharmony_ci            MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&A, &T, X));
2092a8e1175bSopenharmony_ci
2093a8e1175bSopenharmony_ci            if (mbedtls_mpi_cmp_int(&A, 1) == 0) {
2094a8e1175bSopenharmony_ci                break;
2095a8e1175bSopenharmony_ci            }
2096a8e1175bSopenharmony_ci
2097a8e1175bSopenharmony_ci            j++;
2098a8e1175bSopenharmony_ci        }
2099a8e1175bSopenharmony_ci
2100a8e1175bSopenharmony_ci        /*
2101a8e1175bSopenharmony_ci         * not prime if A != |X| - 1 or A == 1
2102a8e1175bSopenharmony_ci         */
2103a8e1175bSopenharmony_ci        if (mbedtls_mpi_cmp_mpi(&A, &W) != 0 ||
2104a8e1175bSopenharmony_ci            mbedtls_mpi_cmp_int(&A,  1) == 0) {
2105a8e1175bSopenharmony_ci            ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2106a8e1175bSopenharmony_ci            break;
2107a8e1175bSopenharmony_ci        }
2108a8e1175bSopenharmony_ci    }
2109a8e1175bSopenharmony_ci
2110a8e1175bSopenharmony_cicleanup:
2111a8e1175bSopenharmony_ci    mbedtls_mpi_free(&W); mbedtls_mpi_free(&R);
2112a8e1175bSopenharmony_ci    mbedtls_mpi_free(&T); mbedtls_mpi_free(&A);
2113a8e1175bSopenharmony_ci    mbedtls_mpi_free(&RR);
2114a8e1175bSopenharmony_ci
2115a8e1175bSopenharmony_ci    return ret;
2116a8e1175bSopenharmony_ci}
2117a8e1175bSopenharmony_ci
2118a8e1175bSopenharmony_ci/*
2119a8e1175bSopenharmony_ci * Pseudo-primality test: small factors, then Miller-Rabin
2120a8e1175bSopenharmony_ci */
2121a8e1175bSopenharmony_ciint mbedtls_mpi_is_prime_ext(const mbedtls_mpi *X, int rounds,
2122a8e1175bSopenharmony_ci                             int (*f_rng)(void *, unsigned char *, size_t),
2123a8e1175bSopenharmony_ci                             void *p_rng)
2124a8e1175bSopenharmony_ci{
2125a8e1175bSopenharmony_ci    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
2126a8e1175bSopenharmony_ci    mbedtls_mpi XX;
2127a8e1175bSopenharmony_ci
2128a8e1175bSopenharmony_ci    XX.s = 1;
2129a8e1175bSopenharmony_ci    XX.n = X->n;
2130a8e1175bSopenharmony_ci    XX.p = X->p;
2131a8e1175bSopenharmony_ci
2132a8e1175bSopenharmony_ci    if (mbedtls_mpi_cmp_int(&XX, 0) == 0 ||
2133a8e1175bSopenharmony_ci        mbedtls_mpi_cmp_int(&XX, 1) == 0) {
2134a8e1175bSopenharmony_ci        return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2135a8e1175bSopenharmony_ci    }
2136a8e1175bSopenharmony_ci
2137a8e1175bSopenharmony_ci    if (mbedtls_mpi_cmp_int(&XX, 2) == 0) {
2138a8e1175bSopenharmony_ci        return 0;
2139a8e1175bSopenharmony_ci    }
2140a8e1175bSopenharmony_ci
2141a8e1175bSopenharmony_ci    if ((ret = mpi_check_small_factors(&XX)) != 0) {
2142a8e1175bSopenharmony_ci        if (ret == 1) {
2143a8e1175bSopenharmony_ci            return 0;
2144a8e1175bSopenharmony_ci        }
2145a8e1175bSopenharmony_ci
2146a8e1175bSopenharmony_ci        return ret;
2147a8e1175bSopenharmony_ci    }
2148a8e1175bSopenharmony_ci
2149a8e1175bSopenharmony_ci    return mpi_miller_rabin(&XX, rounds, f_rng, p_rng);
2150a8e1175bSopenharmony_ci}
2151a8e1175bSopenharmony_ci
2152a8e1175bSopenharmony_ci/*
2153a8e1175bSopenharmony_ci * Prime number generation
2154a8e1175bSopenharmony_ci *
2155a8e1175bSopenharmony_ci * To generate an RSA key in a way recommended by FIPS 186-4, both primes must
2156a8e1175bSopenharmony_ci * be either 1024 bits or 1536 bits long, and flags must contain
2157a8e1175bSopenharmony_ci * MBEDTLS_MPI_GEN_PRIME_FLAG_LOW_ERR.
2158a8e1175bSopenharmony_ci */
2159a8e1175bSopenharmony_ciint mbedtls_mpi_gen_prime(mbedtls_mpi *X, size_t nbits, int flags,
2160a8e1175bSopenharmony_ci                          int (*f_rng)(void *, unsigned char *, size_t),
2161a8e1175bSopenharmony_ci                          void *p_rng)
2162a8e1175bSopenharmony_ci{
2163a8e1175bSopenharmony_ci#ifdef MBEDTLS_HAVE_INT64
2164a8e1175bSopenharmony_ci// ceil(2^63.5)
2165a8e1175bSopenharmony_ci#define CEIL_MAXUINT_DIV_SQRT2 0xb504f333f9de6485ULL
2166a8e1175bSopenharmony_ci#else
2167a8e1175bSopenharmony_ci// ceil(2^31.5)
2168a8e1175bSopenharmony_ci#define CEIL_MAXUINT_DIV_SQRT2 0xb504f334U
2169a8e1175bSopenharmony_ci#endif
2170a8e1175bSopenharmony_ci    int ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2171a8e1175bSopenharmony_ci    size_t k, n;
2172a8e1175bSopenharmony_ci    int rounds;
2173a8e1175bSopenharmony_ci    mbedtls_mpi_uint r;
2174a8e1175bSopenharmony_ci    mbedtls_mpi Y;
2175a8e1175bSopenharmony_ci
2176a8e1175bSopenharmony_ci    if (nbits < 3 || nbits > MBEDTLS_MPI_MAX_BITS) {
2177a8e1175bSopenharmony_ci        return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
2178a8e1175bSopenharmony_ci    }
2179a8e1175bSopenharmony_ci
2180a8e1175bSopenharmony_ci    mbedtls_mpi_init(&Y);
2181a8e1175bSopenharmony_ci
2182a8e1175bSopenharmony_ci    n = BITS_TO_LIMBS(nbits);
2183a8e1175bSopenharmony_ci
2184a8e1175bSopenharmony_ci    if ((flags & MBEDTLS_MPI_GEN_PRIME_FLAG_LOW_ERR) == 0) {
2185a8e1175bSopenharmony_ci        /*
2186a8e1175bSopenharmony_ci         * 2^-80 error probability, number of rounds chosen per HAC, table 4.4
2187a8e1175bSopenharmony_ci         */
2188a8e1175bSopenharmony_ci        rounds = ((nbits >= 1300) ?  2 : (nbits >=  850) ?  3 :
2189a8e1175bSopenharmony_ci                  (nbits >=  650) ?  4 : (nbits >=  350) ?  8 :
2190a8e1175bSopenharmony_ci                  (nbits >=  250) ? 12 : (nbits >=  150) ? 18 : 27);
2191a8e1175bSopenharmony_ci    } else {
2192a8e1175bSopenharmony_ci        /*
2193a8e1175bSopenharmony_ci         * 2^-100 error probability, number of rounds computed based on HAC,
2194a8e1175bSopenharmony_ci         * fact 4.48
2195a8e1175bSopenharmony_ci         */
2196a8e1175bSopenharmony_ci        rounds = ((nbits >= 1450) ?  4 : (nbits >=  1150) ?  5 :
2197a8e1175bSopenharmony_ci                  (nbits >= 1000) ?  6 : (nbits >=   850) ?  7 :
2198a8e1175bSopenharmony_ci                  (nbits >=  750) ?  8 : (nbits >=   500) ? 13 :
2199a8e1175bSopenharmony_ci                  (nbits >=  250) ? 28 : (nbits >=   150) ? 40 : 51);
2200a8e1175bSopenharmony_ci    }
2201a8e1175bSopenharmony_ci
2202a8e1175bSopenharmony_ci    while (1) {
2203a8e1175bSopenharmony_ci        MBEDTLS_MPI_CHK(mbedtls_mpi_fill_random(X, n * ciL, f_rng, p_rng));
2204a8e1175bSopenharmony_ci        /* make sure generated number is at least (nbits-1)+0.5 bits (FIPS 186-4 �B.3.3 steps 4.4, 5.5) */
2205a8e1175bSopenharmony_ci        if (X->p[n-1] < CEIL_MAXUINT_DIV_SQRT2) {
2206a8e1175bSopenharmony_ci            continue;
2207a8e1175bSopenharmony_ci        }
2208a8e1175bSopenharmony_ci
2209a8e1175bSopenharmony_ci        k = n * biL;
2210a8e1175bSopenharmony_ci        if (k > nbits) {
2211a8e1175bSopenharmony_ci            MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(X, k - nbits));
2212a8e1175bSopenharmony_ci        }
2213a8e1175bSopenharmony_ci        X->p[0] |= 1;
2214a8e1175bSopenharmony_ci
2215a8e1175bSopenharmony_ci        if ((flags & MBEDTLS_MPI_GEN_PRIME_FLAG_DH) == 0) {
2216a8e1175bSopenharmony_ci            ret = mbedtls_mpi_is_prime_ext(X, rounds, f_rng, p_rng);
2217a8e1175bSopenharmony_ci
2218a8e1175bSopenharmony_ci            if (ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE) {
2219a8e1175bSopenharmony_ci                goto cleanup;
2220a8e1175bSopenharmony_ci            }
2221a8e1175bSopenharmony_ci        } else {
2222a8e1175bSopenharmony_ci            /*
2223a8e1175bSopenharmony_ci             * A necessary condition for Y and X = 2Y + 1 to be prime
2224a8e1175bSopenharmony_ci             * is X = 2 mod 3 (which is equivalent to Y = 2 mod 3).
2225a8e1175bSopenharmony_ci             * Make sure it is satisfied, while keeping X = 3 mod 4
2226a8e1175bSopenharmony_ci             */
2227a8e1175bSopenharmony_ci
2228a8e1175bSopenharmony_ci            X->p[0] |= 2;
2229a8e1175bSopenharmony_ci
2230a8e1175bSopenharmony_ci            MBEDTLS_MPI_CHK(mbedtls_mpi_mod_int(&r, X, 3));
2231a8e1175bSopenharmony_ci            if (r == 0) {
2232a8e1175bSopenharmony_ci                MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(X, X, 8));
2233a8e1175bSopenharmony_ci            } else if (r == 1) {
2234a8e1175bSopenharmony_ci                MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(X, X, 4));
2235a8e1175bSopenharmony_ci            }
2236a8e1175bSopenharmony_ci
2237a8e1175bSopenharmony_ci            /* Set Y = (X-1) / 2, which is X / 2 because X is odd */
2238a8e1175bSopenharmony_ci            MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&Y, X));
2239a8e1175bSopenharmony_ci            MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&Y, 1));
2240a8e1175bSopenharmony_ci
2241a8e1175bSopenharmony_ci            while (1) {
2242a8e1175bSopenharmony_ci                /*
2243a8e1175bSopenharmony_ci                 * First, check small factors for X and Y
2244a8e1175bSopenharmony_ci                 * before doing Miller-Rabin on any of them
2245a8e1175bSopenharmony_ci                 */
2246a8e1175bSopenharmony_ci                if ((ret = mpi_check_small_factors(X)) == 0 &&
2247a8e1175bSopenharmony_ci                    (ret = mpi_check_small_factors(&Y)) == 0 &&
2248a8e1175bSopenharmony_ci                    (ret = mpi_miller_rabin(X, rounds, f_rng, p_rng))
2249a8e1175bSopenharmony_ci                    == 0 &&
2250a8e1175bSopenharmony_ci                    (ret = mpi_miller_rabin(&Y, rounds, f_rng, p_rng))
2251a8e1175bSopenharmony_ci                    == 0) {
2252a8e1175bSopenharmony_ci                    goto cleanup;
2253a8e1175bSopenharmony_ci                }
2254a8e1175bSopenharmony_ci
2255a8e1175bSopenharmony_ci                if (ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE) {
2256a8e1175bSopenharmony_ci                    goto cleanup;
2257a8e1175bSopenharmony_ci                }
2258a8e1175bSopenharmony_ci
2259a8e1175bSopenharmony_ci                /*
2260a8e1175bSopenharmony_ci                 * Next candidates. We want to preserve Y = (X-1) / 2 and
2261a8e1175bSopenharmony_ci                 * Y = 1 mod 2 and Y = 2 mod 3 (eq X = 3 mod 4 and X = 2 mod 3)
2262a8e1175bSopenharmony_ci                 * so up Y by 6 and X by 12.
2263a8e1175bSopenharmony_ci                 */
2264a8e1175bSopenharmony_ci                MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(X,  X, 12));
2265a8e1175bSopenharmony_ci                MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(&Y, &Y, 6));
2266a8e1175bSopenharmony_ci            }
2267a8e1175bSopenharmony_ci        }
2268a8e1175bSopenharmony_ci    }
2269a8e1175bSopenharmony_ci
2270a8e1175bSopenharmony_cicleanup:
2271a8e1175bSopenharmony_ci
2272a8e1175bSopenharmony_ci    mbedtls_mpi_free(&Y);
2273a8e1175bSopenharmony_ci
2274a8e1175bSopenharmony_ci    return ret;
2275a8e1175bSopenharmony_ci}
2276a8e1175bSopenharmony_ci
2277a8e1175bSopenharmony_ci#endif /* MBEDTLS_GENPRIME */
2278a8e1175bSopenharmony_ci
2279a8e1175bSopenharmony_ci#if defined(MBEDTLS_SELF_TEST)
2280a8e1175bSopenharmony_ci
2281a8e1175bSopenharmony_ci#define GCD_PAIR_COUNT  3
2282a8e1175bSopenharmony_ci
2283a8e1175bSopenharmony_cistatic const int gcd_pairs[GCD_PAIR_COUNT][3] =
2284a8e1175bSopenharmony_ci{
2285a8e1175bSopenharmony_ci    { 693, 609, 21 },
2286a8e1175bSopenharmony_ci    { 1764, 868, 28 },
2287a8e1175bSopenharmony_ci    { 768454923, 542167814, 1 }
2288a8e1175bSopenharmony_ci};
2289a8e1175bSopenharmony_ci
2290a8e1175bSopenharmony_ci/*
2291a8e1175bSopenharmony_ci * Checkup routine
2292a8e1175bSopenharmony_ci */
2293a8e1175bSopenharmony_ciint mbedtls_mpi_self_test(int verbose)
2294a8e1175bSopenharmony_ci{
2295a8e1175bSopenharmony_ci    int ret, i;
2296a8e1175bSopenharmony_ci    mbedtls_mpi A, E, N, X, Y, U, V;
2297a8e1175bSopenharmony_ci
2298a8e1175bSopenharmony_ci    mbedtls_mpi_init(&A); mbedtls_mpi_init(&E); mbedtls_mpi_init(&N); mbedtls_mpi_init(&X);
2299a8e1175bSopenharmony_ci    mbedtls_mpi_init(&Y); mbedtls_mpi_init(&U); mbedtls_mpi_init(&V);
2300a8e1175bSopenharmony_ci
2301a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&A, 16,
2302a8e1175bSopenharmony_ci                                            "EFE021C2645FD1DC586E69184AF4A31E" \
2303a8e1175bSopenharmony_ci                                            "D5F53E93B5F123FA41680867BA110131" \
2304a8e1175bSopenharmony_ci                                            "944FE7952E2517337780CB0DB80E61AA" \
2305a8e1175bSopenharmony_ci                                            "E7C8DDC6C5C6AADEB34EB38A2F40D5E6"));
2306a8e1175bSopenharmony_ci
2307a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&E, 16,
2308a8e1175bSopenharmony_ci                                            "B2E7EFD37075B9F03FF989C7C5051C20" \
2309a8e1175bSopenharmony_ci                                            "34D2A323810251127E7BF8625A4F49A5" \
2310a8e1175bSopenharmony_ci                                            "F3E27F4DA8BD59C47D6DAABA4C8127BD" \
2311a8e1175bSopenharmony_ci                                            "5B5C25763222FEFCCFC38B832366C29E"));
2312a8e1175bSopenharmony_ci
2313a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&N, 16,
2314a8e1175bSopenharmony_ci                                            "0066A198186C18C10B2F5ED9B522752A" \
2315a8e1175bSopenharmony_ci                                            "9830B69916E535C8F047518A889A43A5" \
2316a8e1175bSopenharmony_ci                                            "94B6BED27A168D31D4A52F88925AA8F5"));
2317a8e1175bSopenharmony_ci
2318a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&X, &A, &N));
2319a8e1175bSopenharmony_ci
2320a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&U, 16,
2321a8e1175bSopenharmony_ci                                            "602AB7ECA597A3D6B56FF9829A5E8B85" \
2322a8e1175bSopenharmony_ci                                            "9E857EA95A03512E2BAE7391688D264A" \
2323a8e1175bSopenharmony_ci                                            "A5663B0341DB9CCFD2C4C5F421FEC814" \
2324a8e1175bSopenharmony_ci                                            "8001B72E848A38CAE1C65F78E56ABDEF" \
2325a8e1175bSopenharmony_ci                                            "E12D3C039B8A02D6BE593F0BBBDA56F1" \
2326a8e1175bSopenharmony_ci                                            "ECF677152EF804370C1A305CAF3B5BF1" \
2327a8e1175bSopenharmony_ci                                            "30879B56C61DE584A0F53A2447A51E"));
2328a8e1175bSopenharmony_ci
2329a8e1175bSopenharmony_ci    if (verbose != 0) {
2330a8e1175bSopenharmony_ci        mbedtls_printf("  MPI test #1 (mul_mpi): ");
2331a8e1175bSopenharmony_ci    }
2332a8e1175bSopenharmony_ci
2333a8e1175bSopenharmony_ci    if (mbedtls_mpi_cmp_mpi(&X, &U) != 0) {
2334a8e1175bSopenharmony_ci        if (verbose != 0) {
2335a8e1175bSopenharmony_ci            mbedtls_printf("failed\n");
2336a8e1175bSopenharmony_ci        }
2337a8e1175bSopenharmony_ci
2338a8e1175bSopenharmony_ci        ret = 1;
2339a8e1175bSopenharmony_ci        goto cleanup;
2340a8e1175bSopenharmony_ci    }
2341a8e1175bSopenharmony_ci
2342a8e1175bSopenharmony_ci    if (verbose != 0) {
2343a8e1175bSopenharmony_ci        mbedtls_printf("passed\n");
2344a8e1175bSopenharmony_ci    }
2345a8e1175bSopenharmony_ci
2346a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_div_mpi(&X, &Y, &A, &N));
2347a8e1175bSopenharmony_ci
2348a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&U, 16,
2349a8e1175bSopenharmony_ci                                            "256567336059E52CAE22925474705F39A94"));
2350a8e1175bSopenharmony_ci
2351a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&V, 16,
2352a8e1175bSopenharmony_ci                                            "6613F26162223DF488E9CD48CC132C7A" \
2353a8e1175bSopenharmony_ci                                            "0AC93C701B001B092E4E5B9F73BCD27B" \
2354a8e1175bSopenharmony_ci                                            "9EE50D0657C77F374E903CDFA4C642"));
2355a8e1175bSopenharmony_ci
2356a8e1175bSopenharmony_ci    if (verbose != 0) {
2357a8e1175bSopenharmony_ci        mbedtls_printf("  MPI test #2 (div_mpi): ");
2358a8e1175bSopenharmony_ci    }
2359a8e1175bSopenharmony_ci
2360a8e1175bSopenharmony_ci    if (mbedtls_mpi_cmp_mpi(&X, &U) != 0 ||
2361a8e1175bSopenharmony_ci        mbedtls_mpi_cmp_mpi(&Y, &V) != 0) {
2362a8e1175bSopenharmony_ci        if (verbose != 0) {
2363a8e1175bSopenharmony_ci            mbedtls_printf("failed\n");
2364a8e1175bSopenharmony_ci        }
2365a8e1175bSopenharmony_ci
2366a8e1175bSopenharmony_ci        ret = 1;
2367a8e1175bSopenharmony_ci        goto cleanup;
2368a8e1175bSopenharmony_ci    }
2369a8e1175bSopenharmony_ci
2370a8e1175bSopenharmony_ci    if (verbose != 0) {
2371a8e1175bSopenharmony_ci        mbedtls_printf("passed\n");
2372a8e1175bSopenharmony_ci    }
2373a8e1175bSopenharmony_ci
2374a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&X, &A, &E, &N, NULL));
2375a8e1175bSopenharmony_ci
2376a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&U, 16,
2377a8e1175bSopenharmony_ci                                            "36E139AEA55215609D2816998ED020BB" \
2378a8e1175bSopenharmony_ci                                            "BD96C37890F65171D948E9BC7CBAA4D9" \
2379a8e1175bSopenharmony_ci                                            "325D24D6A3C12710F10A09FA08AB87"));
2380a8e1175bSopenharmony_ci
2381a8e1175bSopenharmony_ci    if (verbose != 0) {
2382a8e1175bSopenharmony_ci        mbedtls_printf("  MPI test #3 (exp_mod): ");
2383a8e1175bSopenharmony_ci    }
2384a8e1175bSopenharmony_ci
2385a8e1175bSopenharmony_ci    if (mbedtls_mpi_cmp_mpi(&X, &U) != 0) {
2386a8e1175bSopenharmony_ci        if (verbose != 0) {
2387a8e1175bSopenharmony_ci            mbedtls_printf("failed\n");
2388a8e1175bSopenharmony_ci        }
2389a8e1175bSopenharmony_ci
2390a8e1175bSopenharmony_ci        ret = 1;
2391a8e1175bSopenharmony_ci        goto cleanup;
2392a8e1175bSopenharmony_ci    }
2393a8e1175bSopenharmony_ci
2394a8e1175bSopenharmony_ci    if (verbose != 0) {
2395a8e1175bSopenharmony_ci        mbedtls_printf("passed\n");
2396a8e1175bSopenharmony_ci    }
2397a8e1175bSopenharmony_ci
2398a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_inv_mod(&X, &A, &N));
2399a8e1175bSopenharmony_ci
2400a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&U, 16,
2401a8e1175bSopenharmony_ci                                            "003A0AAEDD7E784FC07D8F9EC6E3BFD5" \
2402a8e1175bSopenharmony_ci                                            "C3DBA76456363A10869622EAC2DD84EC" \
2403a8e1175bSopenharmony_ci                                            "C5B8A74DAC4D09E03B5E0BE779F2DF61"));
2404a8e1175bSopenharmony_ci
2405a8e1175bSopenharmony_ci    if (verbose != 0) {
2406a8e1175bSopenharmony_ci        mbedtls_printf("  MPI test #4 (inv_mod): ");
2407a8e1175bSopenharmony_ci    }
2408a8e1175bSopenharmony_ci
2409a8e1175bSopenharmony_ci    if (mbedtls_mpi_cmp_mpi(&X, &U) != 0) {
2410a8e1175bSopenharmony_ci        if (verbose != 0) {
2411a8e1175bSopenharmony_ci            mbedtls_printf("failed\n");
2412a8e1175bSopenharmony_ci        }
2413a8e1175bSopenharmony_ci
2414a8e1175bSopenharmony_ci        ret = 1;
2415a8e1175bSopenharmony_ci        goto cleanup;
2416a8e1175bSopenharmony_ci    }
2417a8e1175bSopenharmony_ci
2418a8e1175bSopenharmony_ci    if (verbose != 0) {
2419a8e1175bSopenharmony_ci        mbedtls_printf("passed\n");
2420a8e1175bSopenharmony_ci    }
2421a8e1175bSopenharmony_ci
2422a8e1175bSopenharmony_ci    if (verbose != 0) {
2423a8e1175bSopenharmony_ci        mbedtls_printf("  MPI test #5 (simple gcd): ");
2424a8e1175bSopenharmony_ci    }
2425a8e1175bSopenharmony_ci
2426a8e1175bSopenharmony_ci    for (i = 0; i < GCD_PAIR_COUNT; i++) {
2427a8e1175bSopenharmony_ci        MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&X, gcd_pairs[i][0]));
2428a8e1175bSopenharmony_ci        MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&Y, gcd_pairs[i][1]));
2429a8e1175bSopenharmony_ci
2430a8e1175bSopenharmony_ci        MBEDTLS_MPI_CHK(mbedtls_mpi_gcd(&A, &X, &Y));
2431a8e1175bSopenharmony_ci
2432a8e1175bSopenharmony_ci        if (mbedtls_mpi_cmp_int(&A, gcd_pairs[i][2]) != 0) {
2433a8e1175bSopenharmony_ci            if (verbose != 0) {
2434a8e1175bSopenharmony_ci                mbedtls_printf("failed at %d\n", i);
2435a8e1175bSopenharmony_ci            }
2436a8e1175bSopenharmony_ci
2437a8e1175bSopenharmony_ci            ret = 1;
2438a8e1175bSopenharmony_ci            goto cleanup;
2439a8e1175bSopenharmony_ci        }
2440a8e1175bSopenharmony_ci    }
2441a8e1175bSopenharmony_ci
2442a8e1175bSopenharmony_ci    if (verbose != 0) {
2443a8e1175bSopenharmony_ci        mbedtls_printf("passed\n");
2444a8e1175bSopenharmony_ci    }
2445a8e1175bSopenharmony_ci
2446a8e1175bSopenharmony_cicleanup:
2447a8e1175bSopenharmony_ci
2448a8e1175bSopenharmony_ci    if (ret != 0 && verbose != 0) {
2449a8e1175bSopenharmony_ci        mbedtls_printf("Unexpected error, return code = %08X\n", (unsigned int) ret);
2450a8e1175bSopenharmony_ci    }
2451a8e1175bSopenharmony_ci
2452a8e1175bSopenharmony_ci    mbedtls_mpi_free(&A); mbedtls_mpi_free(&E); mbedtls_mpi_free(&N); mbedtls_mpi_free(&X);
2453a8e1175bSopenharmony_ci    mbedtls_mpi_free(&Y); mbedtls_mpi_free(&U); mbedtls_mpi_free(&V);
2454a8e1175bSopenharmony_ci
2455a8e1175bSopenharmony_ci    if (verbose != 0) {
2456a8e1175bSopenharmony_ci        mbedtls_printf("\n");
2457a8e1175bSopenharmony_ci    }
2458a8e1175bSopenharmony_ci
2459a8e1175bSopenharmony_ci    return ret;
2460a8e1175bSopenharmony_ci}
2461a8e1175bSopenharmony_ci
2462a8e1175bSopenharmony_ci#endif /* MBEDTLS_SELF_TEST */
2463a8e1175bSopenharmony_ci
2464a8e1175bSopenharmony_ci#endif /* MBEDTLS_BIGNUM_C */
2465