xref: /optee_os/lib/libmbedtls/mbedtls/library/bignum.c (revision 11fa71b9ddb429088f325cfda430183003ccd1db)
1c6672fdcSEdison Ai // SPDX-License-Identifier: Apache-2.0
2817466cbSJens Wiklander /*
3817466cbSJens Wiklander  *  Multi-precision integer library
4817466cbSJens Wiklander  *
5817466cbSJens Wiklander  *  Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
6817466cbSJens Wiklander  *
7817466cbSJens Wiklander  *  Licensed under the Apache License, Version 2.0 (the "License"); you may
8817466cbSJens Wiklander  *  not use this file except in compliance with the License.
9817466cbSJens Wiklander  *  You may obtain a copy of the License at
10817466cbSJens Wiklander  *
11817466cbSJens Wiklander  *  http://www.apache.org/licenses/LICENSE-2.0
12817466cbSJens Wiklander  *
13817466cbSJens Wiklander  *  Unless required by applicable law or agreed to in writing, software
14817466cbSJens Wiklander  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15817466cbSJens Wiklander  *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16817466cbSJens Wiklander  *  See the License for the specific language governing permissions and
17817466cbSJens Wiklander  *  limitations under the License.
18817466cbSJens Wiklander  *
19817466cbSJens Wiklander  *  This file is part of mbed TLS (https://tls.mbed.org)
20817466cbSJens Wiklander  */
21817466cbSJens Wiklander 
22817466cbSJens Wiklander /*
23817466cbSJens Wiklander  *  The following sources were referenced in the design of this Multi-precision
24817466cbSJens Wiklander  *  Integer library:
25817466cbSJens Wiklander  *
26817466cbSJens Wiklander  *  [1] Handbook of Applied Cryptography - 1997
27817466cbSJens Wiklander  *      Menezes, van Oorschot and Vanstone
28817466cbSJens Wiklander  *
29817466cbSJens Wiklander  *  [2] Multi-Precision Math
30817466cbSJens Wiklander  *      Tom St Denis
31817466cbSJens Wiklander  *      https://github.com/libtom/libtommath/blob/develop/tommath.pdf
32817466cbSJens Wiklander  *
33817466cbSJens Wiklander  *  [3] GNU Multi-Precision Arithmetic Library
34817466cbSJens Wiklander  *      https://gmplib.org/manual/index.html
35817466cbSJens Wiklander  *
36817466cbSJens Wiklander  */
37817466cbSJens Wiklander 
38817466cbSJens Wiklander #if !defined(MBEDTLS_CONFIG_FILE)
39817466cbSJens Wiklander #include "mbedtls/config.h"
40817466cbSJens Wiklander #else
41817466cbSJens Wiklander #include MBEDTLS_CONFIG_FILE
42817466cbSJens Wiklander #endif
43817466cbSJens Wiklander 
44817466cbSJens Wiklander #if defined(MBEDTLS_BIGNUM_C)
45817466cbSJens Wiklander 
46817466cbSJens Wiklander #include "mbedtls/bignum.h"
47817466cbSJens Wiklander #include "mbedtls/bn_mul.h"
483d3b0591SJens Wiklander #include "mbedtls/platform_util.h"
49*11fa71b9SJerome Forissier #include "mbedtls/error.h"
50817466cbSJens Wiklander 
51817466cbSJens Wiklander #include <string.h>
52817466cbSJens Wiklander 
53817466cbSJens Wiklander #if defined(MBEDTLS_PLATFORM_C)
54817466cbSJens Wiklander #include "mbedtls/platform.h"
55817466cbSJens Wiklander #else
56817466cbSJens Wiklander #include <stdio.h>
57817466cbSJens Wiklander #include <stdlib.h>
58817466cbSJens Wiklander #define mbedtls_printf     printf
59817466cbSJens Wiklander #define mbedtls_calloc    calloc
60817466cbSJens Wiklander #define mbedtls_free       free
61817466cbSJens Wiklander #endif
62817466cbSJens Wiklander 
6398bd5fe3SJens Wiklander #include <mempool.h>
64b99a4a18SJens Wiklander #include <util.h>
6598bd5fe3SJens Wiklander 
663d3b0591SJens Wiklander #define MPI_VALIDATE_RET( cond )                                       \
673d3b0591SJens Wiklander     MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_MPI_BAD_INPUT_DATA )
683d3b0591SJens Wiklander #define MPI_VALIDATE( cond )                                           \
693d3b0591SJens Wiklander     MBEDTLS_INTERNAL_VALIDATE( cond )
70817466cbSJens Wiklander 
71817466cbSJens Wiklander #define ciL    (sizeof(mbedtls_mpi_uint))         /* chars in limb  */
72817466cbSJens Wiklander #define biL    (ciL << 3)               /* bits  in limb  */
73817466cbSJens Wiklander #define biH    (ciL << 2)               /* half limb size */
74817466cbSJens Wiklander 
75817466cbSJens Wiklander #define MPI_SIZE_T_MAX  ( (size_t) -1 ) /* SIZE_T_MAX is not standard */
76817466cbSJens Wiklander 
77817466cbSJens Wiklander /*
78817466cbSJens Wiklander  * Convert between bits/chars and number of limbs
79817466cbSJens Wiklander  * Divide first in order to avoid potential overflows
80817466cbSJens Wiklander  */
81817466cbSJens Wiklander #define BITS_TO_LIMBS(i)  ( (i) / biL + ( (i) % biL != 0 ) )
82817466cbSJens Wiklander #define CHARS_TO_LIMBS(i) ( (i) / ciL + ( (i) % ciL != 0 ) )
83817466cbSJens Wiklander 
8498bd5fe3SJens Wiklander void *mbedtls_mpi_mempool;
8598bd5fe3SJens Wiklander 
863d3b0591SJens Wiklander /* Implementation that should never be optimized out by the compiler */
873d3b0591SJens Wiklander static void mbedtls_mpi_zeroize( mbedtls_mpi_uint *v, size_t n )
883d3b0591SJens Wiklander {
893d3b0591SJens Wiklander     mbedtls_platform_zeroize( v, ciL * n );
903d3b0591SJens Wiklander }
913d3b0591SJens Wiklander 
92817466cbSJens Wiklander /*
93817466cbSJens Wiklander  * Initialize one MPI
94817466cbSJens Wiklander  */
953d3b0591SJens Wiklander static void mpi_init( mbedtls_mpi *X, short use_mempool )
96817466cbSJens Wiklander {
973d3b0591SJens Wiklander     MPI_VALIDATE( X != NULL );
98817466cbSJens Wiklander 
993d3b0591SJens Wiklander     X->s = 1;
1003d3b0591SJens Wiklander     X->use_mempool = use_mempool;
1013d3b0591SJens Wiklander     X->n = 0;
1023d3b0591SJens Wiklander     X->p = NULL;
103817466cbSJens Wiklander }
104817466cbSJens Wiklander 
10598bd5fe3SJens Wiklander void mbedtls_mpi_init( mbedtls_mpi *X )
10698bd5fe3SJens Wiklander {
1073d3b0591SJens Wiklander     mpi_init( X, 0 /*use_mempool*/ );
10898bd5fe3SJens Wiklander }
10998bd5fe3SJens Wiklander 
11098bd5fe3SJens Wiklander void mbedtls_mpi_init_mempool( mbedtls_mpi *X )
11198bd5fe3SJens Wiklander {
1123d3b0591SJens Wiklander     mpi_init( X, !!mbedtls_mpi_mempool /*use_mempool*/ );
11398bd5fe3SJens Wiklander }
11498bd5fe3SJens Wiklander 
115817466cbSJens Wiklander /*
116817466cbSJens Wiklander  * Unallocate one MPI
117817466cbSJens Wiklander  */
118817466cbSJens Wiklander void mbedtls_mpi_free( mbedtls_mpi *X )
119817466cbSJens Wiklander {
120817466cbSJens Wiklander     if( X == NULL )
121817466cbSJens Wiklander         return;
122817466cbSJens Wiklander 
123817466cbSJens Wiklander     if( X->p != NULL )
124817466cbSJens Wiklander     {
125817466cbSJens Wiklander         mbedtls_mpi_zeroize( X->p, X->n );
1263d3b0591SJens Wiklander         if( X->use_mempool )
12718c5148dSJens Wiklander             mempool_free( mbedtls_mpi_mempool, X->p );
1283d3b0591SJens Wiklander         else
1293d3b0591SJens Wiklander             mbedtls_free( X->p );
130817466cbSJens Wiklander     }
131817466cbSJens Wiklander 
132817466cbSJens Wiklander     X->s = 1;
133817466cbSJens Wiklander     X->n = 0;
1343d3b0591SJens Wiklander     X->p = NULL;
135817466cbSJens Wiklander }
136817466cbSJens Wiklander 
137817466cbSJens Wiklander /*
138817466cbSJens Wiklander  * Enlarge to the specified number of limbs
139817466cbSJens Wiklander  */
140817466cbSJens Wiklander int mbedtls_mpi_grow( mbedtls_mpi *X, size_t nblimbs )
141817466cbSJens Wiklander {
142817466cbSJens Wiklander     mbedtls_mpi_uint *p;
1433d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
144817466cbSJens Wiklander 
145817466cbSJens Wiklander     if( nblimbs > MBEDTLS_MPI_MAX_LIMBS )
146817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_ALLOC_FAILED );
147817466cbSJens Wiklander 
1483d3b0591SJens Wiklander     if( X->n < nblimbs )
1493d3b0591SJens Wiklander     {
1503d3b0591SJens Wiklander         if( X->use_mempool )
1513d3b0591SJens Wiklander         {
1523d3b0591SJens Wiklander             p = mempool_alloc( mbedtls_mpi_mempool, nblimbs * ciL );
15318c5148dSJens Wiklander             if( p == NULL )
15418c5148dSJens Wiklander                 return( MBEDTLS_ERR_MPI_ALLOC_FAILED );
1553d3b0591SJens Wiklander             memset( p, 0, nblimbs * ciL );
1563d3b0591SJens Wiklander         }
1573d3b0591SJens Wiklander         else
1583d3b0591SJens Wiklander         {
1593d3b0591SJens Wiklander             p = (mbedtls_mpi_uint*)mbedtls_calloc( nblimbs, ciL );
1603d3b0591SJens Wiklander             if( p == NULL )
1613d3b0591SJens Wiklander                 return( MBEDTLS_ERR_MPI_ALLOC_FAILED );
162817466cbSJens Wiklander         }
163817466cbSJens Wiklander 
1643d3b0591SJens Wiklander         if( X->p != NULL )
1653d3b0591SJens Wiklander         {
1663d3b0591SJens Wiklander             memcpy( p, X->p, X->n * ciL );
1673d3b0591SJens Wiklander             mbedtls_mpi_zeroize( X->p, X->n );
1683d3b0591SJens Wiklander             if( X->use_mempool )
16918c5148dSJens Wiklander                 mempool_free( mbedtls_mpi_mempool, X->p);
1703d3b0591SJens Wiklander             else
1713d3b0591SJens Wiklander                 mbedtls_free( X->p );
1723d3b0591SJens Wiklander         }
17318c5148dSJens Wiklander 
17418c5148dSJens Wiklander         X->n = nblimbs;
1753d3b0591SJens Wiklander         X->p = p;
1763d3b0591SJens Wiklander     }
177817466cbSJens Wiklander 
178817466cbSJens Wiklander     return( 0 );
179817466cbSJens Wiklander }
180817466cbSJens Wiklander 
181817466cbSJens Wiklander /*
182817466cbSJens Wiklander  * Resize down as much as possible,
183817466cbSJens Wiklander  * while keeping at least the specified number of limbs
184817466cbSJens Wiklander  */
185817466cbSJens Wiklander int mbedtls_mpi_shrink( mbedtls_mpi *X, size_t nblimbs )
186817466cbSJens Wiklander {
187817466cbSJens Wiklander     mbedtls_mpi_uint *p;
188817466cbSJens Wiklander     size_t i;
1893d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
1903d3b0591SJens Wiklander 
1913d3b0591SJens Wiklander     if( nblimbs > MBEDTLS_MPI_MAX_LIMBS )
1923d3b0591SJens Wiklander         return( MBEDTLS_ERR_MPI_ALLOC_FAILED );
193817466cbSJens Wiklander 
1945b25c76aSJerome Forissier     /* Actually resize up if there are currently fewer than nblimbs limbs. */
195817466cbSJens Wiklander     if( X->n <= nblimbs )
196817466cbSJens Wiklander         return( mbedtls_mpi_grow( X, nblimbs ) );
1975b25c76aSJerome Forissier     /* After this point, then X->n > nblimbs and in particular X->n > 0. */
198817466cbSJens Wiklander 
199817466cbSJens Wiklander     for( i = X->n - 1; i > 0; i-- )
200817466cbSJens Wiklander         if( X->p[i] != 0 )
201817466cbSJens Wiklander             break;
202817466cbSJens Wiklander     i++;
203817466cbSJens Wiklander 
204817466cbSJens Wiklander     if( i < nblimbs )
205817466cbSJens Wiklander         i = nblimbs;
206817466cbSJens Wiklander 
2073d3b0591SJens Wiklander     if( X->use_mempool )
2083d3b0591SJens Wiklander     {
2093d3b0591SJens Wiklander         p = mempool_alloc( mbedtls_mpi_mempool, nblimbs * ciL );
2103d3b0591SJens Wiklander         if( p == NULL )
21198bd5fe3SJens Wiklander             return( MBEDTLS_ERR_MPI_ALLOC_FAILED );
2123d3b0591SJens Wiklander         memset( p, 0, nblimbs * ciL );
21398bd5fe3SJens Wiklander     }
2143d3b0591SJens Wiklander     else
2153d3b0591SJens Wiklander     {
2163d3b0591SJens Wiklander         p = (mbedtls_mpi_uint*)mbedtls_calloc( nblimbs, ciL );
2173d3b0591SJens Wiklander         if( p == NULL )
2183d3b0591SJens Wiklander             return( MBEDTLS_ERR_MPI_ALLOC_FAILED );
2193d3b0591SJens Wiklander     }
22018c5148dSJens Wiklander 
221817466cbSJens Wiklander     if( X->p != NULL )
222817466cbSJens Wiklander     {
223817466cbSJens Wiklander         memcpy( p, X->p, i * ciL );
224817466cbSJens Wiklander         mbedtls_mpi_zeroize( X->p, X->n );
2253d3b0591SJens Wiklander         if( X->use_mempool )
22618c5148dSJens Wiklander             mempool_free( mbedtls_mpi_mempool, X->p );
2273d3b0591SJens Wiklander         else
2283d3b0591SJens Wiklander             mbedtls_free( X->p );
229817466cbSJens Wiklander     }
230817466cbSJens Wiklander 
23118c5148dSJens Wiklander     X->n = i;
2323d3b0591SJens Wiklander     X->p = p;
233817466cbSJens Wiklander 
234817466cbSJens Wiklander     return( 0 );
235817466cbSJens Wiklander }
236817466cbSJens Wiklander 
237817466cbSJens Wiklander /*
238817466cbSJens Wiklander  * Copy the contents of Y into X
239817466cbSJens Wiklander  */
240817466cbSJens Wiklander int mbedtls_mpi_copy( mbedtls_mpi *X, const mbedtls_mpi *Y )
241817466cbSJens Wiklander {
2423d3b0591SJens Wiklander     int ret = 0;
243817466cbSJens Wiklander     size_t i;
2443d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
2453d3b0591SJens Wiklander     MPI_VALIDATE_RET( Y != NULL );
246817466cbSJens Wiklander 
247817466cbSJens Wiklander     if( X == Y )
248817466cbSJens Wiklander         return( 0 );
249817466cbSJens Wiklander 
2505b25c76aSJerome Forissier     if( Y->n == 0 )
251817466cbSJens Wiklander     {
252817466cbSJens Wiklander         mbedtls_mpi_free( X );
253817466cbSJens Wiklander         return( 0 );
254817466cbSJens Wiklander     }
255817466cbSJens Wiklander 
256817466cbSJens Wiklander     for( i = Y->n - 1; i > 0; i-- )
257817466cbSJens Wiklander         if( Y->p[i] != 0 )
258817466cbSJens Wiklander             break;
259817466cbSJens Wiklander     i++;
260817466cbSJens Wiklander 
261817466cbSJens Wiklander     X->s = Y->s;
262817466cbSJens Wiklander 
2633d3b0591SJens Wiklander     if( X->n < i )
2643d3b0591SJens Wiklander     {
265817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, i ) );
2663d3b0591SJens Wiklander     }
2673d3b0591SJens Wiklander     else
2683d3b0591SJens Wiklander     {
2693d3b0591SJens Wiklander         memset( X->p + i, 0, ( X->n - i ) * ciL );
2703d3b0591SJens Wiklander     }
271817466cbSJens Wiklander 
272817466cbSJens Wiklander     memcpy( X->p, Y->p, i * ciL );
273817466cbSJens Wiklander 
274817466cbSJens Wiklander cleanup:
275817466cbSJens Wiklander 
276817466cbSJens Wiklander     return( ret );
277817466cbSJens Wiklander }
278817466cbSJens Wiklander 
279817466cbSJens Wiklander /*
280817466cbSJens Wiklander  * Swap the contents of X and Y
281817466cbSJens Wiklander  */
282817466cbSJens Wiklander void mbedtls_mpi_swap( mbedtls_mpi *X, mbedtls_mpi *Y )
283817466cbSJens Wiklander {
284817466cbSJens Wiklander     mbedtls_mpi T;
2853d3b0591SJens Wiklander     MPI_VALIDATE( X != NULL );
2863d3b0591SJens Wiklander     MPI_VALIDATE( Y != NULL );
287817466cbSJens Wiklander 
288817466cbSJens Wiklander     memcpy( &T,  X, sizeof( mbedtls_mpi ) );
289817466cbSJens Wiklander     memcpy(  X,  Y, sizeof( mbedtls_mpi ) );
290817466cbSJens Wiklander     memcpy(  Y, &T, sizeof( mbedtls_mpi ) );
291817466cbSJens Wiklander }
292817466cbSJens Wiklander 
293817466cbSJens Wiklander /*
294817466cbSJens Wiklander  * Conditionally assign X = Y, without leaking information
295817466cbSJens Wiklander  * about whether the assignment was made or not.
296817466cbSJens Wiklander  * (Leaking information about the respective sizes of X and Y is ok however.)
297817466cbSJens Wiklander  */
298817466cbSJens Wiklander int mbedtls_mpi_safe_cond_assign( mbedtls_mpi *X, const mbedtls_mpi *Y, unsigned char assign )
299817466cbSJens Wiklander {
300817466cbSJens Wiklander     int ret = 0;
301817466cbSJens Wiklander     size_t i;
3023d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
3033d3b0591SJens Wiklander     MPI_VALIDATE_RET( Y != NULL );
304817466cbSJens Wiklander 
305817466cbSJens Wiklander     /* make sure assign is 0 or 1 in a time-constant manner */
306817466cbSJens Wiklander     assign = (assign | (unsigned char)-assign) >> 7;
307817466cbSJens Wiklander 
308817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, Y->n ) );
309817466cbSJens Wiklander 
310817466cbSJens Wiklander     X->s = X->s * ( 1 - assign ) + Y->s * assign;
311817466cbSJens Wiklander 
312817466cbSJens Wiklander     for( i = 0; i < Y->n; i++ )
313817466cbSJens Wiklander         X->p[i] = X->p[i] * ( 1 - assign ) + Y->p[i] * assign;
314817466cbSJens Wiklander 
315817466cbSJens Wiklander     for( ; i < X->n; i++ )
316817466cbSJens Wiklander         X->p[i] *= ( 1 - assign );
317817466cbSJens Wiklander 
318817466cbSJens Wiklander cleanup:
319817466cbSJens Wiklander     return( ret );
320817466cbSJens Wiklander }
321817466cbSJens Wiklander 
322817466cbSJens Wiklander /*
323817466cbSJens Wiklander  * Conditionally swap X and Y, without leaking information
324817466cbSJens Wiklander  * about whether the swap was made or not.
325817466cbSJens Wiklander  * Here it is not ok to simply swap the pointers, which whould lead to
326817466cbSJens Wiklander  * different memory access patterns when X and Y are used afterwards.
327817466cbSJens Wiklander  */
328817466cbSJens Wiklander int mbedtls_mpi_safe_cond_swap( mbedtls_mpi *X, mbedtls_mpi *Y, unsigned char swap )
329817466cbSJens Wiklander {
330817466cbSJens Wiklander     int ret, s;
331817466cbSJens Wiklander     size_t i;
332817466cbSJens Wiklander     mbedtls_mpi_uint tmp;
3333d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
3343d3b0591SJens Wiklander     MPI_VALIDATE_RET( Y != NULL );
335817466cbSJens Wiklander 
336817466cbSJens Wiklander     if( X == Y )
337817466cbSJens Wiklander         return( 0 );
338817466cbSJens Wiklander 
339817466cbSJens Wiklander     /* make sure swap is 0 or 1 in a time-constant manner */
340817466cbSJens Wiklander     swap = (swap | (unsigned char)-swap) >> 7;
341817466cbSJens Wiklander 
342817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, Y->n ) );
343817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( Y, X->n ) );
344817466cbSJens Wiklander 
345817466cbSJens Wiklander     s = X->s;
346817466cbSJens Wiklander     X->s = X->s * ( 1 - swap ) + Y->s * swap;
347817466cbSJens Wiklander     Y->s = Y->s * ( 1 - swap ) +    s * swap;
348817466cbSJens Wiklander 
349817466cbSJens Wiklander 
350817466cbSJens Wiklander     for( i = 0; i < X->n; i++ )
351817466cbSJens Wiklander     {
352817466cbSJens Wiklander         tmp = X->p[i];
353817466cbSJens Wiklander         X->p[i] = X->p[i] * ( 1 - swap ) + Y->p[i] * swap;
354817466cbSJens Wiklander         Y->p[i] = Y->p[i] * ( 1 - swap ) +     tmp * swap;
355817466cbSJens Wiklander     }
356817466cbSJens Wiklander 
357817466cbSJens Wiklander cleanup:
358817466cbSJens Wiklander     return( ret );
359817466cbSJens Wiklander }
360817466cbSJens Wiklander 
361817466cbSJens Wiklander /*
362817466cbSJens Wiklander  * Set value from integer
363817466cbSJens Wiklander  */
364817466cbSJens Wiklander int mbedtls_mpi_lset( mbedtls_mpi *X, mbedtls_mpi_sint z )
365817466cbSJens Wiklander {
366*11fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
3673d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
368817466cbSJens Wiklander 
369817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, 1 ) );
370817466cbSJens Wiklander     memset( X->p, 0, X->n * ciL );
371817466cbSJens Wiklander 
372817466cbSJens Wiklander     X->p[0] = ( z < 0 ) ? -z : z;
373817466cbSJens Wiklander     X->s    = ( z < 0 ) ? -1 : 1;
374817466cbSJens Wiklander 
375817466cbSJens Wiklander cleanup:
376817466cbSJens Wiklander 
377817466cbSJens Wiklander     return( ret );
378817466cbSJens Wiklander }
379817466cbSJens Wiklander 
380817466cbSJens Wiklander /*
381817466cbSJens Wiklander  * Get a specific bit
382817466cbSJens Wiklander  */
383817466cbSJens Wiklander int mbedtls_mpi_get_bit( const mbedtls_mpi *X, size_t pos )
384817466cbSJens Wiklander {
3853d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
3863d3b0591SJens Wiklander 
387817466cbSJens Wiklander     if( X->n * biL <= pos )
388817466cbSJens Wiklander         return( 0 );
389817466cbSJens Wiklander 
390817466cbSJens Wiklander     return( ( X->p[pos / biL] >> ( pos % biL ) ) & 0x01 );
391817466cbSJens Wiklander }
392817466cbSJens Wiklander 
3933d3b0591SJens Wiklander /* Get a specific byte, without range checks. */
3943d3b0591SJens Wiklander #define GET_BYTE( X, i )                                \
3953d3b0591SJens Wiklander     ( ( ( X )->p[( i ) / ciL] >> ( ( ( i ) % ciL ) * 8 ) ) & 0xff )
3963d3b0591SJens Wiklander 
397817466cbSJens Wiklander /*
398817466cbSJens Wiklander  * Set a bit to a specific value of 0 or 1
399817466cbSJens Wiklander  */
400817466cbSJens Wiklander int mbedtls_mpi_set_bit( mbedtls_mpi *X, size_t pos, unsigned char val )
401817466cbSJens Wiklander {
402817466cbSJens Wiklander     int ret = 0;
403817466cbSJens Wiklander     size_t off = pos / biL;
404817466cbSJens Wiklander     size_t idx = pos % biL;
4053d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
406817466cbSJens Wiklander 
407817466cbSJens Wiklander     if( val != 0 && val != 1 )
408817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
409817466cbSJens Wiklander 
410817466cbSJens Wiklander     if( X->n * biL <= pos )
411817466cbSJens Wiklander     {
412817466cbSJens Wiklander         if( val == 0 )
413817466cbSJens Wiklander             return( 0 );
414817466cbSJens Wiklander 
415817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, off + 1 ) );
416817466cbSJens Wiklander     }
417817466cbSJens Wiklander 
418817466cbSJens Wiklander     X->p[off] &= ~( (mbedtls_mpi_uint) 0x01 << idx );
419817466cbSJens Wiklander     X->p[off] |= (mbedtls_mpi_uint) val << idx;
420817466cbSJens Wiklander 
421817466cbSJens Wiklander cleanup:
422817466cbSJens Wiklander 
423817466cbSJens Wiklander     return( ret );
424817466cbSJens Wiklander }
425817466cbSJens Wiklander 
426817466cbSJens Wiklander /*
427817466cbSJens Wiklander  * Return the number of less significant zero-bits
428817466cbSJens Wiklander  */
429817466cbSJens Wiklander size_t mbedtls_mpi_lsb( const mbedtls_mpi *X )
430817466cbSJens Wiklander {
431817466cbSJens Wiklander     size_t i, j, count = 0;
4323d3b0591SJens Wiklander     MBEDTLS_INTERNAL_VALIDATE_RET( X != NULL, 0 );
433817466cbSJens Wiklander 
434817466cbSJens Wiklander     for( i = 0; i < X->n; i++ )
435817466cbSJens Wiklander         for( j = 0; j < biL; j++, count++ )
436817466cbSJens Wiklander             if( ( ( X->p[i] >> j ) & 1 ) != 0 )
437817466cbSJens Wiklander                 return( count );
438817466cbSJens Wiklander 
439817466cbSJens Wiklander     return( 0 );
440817466cbSJens Wiklander }
441817466cbSJens Wiklander 
442817466cbSJens Wiklander /*
443817466cbSJens Wiklander  * Count leading zero bits in a given integer
444817466cbSJens Wiklander  */
445817466cbSJens Wiklander static size_t mbedtls_clz( const mbedtls_mpi_uint x )
446817466cbSJens Wiklander {
447817466cbSJens Wiklander     size_t j;
448817466cbSJens Wiklander     mbedtls_mpi_uint mask = (mbedtls_mpi_uint) 1 << (biL - 1);
449817466cbSJens Wiklander 
450817466cbSJens Wiklander     for( j = 0; j < biL; j++ )
451817466cbSJens Wiklander     {
452817466cbSJens Wiklander         if( x & mask ) break;
453817466cbSJens Wiklander 
454817466cbSJens Wiklander         mask >>= 1;
455817466cbSJens Wiklander     }
456817466cbSJens Wiklander 
457817466cbSJens Wiklander     return j;
458817466cbSJens Wiklander }
459817466cbSJens Wiklander 
460817466cbSJens Wiklander /*
461817466cbSJens Wiklander  * Return the number of bits
462817466cbSJens Wiklander  */
463817466cbSJens Wiklander size_t mbedtls_mpi_bitlen( const mbedtls_mpi *X )
464817466cbSJens Wiklander {
465817466cbSJens Wiklander     size_t i, j;
466817466cbSJens Wiklander 
467817466cbSJens Wiklander     if( X->n == 0 )
468817466cbSJens Wiklander         return( 0 );
469817466cbSJens Wiklander 
470817466cbSJens Wiklander     for( i = X->n - 1; i > 0; i-- )
471817466cbSJens Wiklander         if( X->p[i] != 0 )
472817466cbSJens Wiklander             break;
473817466cbSJens Wiklander 
474817466cbSJens Wiklander     j = biL - mbedtls_clz( X->p[i] );
475817466cbSJens Wiklander 
476817466cbSJens Wiklander     return( ( i * biL ) + j );
477817466cbSJens Wiklander }
478817466cbSJens Wiklander 
479817466cbSJens Wiklander /*
480817466cbSJens Wiklander  * Return the total size in bytes
481817466cbSJens Wiklander  */
482817466cbSJens Wiklander size_t mbedtls_mpi_size( const mbedtls_mpi *X )
483817466cbSJens Wiklander {
484817466cbSJens Wiklander     return( ( mbedtls_mpi_bitlen( X ) + 7 ) >> 3 );
485817466cbSJens Wiklander }
486817466cbSJens Wiklander 
487817466cbSJens Wiklander /*
488817466cbSJens Wiklander  * Convert an ASCII character to digit value
489817466cbSJens Wiklander  */
490817466cbSJens Wiklander static int mpi_get_digit( mbedtls_mpi_uint *d, int radix, char c )
491817466cbSJens Wiklander {
492817466cbSJens Wiklander     *d = 255;
493817466cbSJens Wiklander 
494817466cbSJens Wiklander     if( c >= 0x30 && c <= 0x39 ) *d = c - 0x30;
495817466cbSJens Wiklander     if( c >= 0x41 && c <= 0x46 ) *d = c - 0x37;
496817466cbSJens Wiklander     if( c >= 0x61 && c <= 0x66 ) *d = c - 0x57;
497817466cbSJens Wiklander 
498817466cbSJens Wiklander     if( *d >= (mbedtls_mpi_uint) radix )
499817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_INVALID_CHARACTER );
500817466cbSJens Wiklander 
501817466cbSJens Wiklander     return( 0 );
502817466cbSJens Wiklander }
503817466cbSJens Wiklander 
504817466cbSJens Wiklander /*
505817466cbSJens Wiklander  * Import from an ASCII string
506817466cbSJens Wiklander  */
507817466cbSJens Wiklander int mbedtls_mpi_read_string( mbedtls_mpi *X, int radix, const char *s )
508817466cbSJens Wiklander {
509*11fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
510817466cbSJens Wiklander     size_t i, j, slen, n;
511817466cbSJens Wiklander     mbedtls_mpi_uint d;
512817466cbSJens Wiklander     mbedtls_mpi T;
5133d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
5143d3b0591SJens Wiklander     MPI_VALIDATE_RET( s != NULL );
515817466cbSJens Wiklander 
516817466cbSJens Wiklander     if( radix < 2 || radix > 16 )
517817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
518817466cbSJens Wiklander 
51998bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &T );
520817466cbSJens Wiklander 
521817466cbSJens Wiklander     slen = strlen( s );
522817466cbSJens Wiklander 
523817466cbSJens Wiklander     if( radix == 16 )
524817466cbSJens Wiklander     {
525817466cbSJens Wiklander         if( slen > MPI_SIZE_T_MAX >> 2 )
526817466cbSJens Wiklander             return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
527817466cbSJens Wiklander 
528817466cbSJens Wiklander         n = BITS_TO_LIMBS( slen << 2 );
529817466cbSJens Wiklander 
530817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, n ) );
531817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) );
532817466cbSJens Wiklander 
533817466cbSJens Wiklander         for( i = slen, j = 0; i > 0; i--, j++ )
534817466cbSJens Wiklander         {
535817466cbSJens Wiklander             if( i == 1 && s[i - 1] == '-' )
536817466cbSJens Wiklander             {
537817466cbSJens Wiklander                 X->s = -1;
538817466cbSJens Wiklander                 break;
539817466cbSJens Wiklander             }
540817466cbSJens Wiklander 
541817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mpi_get_digit( &d, radix, s[i - 1] ) );
542817466cbSJens Wiklander             X->p[j / ( 2 * ciL )] |= d << ( ( j % ( 2 * ciL ) ) << 2 );
543817466cbSJens Wiklander         }
544817466cbSJens Wiklander     }
545817466cbSJens Wiklander     else
546817466cbSJens Wiklander     {
547817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) );
548817466cbSJens Wiklander 
549817466cbSJens Wiklander         for( i = 0; i < slen; i++ )
550817466cbSJens Wiklander         {
551817466cbSJens Wiklander             if( i == 0 && s[i] == '-' )
552817466cbSJens Wiklander             {
553817466cbSJens Wiklander                 X->s = -1;
554817466cbSJens Wiklander                 continue;
555817466cbSJens Wiklander             }
556817466cbSJens Wiklander 
557817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mpi_get_digit( &d, radix, s[i] ) );
558817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &T, X, radix ) );
559817466cbSJens Wiklander 
560817466cbSJens Wiklander             if( X->s == 1 )
561817466cbSJens Wiklander             {
562817466cbSJens Wiklander                 MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, &T, d ) );
563817466cbSJens Wiklander             }
564817466cbSJens Wiklander             else
565817466cbSJens Wiklander             {
566817466cbSJens Wiklander                 MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( X, &T, d ) );
567817466cbSJens Wiklander             }
568817466cbSJens Wiklander         }
569817466cbSJens Wiklander     }
570817466cbSJens Wiklander 
571817466cbSJens Wiklander cleanup:
572817466cbSJens Wiklander 
573817466cbSJens Wiklander     mbedtls_mpi_free( &T );
574817466cbSJens Wiklander 
575817466cbSJens Wiklander     return( ret );
576817466cbSJens Wiklander }
577817466cbSJens Wiklander 
578817466cbSJens Wiklander /*
5795b25c76aSJerome Forissier  * Helper to write the digits high-order first.
580817466cbSJens Wiklander  */
5815b25c76aSJerome Forissier static int mpi_write_hlp( mbedtls_mpi *X, int radix,
5825b25c76aSJerome Forissier                           char **p, const size_t buflen )
583817466cbSJens Wiklander {
584*11fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
585817466cbSJens Wiklander     mbedtls_mpi_uint r;
5865b25c76aSJerome Forissier     size_t length = 0;
5875b25c76aSJerome Forissier     char *p_end = *p + buflen;
588817466cbSJens Wiklander 
5895b25c76aSJerome Forissier     do
5905b25c76aSJerome Forissier     {
5915b25c76aSJerome Forissier         if( length >= buflen )
5925b25c76aSJerome Forissier         {
5935b25c76aSJerome Forissier             return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL );
5945b25c76aSJerome Forissier         }
595817466cbSJens Wiklander 
596817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mod_int( &r, X, radix ) );
597817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_div_int( X, NULL, X, radix ) );
5985b25c76aSJerome Forissier         /*
5995b25c76aSJerome Forissier          * Write the residue in the current position, as an ASCII character.
6005b25c76aSJerome Forissier          */
6015b25c76aSJerome Forissier         if( r < 0xA )
6025b25c76aSJerome Forissier             *(--p_end) = (char)( '0' + r );
603817466cbSJens Wiklander         else
6045b25c76aSJerome Forissier             *(--p_end) = (char)( 'A' + ( r - 0xA ) );
6055b25c76aSJerome Forissier 
6065b25c76aSJerome Forissier         length++;
6075b25c76aSJerome Forissier     } while( mbedtls_mpi_cmp_int( X, 0 ) != 0 );
6085b25c76aSJerome Forissier 
6095b25c76aSJerome Forissier     memmove( *p, p_end, length );
6105b25c76aSJerome Forissier     *p += length;
611817466cbSJens Wiklander 
612817466cbSJens Wiklander cleanup:
613817466cbSJens Wiklander 
614817466cbSJens Wiklander     return( ret );
615817466cbSJens Wiklander }
616817466cbSJens Wiklander 
617817466cbSJens Wiklander /*
618817466cbSJens Wiklander  * Export into an ASCII string
619817466cbSJens Wiklander  */
620817466cbSJens Wiklander int mbedtls_mpi_write_string( const mbedtls_mpi *X, int radix,
621817466cbSJens Wiklander                               char *buf, size_t buflen, size_t *olen )
622817466cbSJens Wiklander {
623817466cbSJens Wiklander     int ret = 0;
624817466cbSJens Wiklander     size_t n;
625817466cbSJens Wiklander     char *p;
626817466cbSJens Wiklander     mbedtls_mpi T;
6273d3b0591SJens Wiklander     MPI_VALIDATE_RET( X    != NULL );
6283d3b0591SJens Wiklander     MPI_VALIDATE_RET( olen != NULL );
6293d3b0591SJens Wiklander     MPI_VALIDATE_RET( buflen == 0 || buf != NULL );
630817466cbSJens Wiklander 
631817466cbSJens Wiklander     if( radix < 2 || radix > 16 )
632817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
633817466cbSJens Wiklander 
6345b25c76aSJerome Forissier     n = mbedtls_mpi_bitlen( X ); /* Number of bits necessary to present `n`. */
6355b25c76aSJerome Forissier     if( radix >=  4 ) n >>= 1;   /* Number of 4-adic digits necessary to present
6365b25c76aSJerome Forissier                                   * `n`. If radix > 4, this might be a strict
6375b25c76aSJerome Forissier                                   * overapproximation of the number of
6385b25c76aSJerome Forissier                                   * radix-adic digits needed to present `n`. */
6395b25c76aSJerome Forissier     if( radix >= 16 ) n >>= 1;   /* Number of hexadecimal digits necessary to
6405b25c76aSJerome Forissier                                   * present `n`. */
6415b25c76aSJerome Forissier 
6425b25c76aSJerome Forissier     n += 1; /* Terminating null byte */
6435b25c76aSJerome Forissier     n += 1; /* Compensate for the divisions above, which round down `n`
6445b25c76aSJerome Forissier              * in case it's not even. */
6455b25c76aSJerome Forissier     n += 1; /* Potential '-'-sign. */
6465b25c76aSJerome Forissier     n += ( n & 1 ); /* Make n even to have enough space for hexadecimal writing,
6475b25c76aSJerome Forissier                      * which always uses an even number of hex-digits. */
648817466cbSJens Wiklander 
649817466cbSJens Wiklander     if( buflen < n )
650817466cbSJens Wiklander     {
651817466cbSJens Wiklander         *olen = n;
652817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL );
653817466cbSJens Wiklander     }
654817466cbSJens Wiklander 
655817466cbSJens Wiklander     p = buf;
65698bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &T );
657817466cbSJens Wiklander 
658817466cbSJens Wiklander     if( X->s == -1 )
6595b25c76aSJerome Forissier     {
660817466cbSJens Wiklander         *p++ = '-';
6615b25c76aSJerome Forissier         buflen--;
6625b25c76aSJerome Forissier     }
663817466cbSJens Wiklander 
664817466cbSJens Wiklander     if( radix == 16 )
665817466cbSJens Wiklander     {
666817466cbSJens Wiklander         int c;
667817466cbSJens Wiklander         size_t i, j, k;
668817466cbSJens Wiklander 
669817466cbSJens Wiklander         for( i = X->n, k = 0; i > 0; i-- )
670817466cbSJens Wiklander         {
671817466cbSJens Wiklander             for( j = ciL; j > 0; j-- )
672817466cbSJens Wiklander             {
673817466cbSJens Wiklander                 c = ( X->p[i - 1] >> ( ( j - 1 ) << 3) ) & 0xFF;
674817466cbSJens Wiklander 
675817466cbSJens Wiklander                 if( c == 0 && k == 0 && ( i + j ) != 2 )
676817466cbSJens Wiklander                     continue;
677817466cbSJens Wiklander 
678817466cbSJens Wiklander                 *(p++) = "0123456789ABCDEF" [c / 16];
679817466cbSJens Wiklander                 *(p++) = "0123456789ABCDEF" [c % 16];
680817466cbSJens Wiklander                 k = 1;
681817466cbSJens Wiklander             }
682817466cbSJens Wiklander         }
683817466cbSJens Wiklander     }
684817466cbSJens Wiklander     else
685817466cbSJens Wiklander     {
686817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &T, X ) );
687817466cbSJens Wiklander 
688817466cbSJens Wiklander         if( T.s == -1 )
689817466cbSJens Wiklander             T.s = 1;
690817466cbSJens Wiklander 
6915b25c76aSJerome Forissier         MBEDTLS_MPI_CHK( mpi_write_hlp( &T, radix, &p, buflen ) );
692817466cbSJens Wiklander     }
693817466cbSJens Wiklander 
694817466cbSJens Wiklander     *p++ = '\0';
695817466cbSJens Wiklander     *olen = p - buf;
696817466cbSJens Wiklander 
697817466cbSJens Wiklander cleanup:
698817466cbSJens Wiklander 
699817466cbSJens Wiklander     mbedtls_mpi_free( &T );
700817466cbSJens Wiklander 
701817466cbSJens Wiklander     return( ret );
702817466cbSJens Wiklander }
703817466cbSJens Wiklander 
704817466cbSJens Wiklander #if defined(MBEDTLS_FS_IO)
705817466cbSJens Wiklander /*
706817466cbSJens Wiklander  * Read X from an opened file
707817466cbSJens Wiklander  */
708817466cbSJens Wiklander int mbedtls_mpi_read_file( mbedtls_mpi *X, int radix, FILE *fin )
709817466cbSJens Wiklander {
710817466cbSJens Wiklander     mbedtls_mpi_uint d;
711817466cbSJens Wiklander     size_t slen;
712817466cbSJens Wiklander     char *p;
713817466cbSJens Wiklander     /*
714817466cbSJens Wiklander      * Buffer should have space for (short) label and decimal formatted MPI,
715817466cbSJens Wiklander      * newline characters and '\0'
716817466cbSJens Wiklander      */
717817466cbSJens Wiklander     char s[ MBEDTLS_MPI_RW_BUFFER_SIZE ];
718817466cbSJens Wiklander 
7193d3b0591SJens Wiklander     MPI_VALIDATE_RET( X   != NULL );
7203d3b0591SJens Wiklander     MPI_VALIDATE_RET( fin != NULL );
7213d3b0591SJens Wiklander 
7223d3b0591SJens Wiklander     if( radix < 2 || radix > 16 )
7233d3b0591SJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
7243d3b0591SJens Wiklander 
725817466cbSJens Wiklander     memset( s, 0, sizeof( s ) );
726817466cbSJens Wiklander     if( fgets( s, sizeof( s ) - 1, fin ) == NULL )
727817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_FILE_IO_ERROR );
728817466cbSJens Wiklander 
729817466cbSJens Wiklander     slen = strlen( s );
730817466cbSJens Wiklander     if( slen == sizeof( s ) - 2 )
731817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL );
732817466cbSJens Wiklander 
733817466cbSJens Wiklander     if( slen > 0 && s[slen - 1] == '\n' ) { slen--; s[slen] = '\0'; }
734817466cbSJens Wiklander     if( slen > 0 && s[slen - 1] == '\r' ) { slen--; s[slen] = '\0'; }
735817466cbSJens Wiklander 
736817466cbSJens Wiklander     p = s + slen;
737817466cbSJens Wiklander     while( p-- > s )
738817466cbSJens Wiklander         if( mpi_get_digit( &d, radix, *p ) != 0 )
739817466cbSJens Wiklander             break;
740817466cbSJens Wiklander 
741817466cbSJens Wiklander     return( mbedtls_mpi_read_string( X, radix, p + 1 ) );
742817466cbSJens Wiklander }
743817466cbSJens Wiklander 
744817466cbSJens Wiklander /*
745817466cbSJens Wiklander  * Write X into an opened file (or stdout if fout == NULL)
746817466cbSJens Wiklander  */
747817466cbSJens Wiklander int mbedtls_mpi_write_file( const char *p, const mbedtls_mpi *X, int radix, FILE *fout )
748817466cbSJens Wiklander {
749*11fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
750817466cbSJens Wiklander     size_t n, slen, plen;
751817466cbSJens Wiklander     /*
752817466cbSJens Wiklander      * Buffer should have space for (short) label and decimal formatted MPI,
753817466cbSJens Wiklander      * newline characters and '\0'
754817466cbSJens Wiklander      */
755817466cbSJens Wiklander     char s[ MBEDTLS_MPI_RW_BUFFER_SIZE ];
7563d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
7573d3b0591SJens Wiklander 
7583d3b0591SJens Wiklander     if( radix < 2 || radix > 16 )
7593d3b0591SJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
760817466cbSJens Wiklander 
761817466cbSJens Wiklander     memset( s, 0, sizeof( s ) );
762817466cbSJens Wiklander 
763817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_write_string( X, radix, s, sizeof( s ) - 2, &n ) );
764817466cbSJens Wiklander 
765817466cbSJens Wiklander     if( p == NULL ) p = "";
766817466cbSJens Wiklander 
767817466cbSJens Wiklander     plen = strlen( p );
768817466cbSJens Wiklander     slen = strlen( s );
769817466cbSJens Wiklander     s[slen++] = '\r';
770817466cbSJens Wiklander     s[slen++] = '\n';
771817466cbSJens Wiklander 
772817466cbSJens Wiklander     if( fout != NULL )
773817466cbSJens Wiklander     {
774817466cbSJens Wiklander         if( fwrite( p, 1, plen, fout ) != plen ||
775817466cbSJens Wiklander             fwrite( s, 1, slen, fout ) != slen )
776817466cbSJens Wiklander             return( MBEDTLS_ERR_MPI_FILE_IO_ERROR );
777817466cbSJens Wiklander     }
778817466cbSJens Wiklander     else
779817466cbSJens Wiklander         mbedtls_printf( "%s%s", p, s );
780817466cbSJens Wiklander 
781817466cbSJens Wiklander cleanup:
782817466cbSJens Wiklander 
783817466cbSJens Wiklander     return( ret );
784817466cbSJens Wiklander }
785817466cbSJens Wiklander #endif /* MBEDTLS_FS_IO */
786817466cbSJens Wiklander 
7875b25c76aSJerome Forissier 
7885b25c76aSJerome Forissier /* Convert a big-endian byte array aligned to the size of mbedtls_mpi_uint
7895b25c76aSJerome Forissier  * into the storage form used by mbedtls_mpi. */
7905b25c76aSJerome Forissier 
7915b25c76aSJerome Forissier static mbedtls_mpi_uint mpi_uint_bigendian_to_host_c( mbedtls_mpi_uint x )
7925b25c76aSJerome Forissier {
7935b25c76aSJerome Forissier     uint8_t i;
7945b25c76aSJerome Forissier     unsigned char *x_ptr;
7955b25c76aSJerome Forissier     mbedtls_mpi_uint tmp = 0;
7965b25c76aSJerome Forissier 
7975b25c76aSJerome Forissier     for( i = 0, x_ptr = (unsigned char*) &x; i < ciL; i++, x_ptr++ )
7985b25c76aSJerome Forissier     {
7995b25c76aSJerome Forissier         tmp <<= CHAR_BIT;
8005b25c76aSJerome Forissier         tmp |= (mbedtls_mpi_uint) *x_ptr;
8015b25c76aSJerome Forissier     }
8025b25c76aSJerome Forissier 
8035b25c76aSJerome Forissier     return( tmp );
8045b25c76aSJerome Forissier }
8055b25c76aSJerome Forissier 
8065b25c76aSJerome Forissier static mbedtls_mpi_uint mpi_uint_bigendian_to_host( mbedtls_mpi_uint x )
8075b25c76aSJerome Forissier {
8085b25c76aSJerome Forissier #if defined(__BYTE_ORDER__)
8095b25c76aSJerome Forissier 
8105b25c76aSJerome Forissier /* Nothing to do on bigendian systems. */
8115b25c76aSJerome Forissier #if ( __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ )
8125b25c76aSJerome Forissier     return( x );
8135b25c76aSJerome Forissier #endif /* __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ */
8145b25c76aSJerome Forissier 
8155b25c76aSJerome Forissier #if ( __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ )
8165b25c76aSJerome Forissier 
8175b25c76aSJerome Forissier /* For GCC and Clang, have builtins for byte swapping. */
8185b25c76aSJerome Forissier #if defined(__GNUC__) && defined(__GNUC_PREREQ)
8195b25c76aSJerome Forissier #if __GNUC_PREREQ(4,3)
8205b25c76aSJerome Forissier #define have_bswap
8215b25c76aSJerome Forissier #endif
8225b25c76aSJerome Forissier #endif
8235b25c76aSJerome Forissier 
8245b25c76aSJerome Forissier #if defined(__clang__) && defined(__has_builtin)
8255b25c76aSJerome Forissier #if __has_builtin(__builtin_bswap32)  &&                 \
8265b25c76aSJerome Forissier     __has_builtin(__builtin_bswap64)
8275b25c76aSJerome Forissier #define have_bswap
8285b25c76aSJerome Forissier #endif
8295b25c76aSJerome Forissier #endif
8305b25c76aSJerome Forissier 
8315b25c76aSJerome Forissier #if defined(have_bswap)
8325b25c76aSJerome Forissier     /* The compiler is hopefully able to statically evaluate this! */
8335b25c76aSJerome Forissier     switch( sizeof(mbedtls_mpi_uint) )
8345b25c76aSJerome Forissier     {
8355b25c76aSJerome Forissier         case 4:
8365b25c76aSJerome Forissier             return( __builtin_bswap32(x) );
8375b25c76aSJerome Forissier         case 8:
8385b25c76aSJerome Forissier             return( __builtin_bswap64(x) );
8395b25c76aSJerome Forissier     }
8405b25c76aSJerome Forissier #endif
8415b25c76aSJerome Forissier #endif /* __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ */
8425b25c76aSJerome Forissier #endif /* __BYTE_ORDER__ */
8435b25c76aSJerome Forissier 
8445b25c76aSJerome Forissier     /* Fall back to C-based reordering if we don't know the byte order
8455b25c76aSJerome Forissier      * or we couldn't use a compiler-specific builtin. */
8465b25c76aSJerome Forissier     return( mpi_uint_bigendian_to_host_c( x ) );
8475b25c76aSJerome Forissier }
8485b25c76aSJerome Forissier 
8495b25c76aSJerome Forissier static void mpi_bigendian_to_host( mbedtls_mpi_uint * const p, size_t limbs )
8505b25c76aSJerome Forissier {
8515b25c76aSJerome Forissier     mbedtls_mpi_uint *cur_limb_left;
8525b25c76aSJerome Forissier     mbedtls_mpi_uint *cur_limb_right;
8535b25c76aSJerome Forissier     if( limbs == 0 )
8545b25c76aSJerome Forissier         return;
8555b25c76aSJerome Forissier 
8565b25c76aSJerome Forissier     /*
8575b25c76aSJerome Forissier      * Traverse limbs and
8585b25c76aSJerome Forissier      * - adapt byte-order in each limb
8595b25c76aSJerome Forissier      * - swap the limbs themselves.
8605b25c76aSJerome Forissier      * For that, simultaneously traverse the limbs from left to right
8615b25c76aSJerome Forissier      * and from right to left, as long as the left index is not bigger
8625b25c76aSJerome Forissier      * than the right index (it's not a problem if limbs is odd and the
8635b25c76aSJerome Forissier      * indices coincide in the last iteration).
8645b25c76aSJerome Forissier      */
8655b25c76aSJerome Forissier     for( cur_limb_left = p, cur_limb_right = p + ( limbs - 1 );
8665b25c76aSJerome Forissier          cur_limb_left <= cur_limb_right;
8675b25c76aSJerome Forissier          cur_limb_left++, cur_limb_right-- )
8685b25c76aSJerome Forissier     {
8695b25c76aSJerome Forissier         mbedtls_mpi_uint tmp;
8705b25c76aSJerome Forissier         /* Note that if cur_limb_left == cur_limb_right,
8715b25c76aSJerome Forissier          * this code effectively swaps the bytes only once. */
8725b25c76aSJerome Forissier         tmp             = mpi_uint_bigendian_to_host( *cur_limb_left  );
8735b25c76aSJerome Forissier         *cur_limb_left  = mpi_uint_bigendian_to_host( *cur_limb_right );
8745b25c76aSJerome Forissier         *cur_limb_right = tmp;
8755b25c76aSJerome Forissier     }
8765b25c76aSJerome Forissier }
8775b25c76aSJerome Forissier 
878817466cbSJens Wiklander /*
879*11fa71b9SJerome Forissier  * Import X from unsigned binary data, little endian
880*11fa71b9SJerome Forissier  */
881*11fa71b9SJerome Forissier int mbedtls_mpi_read_binary_le( mbedtls_mpi *X,
882*11fa71b9SJerome Forissier                                 const unsigned char *buf, size_t buflen )
883*11fa71b9SJerome Forissier {
884*11fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
885*11fa71b9SJerome Forissier     size_t i;
886*11fa71b9SJerome Forissier     size_t const limbs = CHARS_TO_LIMBS( buflen );
887*11fa71b9SJerome Forissier 
888*11fa71b9SJerome Forissier     /* Ensure that target MPI has exactly the necessary number of limbs */
889*11fa71b9SJerome Forissier     if( X->n != limbs )
890*11fa71b9SJerome Forissier     {
891*11fa71b9SJerome Forissier         mbedtls_mpi_free( X );
892*11fa71b9SJerome Forissier         mbedtls_mpi_init( X );
893*11fa71b9SJerome Forissier         MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, limbs ) );
894*11fa71b9SJerome Forissier     }
895*11fa71b9SJerome Forissier 
896*11fa71b9SJerome Forissier     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) );
897*11fa71b9SJerome Forissier 
898*11fa71b9SJerome Forissier     for( i = 0; i < buflen; i++ )
899*11fa71b9SJerome Forissier         X->p[i / ciL] |= ((mbedtls_mpi_uint) buf[i]) << ((i % ciL) << 3);
900*11fa71b9SJerome Forissier 
901*11fa71b9SJerome Forissier cleanup:
902*11fa71b9SJerome Forissier 
903*11fa71b9SJerome Forissier     /*
904*11fa71b9SJerome Forissier      * This function is also used to import keys. However, wiping the buffers
905*11fa71b9SJerome Forissier      * upon failure is not necessary because failure only can happen before any
906*11fa71b9SJerome Forissier      * input is copied.
907*11fa71b9SJerome Forissier      */
908*11fa71b9SJerome Forissier     return( ret );
909*11fa71b9SJerome Forissier }
910*11fa71b9SJerome Forissier 
911*11fa71b9SJerome Forissier /*
912817466cbSJens Wiklander  * Import X from unsigned binary data, big endian
913817466cbSJens Wiklander  */
914817466cbSJens Wiklander int mbedtls_mpi_read_binary( mbedtls_mpi *X, const unsigned char *buf, size_t buflen )
915817466cbSJens Wiklander {
916*11fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
9173d3b0591SJens Wiklander     size_t const limbs    = CHARS_TO_LIMBS( buflen );
9185b25c76aSJerome Forissier     size_t const overhead = ( limbs * ciL ) - buflen;
9195b25c76aSJerome Forissier     unsigned char *Xp;
920817466cbSJens Wiklander 
9213d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
9223d3b0591SJens Wiklander     MPI_VALIDATE_RET( buflen == 0 || buf != NULL );
923817466cbSJens Wiklander 
9243d3b0591SJens Wiklander     /* Ensure that target MPI has exactly the necessary number of limbs */
9253d3b0591SJens Wiklander     if( X->n != limbs )
9263d3b0591SJens Wiklander     {
9272976273fSJens Wiklander         short use_mempool = X->use_mempool;
9282976273fSJens Wiklander 
9293d3b0591SJens Wiklander         mbedtls_mpi_free( X );
9302976273fSJens Wiklander         mpi_init( X, use_mempool );
9313d3b0591SJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, limbs ) );
9323d3b0591SJens Wiklander     }
933817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) );
934817466cbSJens Wiklander 
9355b25c76aSJerome Forissier     /* Avoid calling `memcpy` with NULL source argument,
9365b25c76aSJerome Forissier      * even if buflen is 0. */
9375b25c76aSJerome Forissier     if( buf != NULL )
9385b25c76aSJerome Forissier     {
9395b25c76aSJerome Forissier         Xp = (unsigned char*) X->p;
9405b25c76aSJerome Forissier         memcpy( Xp + overhead, buf, buflen );
9415b25c76aSJerome Forissier 
9425b25c76aSJerome Forissier         mpi_bigendian_to_host( X->p, limbs );
9435b25c76aSJerome Forissier     }
944817466cbSJens Wiklander 
945817466cbSJens Wiklander cleanup:
946817466cbSJens Wiklander 
947*11fa71b9SJerome Forissier     /*
948*11fa71b9SJerome Forissier      * This function is also used to import keys. However, wiping the buffers
949*11fa71b9SJerome Forissier      * upon failure is not necessary because failure only can happen before any
950*11fa71b9SJerome Forissier      * input is copied.
951*11fa71b9SJerome Forissier      */
952817466cbSJens Wiklander     return( ret );
953817466cbSJens Wiklander }
954817466cbSJens Wiklander 
955817466cbSJens Wiklander /*
956*11fa71b9SJerome Forissier  * Export X into unsigned binary data, little endian
957*11fa71b9SJerome Forissier  */
958*11fa71b9SJerome Forissier int mbedtls_mpi_write_binary_le( const mbedtls_mpi *X,
959*11fa71b9SJerome Forissier                                  unsigned char *buf, size_t buflen )
960*11fa71b9SJerome Forissier {
961*11fa71b9SJerome Forissier     size_t stored_bytes = X->n * ciL;
962*11fa71b9SJerome Forissier     size_t bytes_to_copy;
963*11fa71b9SJerome Forissier     size_t i;
964*11fa71b9SJerome Forissier 
965*11fa71b9SJerome Forissier     if( stored_bytes < buflen )
966*11fa71b9SJerome Forissier     {
967*11fa71b9SJerome Forissier         bytes_to_copy = stored_bytes;
968*11fa71b9SJerome Forissier     }
969*11fa71b9SJerome Forissier     else
970*11fa71b9SJerome Forissier     {
971*11fa71b9SJerome Forissier         bytes_to_copy = buflen;
972*11fa71b9SJerome Forissier 
973*11fa71b9SJerome Forissier         /* The output buffer is smaller than the allocated size of X.
974*11fa71b9SJerome Forissier          * However X may fit if its leading bytes are zero. */
975*11fa71b9SJerome Forissier         for( i = bytes_to_copy; i < stored_bytes; i++ )
976*11fa71b9SJerome Forissier         {
977*11fa71b9SJerome Forissier             if( GET_BYTE( X, i ) != 0 )
978*11fa71b9SJerome Forissier                 return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL );
979*11fa71b9SJerome Forissier         }
980*11fa71b9SJerome Forissier     }
981*11fa71b9SJerome Forissier 
982*11fa71b9SJerome Forissier     for( i = 0; i < bytes_to_copy; i++ )
983*11fa71b9SJerome Forissier         buf[i] = GET_BYTE( X, i );
984*11fa71b9SJerome Forissier 
985*11fa71b9SJerome Forissier     if( stored_bytes < buflen )
986*11fa71b9SJerome Forissier     {
987*11fa71b9SJerome Forissier         /* Write trailing 0 bytes */
988*11fa71b9SJerome Forissier         memset( buf + stored_bytes, 0, buflen - stored_bytes );
989*11fa71b9SJerome Forissier     }
990*11fa71b9SJerome Forissier 
991*11fa71b9SJerome Forissier     return( 0 );
992*11fa71b9SJerome Forissier }
993*11fa71b9SJerome Forissier 
994*11fa71b9SJerome Forissier /*
995817466cbSJens Wiklander  * Export X into unsigned binary data, big endian
996817466cbSJens Wiklander  */
9973d3b0591SJens Wiklander int mbedtls_mpi_write_binary( const mbedtls_mpi *X,
9983d3b0591SJens Wiklander                               unsigned char *buf, size_t buflen )
999817466cbSJens Wiklander {
10003d3b0591SJens Wiklander     size_t stored_bytes;
10013d3b0591SJens Wiklander     size_t bytes_to_copy;
10023d3b0591SJens Wiklander     unsigned char *p;
10033d3b0591SJens Wiklander     size_t i;
1004817466cbSJens Wiklander 
10053d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
10063d3b0591SJens Wiklander     MPI_VALIDATE_RET( buflen == 0 || buf != NULL );
1007817466cbSJens Wiklander 
10083d3b0591SJens Wiklander     stored_bytes = X->n * ciL;
10093d3b0591SJens Wiklander 
10103d3b0591SJens Wiklander     if( stored_bytes < buflen )
10113d3b0591SJens Wiklander     {
10123d3b0591SJens Wiklander         /* There is enough space in the output buffer. Write initial
10133d3b0591SJens Wiklander          * null bytes and record the position at which to start
10143d3b0591SJens Wiklander          * writing the significant bytes. In this case, the execution
10153d3b0591SJens Wiklander          * trace of this function does not depend on the value of the
10163d3b0591SJens Wiklander          * number. */
10173d3b0591SJens Wiklander         bytes_to_copy = stored_bytes;
10183d3b0591SJens Wiklander         p = buf + buflen - stored_bytes;
10193d3b0591SJens Wiklander         memset( buf, 0, buflen - stored_bytes );
10203d3b0591SJens Wiklander     }
10213d3b0591SJens Wiklander     else
10223d3b0591SJens Wiklander     {
10233d3b0591SJens Wiklander         /* The output buffer is smaller than the allocated size of X.
10243d3b0591SJens Wiklander          * However X may fit if its leading bytes are zero. */
10253d3b0591SJens Wiklander         bytes_to_copy = buflen;
10263d3b0591SJens Wiklander         p = buf;
10273d3b0591SJens Wiklander         for( i = bytes_to_copy; i < stored_bytes; i++ )
10283d3b0591SJens Wiklander         {
10293d3b0591SJens Wiklander             if( GET_BYTE( X, i ) != 0 )
1030817466cbSJens Wiklander                 return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL );
10313d3b0591SJens Wiklander         }
10323d3b0591SJens Wiklander     }
1033817466cbSJens Wiklander 
10343d3b0591SJens Wiklander     for( i = 0; i < bytes_to_copy; i++ )
10353d3b0591SJens Wiklander         p[bytes_to_copy - i - 1] = GET_BYTE( X, i );
1036817466cbSJens Wiklander 
1037817466cbSJens Wiklander     return( 0 );
1038817466cbSJens Wiklander }
1039817466cbSJens Wiklander 
1040817466cbSJens Wiklander /*
1041817466cbSJens Wiklander  * Left-shift: X <<= count
1042817466cbSJens Wiklander  */
1043817466cbSJens Wiklander int mbedtls_mpi_shift_l( mbedtls_mpi *X, size_t count )
1044817466cbSJens Wiklander {
1045*11fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
1046817466cbSJens Wiklander     size_t i, v0, t1;
1047817466cbSJens Wiklander     mbedtls_mpi_uint r0 = 0, r1;
10483d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
1049817466cbSJens Wiklander 
1050817466cbSJens Wiklander     v0 = count / (biL    );
1051817466cbSJens Wiklander     t1 = count & (biL - 1);
1052817466cbSJens Wiklander 
1053817466cbSJens Wiklander     i = mbedtls_mpi_bitlen( X ) + count;
1054817466cbSJens Wiklander 
1055817466cbSJens Wiklander     if( X->n * biL < i )
1056817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, BITS_TO_LIMBS( i ) ) );
1057817466cbSJens Wiklander 
1058817466cbSJens Wiklander     ret = 0;
1059817466cbSJens Wiklander 
1060817466cbSJens Wiklander     /*
1061817466cbSJens Wiklander      * shift by count / limb_size
1062817466cbSJens Wiklander      */
1063817466cbSJens Wiklander     if( v0 > 0 )
1064817466cbSJens Wiklander     {
1065817466cbSJens Wiklander         for( i = X->n; i > v0; i-- )
1066817466cbSJens Wiklander             X->p[i - 1] = X->p[i - v0 - 1];
1067817466cbSJens Wiklander 
1068817466cbSJens Wiklander         for( ; i > 0; i-- )
1069817466cbSJens Wiklander             X->p[i - 1] = 0;
1070817466cbSJens Wiklander     }
1071817466cbSJens Wiklander 
1072817466cbSJens Wiklander     /*
1073817466cbSJens Wiklander      * shift by count % limb_size
1074817466cbSJens Wiklander      */
1075817466cbSJens Wiklander     if( t1 > 0 )
1076817466cbSJens Wiklander     {
1077817466cbSJens Wiklander         for( i = v0; i < X->n; i++ )
1078817466cbSJens Wiklander         {
1079817466cbSJens Wiklander             r1 = X->p[i] >> (biL - t1);
1080817466cbSJens Wiklander             X->p[i] <<= t1;
1081817466cbSJens Wiklander             X->p[i] |= r0;
1082817466cbSJens Wiklander             r0 = r1;
1083817466cbSJens Wiklander         }
1084817466cbSJens Wiklander     }
1085817466cbSJens Wiklander 
1086817466cbSJens Wiklander cleanup:
1087817466cbSJens Wiklander 
1088817466cbSJens Wiklander     return( ret );
1089817466cbSJens Wiklander }
1090817466cbSJens Wiklander 
1091817466cbSJens Wiklander /*
1092817466cbSJens Wiklander  * Right-shift: X >>= count
1093817466cbSJens Wiklander  */
1094817466cbSJens Wiklander int mbedtls_mpi_shift_r( mbedtls_mpi *X, size_t count )
1095817466cbSJens Wiklander {
1096817466cbSJens Wiklander     size_t i, v0, v1;
1097817466cbSJens Wiklander     mbedtls_mpi_uint r0 = 0, r1;
10983d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
1099817466cbSJens Wiklander 
1100817466cbSJens Wiklander     v0 = count /  biL;
1101817466cbSJens Wiklander     v1 = count & (biL - 1);
1102817466cbSJens Wiklander 
1103817466cbSJens Wiklander     if( v0 > X->n || ( v0 == X->n && v1 > 0 ) )
1104817466cbSJens Wiklander         return mbedtls_mpi_lset( X, 0 );
1105817466cbSJens Wiklander 
1106817466cbSJens Wiklander     /*
1107817466cbSJens Wiklander      * shift by count / limb_size
1108817466cbSJens Wiklander      */
1109817466cbSJens Wiklander     if( v0 > 0 )
1110817466cbSJens Wiklander     {
1111817466cbSJens Wiklander         for( i = 0; i < X->n - v0; i++ )
1112817466cbSJens Wiklander             X->p[i] = X->p[i + v0];
1113817466cbSJens Wiklander 
1114817466cbSJens Wiklander         for( ; i < X->n; i++ )
1115817466cbSJens Wiklander             X->p[i] = 0;
1116817466cbSJens Wiklander     }
1117817466cbSJens Wiklander 
1118817466cbSJens Wiklander     /*
1119817466cbSJens Wiklander      * shift by count % limb_size
1120817466cbSJens Wiklander      */
1121817466cbSJens Wiklander     if( v1 > 0 )
1122817466cbSJens Wiklander     {
1123817466cbSJens Wiklander         for( i = X->n; i > 0; i-- )
1124817466cbSJens Wiklander         {
1125817466cbSJens Wiklander             r1 = X->p[i - 1] << (biL - v1);
1126817466cbSJens Wiklander             X->p[i - 1] >>= v1;
1127817466cbSJens Wiklander             X->p[i - 1] |= r0;
1128817466cbSJens Wiklander             r0 = r1;
1129817466cbSJens Wiklander         }
1130817466cbSJens Wiklander     }
1131817466cbSJens Wiklander 
1132817466cbSJens Wiklander     return( 0 );
1133817466cbSJens Wiklander }
1134817466cbSJens Wiklander 
1135817466cbSJens Wiklander /*
1136817466cbSJens Wiklander  * Compare unsigned values
1137817466cbSJens Wiklander  */
1138817466cbSJens Wiklander int mbedtls_mpi_cmp_abs( const mbedtls_mpi *X, const mbedtls_mpi *Y )
1139817466cbSJens Wiklander {
1140817466cbSJens Wiklander     size_t i, j;
11413d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
11423d3b0591SJens Wiklander     MPI_VALIDATE_RET( Y != NULL );
1143817466cbSJens Wiklander 
1144817466cbSJens Wiklander     for( i = X->n; i > 0; i-- )
1145817466cbSJens Wiklander         if( X->p[i - 1] != 0 )
1146817466cbSJens Wiklander             break;
1147817466cbSJens Wiklander 
1148817466cbSJens Wiklander     for( j = Y->n; j > 0; j-- )
1149817466cbSJens Wiklander         if( Y->p[j - 1] != 0 )
1150817466cbSJens Wiklander             break;
1151817466cbSJens Wiklander 
1152817466cbSJens Wiklander     if( i == 0 && j == 0 )
1153817466cbSJens Wiklander         return( 0 );
1154817466cbSJens Wiklander 
1155817466cbSJens Wiklander     if( i > j ) return(  1 );
1156817466cbSJens Wiklander     if( j > i ) return( -1 );
1157817466cbSJens Wiklander 
1158817466cbSJens Wiklander     for( ; i > 0; i-- )
1159817466cbSJens Wiklander     {
1160817466cbSJens Wiklander         if( X->p[i - 1] > Y->p[i - 1] ) return(  1 );
1161817466cbSJens Wiklander         if( X->p[i - 1] < Y->p[i - 1] ) return( -1 );
1162817466cbSJens Wiklander     }
1163817466cbSJens Wiklander 
1164817466cbSJens Wiklander     return( 0 );
1165817466cbSJens Wiklander }
1166817466cbSJens Wiklander 
1167817466cbSJens Wiklander /*
1168817466cbSJens Wiklander  * Compare signed values
1169817466cbSJens Wiklander  */
1170817466cbSJens Wiklander int mbedtls_mpi_cmp_mpi( const mbedtls_mpi *X, const mbedtls_mpi *Y )
1171817466cbSJens Wiklander {
1172817466cbSJens Wiklander     size_t i, j;
11733d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
11743d3b0591SJens Wiklander     MPI_VALIDATE_RET( Y != NULL );
1175817466cbSJens Wiklander 
1176817466cbSJens Wiklander     for( i = X->n; i > 0; i-- )
1177817466cbSJens Wiklander         if( X->p[i - 1] != 0 )
1178817466cbSJens Wiklander             break;
1179817466cbSJens Wiklander 
1180817466cbSJens Wiklander     for( j = Y->n; j > 0; j-- )
1181817466cbSJens Wiklander         if( Y->p[j - 1] != 0 )
1182817466cbSJens Wiklander             break;
1183817466cbSJens Wiklander 
1184817466cbSJens Wiklander     if( i == 0 && j == 0 )
1185817466cbSJens Wiklander         return( 0 );
1186817466cbSJens Wiklander 
1187817466cbSJens Wiklander     if( i > j ) return(  X->s );
1188817466cbSJens Wiklander     if( j > i ) return( -Y->s );
1189817466cbSJens Wiklander 
1190817466cbSJens Wiklander     if( X->s > 0 && Y->s < 0 ) return(  1 );
1191817466cbSJens Wiklander     if( Y->s > 0 && X->s < 0 ) return( -1 );
1192817466cbSJens Wiklander 
1193817466cbSJens Wiklander     for( ; i > 0; i-- )
1194817466cbSJens Wiklander     {
1195817466cbSJens Wiklander         if( X->p[i - 1] > Y->p[i - 1] ) return(  X->s );
1196817466cbSJens Wiklander         if( X->p[i - 1] < Y->p[i - 1] ) return( -X->s );
1197817466cbSJens Wiklander     }
1198817466cbSJens Wiklander 
1199817466cbSJens Wiklander     return( 0 );
1200817466cbSJens Wiklander }
1201817466cbSJens Wiklander 
12025b25c76aSJerome Forissier /** Decide if an integer is less than the other, without branches.
12035b25c76aSJerome Forissier  *
12045b25c76aSJerome Forissier  * \param x         First integer.
12055b25c76aSJerome Forissier  * \param y         Second integer.
12065b25c76aSJerome Forissier  *
12075b25c76aSJerome Forissier  * \return          1 if \p x is less than \p y, 0 otherwise
12085b25c76aSJerome Forissier  */
12095b25c76aSJerome Forissier static unsigned ct_lt_mpi_uint( const mbedtls_mpi_uint x,
12105b25c76aSJerome Forissier         const mbedtls_mpi_uint y )
12115b25c76aSJerome Forissier {
12125b25c76aSJerome Forissier     mbedtls_mpi_uint ret;
12135b25c76aSJerome Forissier     mbedtls_mpi_uint cond;
12145b25c76aSJerome Forissier 
12155b25c76aSJerome Forissier     /*
12165b25c76aSJerome Forissier      * Check if the most significant bits (MSB) of the operands are different.
12175b25c76aSJerome Forissier      */
12185b25c76aSJerome Forissier     cond = ( x ^ y );
12195b25c76aSJerome Forissier     /*
12205b25c76aSJerome Forissier      * If the MSB are the same then the difference x-y will be negative (and
12215b25c76aSJerome Forissier      * have its MSB set to 1 during conversion to unsigned) if and only if x<y.
12225b25c76aSJerome Forissier      */
12235b25c76aSJerome Forissier     ret = ( x - y ) & ~cond;
12245b25c76aSJerome Forissier     /*
12255b25c76aSJerome Forissier      * If the MSB are different, then the operand with the MSB of 1 is the
12265b25c76aSJerome Forissier      * bigger. (That is if y has MSB of 1, then x<y is true and it is false if
12275b25c76aSJerome Forissier      * the MSB of y is 0.)
12285b25c76aSJerome Forissier      */
12295b25c76aSJerome Forissier     ret |= y & cond;
12305b25c76aSJerome Forissier 
12315b25c76aSJerome Forissier 
12325b25c76aSJerome Forissier     ret = ret >> ( biL - 1 );
12335b25c76aSJerome Forissier 
12345b25c76aSJerome Forissier     return (unsigned) ret;
12355b25c76aSJerome Forissier }
12365b25c76aSJerome Forissier 
12375b25c76aSJerome Forissier /*
12385b25c76aSJerome Forissier  * Compare signed values in constant time
12395b25c76aSJerome Forissier  */
12405b25c76aSJerome Forissier int mbedtls_mpi_lt_mpi_ct( const mbedtls_mpi *X, const mbedtls_mpi *Y,
12415b25c76aSJerome Forissier         unsigned *ret )
12425b25c76aSJerome Forissier {
12435b25c76aSJerome Forissier     size_t i;
12445b25c76aSJerome Forissier     /* The value of any of these variables is either 0 or 1 at all times. */
12455b25c76aSJerome Forissier     unsigned cond, done, X_is_negative, Y_is_negative;
12465b25c76aSJerome Forissier 
12475b25c76aSJerome Forissier     MPI_VALIDATE_RET( X != NULL );
12485b25c76aSJerome Forissier     MPI_VALIDATE_RET( Y != NULL );
12495b25c76aSJerome Forissier     MPI_VALIDATE_RET( ret != NULL );
12505b25c76aSJerome Forissier 
12515b25c76aSJerome Forissier     if( X->n != Y->n )
12525b25c76aSJerome Forissier         return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
12535b25c76aSJerome Forissier 
12545b25c76aSJerome Forissier     /*
12555b25c76aSJerome Forissier      * Set sign_N to 1 if N >= 0, 0 if N < 0.
12565b25c76aSJerome Forissier      * We know that N->s == 1 if N >= 0 and N->s == -1 if N < 0.
12575b25c76aSJerome Forissier      */
12585b25c76aSJerome Forissier     X_is_negative = ( X->s & 2 ) >> 1;
12595b25c76aSJerome Forissier     Y_is_negative = ( Y->s & 2 ) >> 1;
12605b25c76aSJerome Forissier 
12615b25c76aSJerome Forissier     /*
12625b25c76aSJerome Forissier      * If the signs are different, then the positive operand is the bigger.
12635b25c76aSJerome Forissier      * That is if X is negative (X_is_negative == 1), then X < Y is true and it
12645b25c76aSJerome Forissier      * is false if X is positive (X_is_negative == 0).
12655b25c76aSJerome Forissier      */
12665b25c76aSJerome Forissier     cond = ( X_is_negative ^ Y_is_negative );
12675b25c76aSJerome Forissier     *ret = cond & X_is_negative;
12685b25c76aSJerome Forissier 
12695b25c76aSJerome Forissier     /*
12705b25c76aSJerome Forissier      * This is a constant-time function. We might have the result, but we still
12715b25c76aSJerome Forissier      * need to go through the loop. Record if we have the result already.
12725b25c76aSJerome Forissier      */
12735b25c76aSJerome Forissier     done = cond;
12745b25c76aSJerome Forissier 
12755b25c76aSJerome Forissier     for( i = X->n; i > 0; i-- )
12765b25c76aSJerome Forissier     {
12775b25c76aSJerome Forissier         /*
12785b25c76aSJerome Forissier          * If Y->p[i - 1] < X->p[i - 1] then X < Y is true if and only if both
12795b25c76aSJerome Forissier          * X and Y are negative.
12805b25c76aSJerome Forissier          *
12815b25c76aSJerome Forissier          * Again even if we can make a decision, we just mark the result and
12825b25c76aSJerome Forissier          * the fact that we are done and continue looping.
12835b25c76aSJerome Forissier          */
12845b25c76aSJerome Forissier         cond = ct_lt_mpi_uint( Y->p[i - 1], X->p[i - 1] );
12855b25c76aSJerome Forissier         *ret |= cond & ( 1 - done ) & X_is_negative;
12865b25c76aSJerome Forissier         done |= cond;
12875b25c76aSJerome Forissier 
12885b25c76aSJerome Forissier         /*
12895b25c76aSJerome Forissier          * If X->p[i - 1] < Y->p[i - 1] then X < Y is true if and only if both
12905b25c76aSJerome Forissier          * X and Y are positive.
12915b25c76aSJerome Forissier          *
12925b25c76aSJerome Forissier          * Again even if we can make a decision, we just mark the result and
12935b25c76aSJerome Forissier          * the fact that we are done and continue looping.
12945b25c76aSJerome Forissier          */
12955b25c76aSJerome Forissier         cond = ct_lt_mpi_uint( X->p[i - 1], Y->p[i - 1] );
12965b25c76aSJerome Forissier         *ret |= cond & ( 1 - done ) & ( 1 - X_is_negative );
12975b25c76aSJerome Forissier         done |= cond;
12985b25c76aSJerome Forissier     }
12995b25c76aSJerome Forissier 
13005b25c76aSJerome Forissier     return( 0 );
13015b25c76aSJerome Forissier }
13025b25c76aSJerome Forissier 
1303817466cbSJens Wiklander /*
1304817466cbSJens Wiklander  * Compare signed values
1305817466cbSJens Wiklander  */
1306817466cbSJens Wiklander int mbedtls_mpi_cmp_int( const mbedtls_mpi *X, mbedtls_mpi_sint z )
1307817466cbSJens Wiklander {
1308817466cbSJens Wiklander     mbedtls_mpi Y;
1309817466cbSJens Wiklander     mbedtls_mpi_uint p[1];
13103d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
1311817466cbSJens Wiklander 
1312817466cbSJens Wiklander     *p  = ( z < 0 ) ? -z : z;
1313817466cbSJens Wiklander     Y.s = ( z < 0 ) ? -1 : 1;
1314817466cbSJens Wiklander     Y.n = 1;
1315817466cbSJens Wiklander     Y.p = p;
1316817466cbSJens Wiklander 
1317817466cbSJens Wiklander     return( mbedtls_mpi_cmp_mpi( X, &Y ) );
1318817466cbSJens Wiklander }
1319817466cbSJens Wiklander 
1320817466cbSJens Wiklander /*
1321817466cbSJens Wiklander  * Unsigned addition: X = |A| + |B|  (HAC 14.7)
1322817466cbSJens Wiklander  */
1323817466cbSJens Wiklander int mbedtls_mpi_add_abs( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B )
1324817466cbSJens Wiklander {
1325*11fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
1326817466cbSJens Wiklander     size_t i, j;
1327817466cbSJens Wiklander     mbedtls_mpi_uint *o, *p, c, tmp;
13283d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
13293d3b0591SJens Wiklander     MPI_VALIDATE_RET( A != NULL );
13303d3b0591SJens Wiklander     MPI_VALIDATE_RET( B != NULL );
1331817466cbSJens Wiklander 
1332817466cbSJens Wiklander     if( X == B )
1333817466cbSJens Wiklander     {
1334817466cbSJens Wiklander         const mbedtls_mpi *T = A; A = X; B = T;
1335817466cbSJens Wiklander     }
1336817466cbSJens Wiklander 
1337817466cbSJens Wiklander     if( X != A )
1338817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, A ) );
1339817466cbSJens Wiklander 
1340817466cbSJens Wiklander     /*
1341817466cbSJens Wiklander      * X should always be positive as a result of unsigned additions.
1342817466cbSJens Wiklander      */
1343817466cbSJens Wiklander     X->s = 1;
1344817466cbSJens Wiklander 
1345817466cbSJens Wiklander     for( j = B->n; j > 0; j-- )
1346817466cbSJens Wiklander         if( B->p[j - 1] != 0 )
1347817466cbSJens Wiklander             break;
1348817466cbSJens Wiklander 
1349817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, j ) );
1350817466cbSJens Wiklander 
1351817466cbSJens Wiklander     o = B->p; p = X->p; c = 0;
1352817466cbSJens Wiklander 
1353817466cbSJens Wiklander     /*
1354817466cbSJens Wiklander      * tmp is used because it might happen that p == o
1355817466cbSJens Wiklander      */
1356817466cbSJens Wiklander     for( i = 0; i < j; i++, o++, p++ )
1357817466cbSJens Wiklander     {
1358817466cbSJens Wiklander         tmp= *o;
1359817466cbSJens Wiklander         *p +=  c; c  = ( *p <  c );
1360817466cbSJens Wiklander         *p += tmp; c += ( *p < tmp );
1361817466cbSJens Wiklander     }
1362817466cbSJens Wiklander 
1363817466cbSJens Wiklander     while( c != 0 )
1364817466cbSJens Wiklander     {
1365817466cbSJens Wiklander         if( i >= X->n )
1366817466cbSJens Wiklander         {
1367817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, i + 1 ) );
1368817466cbSJens Wiklander             p = X->p + i;
1369817466cbSJens Wiklander         }
1370817466cbSJens Wiklander 
1371817466cbSJens Wiklander         *p += c; c = ( *p < c ); i++; p++;
1372817466cbSJens Wiklander     }
1373817466cbSJens Wiklander 
1374817466cbSJens Wiklander cleanup:
1375817466cbSJens Wiklander 
1376817466cbSJens Wiklander     return( ret );
1377817466cbSJens Wiklander }
1378817466cbSJens Wiklander 
1379817466cbSJens Wiklander /*
1380817466cbSJens Wiklander  * Helper for mbedtls_mpi subtraction
1381817466cbSJens Wiklander  */
1382817466cbSJens Wiklander static void mpi_sub_hlp( size_t n, mbedtls_mpi_uint *s, mbedtls_mpi_uint *d )
1383817466cbSJens Wiklander {
1384817466cbSJens Wiklander     size_t i;
1385817466cbSJens Wiklander     mbedtls_mpi_uint c, z;
1386817466cbSJens Wiklander 
1387817466cbSJens Wiklander     for( i = c = 0; i < n; i++, s++, d++ )
1388817466cbSJens Wiklander     {
1389817466cbSJens Wiklander         z = ( *d <  c );     *d -=  c;
1390817466cbSJens Wiklander         c = ( *d < *s ) + z; *d -= *s;
1391817466cbSJens Wiklander     }
1392817466cbSJens Wiklander 
1393817466cbSJens Wiklander     while( c != 0 )
1394817466cbSJens Wiklander     {
1395817466cbSJens Wiklander         z = ( *d < c ); *d -= c;
13963d3b0591SJens Wiklander         c = z; d++;
1397817466cbSJens Wiklander     }
1398817466cbSJens Wiklander }
1399817466cbSJens Wiklander 
1400817466cbSJens Wiklander /*
1401817466cbSJens Wiklander  * Unsigned subtraction: X = |A| - |B|  (HAC 14.9)
1402817466cbSJens Wiklander  */
1403817466cbSJens Wiklander int mbedtls_mpi_sub_abs( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B )
1404817466cbSJens Wiklander {
1405817466cbSJens Wiklander     mbedtls_mpi TB;
1406*11fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
1407817466cbSJens Wiklander     size_t n;
14083d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
14093d3b0591SJens Wiklander     MPI_VALIDATE_RET( A != NULL );
14103d3b0591SJens Wiklander     MPI_VALIDATE_RET( B != NULL );
1411817466cbSJens Wiklander 
1412817466cbSJens Wiklander     if( mbedtls_mpi_cmp_abs( A, B ) < 0 )
1413817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_NEGATIVE_VALUE );
1414817466cbSJens Wiklander 
141598bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &TB );
1416817466cbSJens Wiklander 
1417817466cbSJens Wiklander     if( X == B )
1418817466cbSJens Wiklander     {
1419817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, B ) );
1420817466cbSJens Wiklander         B = &TB;
1421817466cbSJens Wiklander     }
1422817466cbSJens Wiklander 
1423817466cbSJens Wiklander     if( X != A )
1424817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, A ) );
1425817466cbSJens Wiklander 
1426817466cbSJens Wiklander     /*
1427817466cbSJens Wiklander      * X should always be positive as a result of unsigned subtractions.
1428817466cbSJens Wiklander      */
1429817466cbSJens Wiklander     X->s = 1;
1430817466cbSJens Wiklander 
1431817466cbSJens Wiklander     ret = 0;
1432817466cbSJens Wiklander 
1433817466cbSJens Wiklander     for( n = B->n; n > 0; n-- )
1434817466cbSJens Wiklander         if( B->p[n - 1] != 0 )
1435817466cbSJens Wiklander             break;
1436817466cbSJens Wiklander 
1437817466cbSJens Wiklander     mpi_sub_hlp( n, B->p, X->p );
1438817466cbSJens Wiklander 
1439817466cbSJens Wiklander cleanup:
1440817466cbSJens Wiklander 
1441817466cbSJens Wiklander     mbedtls_mpi_free( &TB );
1442817466cbSJens Wiklander 
1443817466cbSJens Wiklander     return( ret );
1444817466cbSJens Wiklander }
1445817466cbSJens Wiklander 
1446817466cbSJens Wiklander /*
1447817466cbSJens Wiklander  * Signed addition: X = A + B
1448817466cbSJens Wiklander  */
1449817466cbSJens Wiklander int mbedtls_mpi_add_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B )
1450817466cbSJens Wiklander {
14513d3b0591SJens Wiklander     int ret, s;
14523d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
14533d3b0591SJens Wiklander     MPI_VALIDATE_RET( A != NULL );
14543d3b0591SJens Wiklander     MPI_VALIDATE_RET( B != NULL );
1455817466cbSJens Wiklander 
14563d3b0591SJens Wiklander     s = A->s;
1457817466cbSJens Wiklander     if( A->s * B->s < 0 )
1458817466cbSJens Wiklander     {
1459817466cbSJens Wiklander         if( mbedtls_mpi_cmp_abs( A, B ) >= 0 )
1460817466cbSJens Wiklander         {
1461817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, A, B ) );
1462817466cbSJens Wiklander             X->s =  s;
1463817466cbSJens Wiklander         }
1464817466cbSJens Wiklander         else
1465817466cbSJens Wiklander         {
1466817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, B, A ) );
1467817466cbSJens Wiklander             X->s = -s;
1468817466cbSJens Wiklander         }
1469817466cbSJens Wiklander     }
1470817466cbSJens Wiklander     else
1471817466cbSJens Wiklander     {
1472817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_add_abs( X, A, B ) );
1473817466cbSJens Wiklander         X->s = s;
1474817466cbSJens Wiklander     }
1475817466cbSJens Wiklander 
1476817466cbSJens Wiklander cleanup:
1477817466cbSJens Wiklander 
1478817466cbSJens Wiklander     return( ret );
1479817466cbSJens Wiklander }
1480817466cbSJens Wiklander 
1481817466cbSJens Wiklander /*
1482817466cbSJens Wiklander  * Signed subtraction: X = A - B
1483817466cbSJens Wiklander  */
1484817466cbSJens Wiklander int mbedtls_mpi_sub_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B )
1485817466cbSJens Wiklander {
14863d3b0591SJens Wiklander     int ret, s;
14873d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
14883d3b0591SJens Wiklander     MPI_VALIDATE_RET( A != NULL );
14893d3b0591SJens Wiklander     MPI_VALIDATE_RET( B != NULL );
1490817466cbSJens Wiklander 
14913d3b0591SJens Wiklander     s = A->s;
1492817466cbSJens Wiklander     if( A->s * B->s > 0 )
1493817466cbSJens Wiklander     {
1494817466cbSJens Wiklander         if( mbedtls_mpi_cmp_abs( A, B ) >= 0 )
1495817466cbSJens Wiklander         {
1496817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, A, B ) );
1497817466cbSJens Wiklander             X->s =  s;
1498817466cbSJens Wiklander         }
1499817466cbSJens Wiklander         else
1500817466cbSJens Wiklander         {
1501817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, B, A ) );
1502817466cbSJens Wiklander             X->s = -s;
1503817466cbSJens Wiklander         }
1504817466cbSJens Wiklander     }
1505817466cbSJens Wiklander     else
1506817466cbSJens Wiklander     {
1507817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_add_abs( X, A, B ) );
1508817466cbSJens Wiklander         X->s = s;
1509817466cbSJens Wiklander     }
1510817466cbSJens Wiklander 
1511817466cbSJens Wiklander cleanup:
1512817466cbSJens Wiklander 
1513817466cbSJens Wiklander     return( ret );
1514817466cbSJens Wiklander }
1515817466cbSJens Wiklander 
1516817466cbSJens Wiklander /*
1517817466cbSJens Wiklander  * Signed addition: X = A + b
1518817466cbSJens Wiklander  */
1519817466cbSJens Wiklander int mbedtls_mpi_add_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b )
1520817466cbSJens Wiklander {
1521817466cbSJens Wiklander     mbedtls_mpi _B;
1522817466cbSJens Wiklander     mbedtls_mpi_uint p[1];
15233d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
15243d3b0591SJens Wiklander     MPI_VALIDATE_RET( A != NULL );
1525817466cbSJens Wiklander 
1526817466cbSJens Wiklander     p[0] = ( b < 0 ) ? -b : b;
1527817466cbSJens Wiklander     _B.s = ( b < 0 ) ? -1 : 1;
1528817466cbSJens Wiklander     _B.n = 1;
1529817466cbSJens Wiklander     _B.p = p;
1530817466cbSJens Wiklander 
1531817466cbSJens Wiklander     return( mbedtls_mpi_add_mpi( X, A, &_B ) );
1532817466cbSJens Wiklander }
1533817466cbSJens Wiklander 
1534817466cbSJens Wiklander /*
1535817466cbSJens Wiklander  * Signed subtraction: X = A - b
1536817466cbSJens Wiklander  */
1537817466cbSJens Wiklander int mbedtls_mpi_sub_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b )
1538817466cbSJens Wiklander {
1539817466cbSJens Wiklander     mbedtls_mpi _B;
1540817466cbSJens Wiklander     mbedtls_mpi_uint p[1];
15413d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
15423d3b0591SJens Wiklander     MPI_VALIDATE_RET( A != NULL );
1543817466cbSJens Wiklander 
1544817466cbSJens Wiklander     p[0] = ( b < 0 ) ? -b : b;
1545817466cbSJens Wiklander     _B.s = ( b < 0 ) ? -1 : 1;
1546817466cbSJens Wiklander     _B.n = 1;
1547817466cbSJens Wiklander     _B.p = p;
1548817466cbSJens Wiklander 
1549817466cbSJens Wiklander     return( mbedtls_mpi_sub_mpi( X, A, &_B ) );
1550817466cbSJens Wiklander }
1551817466cbSJens Wiklander 
1552817466cbSJens Wiklander /*
1553817466cbSJens Wiklander  * Helper for mbedtls_mpi multiplication
1554817466cbSJens Wiklander  */
1555817466cbSJens Wiklander static
1556817466cbSJens Wiklander #if defined(__APPLE__) && defined(__arm__)
1557817466cbSJens Wiklander /*
1558817466cbSJens Wiklander  * Apple LLVM version 4.2 (clang-425.0.24) (based on LLVM 3.2svn)
1559817466cbSJens Wiklander  * appears to need this to prevent bad ARM code generation at -O3.
1560817466cbSJens Wiklander  */
1561817466cbSJens Wiklander __attribute__ ((noinline))
1562817466cbSJens Wiklander #endif
1563817466cbSJens Wiklander void mpi_mul_hlp( size_t i, mbedtls_mpi_uint *s, mbedtls_mpi_uint *d, mbedtls_mpi_uint b )
1564817466cbSJens Wiklander {
1565817466cbSJens Wiklander     mbedtls_mpi_uint c = 0, t = 0;
1566817466cbSJens Wiklander 
1567817466cbSJens Wiklander #if defined(MULADDC_HUIT)
1568817466cbSJens Wiklander     for( ; i >= 8; i -= 8 )
1569817466cbSJens Wiklander     {
1570817466cbSJens Wiklander         MULADDC_INIT
1571817466cbSJens Wiklander         MULADDC_HUIT
1572817466cbSJens Wiklander         MULADDC_STOP
1573817466cbSJens Wiklander     }
1574817466cbSJens Wiklander 
1575817466cbSJens Wiklander     for( ; i > 0; i-- )
1576817466cbSJens Wiklander     {
1577817466cbSJens Wiklander         MULADDC_INIT
1578817466cbSJens Wiklander         MULADDC_CORE
1579817466cbSJens Wiklander         MULADDC_STOP
1580817466cbSJens Wiklander     }
1581817466cbSJens Wiklander #else /* MULADDC_HUIT */
1582817466cbSJens Wiklander     for( ; i >= 16; i -= 16 )
1583817466cbSJens Wiklander     {
1584817466cbSJens Wiklander         MULADDC_INIT
1585817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1586817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1587817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1588817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1589817466cbSJens Wiklander 
1590817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1591817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1592817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1593817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1594817466cbSJens Wiklander         MULADDC_STOP
1595817466cbSJens Wiklander     }
1596817466cbSJens Wiklander 
1597817466cbSJens Wiklander     for( ; i >= 8; i -= 8 )
1598817466cbSJens Wiklander     {
1599817466cbSJens Wiklander         MULADDC_INIT
1600817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1601817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1602817466cbSJens Wiklander 
1603817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1604817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1605817466cbSJens Wiklander         MULADDC_STOP
1606817466cbSJens Wiklander     }
1607817466cbSJens Wiklander 
1608817466cbSJens Wiklander     for( ; i > 0; i-- )
1609817466cbSJens Wiklander     {
1610817466cbSJens Wiklander         MULADDC_INIT
1611817466cbSJens Wiklander         MULADDC_CORE
1612817466cbSJens Wiklander         MULADDC_STOP
1613817466cbSJens Wiklander     }
1614817466cbSJens Wiklander #endif /* MULADDC_HUIT */
1615817466cbSJens Wiklander 
1616817466cbSJens Wiklander     t++;
1617817466cbSJens Wiklander 
1618817466cbSJens Wiklander     do {
1619817466cbSJens Wiklander         *d += c; c = ( *d < c ); d++;
1620817466cbSJens Wiklander     }
1621817466cbSJens Wiklander     while( c != 0 );
1622817466cbSJens Wiklander }
1623817466cbSJens Wiklander 
1624817466cbSJens Wiklander /*
1625817466cbSJens Wiklander  * Baseline multiplication: X = A * B  (HAC 14.12)
1626817466cbSJens Wiklander  */
1627817466cbSJens Wiklander int mbedtls_mpi_mul_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B )
1628817466cbSJens Wiklander {
1629*11fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
1630817466cbSJens Wiklander     size_t i, j;
1631817466cbSJens Wiklander     mbedtls_mpi TA, TB;
16323d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
16333d3b0591SJens Wiklander     MPI_VALIDATE_RET( A != NULL );
16343d3b0591SJens Wiklander     MPI_VALIDATE_RET( B != NULL );
1635817466cbSJens Wiklander 
163698bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &TA ); mbedtls_mpi_init_mempool( &TB );
1637817466cbSJens Wiklander 
1638817466cbSJens Wiklander     if( X == A ) { MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TA, A ) ); A = &TA; }
1639817466cbSJens Wiklander     if( X == B ) { MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, B ) ); B = &TB; }
1640817466cbSJens Wiklander 
1641817466cbSJens Wiklander     for( i = A->n; i > 0; i-- )
1642817466cbSJens Wiklander         if( A->p[i - 1] != 0 )
1643817466cbSJens Wiklander             break;
1644817466cbSJens Wiklander 
1645817466cbSJens Wiklander     for( j = B->n; j > 0; j-- )
1646817466cbSJens Wiklander         if( B->p[j - 1] != 0 )
1647817466cbSJens Wiklander             break;
1648817466cbSJens Wiklander 
1649817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, i + j ) );
1650817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) );
1651817466cbSJens Wiklander 
16523d3b0591SJens Wiklander     for( ; j > 0; j-- )
16533d3b0591SJens Wiklander         mpi_mul_hlp( i, A->p, X->p + j - 1, B->p[j - 1] );
1654817466cbSJens Wiklander 
1655817466cbSJens Wiklander     X->s = A->s * B->s;
1656817466cbSJens Wiklander 
1657817466cbSJens Wiklander cleanup:
1658817466cbSJens Wiklander 
1659817466cbSJens Wiklander     mbedtls_mpi_free( &TB ); mbedtls_mpi_free( &TA );
1660817466cbSJens Wiklander 
1661817466cbSJens Wiklander     return( ret );
1662817466cbSJens Wiklander }
1663817466cbSJens Wiklander 
1664817466cbSJens Wiklander /*
1665817466cbSJens Wiklander  * Baseline multiplication: X = A * b
1666817466cbSJens Wiklander  */
1667817466cbSJens Wiklander int mbedtls_mpi_mul_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_uint b )
1668817466cbSJens Wiklander {
1669817466cbSJens Wiklander     mbedtls_mpi _B;
1670817466cbSJens Wiklander     mbedtls_mpi_uint p[1];
16713d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
16723d3b0591SJens Wiklander     MPI_VALIDATE_RET( A != NULL );
1673817466cbSJens Wiklander 
1674817466cbSJens Wiklander     _B.s = 1;
1675817466cbSJens Wiklander     _B.n = 1;
1676817466cbSJens Wiklander     _B.p = p;
1677817466cbSJens Wiklander     p[0] = b;
1678817466cbSJens Wiklander 
1679817466cbSJens Wiklander     return( mbedtls_mpi_mul_mpi( X, A, &_B ) );
1680817466cbSJens Wiklander }
1681817466cbSJens Wiklander 
1682817466cbSJens Wiklander /*
1683817466cbSJens Wiklander  * Unsigned integer divide - double mbedtls_mpi_uint dividend, u1/u0, and
1684817466cbSJens Wiklander  * mbedtls_mpi_uint divisor, d
1685817466cbSJens Wiklander  */
1686817466cbSJens Wiklander static mbedtls_mpi_uint mbedtls_int_div_int( mbedtls_mpi_uint u1,
1687817466cbSJens Wiklander             mbedtls_mpi_uint u0, mbedtls_mpi_uint d, mbedtls_mpi_uint *r )
1688817466cbSJens Wiklander {
1689817466cbSJens Wiklander #if defined(MBEDTLS_HAVE_UDBL)
1690817466cbSJens Wiklander     mbedtls_t_udbl dividend, quotient;
1691817466cbSJens Wiklander #else
1692817466cbSJens Wiklander     const mbedtls_mpi_uint radix = (mbedtls_mpi_uint) 1 << biH;
1693817466cbSJens Wiklander     const mbedtls_mpi_uint uint_halfword_mask = ( (mbedtls_mpi_uint) 1 << biH ) - 1;
1694817466cbSJens Wiklander     mbedtls_mpi_uint d0, d1, q0, q1, rAX, r0, quotient;
1695817466cbSJens Wiklander     mbedtls_mpi_uint u0_msw, u0_lsw;
1696817466cbSJens Wiklander     size_t s;
1697817466cbSJens Wiklander #endif
1698817466cbSJens Wiklander 
1699817466cbSJens Wiklander     /*
1700817466cbSJens Wiklander      * Check for overflow
1701817466cbSJens Wiklander      */
1702817466cbSJens Wiklander     if( 0 == d || u1 >= d )
1703817466cbSJens Wiklander     {
1704817466cbSJens Wiklander         if (r != NULL) *r = ~0;
1705817466cbSJens Wiklander 
1706817466cbSJens Wiklander         return ( ~0 );
1707817466cbSJens Wiklander     }
1708817466cbSJens Wiklander 
1709817466cbSJens Wiklander #if defined(MBEDTLS_HAVE_UDBL)
1710817466cbSJens Wiklander     dividend  = (mbedtls_t_udbl) u1 << biL;
1711817466cbSJens Wiklander     dividend |= (mbedtls_t_udbl) u0;
1712817466cbSJens Wiklander     quotient = dividend / d;
1713817466cbSJens Wiklander     if( quotient > ( (mbedtls_t_udbl) 1 << biL ) - 1 )
1714817466cbSJens Wiklander         quotient = ( (mbedtls_t_udbl) 1 << biL ) - 1;
1715817466cbSJens Wiklander 
1716817466cbSJens Wiklander     if( r != NULL )
1717817466cbSJens Wiklander         *r = (mbedtls_mpi_uint)( dividend - (quotient * d ) );
1718817466cbSJens Wiklander 
1719817466cbSJens Wiklander     return (mbedtls_mpi_uint) quotient;
1720817466cbSJens Wiklander #else
1721817466cbSJens Wiklander 
1722817466cbSJens Wiklander     /*
1723817466cbSJens Wiklander      * Algorithm D, Section 4.3.1 - The Art of Computer Programming
1724817466cbSJens Wiklander      *   Vol. 2 - Seminumerical Algorithms, Knuth
1725817466cbSJens Wiklander      */
1726817466cbSJens Wiklander 
1727817466cbSJens Wiklander     /*
1728817466cbSJens Wiklander      * Normalize the divisor, d, and dividend, u0, u1
1729817466cbSJens Wiklander      */
1730817466cbSJens Wiklander     s = mbedtls_clz( d );
1731817466cbSJens Wiklander     d = d << s;
1732817466cbSJens Wiklander 
1733817466cbSJens Wiklander     u1 = u1 << s;
1734817466cbSJens Wiklander     u1 |= ( u0 >> ( biL - s ) ) & ( -(mbedtls_mpi_sint)s >> ( biL - 1 ) );
1735817466cbSJens Wiklander     u0 =  u0 << s;
1736817466cbSJens Wiklander 
1737817466cbSJens Wiklander     d1 = d >> biH;
1738817466cbSJens Wiklander     d0 = d & uint_halfword_mask;
1739817466cbSJens Wiklander 
1740817466cbSJens Wiklander     u0_msw = u0 >> biH;
1741817466cbSJens Wiklander     u0_lsw = u0 & uint_halfword_mask;
1742817466cbSJens Wiklander 
1743817466cbSJens Wiklander     /*
1744817466cbSJens Wiklander      * Find the first quotient and remainder
1745817466cbSJens Wiklander      */
1746817466cbSJens Wiklander     q1 = u1 / d1;
1747817466cbSJens Wiklander     r0 = u1 - d1 * q1;
1748817466cbSJens Wiklander 
1749817466cbSJens Wiklander     while( q1 >= radix || ( q1 * d0 > radix * r0 + u0_msw ) )
1750817466cbSJens Wiklander     {
1751817466cbSJens Wiklander         q1 -= 1;
1752817466cbSJens Wiklander         r0 += d1;
1753817466cbSJens Wiklander 
1754817466cbSJens Wiklander         if ( r0 >= radix ) break;
1755817466cbSJens Wiklander     }
1756817466cbSJens Wiklander 
1757817466cbSJens Wiklander     rAX = ( u1 * radix ) + ( u0_msw - q1 * d );
1758817466cbSJens Wiklander     q0 = rAX / d1;
1759817466cbSJens Wiklander     r0 = rAX - q0 * d1;
1760817466cbSJens Wiklander 
1761817466cbSJens Wiklander     while( q0 >= radix || ( q0 * d0 > radix * r0 + u0_lsw ) )
1762817466cbSJens Wiklander     {
1763817466cbSJens Wiklander         q0 -= 1;
1764817466cbSJens Wiklander         r0 += d1;
1765817466cbSJens Wiklander 
1766817466cbSJens Wiklander         if ( r0 >= radix ) break;
1767817466cbSJens Wiklander     }
1768817466cbSJens Wiklander 
1769817466cbSJens Wiklander     if (r != NULL)
1770817466cbSJens Wiklander         *r = ( rAX * radix + u0_lsw - q0 * d ) >> s;
1771817466cbSJens Wiklander 
1772817466cbSJens Wiklander     quotient = q1 * radix + q0;
1773817466cbSJens Wiklander 
1774817466cbSJens Wiklander     return quotient;
1775817466cbSJens Wiklander #endif
1776817466cbSJens Wiklander }
1777817466cbSJens Wiklander 
1778817466cbSJens Wiklander /*
1779817466cbSJens Wiklander  * Division by mbedtls_mpi: A = Q * B + R  (HAC 14.20)
1780817466cbSJens Wiklander  */
17813d3b0591SJens Wiklander int mbedtls_mpi_div_mpi( mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A,
17823d3b0591SJens Wiklander                          const mbedtls_mpi *B )
1783817466cbSJens Wiklander {
1784*11fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
1785817466cbSJens Wiklander     size_t i, n, t, k;
1786817466cbSJens Wiklander     mbedtls_mpi X, Y, Z, T1, T2;
1787*11fa71b9SJerome Forissier     mbedtls_mpi_uint TP2[3];
17883d3b0591SJens Wiklander     MPI_VALIDATE_RET( A != NULL );
17893d3b0591SJens Wiklander     MPI_VALIDATE_RET( B != NULL );
1790817466cbSJens Wiklander 
1791817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( B, 0 ) == 0 )
1792817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_DIVISION_BY_ZERO );
1793817466cbSJens Wiklander 
179498bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &X ); mbedtls_mpi_init_mempool( &Y );
179598bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &Z ); mbedtls_mpi_init_mempool( &T1 );
1796*11fa71b9SJerome Forissier     /*
1797*11fa71b9SJerome Forissier      * Avoid dynamic memory allocations for constant-size T2.
1798*11fa71b9SJerome Forissier      *
1799*11fa71b9SJerome Forissier      * T2 is used for comparison only and the 3 limbs are assigned explicitly,
1800*11fa71b9SJerome Forissier      * so nobody increase the size of the MPI and we're safe to use an on-stack
1801*11fa71b9SJerome Forissier      * buffer.
1802*11fa71b9SJerome Forissier      */
1803*11fa71b9SJerome Forissier     T2.s = 1;
1804*11fa71b9SJerome Forissier     T2.n = sizeof( TP2 ) / sizeof( *TP2 );
1805*11fa71b9SJerome Forissier     T2.p = TP2;
1806817466cbSJens Wiklander 
1807817466cbSJens Wiklander     if( mbedtls_mpi_cmp_abs( A, B ) < 0 )
1808817466cbSJens Wiklander     {
1809817466cbSJens Wiklander         if( Q != NULL ) MBEDTLS_MPI_CHK( mbedtls_mpi_lset( Q, 0 ) );
1810817466cbSJens Wiklander         if( R != NULL ) MBEDTLS_MPI_CHK( mbedtls_mpi_copy( R, A ) );
1811817466cbSJens Wiklander         return( 0 );
1812817466cbSJens Wiklander     }
1813817466cbSJens Wiklander 
1814817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &X, A ) );
1815817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &Y, B ) );
1816817466cbSJens Wiklander     X.s = Y.s = 1;
1817817466cbSJens Wiklander 
1818817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &Z, A->n + 2 ) );
1819817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &Z,  0 ) );
1820817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &T1, 2 ) );
1821817466cbSJens Wiklander 
1822817466cbSJens Wiklander     k = mbedtls_mpi_bitlen( &Y ) % biL;
1823817466cbSJens Wiklander     if( k < biL - 1 )
1824817466cbSJens Wiklander     {
1825817466cbSJens Wiklander         k = biL - 1 - k;
1826817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &X, k ) );
1827817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &Y, k ) );
1828817466cbSJens Wiklander     }
1829817466cbSJens Wiklander     else k = 0;
1830817466cbSJens Wiklander 
1831817466cbSJens Wiklander     n = X.n - 1;
1832817466cbSJens Wiklander     t = Y.n - 1;
1833817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &Y, biL * ( n - t ) ) );
1834817466cbSJens Wiklander 
1835817466cbSJens Wiklander     while( mbedtls_mpi_cmp_mpi( &X, &Y ) >= 0 )
1836817466cbSJens Wiklander     {
1837817466cbSJens Wiklander         Z.p[n - t]++;
1838817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &X, &X, &Y ) );
1839817466cbSJens Wiklander     }
1840817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &Y, biL * ( n - t ) ) );
1841817466cbSJens Wiklander 
1842817466cbSJens Wiklander     for( i = n; i > t ; i-- )
1843817466cbSJens Wiklander     {
1844817466cbSJens Wiklander         if( X.p[i] >= Y.p[t] )
1845817466cbSJens Wiklander             Z.p[i - t - 1] = ~0;
1846817466cbSJens Wiklander         else
1847817466cbSJens Wiklander         {
1848817466cbSJens Wiklander             Z.p[i - t - 1] = mbedtls_int_div_int( X.p[i], X.p[i - 1],
1849817466cbSJens Wiklander                                                             Y.p[t], NULL);
1850817466cbSJens Wiklander         }
1851817466cbSJens Wiklander 
1852*11fa71b9SJerome Forissier         T2.p[0] = ( i < 2 ) ? 0 : X.p[i - 2];
1853*11fa71b9SJerome Forissier         T2.p[1] = ( i < 1 ) ? 0 : X.p[i - 1];
1854*11fa71b9SJerome Forissier         T2.p[2] = X.p[i];
1855*11fa71b9SJerome Forissier 
1856817466cbSJens Wiklander         Z.p[i - t - 1]++;
1857817466cbSJens Wiklander         do
1858817466cbSJens Wiklander         {
1859817466cbSJens Wiklander             Z.p[i - t - 1]--;
1860817466cbSJens Wiklander 
1861817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &T1, 0 ) );
1862817466cbSJens Wiklander             T1.p[0] = ( t < 1 ) ? 0 : Y.p[t - 1];
1863817466cbSJens Wiklander             T1.p[1] = Y.p[t];
1864817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &T1, &T1, Z.p[i - t - 1] ) );
1865817466cbSJens Wiklander         }
1866817466cbSJens Wiklander         while( mbedtls_mpi_cmp_mpi( &T1, &T2 ) > 0 );
1867817466cbSJens Wiklander 
1868817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &T1, &Y, Z.p[i - t - 1] ) );
1869817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &T1,  biL * ( i - t - 1 ) ) );
1870817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &X, &X, &T1 ) );
1871817466cbSJens Wiklander 
1872817466cbSJens Wiklander         if( mbedtls_mpi_cmp_int( &X, 0 ) < 0 )
1873817466cbSJens Wiklander         {
1874817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &T1, &Y ) );
1875817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &T1, biL * ( i - t - 1 ) ) );
1876817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &X, &X, &T1 ) );
1877817466cbSJens Wiklander             Z.p[i - t - 1]--;
1878817466cbSJens Wiklander         }
1879817466cbSJens Wiklander     }
1880817466cbSJens Wiklander 
1881817466cbSJens Wiklander     if( Q != NULL )
1882817466cbSJens Wiklander     {
1883817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( Q, &Z ) );
1884817466cbSJens Wiklander         Q->s = A->s * B->s;
1885817466cbSJens Wiklander     }
1886817466cbSJens Wiklander 
1887817466cbSJens Wiklander     if( R != NULL )
1888817466cbSJens Wiklander     {
1889817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &X, k ) );
1890817466cbSJens Wiklander         X.s = A->s;
1891817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( R, &X ) );
1892817466cbSJens Wiklander 
1893817466cbSJens Wiklander         if( mbedtls_mpi_cmp_int( R, 0 ) == 0 )
1894817466cbSJens Wiklander             R->s = 1;
1895817466cbSJens Wiklander     }
1896817466cbSJens Wiklander 
1897817466cbSJens Wiklander cleanup:
1898817466cbSJens Wiklander 
1899817466cbSJens Wiklander     mbedtls_mpi_free( &X ); mbedtls_mpi_free( &Y ); mbedtls_mpi_free( &Z );
1900*11fa71b9SJerome Forissier     mbedtls_mpi_free( &T1 );
1901*11fa71b9SJerome Forissier     mbedtls_platform_zeroize( TP2, sizeof( TP2 ) );
1902817466cbSJens Wiklander 
1903817466cbSJens Wiklander     return( ret );
1904817466cbSJens Wiklander }
1905817466cbSJens Wiklander 
1906817466cbSJens Wiklander /*
1907817466cbSJens Wiklander  * Division by int: A = Q * b + R
1908817466cbSJens Wiklander  */
19093d3b0591SJens Wiklander int mbedtls_mpi_div_int( mbedtls_mpi *Q, mbedtls_mpi *R,
19103d3b0591SJens Wiklander                          const mbedtls_mpi *A,
19113d3b0591SJens Wiklander                          mbedtls_mpi_sint b )
1912817466cbSJens Wiklander {
1913817466cbSJens Wiklander     mbedtls_mpi _B;
1914817466cbSJens Wiklander     mbedtls_mpi_uint p[1];
19153d3b0591SJens Wiklander     MPI_VALIDATE_RET( A != NULL );
1916817466cbSJens Wiklander 
1917817466cbSJens Wiklander     p[0] = ( b < 0 ) ? -b : b;
1918817466cbSJens Wiklander     _B.s = ( b < 0 ) ? -1 : 1;
1919817466cbSJens Wiklander     _B.n = 1;
1920817466cbSJens Wiklander     _B.p = p;
1921817466cbSJens Wiklander 
1922817466cbSJens Wiklander     return( mbedtls_mpi_div_mpi( Q, R, A, &_B ) );
1923817466cbSJens Wiklander }
1924817466cbSJens Wiklander 
1925817466cbSJens Wiklander /*
1926817466cbSJens Wiklander  * Modulo: R = A mod B
1927817466cbSJens Wiklander  */
1928817466cbSJens Wiklander int mbedtls_mpi_mod_mpi( mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B )
1929817466cbSJens Wiklander {
1930*11fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
19313d3b0591SJens Wiklander     MPI_VALIDATE_RET( R != NULL );
19323d3b0591SJens Wiklander     MPI_VALIDATE_RET( A != NULL );
19333d3b0591SJens Wiklander     MPI_VALIDATE_RET( B != NULL );
1934817466cbSJens Wiklander 
1935817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( B, 0 ) < 0 )
1936817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_NEGATIVE_VALUE );
1937817466cbSJens Wiklander 
1938817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_div_mpi( NULL, R, A, B ) );
1939817466cbSJens Wiklander 
1940817466cbSJens Wiklander     while( mbedtls_mpi_cmp_int( R, 0 ) < 0 )
1941817466cbSJens Wiklander       MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( R, R, B ) );
1942817466cbSJens Wiklander 
1943817466cbSJens Wiklander     while( mbedtls_mpi_cmp_mpi( R, B ) >= 0 )
1944817466cbSJens Wiklander       MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( R, R, B ) );
1945817466cbSJens Wiklander 
1946817466cbSJens Wiklander cleanup:
1947817466cbSJens Wiklander 
1948817466cbSJens Wiklander     return( ret );
1949817466cbSJens Wiklander }
1950817466cbSJens Wiklander 
1951817466cbSJens Wiklander /*
1952817466cbSJens Wiklander  * Modulo: r = A mod b
1953817466cbSJens Wiklander  */
1954817466cbSJens Wiklander int mbedtls_mpi_mod_int( mbedtls_mpi_uint *r, const mbedtls_mpi *A, mbedtls_mpi_sint b )
1955817466cbSJens Wiklander {
1956817466cbSJens Wiklander     size_t i;
1957817466cbSJens Wiklander     mbedtls_mpi_uint x, y, z;
19583d3b0591SJens Wiklander     MPI_VALIDATE_RET( r != NULL );
19593d3b0591SJens Wiklander     MPI_VALIDATE_RET( A != NULL );
1960817466cbSJens Wiklander 
1961817466cbSJens Wiklander     if( b == 0 )
1962817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_DIVISION_BY_ZERO );
1963817466cbSJens Wiklander 
1964817466cbSJens Wiklander     if( b < 0 )
1965817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_NEGATIVE_VALUE );
1966817466cbSJens Wiklander 
1967817466cbSJens Wiklander     /*
1968817466cbSJens Wiklander      * handle trivial cases
1969817466cbSJens Wiklander      */
1970817466cbSJens Wiklander     if( b == 1 )
1971817466cbSJens Wiklander     {
1972817466cbSJens Wiklander         *r = 0;
1973817466cbSJens Wiklander         return( 0 );
1974817466cbSJens Wiklander     }
1975817466cbSJens Wiklander 
1976817466cbSJens Wiklander     if( b == 2 )
1977817466cbSJens Wiklander     {
1978817466cbSJens Wiklander         *r = A->p[0] & 1;
1979817466cbSJens Wiklander         return( 0 );
1980817466cbSJens Wiklander     }
1981817466cbSJens Wiklander 
1982817466cbSJens Wiklander     /*
1983817466cbSJens Wiklander      * general case
1984817466cbSJens Wiklander      */
1985817466cbSJens Wiklander     for( i = A->n, y = 0; i > 0; i-- )
1986817466cbSJens Wiklander     {
1987817466cbSJens Wiklander         x  = A->p[i - 1];
1988817466cbSJens Wiklander         y  = ( y << biH ) | ( x >> biH );
1989817466cbSJens Wiklander         z  = y / b;
1990817466cbSJens Wiklander         y -= z * b;
1991817466cbSJens Wiklander 
1992817466cbSJens Wiklander         x <<= biH;
1993817466cbSJens Wiklander         y  = ( y << biH ) | ( x >> biH );
1994817466cbSJens Wiklander         z  = y / b;
1995817466cbSJens Wiklander         y -= z * b;
1996817466cbSJens Wiklander     }
1997817466cbSJens Wiklander 
1998817466cbSJens Wiklander     /*
1999817466cbSJens Wiklander      * If A is negative, then the current y represents a negative value.
2000817466cbSJens Wiklander      * Flipping it to the positive side.
2001817466cbSJens Wiklander      */
2002817466cbSJens Wiklander     if( A->s < 0 && y != 0 )
2003817466cbSJens Wiklander         y = b - y;
2004817466cbSJens Wiklander 
2005817466cbSJens Wiklander     *r = y;
2006817466cbSJens Wiklander 
2007817466cbSJens Wiklander     return( 0 );
2008817466cbSJens Wiklander }
2009817466cbSJens Wiklander 
2010817466cbSJens Wiklander /*
2011817466cbSJens Wiklander  * Fast Montgomery initialization (thanks to Tom St Denis)
2012817466cbSJens Wiklander  */
201362f21181SJens Wiklander void mbedtls_mpi_montg_init( mbedtls_mpi_uint *mm, const mbedtls_mpi *N )
2014817466cbSJens Wiklander {
2015817466cbSJens Wiklander     mbedtls_mpi_uint x, m0 = N->p[0];
2016817466cbSJens Wiklander     unsigned int i;
2017817466cbSJens Wiklander 
2018817466cbSJens Wiklander     x  = m0;
2019817466cbSJens Wiklander     x += ( ( m0 + 2 ) & 4 ) << 1;
2020817466cbSJens Wiklander 
2021817466cbSJens Wiklander     for( i = biL; i >= 8; i /= 2 )
2022817466cbSJens Wiklander         x *= ( 2 - ( m0 * x ) );
2023817466cbSJens Wiklander 
2024817466cbSJens Wiklander     *mm = ~x + 1;
2025817466cbSJens Wiklander }
2026817466cbSJens Wiklander 
2027817466cbSJens Wiklander /*
2028817466cbSJens Wiklander  * Montgomery multiplication: A = A * B * R^-1 mod N  (HAC 14.36)
2029817466cbSJens Wiklander  */
203062f21181SJens Wiklander int mbedtls_mpi_montmul( mbedtls_mpi *A, const mbedtls_mpi *B,
203162f21181SJens Wiklander 			 const mbedtls_mpi *N, mbedtls_mpi_uint mm,
2032817466cbSJens Wiklander                          const mbedtls_mpi *T )
2033817466cbSJens Wiklander {
2034817466cbSJens Wiklander     size_t i, n, m;
2035817466cbSJens Wiklander     mbedtls_mpi_uint u0, u1, *d;
2036817466cbSJens Wiklander 
2037817466cbSJens Wiklander     if( T->n < N->n + 1 || T->p == NULL )
2038817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
2039817466cbSJens Wiklander 
2040817466cbSJens Wiklander     memset( T->p, 0, T->n * ciL );
2041817466cbSJens Wiklander 
2042817466cbSJens Wiklander     d = T->p;
2043817466cbSJens Wiklander     n = N->n;
2044817466cbSJens Wiklander     m = ( B->n < n ) ? B->n : n;
2045817466cbSJens Wiklander 
2046817466cbSJens Wiklander     for( i = 0; i < n; i++ )
2047817466cbSJens Wiklander     {
2048817466cbSJens Wiklander         /*
2049817466cbSJens Wiklander          * T = (T + u0*B + u1*N) / 2^biL
2050817466cbSJens Wiklander          */
2051817466cbSJens Wiklander         u0 = A->p[i];
2052817466cbSJens Wiklander         u1 = ( d[0] + u0 * B->p[0] ) * mm;
2053817466cbSJens Wiklander 
2054817466cbSJens Wiklander         mpi_mul_hlp( m, B->p, d, u0 );
2055817466cbSJens Wiklander         mpi_mul_hlp( n, N->p, d, u1 );
2056817466cbSJens Wiklander 
2057817466cbSJens Wiklander         *d++ = u0; d[n + 1] = 0;
2058817466cbSJens Wiklander     }
2059817466cbSJens Wiklander 
2060817466cbSJens Wiklander     memcpy( A->p, d, ( n + 1 ) * ciL );
2061817466cbSJens Wiklander 
2062817466cbSJens Wiklander     if( mbedtls_mpi_cmp_abs( A, N ) >= 0 )
2063817466cbSJens Wiklander         mpi_sub_hlp( n, N->p, A->p );
2064817466cbSJens Wiklander     else
2065817466cbSJens Wiklander         /* prevent timing attacks */
2066817466cbSJens Wiklander         mpi_sub_hlp( n, A->p, T->p );
2067817466cbSJens Wiklander 
2068817466cbSJens Wiklander     return( 0 );
2069817466cbSJens Wiklander }
2070817466cbSJens Wiklander 
2071817466cbSJens Wiklander /*
2072817466cbSJens Wiklander  * Montgomery reduction: A = A * R^-1 mod N
2073817466cbSJens Wiklander  */
207462f21181SJens Wiklander int mbedtls_mpi_montred( mbedtls_mpi *A, const mbedtls_mpi *N,
207562f21181SJens Wiklander 			 mbedtls_mpi_uint mm, const mbedtls_mpi *T )
2076817466cbSJens Wiklander {
2077817466cbSJens Wiklander     mbedtls_mpi_uint z = 1;
2078817466cbSJens Wiklander     mbedtls_mpi U;
2079817466cbSJens Wiklander 
2080817466cbSJens Wiklander     U.n = U.s = (int) z;
2081817466cbSJens Wiklander     U.p = &z;
2082817466cbSJens Wiklander 
208362f21181SJens Wiklander     return( mbedtls_mpi_montmul( A, &U, N, mm, T ) );
2084817466cbSJens Wiklander }
2085817466cbSJens Wiklander 
2086817466cbSJens Wiklander /*
2087817466cbSJens Wiklander  * Sliding-window exponentiation: X = A^E mod N  (HAC 14.85)
2088817466cbSJens Wiklander  */
20893d3b0591SJens Wiklander int mbedtls_mpi_exp_mod( mbedtls_mpi *X, const mbedtls_mpi *A,
20903d3b0591SJens Wiklander                          const mbedtls_mpi *E, const mbedtls_mpi *N,
20913d3b0591SJens Wiklander                          mbedtls_mpi *_RR )
2092817466cbSJens Wiklander {
2093*11fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
2094817466cbSJens Wiklander     size_t wbits, wsize, one = 1;
2095817466cbSJens Wiklander     size_t i, j, nblimbs;
2096817466cbSJens Wiklander     size_t bufsize, nbits;
2097817466cbSJens Wiklander     mbedtls_mpi_uint ei, mm, state;
209841e5aa8fSJens Wiklander     mbedtls_mpi RR, T, Apos;
2099ad443200SJens Wiklander     mbedtls_mpi *W = NULL;
210041e5aa8fSJens Wiklander     const size_t array_size_W = 2 << MBEDTLS_MPI_WINDOW_SIZE;
2101817466cbSJens Wiklander     int neg;
2102817466cbSJens Wiklander 
21033d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
21043d3b0591SJens Wiklander     MPI_VALIDATE_RET( A != NULL );
21053d3b0591SJens Wiklander     MPI_VALIDATE_RET( E != NULL );
21063d3b0591SJens Wiklander     MPI_VALIDATE_RET( N != NULL );
21073d3b0591SJens Wiklander 
21083d3b0591SJens Wiklander     if( mbedtls_mpi_cmp_int( N, 0 ) <= 0 || ( N->p[0] & 1 ) == 0 )
2109817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
2110817466cbSJens Wiklander 
2111817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( E, 0 ) < 0 )
2112817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
2113817466cbSJens Wiklander 
2114817466cbSJens Wiklander     /*
2115817466cbSJens Wiklander      * Init temps and window size
2116817466cbSJens Wiklander      */
211762f21181SJens Wiklander     mbedtls_mpi_montg_init( &mm, N );
211898bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &RR ); mbedtls_mpi_init_mempool( &T );
211998bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &Apos );
2120817466cbSJens Wiklander 
2121817466cbSJens Wiklander     i = mbedtls_mpi_bitlen( E );
2122817466cbSJens Wiklander 
2123817466cbSJens Wiklander     wsize = ( i > 671 ) ? 6 : ( i > 239 ) ? 5 :
2124817466cbSJens Wiklander             ( i >  79 ) ? 4 : ( i >  23 ) ? 3 : 1;
2125817466cbSJens Wiklander 
21265b25c76aSJerome Forissier #if( MBEDTLS_MPI_WINDOW_SIZE < 6 )
2127817466cbSJens Wiklander     if( wsize > MBEDTLS_MPI_WINDOW_SIZE )
2128817466cbSJens Wiklander         wsize = MBEDTLS_MPI_WINDOW_SIZE;
21295b25c76aSJerome Forissier #endif
2130817466cbSJens Wiklander 
2131817466cbSJens Wiklander     j = N->n + 1;
2132817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, j ) );
2133ad443200SJens Wiklander 
2134817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &T, j * 2 ) );
2135817466cbSJens Wiklander 
2136817466cbSJens Wiklander     /*
2137817466cbSJens Wiklander      * Compensate for negative A (and correct at the end)
2138817466cbSJens Wiklander      */
2139817466cbSJens Wiklander     neg = ( A->s == -1 );
2140817466cbSJens Wiklander     if( neg )
2141817466cbSJens Wiklander     {
2142817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &Apos, A ) );
2143817466cbSJens Wiklander         Apos.s = 1;
2144817466cbSJens Wiklander         A = &Apos;
2145817466cbSJens Wiklander     }
2146817466cbSJens Wiklander 
2147817466cbSJens Wiklander     /*
2148817466cbSJens Wiklander      * If 1st call, pre-compute R^2 mod N
2149817466cbSJens Wiklander      */
2150817466cbSJens Wiklander     if( _RR == NULL || _RR->p == NULL )
2151817466cbSJens Wiklander     {
2152817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &RR, 1 ) );
2153817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &RR, N->n * 2 * biL ) );
2154817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &RR, &RR, N ) );
2155817466cbSJens Wiklander 
2156817466cbSJens Wiklander         if( _RR != NULL )
2157817466cbSJens Wiklander             memcpy( _RR, &RR, sizeof( mbedtls_mpi ) );
2158817466cbSJens Wiklander     }
2159817466cbSJens Wiklander     else
2160817466cbSJens Wiklander         memcpy( &RR, _RR, sizeof( mbedtls_mpi ) );
2161817466cbSJens Wiklander 
2162ad443200SJens Wiklander     W = mempool_alloc( mbedtls_mpi_mempool,
2163ad443200SJens Wiklander                        sizeof( mbedtls_mpi ) * array_size_W );
2164ad443200SJens Wiklander     if( W == NULL ) {
2165ad443200SJens Wiklander         ret = MBEDTLS_ERR_MPI_ALLOC_FAILED;
2166ad443200SJens Wiklander         goto cleanup;
2167ad443200SJens Wiklander     }
2168ad443200SJens Wiklander     for( i = 0; i < array_size_W; i++ )
2169ad443200SJens Wiklander         mbedtls_mpi_init_mempool( W + i );
2170ad443200SJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[1],  j ) );
2171ad443200SJens Wiklander 
2172817466cbSJens Wiklander     /*
2173817466cbSJens Wiklander      * W[1] = A * R^2 * R^-1 mod N = A * R mod N
2174817466cbSJens Wiklander      */
2175817466cbSJens Wiklander     if( mbedtls_mpi_cmp_mpi( A, N ) >= 0 )
2176817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &W[1], A, N ) );
2177817466cbSJens Wiklander     else
2178817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &W[1], A ) );
2179817466cbSJens Wiklander 
218062f21181SJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_montmul( &W[1], &RR, N, mm, &T ) );
2181817466cbSJens Wiklander 
2182817466cbSJens Wiklander     /*
2183817466cbSJens Wiklander      * X = R^2 * R^-1 mod N = R mod N
2184817466cbSJens Wiklander      */
2185817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, &RR ) );
218662f21181SJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_montred( X, N, mm, &T ) );
2187817466cbSJens Wiklander 
2188817466cbSJens Wiklander     if( wsize > 1 )
2189817466cbSJens Wiklander     {
2190817466cbSJens Wiklander         /*
2191817466cbSJens Wiklander          * W[1 << (wsize - 1)] = W[1] ^ (wsize - 1)
2192817466cbSJens Wiklander          */
2193817466cbSJens Wiklander         j =  one << ( wsize - 1 );
2194817466cbSJens Wiklander 
2195817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[j], N->n + 1 ) );
2196817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &W[j], &W[1]    ) );
2197817466cbSJens Wiklander 
2198817466cbSJens Wiklander         for( i = 0; i < wsize - 1; i++ )
219962f21181SJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_montmul( &W[j], &W[j], N, mm, &T ) );
2200817466cbSJens Wiklander 
2201817466cbSJens Wiklander         /*
2202817466cbSJens Wiklander          * W[i] = W[i - 1] * W[1]
2203817466cbSJens Wiklander          */
2204817466cbSJens Wiklander         for( i = j + 1; i < ( one << wsize ); i++ )
2205817466cbSJens Wiklander         {
2206817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[i], N->n + 1 ) );
2207817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &W[i], &W[i - 1] ) );
2208817466cbSJens Wiklander 
220962f21181SJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_montmul( &W[i], &W[1], N, mm, &T ) );
2210817466cbSJens Wiklander         }
2211817466cbSJens Wiklander     }
2212817466cbSJens Wiklander 
2213817466cbSJens Wiklander     nblimbs = E->n;
2214817466cbSJens Wiklander     bufsize = 0;
2215817466cbSJens Wiklander     nbits   = 0;
2216817466cbSJens Wiklander     wbits   = 0;
2217817466cbSJens Wiklander     state   = 0;
2218817466cbSJens Wiklander 
2219817466cbSJens Wiklander     while( 1 )
2220817466cbSJens Wiklander     {
2221817466cbSJens Wiklander         if( bufsize == 0 )
2222817466cbSJens Wiklander         {
2223817466cbSJens Wiklander             if( nblimbs == 0 )
2224817466cbSJens Wiklander                 break;
2225817466cbSJens Wiklander 
2226817466cbSJens Wiklander             nblimbs--;
2227817466cbSJens Wiklander 
2228817466cbSJens Wiklander             bufsize = sizeof( mbedtls_mpi_uint ) << 3;
2229817466cbSJens Wiklander         }
2230817466cbSJens Wiklander 
2231817466cbSJens Wiklander         bufsize--;
2232817466cbSJens Wiklander 
2233817466cbSJens Wiklander         ei = (E->p[nblimbs] >> bufsize) & 1;
2234817466cbSJens Wiklander 
2235817466cbSJens Wiklander         /*
2236817466cbSJens Wiklander          * skip leading 0s
2237817466cbSJens Wiklander          */
2238817466cbSJens Wiklander         if( ei == 0 && state == 0 )
2239817466cbSJens Wiklander             continue;
2240817466cbSJens Wiklander 
2241817466cbSJens Wiklander         if( ei == 0 && state == 1 )
2242817466cbSJens Wiklander         {
2243817466cbSJens Wiklander             /*
2244817466cbSJens Wiklander              * out of window, square X
2245817466cbSJens Wiklander              */
224662f21181SJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_montmul( X, X, N, mm, &T ) );
2247817466cbSJens Wiklander             continue;
2248817466cbSJens Wiklander         }
2249817466cbSJens Wiklander 
2250817466cbSJens Wiklander         /*
2251817466cbSJens Wiklander          * add ei to current window
2252817466cbSJens Wiklander          */
2253817466cbSJens Wiklander         state = 2;
2254817466cbSJens Wiklander 
2255817466cbSJens Wiklander         nbits++;
2256817466cbSJens Wiklander         wbits |= ( ei << ( wsize - nbits ) );
2257817466cbSJens Wiklander 
2258817466cbSJens Wiklander         if( nbits == wsize )
2259817466cbSJens Wiklander         {
2260817466cbSJens Wiklander             /*
2261817466cbSJens Wiklander              * X = X^wsize R^-1 mod N
2262817466cbSJens Wiklander              */
2263817466cbSJens Wiklander             for( i = 0; i < wsize; i++ )
226462f21181SJens Wiklander                 MBEDTLS_MPI_CHK( mbedtls_mpi_montmul( X, X, N, mm, &T ) );
2265817466cbSJens Wiklander 
2266817466cbSJens Wiklander             /*
2267817466cbSJens Wiklander              * X = X * W[wbits] R^-1 mod N
2268817466cbSJens Wiklander              */
226962f21181SJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_montmul( X, &W[wbits], N, mm, &T ) );
2270817466cbSJens Wiklander 
2271817466cbSJens Wiklander             state--;
2272817466cbSJens Wiklander             nbits = 0;
2273817466cbSJens Wiklander             wbits = 0;
2274817466cbSJens Wiklander         }
2275817466cbSJens Wiklander     }
2276817466cbSJens Wiklander 
2277817466cbSJens Wiklander     /*
2278817466cbSJens Wiklander      * process the remaining bits
2279817466cbSJens Wiklander      */
2280817466cbSJens Wiklander     for( i = 0; i < nbits; i++ )
2281817466cbSJens Wiklander     {
228262f21181SJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_montmul( X, X, N, mm, &T ) );
2283817466cbSJens Wiklander 
2284817466cbSJens Wiklander         wbits <<= 1;
2285817466cbSJens Wiklander 
2286817466cbSJens Wiklander         if( ( wbits & ( one << wsize ) ) != 0 )
228762f21181SJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_montmul( X, &W[1], N, mm, &T ) );
2288817466cbSJens Wiklander     }
2289817466cbSJens Wiklander 
2290817466cbSJens Wiklander     /*
2291817466cbSJens Wiklander      * X = A^E * R * R^-1 mod N = A^E mod N
2292817466cbSJens Wiklander      */
229362f21181SJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_montred( X, N, mm, &T ) );
2294817466cbSJens Wiklander 
2295817466cbSJens Wiklander     if( neg && E->n != 0 && ( E->p[0] & 1 ) != 0 )
2296817466cbSJens Wiklander     {
2297817466cbSJens Wiklander         X->s = -1;
2298817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( X, N, X ) );
2299817466cbSJens Wiklander     }
2300817466cbSJens Wiklander 
2301817466cbSJens Wiklander cleanup:
2302817466cbSJens Wiklander 
2303ad443200SJens Wiklander     if( W )
230441e5aa8fSJens Wiklander         for( i = 0; i < array_size_W; i++ )
2305b99a4a18SJens Wiklander             mbedtls_mpi_free( W + i );
230641e5aa8fSJens Wiklander     mempool_free( mbedtls_mpi_mempool , W );
2307817466cbSJens Wiklander 
2308b99a4a18SJens Wiklander     mbedtls_mpi_free( &T ); mbedtls_mpi_free( &Apos );
2309817466cbSJens Wiklander 
2310817466cbSJens Wiklander     if( _RR == NULL || _RR->p == NULL )
2311817466cbSJens Wiklander         mbedtls_mpi_free( &RR );
2312817466cbSJens Wiklander 
2313817466cbSJens Wiklander     return( ret );
2314817466cbSJens Wiklander }
2315817466cbSJens Wiklander 
2316817466cbSJens Wiklander /*
2317817466cbSJens Wiklander  * Greatest common divisor: G = gcd(A, B)  (HAC 14.54)
2318817466cbSJens Wiklander  */
2319817466cbSJens Wiklander int mbedtls_mpi_gcd( mbedtls_mpi *G, const mbedtls_mpi *A, const mbedtls_mpi *B )
2320817466cbSJens Wiklander {
2321*11fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
2322817466cbSJens Wiklander     size_t lz, lzt;
2323*11fa71b9SJerome Forissier     mbedtls_mpi TA, TB;
2324817466cbSJens Wiklander 
23253d3b0591SJens Wiklander     MPI_VALIDATE_RET( G != NULL );
23263d3b0591SJens Wiklander     MPI_VALIDATE_RET( A != NULL );
23273d3b0591SJens Wiklander     MPI_VALIDATE_RET( B != NULL );
23283d3b0591SJens Wiklander 
2329*11fa71b9SJerome Forissier     mbedtls_mpi_init_mempool( &TA ); mbedtls_mpi_init_mempool( &TB );
2330817466cbSJens Wiklander 
2331817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TA, A ) );
2332817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, B ) );
2333817466cbSJens Wiklander 
2334817466cbSJens Wiklander     lz = mbedtls_mpi_lsb( &TA );
2335817466cbSJens Wiklander     lzt = mbedtls_mpi_lsb( &TB );
2336817466cbSJens Wiklander 
2337817466cbSJens Wiklander     if( lzt < lz )
2338817466cbSJens Wiklander         lz = lzt;
2339817466cbSJens Wiklander 
2340817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TA, lz ) );
2341817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TB, lz ) );
2342817466cbSJens Wiklander 
2343817466cbSJens Wiklander     TA.s = TB.s = 1;
2344817466cbSJens Wiklander 
2345817466cbSJens Wiklander     while( mbedtls_mpi_cmp_int( &TA, 0 ) != 0 )
2346817466cbSJens Wiklander     {
2347817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TA, mbedtls_mpi_lsb( &TA ) ) );
2348817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TB, mbedtls_mpi_lsb( &TB ) ) );
2349817466cbSJens Wiklander 
2350817466cbSJens Wiklander         if( mbedtls_mpi_cmp_mpi( &TA, &TB ) >= 0 )
2351817466cbSJens Wiklander         {
2352817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( &TA, &TA, &TB ) );
2353817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TA, 1 ) );
2354817466cbSJens Wiklander         }
2355817466cbSJens Wiklander         else
2356817466cbSJens Wiklander         {
2357817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( &TB, &TB, &TA ) );
2358817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TB, 1 ) );
2359817466cbSJens Wiklander         }
2360817466cbSJens Wiklander     }
2361817466cbSJens Wiklander 
2362817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &TB, lz ) );
2363817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( G, &TB ) );
2364817466cbSJens Wiklander 
2365817466cbSJens Wiklander cleanup:
2366817466cbSJens Wiklander 
2367*11fa71b9SJerome Forissier     mbedtls_mpi_free( &TA ); mbedtls_mpi_free( &TB );
2368817466cbSJens Wiklander 
2369817466cbSJens Wiklander     return( ret );
2370817466cbSJens Wiklander }
2371817466cbSJens Wiklander 
2372817466cbSJens Wiklander /*
2373817466cbSJens Wiklander  * Fill X with size bytes of random.
2374817466cbSJens Wiklander  *
2375817466cbSJens Wiklander  * Use a temporary bytes representation to make sure the result is the same
2376817466cbSJens Wiklander  * regardless of the platform endianness (useful when f_rng is actually
2377817466cbSJens Wiklander  * deterministic, eg for tests).
2378817466cbSJens Wiklander  */
2379817466cbSJens Wiklander int mbedtls_mpi_fill_random( mbedtls_mpi *X, size_t size,
2380817466cbSJens Wiklander                      int (*f_rng)(void *, unsigned char *, size_t),
2381817466cbSJens Wiklander                      void *p_rng )
2382817466cbSJens Wiklander {
2383*11fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
23845b25c76aSJerome Forissier     size_t const limbs = CHARS_TO_LIMBS( size );
23855b25c76aSJerome Forissier     size_t const overhead = ( limbs * ciL ) - size;
23865b25c76aSJerome Forissier     unsigned char *Xp;
23875b25c76aSJerome Forissier 
23883d3b0591SJens Wiklander     MPI_VALIDATE_RET( X     != NULL );
23893d3b0591SJens Wiklander     MPI_VALIDATE_RET( f_rng != NULL );
2390817466cbSJens Wiklander 
23915b25c76aSJerome Forissier     /* Ensure that target MPI has exactly the necessary number of limbs */
23925b25c76aSJerome Forissier     if( X->n != limbs )
23935b25c76aSJerome Forissier     {
23945b25c76aSJerome Forissier         mbedtls_mpi_free( X );
23955b25c76aSJerome Forissier         mbedtls_mpi_init( X );
23965b25c76aSJerome Forissier         MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, limbs ) );
23975b25c76aSJerome Forissier     }
23985b25c76aSJerome Forissier     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) );
2399817466cbSJens Wiklander 
24005b25c76aSJerome Forissier     Xp = (unsigned char*) X->p;
24015b25c76aSJerome Forissier     f_rng( p_rng, Xp + overhead, size );
24025b25c76aSJerome Forissier 
24035b25c76aSJerome Forissier     mpi_bigendian_to_host( X->p, limbs );
2404817466cbSJens Wiklander 
2405817466cbSJens Wiklander cleanup:
2406817466cbSJens Wiklander     return( ret );
2407817466cbSJens Wiklander }
2408817466cbSJens Wiklander 
2409817466cbSJens Wiklander /*
2410817466cbSJens Wiklander  * Modular inverse: X = A^-1 mod N  (HAC 14.61 / 14.64)
2411817466cbSJens Wiklander  */
2412817466cbSJens Wiklander int mbedtls_mpi_inv_mod( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *N )
2413817466cbSJens Wiklander {
2414*11fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
2415817466cbSJens Wiklander     mbedtls_mpi G, TA, TU, U1, U2, TB, TV, V1, V2;
24163d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
24173d3b0591SJens Wiklander     MPI_VALIDATE_RET( A != NULL );
24183d3b0591SJens Wiklander     MPI_VALIDATE_RET( N != NULL );
2419817466cbSJens Wiklander 
2420817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( N, 1 ) <= 0 )
2421817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
2422817466cbSJens Wiklander 
242398bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &TA ); mbedtls_mpi_init_mempool( &TU );
242498bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &U1 ); mbedtls_mpi_init_mempool( &U2 );
242598bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &G ); mbedtls_mpi_init_mempool( &TB );
242698bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &TV ); mbedtls_mpi_init_mempool( &V1 );
242798bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &V2 );
2428817466cbSJens Wiklander 
2429817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &G, A, N ) );
2430817466cbSJens Wiklander 
2431817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( &G, 1 ) != 0 )
2432817466cbSJens Wiklander     {
2433817466cbSJens Wiklander         ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2434817466cbSJens Wiklander         goto cleanup;
2435817466cbSJens Wiklander     }
2436817466cbSJens Wiklander 
2437817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &TA, A, N ) );
2438817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TU, &TA ) );
2439817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, N ) );
2440817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TV, N ) );
2441817466cbSJens Wiklander 
2442817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &U1, 1 ) );
2443817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &U2, 0 ) );
2444817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &V1, 0 ) );
2445817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &V2, 1 ) );
2446817466cbSJens Wiklander 
2447817466cbSJens Wiklander     do
2448817466cbSJens Wiklander     {
2449817466cbSJens Wiklander         while( ( TU.p[0] & 1 ) == 0 )
2450817466cbSJens Wiklander         {
2451817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TU, 1 ) );
2452817466cbSJens Wiklander 
2453817466cbSJens Wiklander             if( ( U1.p[0] & 1 ) != 0 || ( U2.p[0] & 1 ) != 0 )
2454817466cbSJens Wiklander             {
2455817466cbSJens Wiklander                 MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &U1, &U1, &TB ) );
2456817466cbSJens Wiklander                 MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &U2, &U2, &TA ) );
2457817466cbSJens Wiklander             }
2458817466cbSJens Wiklander 
2459817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &U1, 1 ) );
2460817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &U2, 1 ) );
2461817466cbSJens Wiklander         }
2462817466cbSJens Wiklander 
2463817466cbSJens Wiklander         while( ( TV.p[0] & 1 ) == 0 )
2464817466cbSJens Wiklander         {
2465817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TV, 1 ) );
2466817466cbSJens Wiklander 
2467817466cbSJens Wiklander             if( ( V1.p[0] & 1 ) != 0 || ( V2.p[0] & 1 ) != 0 )
2468817466cbSJens Wiklander             {
2469817466cbSJens Wiklander                 MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &V1, &V1, &TB ) );
2470817466cbSJens Wiklander                 MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &V2, &V2, &TA ) );
2471817466cbSJens Wiklander             }
2472817466cbSJens Wiklander 
2473817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &V1, 1 ) );
2474817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &V2, 1 ) );
2475817466cbSJens Wiklander         }
2476817466cbSJens Wiklander 
2477817466cbSJens Wiklander         if( mbedtls_mpi_cmp_mpi( &TU, &TV ) >= 0 )
2478817466cbSJens Wiklander         {
2479817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &TU, &TU, &TV ) );
2480817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &U1, &U1, &V1 ) );
2481817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &U2, &U2, &V2 ) );
2482817466cbSJens Wiklander         }
2483817466cbSJens Wiklander         else
2484817466cbSJens Wiklander         {
2485817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &TV, &TV, &TU ) );
2486817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &V1, &V1, &U1 ) );
2487817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &V2, &V2, &U2 ) );
2488817466cbSJens Wiklander         }
2489817466cbSJens Wiklander     }
2490817466cbSJens Wiklander     while( mbedtls_mpi_cmp_int( &TU, 0 ) != 0 );
2491817466cbSJens Wiklander 
2492817466cbSJens Wiklander     while( mbedtls_mpi_cmp_int( &V1, 0 ) < 0 )
2493817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &V1, &V1, N ) );
2494817466cbSJens Wiklander 
2495817466cbSJens Wiklander     while( mbedtls_mpi_cmp_mpi( &V1, N ) >= 0 )
2496817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &V1, &V1, N ) );
2497817466cbSJens Wiklander 
2498817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, &V1 ) );
2499817466cbSJens Wiklander 
2500817466cbSJens Wiklander cleanup:
2501817466cbSJens Wiklander 
2502817466cbSJens Wiklander     mbedtls_mpi_free( &TA ); mbedtls_mpi_free( &TU ); mbedtls_mpi_free( &U1 ); mbedtls_mpi_free( &U2 );
2503817466cbSJens Wiklander     mbedtls_mpi_free( &G ); mbedtls_mpi_free( &TB ); mbedtls_mpi_free( &TV );
2504817466cbSJens Wiklander     mbedtls_mpi_free( &V1 ); mbedtls_mpi_free( &V2 );
2505817466cbSJens Wiklander 
2506817466cbSJens Wiklander     return( ret );
2507817466cbSJens Wiklander }
2508817466cbSJens Wiklander 
2509817466cbSJens Wiklander #if defined(MBEDTLS_GENPRIME)
2510817466cbSJens Wiklander 
2511817466cbSJens Wiklander static const int small_prime[] =
2512817466cbSJens Wiklander {
2513817466cbSJens Wiklander         3,    5,    7,   11,   13,   17,   19,   23,
2514817466cbSJens Wiklander        29,   31,   37,   41,   43,   47,   53,   59,
2515817466cbSJens Wiklander        61,   67,   71,   73,   79,   83,   89,   97,
2516817466cbSJens Wiklander       101,  103,  107,  109,  113,  127,  131,  137,
2517817466cbSJens Wiklander       139,  149,  151,  157,  163,  167,  173,  179,
2518817466cbSJens Wiklander       181,  191,  193,  197,  199,  211,  223,  227,
2519817466cbSJens Wiklander       229,  233,  239,  241,  251,  257,  263,  269,
2520817466cbSJens Wiklander       271,  277,  281,  283,  293,  307,  311,  313,
2521817466cbSJens Wiklander       317,  331,  337,  347,  349,  353,  359,  367,
2522817466cbSJens Wiklander       373,  379,  383,  389,  397,  401,  409,  419,
2523817466cbSJens Wiklander       421,  431,  433,  439,  443,  449,  457,  461,
2524817466cbSJens Wiklander       463,  467,  479,  487,  491,  499,  503,  509,
2525817466cbSJens Wiklander       521,  523,  541,  547,  557,  563,  569,  571,
2526817466cbSJens Wiklander       577,  587,  593,  599,  601,  607,  613,  617,
2527817466cbSJens Wiklander       619,  631,  641,  643,  647,  653,  659,  661,
2528817466cbSJens Wiklander       673,  677,  683,  691,  701,  709,  719,  727,
2529817466cbSJens Wiklander       733,  739,  743,  751,  757,  761,  769,  773,
2530817466cbSJens Wiklander       787,  797,  809,  811,  821,  823,  827,  829,
2531817466cbSJens Wiklander       839,  853,  857,  859,  863,  877,  881,  883,
2532817466cbSJens Wiklander       887,  907,  911,  919,  929,  937,  941,  947,
2533817466cbSJens Wiklander       953,  967,  971,  977,  983,  991,  997, -103
2534817466cbSJens Wiklander };
2535817466cbSJens Wiklander 
2536817466cbSJens Wiklander /*
2537817466cbSJens Wiklander  * Small divisors test (X must be positive)
2538817466cbSJens Wiklander  *
2539817466cbSJens Wiklander  * Return values:
2540817466cbSJens Wiklander  * 0: no small factor (possible prime, more tests needed)
2541817466cbSJens Wiklander  * 1: certain prime
2542817466cbSJens Wiklander  * MBEDTLS_ERR_MPI_NOT_ACCEPTABLE: certain non-prime
2543817466cbSJens Wiklander  * other negative: error
2544817466cbSJens Wiklander  */
2545817466cbSJens Wiklander static int mpi_check_small_factors( const mbedtls_mpi *X )
2546817466cbSJens Wiklander {
2547817466cbSJens Wiklander     int ret = 0;
2548817466cbSJens Wiklander     size_t i;
2549817466cbSJens Wiklander     mbedtls_mpi_uint r;
2550817466cbSJens Wiklander 
2551817466cbSJens Wiklander     if( ( X->p[0] & 1 ) == 0 )
2552817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE );
2553817466cbSJens Wiklander 
2554817466cbSJens Wiklander     for( i = 0; small_prime[i] > 0; i++ )
2555817466cbSJens Wiklander     {
2556817466cbSJens Wiklander         if( mbedtls_mpi_cmp_int( X, small_prime[i] ) <= 0 )
2557817466cbSJens Wiklander             return( 1 );
2558817466cbSJens Wiklander 
2559817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mod_int( &r, X, small_prime[i] ) );
2560817466cbSJens Wiklander 
2561817466cbSJens Wiklander         if( r == 0 )
2562817466cbSJens Wiklander             return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE );
2563817466cbSJens Wiklander     }
2564817466cbSJens Wiklander 
2565817466cbSJens Wiklander cleanup:
2566817466cbSJens Wiklander     return( ret );
2567817466cbSJens Wiklander }
2568817466cbSJens Wiklander 
2569817466cbSJens Wiklander /*
2570817466cbSJens Wiklander  * Miller-Rabin pseudo-primality test  (HAC 4.24)
2571817466cbSJens Wiklander  */
25723d3b0591SJens Wiklander static int mpi_miller_rabin( const mbedtls_mpi *X, size_t rounds,
2573817466cbSJens Wiklander                              int (*f_rng)(void *, unsigned char *, size_t),
2574817466cbSJens Wiklander                              void *p_rng )
2575817466cbSJens Wiklander {
2576817466cbSJens Wiklander     int ret, count;
25773d3b0591SJens Wiklander     size_t i, j, k, s;
2578817466cbSJens Wiklander     mbedtls_mpi W, R, T, A, RR;
2579817466cbSJens Wiklander 
25803d3b0591SJens Wiklander     MPI_VALIDATE_RET( X     != NULL );
25813d3b0591SJens Wiklander     MPI_VALIDATE_RET( f_rng != NULL );
25823d3b0591SJens Wiklander 
258398bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &W ); mbedtls_mpi_init_mempool( &R );
258498bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &T ); mbedtls_mpi_init_mempool( &A );
258598bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &RR );
2586817466cbSJens Wiklander 
2587817466cbSJens Wiklander     /*
2588817466cbSJens Wiklander      * W = |X| - 1
2589817466cbSJens Wiklander      * R = W >> lsb( W )
2590817466cbSJens Wiklander      */
2591817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &W, X, 1 ) );
2592817466cbSJens Wiklander     s = mbedtls_mpi_lsb( &W );
2593817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &R, &W ) );
2594817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &R, s ) );
2595817466cbSJens Wiklander 
25963d3b0591SJens Wiklander     for( i = 0; i < rounds; i++ )
2597817466cbSJens Wiklander     {
2598817466cbSJens Wiklander         /*
2599817466cbSJens Wiklander          * pick a random A, 1 < A < |X| - 1
2600817466cbSJens Wiklander          */
2601817466cbSJens Wiklander         count = 0;
2602817466cbSJens Wiklander         do {
2603817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &A, X->n * ciL, f_rng, p_rng ) );
2604817466cbSJens Wiklander 
2605817466cbSJens Wiklander             j = mbedtls_mpi_bitlen( &A );
2606817466cbSJens Wiklander             k = mbedtls_mpi_bitlen( &W );
2607817466cbSJens Wiklander             if (j > k) {
26083d3b0591SJens Wiklander                 A.p[A.n - 1] &= ( (mbedtls_mpi_uint) 1 << ( k - ( A.n - 1 ) * biL - 1 ) ) - 1;
2609817466cbSJens Wiklander             }
2610817466cbSJens Wiklander 
2611117cce93SJens Wiklander             if (count++ > 300) {
2612336e3299SJens Wiklander                 ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2613336e3299SJens Wiklander                 goto cleanup;
2614817466cbSJens Wiklander             }
2615817466cbSJens Wiklander 
2616817466cbSJens Wiklander         } while ( mbedtls_mpi_cmp_mpi( &A, &W ) >= 0 ||
2617817466cbSJens Wiklander                   mbedtls_mpi_cmp_int( &A, 1 )  <= 0    );
2618817466cbSJens Wiklander 
2619817466cbSJens Wiklander         /*
2620817466cbSJens Wiklander          * A = A^R mod |X|
2621817466cbSJens Wiklander          */
2622817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &A, &A, &R, X, &RR ) );
2623817466cbSJens Wiklander 
2624817466cbSJens Wiklander         if( mbedtls_mpi_cmp_mpi( &A, &W ) == 0 ||
2625817466cbSJens Wiklander             mbedtls_mpi_cmp_int( &A,  1 ) == 0 )
2626817466cbSJens Wiklander             continue;
2627817466cbSJens Wiklander 
2628817466cbSJens Wiklander         j = 1;
2629817466cbSJens Wiklander         while( j < s && mbedtls_mpi_cmp_mpi( &A, &W ) != 0 )
2630817466cbSJens Wiklander         {
2631817466cbSJens Wiklander             /*
2632817466cbSJens Wiklander              * A = A * A mod |X|
2633817466cbSJens Wiklander              */
2634817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T, &A, &A ) );
2635817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &A, &T, X  ) );
2636817466cbSJens Wiklander 
2637817466cbSJens Wiklander             if( mbedtls_mpi_cmp_int( &A, 1 ) == 0 )
2638817466cbSJens Wiklander                 break;
2639817466cbSJens Wiklander 
2640817466cbSJens Wiklander             j++;
2641817466cbSJens Wiklander         }
2642817466cbSJens Wiklander 
2643817466cbSJens Wiklander         /*
2644817466cbSJens Wiklander          * not prime if A != |X| - 1 or A == 1
2645817466cbSJens Wiklander          */
2646817466cbSJens Wiklander         if( mbedtls_mpi_cmp_mpi( &A, &W ) != 0 ||
2647817466cbSJens Wiklander             mbedtls_mpi_cmp_int( &A,  1 ) == 0 )
2648817466cbSJens Wiklander         {
2649817466cbSJens Wiklander             ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2650817466cbSJens Wiklander             break;
2651817466cbSJens Wiklander         }
2652817466cbSJens Wiklander     }
2653817466cbSJens Wiklander 
2654817466cbSJens Wiklander cleanup:
26553d3b0591SJens Wiklander     mbedtls_mpi_free( &W ); mbedtls_mpi_free( &R );
26563d3b0591SJens Wiklander     mbedtls_mpi_free( &T ); mbedtls_mpi_free( &A );
2657817466cbSJens Wiklander     mbedtls_mpi_free( &RR );
2658817466cbSJens Wiklander 
2659817466cbSJens Wiklander     return( ret );
2660817466cbSJens Wiklander }
2661817466cbSJens Wiklander 
2662817466cbSJens Wiklander /*
2663817466cbSJens Wiklander  * Pseudo-primality test: small factors, then Miller-Rabin
2664817466cbSJens Wiklander  */
26653d3b0591SJens Wiklander int mbedtls_mpi_is_prime_ext( const mbedtls_mpi *X, int rounds,
2666817466cbSJens Wiklander                               int (*f_rng)(void *, unsigned char *, size_t),
2667817466cbSJens Wiklander                               void *p_rng )
2668817466cbSJens Wiklander {
2669*11fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
2670817466cbSJens Wiklander     mbedtls_mpi XX;
26713d3b0591SJens Wiklander     MPI_VALIDATE_RET( X     != NULL );
26723d3b0591SJens Wiklander     MPI_VALIDATE_RET( f_rng != NULL );
2673817466cbSJens Wiklander 
2674817466cbSJens Wiklander     XX.s = 1;
2675817466cbSJens Wiklander     XX.n = X->n;
2676817466cbSJens Wiklander     XX.p = X->p;
2677817466cbSJens Wiklander 
2678817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( &XX, 0 ) == 0 ||
2679817466cbSJens Wiklander         mbedtls_mpi_cmp_int( &XX, 1 ) == 0 )
2680817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE );
2681817466cbSJens Wiklander 
2682817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( &XX, 2 ) == 0 )
2683817466cbSJens Wiklander         return( 0 );
2684817466cbSJens Wiklander 
2685817466cbSJens Wiklander     if( ( ret = mpi_check_small_factors( &XX ) ) != 0 )
2686817466cbSJens Wiklander     {
2687817466cbSJens Wiklander         if( ret == 1 )
2688817466cbSJens Wiklander             return( 0 );
2689817466cbSJens Wiklander 
2690817466cbSJens Wiklander         return( ret );
2691817466cbSJens Wiklander     }
2692817466cbSJens Wiklander 
26933d3b0591SJens Wiklander     return( mpi_miller_rabin( &XX, rounds, f_rng, p_rng ) );
2694817466cbSJens Wiklander }
2695817466cbSJens Wiklander 
26963d3b0591SJens Wiklander #if !defined(MBEDTLS_DEPRECATED_REMOVED)
2697817466cbSJens Wiklander /*
26983d3b0591SJens Wiklander  * Pseudo-primality test, error probability 2^-80
2699817466cbSJens Wiklander  */
27003d3b0591SJens Wiklander int mbedtls_mpi_is_prime( const mbedtls_mpi *X,
2701817466cbSJens Wiklander                   int (*f_rng)(void *, unsigned char *, size_t),
2702817466cbSJens Wiklander                   void *p_rng )
2703817466cbSJens Wiklander {
27043d3b0591SJens Wiklander     MPI_VALIDATE_RET( X     != NULL );
27053d3b0591SJens Wiklander     MPI_VALIDATE_RET( f_rng != NULL );
27063d3b0591SJens Wiklander 
27073d3b0591SJens Wiklander     /*
27083d3b0591SJens Wiklander      * In the past our key generation aimed for an error rate of at most
27093d3b0591SJens Wiklander      * 2^-80. Since this function is deprecated, aim for the same certainty
27103d3b0591SJens Wiklander      * here as well.
27113d3b0591SJens Wiklander      */
27123d3b0591SJens Wiklander     return( mbedtls_mpi_is_prime_ext( X, 40, f_rng, p_rng ) );
27133d3b0591SJens Wiklander }
27143d3b0591SJens Wiklander #endif
27153d3b0591SJens Wiklander 
27163d3b0591SJens Wiklander /*
27173d3b0591SJens Wiklander  * Prime number generation
27183d3b0591SJens Wiklander  *
27193d3b0591SJens Wiklander  * To generate an RSA key in a way recommended by FIPS 186-4, both primes must
27203d3b0591SJens Wiklander  * be either 1024 bits or 1536 bits long, and flags must contain
27213d3b0591SJens Wiklander  * MBEDTLS_MPI_GEN_PRIME_FLAG_LOW_ERR.
27223d3b0591SJens Wiklander  */
27233d3b0591SJens Wiklander int mbedtls_mpi_gen_prime( mbedtls_mpi *X, size_t nbits, int flags,
27243d3b0591SJens Wiklander                    int (*f_rng)(void *, unsigned char *, size_t),
27253d3b0591SJens Wiklander                    void *p_rng )
27263d3b0591SJens Wiklander {
27273d3b0591SJens Wiklander #ifdef MBEDTLS_HAVE_INT64
27283d3b0591SJens Wiklander // ceil(2^63.5)
27293d3b0591SJens Wiklander #define CEIL_MAXUINT_DIV_SQRT2 0xb504f333f9de6485ULL
27303d3b0591SJens Wiklander #else
27313d3b0591SJens Wiklander // ceil(2^31.5)
27323d3b0591SJens Wiklander #define CEIL_MAXUINT_DIV_SQRT2 0xb504f334U
27333d3b0591SJens Wiklander #endif
27343d3b0591SJens Wiklander     int ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2735817466cbSJens Wiklander     size_t k, n;
27363d3b0591SJens Wiklander     int rounds;
2737817466cbSJens Wiklander     mbedtls_mpi_uint r;
2738817466cbSJens Wiklander     mbedtls_mpi Y;
2739817466cbSJens Wiklander 
27403d3b0591SJens Wiklander     MPI_VALIDATE_RET( X     != NULL );
27413d3b0591SJens Wiklander     MPI_VALIDATE_RET( f_rng != NULL );
27423d3b0591SJens Wiklander 
2743817466cbSJens Wiklander     if( nbits < 3 || nbits > MBEDTLS_MPI_MAX_BITS )
2744817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
2745817466cbSJens Wiklander 
274698bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &Y );
2747817466cbSJens Wiklander 
2748817466cbSJens Wiklander     n = BITS_TO_LIMBS( nbits );
2749817466cbSJens Wiklander 
27503d3b0591SJens Wiklander     if( ( flags & MBEDTLS_MPI_GEN_PRIME_FLAG_LOW_ERR ) == 0 )
27513d3b0591SJens Wiklander     {
27523d3b0591SJens Wiklander         /*
27533d3b0591SJens Wiklander          * 2^-80 error probability, number of rounds chosen per HAC, table 4.4
27543d3b0591SJens Wiklander          */
27553d3b0591SJens Wiklander         rounds = ( ( nbits >= 1300 ) ?  2 : ( nbits >=  850 ) ?  3 :
27563d3b0591SJens Wiklander                    ( nbits >=  650 ) ?  4 : ( nbits >=  350 ) ?  8 :
27573d3b0591SJens Wiklander                    ( nbits >=  250 ) ? 12 : ( nbits >=  150 ) ? 18 : 27 );
27583d3b0591SJens Wiklander     }
27593d3b0591SJens Wiklander     else
27603d3b0591SJens Wiklander     {
27613d3b0591SJens Wiklander         /*
27623d3b0591SJens Wiklander          * 2^-100 error probability, number of rounds computed based on HAC,
27633d3b0591SJens Wiklander          * fact 4.48
27643d3b0591SJens Wiklander          */
27653d3b0591SJens Wiklander         rounds = ( ( nbits >= 1450 ) ?  4 : ( nbits >=  1150 ) ?  5 :
27663d3b0591SJens Wiklander                    ( nbits >= 1000 ) ?  6 : ( nbits >=   850 ) ?  7 :
27673d3b0591SJens Wiklander                    ( nbits >=  750 ) ?  8 : ( nbits >=   500 ) ? 13 :
27683d3b0591SJens Wiklander                    ( nbits >=  250 ) ? 28 : ( nbits >=   150 ) ? 40 : 51 );
27693d3b0591SJens Wiklander     }
27703d3b0591SJens Wiklander 
27713d3b0591SJens Wiklander     while( 1 )
27723d3b0591SJens Wiklander     {
2773817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( X, n * ciL, f_rng, p_rng ) );
27743d3b0591SJens Wiklander         /* make sure generated number is at least (nbits-1)+0.5 bits (FIPS 186-4 §B.3.3 steps 4.4, 5.5) */
27753d3b0591SJens Wiklander         if( X->p[n-1] < CEIL_MAXUINT_DIV_SQRT2 ) continue;
2776817466cbSJens Wiklander 
27773d3b0591SJens Wiklander         k = n * biL;
27783d3b0591SJens Wiklander         if( k > nbits ) MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( X, k - nbits ) );
2779817466cbSJens Wiklander         X->p[0] |= 1;
2780817466cbSJens Wiklander 
27813d3b0591SJens Wiklander         if( ( flags & MBEDTLS_MPI_GEN_PRIME_FLAG_DH ) == 0 )
2782817466cbSJens Wiklander         {
27833d3b0591SJens Wiklander             ret = mbedtls_mpi_is_prime_ext( X, rounds, f_rng, p_rng );
27843d3b0591SJens Wiklander 
2785817466cbSJens Wiklander             if( ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE )
2786817466cbSJens Wiklander                 goto cleanup;
2787817466cbSJens Wiklander         }
2788817466cbSJens Wiklander         else
2789817466cbSJens Wiklander         {
2790817466cbSJens Wiklander             /*
2791817466cbSJens Wiklander              * An necessary condition for Y and X = 2Y + 1 to be prime
2792817466cbSJens Wiklander              * is X = 2 mod 3 (which is equivalent to Y = 2 mod 3).
2793817466cbSJens Wiklander              * Make sure it is satisfied, while keeping X = 3 mod 4
2794817466cbSJens Wiklander              */
2795817466cbSJens Wiklander 
2796817466cbSJens Wiklander             X->p[0] |= 2;
2797817466cbSJens Wiklander 
2798817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_mod_int( &r, X, 3 ) );
2799817466cbSJens Wiklander             if( r == 0 )
2800817466cbSJens Wiklander                 MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, X, 8 ) );
2801817466cbSJens Wiklander             else if( r == 1 )
2802817466cbSJens Wiklander                 MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, X, 4 ) );
2803817466cbSJens Wiklander 
2804817466cbSJens Wiklander             /* Set Y = (X-1) / 2, which is X / 2 because X is odd */
2805817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &Y, X ) );
2806817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &Y, 1 ) );
2807817466cbSJens Wiklander 
2808817466cbSJens Wiklander             while( 1 )
2809817466cbSJens Wiklander             {
2810817466cbSJens Wiklander                 /*
2811817466cbSJens Wiklander                  * First, check small factors for X and Y
2812817466cbSJens Wiklander                  * before doing Miller-Rabin on any of them
2813817466cbSJens Wiklander                  */
2814817466cbSJens Wiklander                 if( ( ret = mpi_check_small_factors(  X         ) ) == 0 &&
2815817466cbSJens Wiklander                     ( ret = mpi_check_small_factors( &Y         ) ) == 0 &&
28163d3b0591SJens Wiklander                     ( ret = mpi_miller_rabin(  X, rounds, f_rng, p_rng  ) )
28173d3b0591SJens Wiklander                                                                     == 0 &&
28183d3b0591SJens Wiklander                     ( ret = mpi_miller_rabin( &Y, rounds, f_rng, p_rng  ) )
28193d3b0591SJens Wiklander                                                                     == 0 )
28203d3b0591SJens Wiklander                     goto cleanup;
2821817466cbSJens Wiklander 
2822817466cbSJens Wiklander                 if( ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE )
2823817466cbSJens Wiklander                     goto cleanup;
2824817466cbSJens Wiklander 
2825817466cbSJens Wiklander                 /*
2826817466cbSJens Wiklander                  * Next candidates. We want to preserve Y = (X-1) / 2 and
2827817466cbSJens Wiklander                  * Y = 1 mod 2 and Y = 2 mod 3 (eq X = 3 mod 4 and X = 2 mod 3)
2828817466cbSJens Wiklander                  * so up Y by 6 and X by 12.
2829817466cbSJens Wiklander                  */
2830817466cbSJens Wiklander                 MBEDTLS_MPI_CHK( mbedtls_mpi_add_int(  X,  X, 12 ) );
2831817466cbSJens Wiklander                 MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( &Y, &Y, 6  ) );
2832817466cbSJens Wiklander             }
2833817466cbSJens Wiklander         }
28343d3b0591SJens Wiklander     }
2835817466cbSJens Wiklander 
2836817466cbSJens Wiklander cleanup:
2837817466cbSJens Wiklander 
2838817466cbSJens Wiklander     mbedtls_mpi_free( &Y );
2839817466cbSJens Wiklander 
2840817466cbSJens Wiklander     return( ret );
2841817466cbSJens Wiklander }
2842817466cbSJens Wiklander 
2843817466cbSJens Wiklander #endif /* MBEDTLS_GENPRIME */
2844817466cbSJens Wiklander 
2845817466cbSJens Wiklander #if defined(MBEDTLS_SELF_TEST)
2846817466cbSJens Wiklander 
2847817466cbSJens Wiklander #define GCD_PAIR_COUNT  3
2848817466cbSJens Wiklander 
2849817466cbSJens Wiklander static const int gcd_pairs[GCD_PAIR_COUNT][3] =
2850817466cbSJens Wiklander {
2851817466cbSJens Wiklander     { 693, 609, 21 },
2852817466cbSJens Wiklander     { 1764, 868, 28 },
2853817466cbSJens Wiklander     { 768454923, 542167814, 1 }
2854817466cbSJens Wiklander };
2855817466cbSJens Wiklander 
2856817466cbSJens Wiklander /*
2857817466cbSJens Wiklander  * Checkup routine
2858817466cbSJens Wiklander  */
2859817466cbSJens Wiklander int mbedtls_mpi_self_test( int verbose )
2860817466cbSJens Wiklander {
2861817466cbSJens Wiklander     int ret, i;
2862817466cbSJens Wiklander     mbedtls_mpi A, E, N, X, Y, U, V;
2863817466cbSJens Wiklander 
286498bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &A ); mbedtls_mpi_init_mempool( &E );
286598bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &N ); mbedtls_mpi_init_mempool( &X );
286698bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &Y ); mbedtls_mpi_init_mempool( &U );
286798bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &V );
2868817466cbSJens Wiklander 
2869817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &A, 16,
2870817466cbSJens Wiklander         "EFE021C2645FD1DC586E69184AF4A31E" \
2871817466cbSJens Wiklander         "D5F53E93B5F123FA41680867BA110131" \
2872817466cbSJens Wiklander         "944FE7952E2517337780CB0DB80E61AA" \
2873817466cbSJens Wiklander         "E7C8DDC6C5C6AADEB34EB38A2F40D5E6" ) );
2874817466cbSJens Wiklander 
2875817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &E, 16,
2876817466cbSJens Wiklander         "B2E7EFD37075B9F03FF989C7C5051C20" \
2877817466cbSJens Wiklander         "34D2A323810251127E7BF8625A4F49A5" \
2878817466cbSJens Wiklander         "F3E27F4DA8BD59C47D6DAABA4C8127BD" \
2879817466cbSJens Wiklander         "5B5C25763222FEFCCFC38B832366C29E" ) );
2880817466cbSJens Wiklander 
2881817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &N, 16,
2882817466cbSJens Wiklander         "0066A198186C18C10B2F5ED9B522752A" \
2883817466cbSJens Wiklander         "9830B69916E535C8F047518A889A43A5" \
2884817466cbSJens Wiklander         "94B6BED27A168D31D4A52F88925AA8F5" ) );
2885817466cbSJens Wiklander 
2886817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &X, &A, &N ) );
2887817466cbSJens Wiklander 
2888817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &U, 16,
2889817466cbSJens Wiklander         "602AB7ECA597A3D6B56FF9829A5E8B85" \
2890817466cbSJens Wiklander         "9E857EA95A03512E2BAE7391688D264A" \
2891817466cbSJens Wiklander         "A5663B0341DB9CCFD2C4C5F421FEC814" \
2892817466cbSJens Wiklander         "8001B72E848A38CAE1C65F78E56ABDEF" \
2893817466cbSJens Wiklander         "E12D3C039B8A02D6BE593F0BBBDA56F1" \
2894817466cbSJens Wiklander         "ECF677152EF804370C1A305CAF3B5BF1" \
2895817466cbSJens Wiklander         "30879B56C61DE584A0F53A2447A51E" ) );
2896817466cbSJens Wiklander 
2897817466cbSJens Wiklander     if( verbose != 0 )
2898817466cbSJens Wiklander         mbedtls_printf( "  MPI test #1 (mul_mpi): " );
2899817466cbSJens Wiklander 
2900817466cbSJens Wiklander     if( mbedtls_mpi_cmp_mpi( &X, &U ) != 0 )
2901817466cbSJens Wiklander     {
2902817466cbSJens Wiklander         if( verbose != 0 )
2903817466cbSJens Wiklander             mbedtls_printf( "failed\n" );
2904817466cbSJens Wiklander 
2905817466cbSJens Wiklander         ret = 1;
2906817466cbSJens Wiklander         goto cleanup;
2907817466cbSJens Wiklander     }
2908817466cbSJens Wiklander 
2909817466cbSJens Wiklander     if( verbose != 0 )
2910817466cbSJens Wiklander         mbedtls_printf( "passed\n" );
2911817466cbSJens Wiklander 
2912817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_div_mpi( &X, &Y, &A, &N ) );
2913817466cbSJens Wiklander 
2914817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &U, 16,
2915817466cbSJens Wiklander         "256567336059E52CAE22925474705F39A94" ) );
2916817466cbSJens Wiklander 
2917817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &V, 16,
2918817466cbSJens Wiklander         "6613F26162223DF488E9CD48CC132C7A" \
2919817466cbSJens Wiklander         "0AC93C701B001B092E4E5B9F73BCD27B" \
2920817466cbSJens Wiklander         "9EE50D0657C77F374E903CDFA4C642" ) );
2921817466cbSJens Wiklander 
2922817466cbSJens Wiklander     if( verbose != 0 )
2923817466cbSJens Wiklander         mbedtls_printf( "  MPI test #2 (div_mpi): " );
2924817466cbSJens Wiklander 
2925817466cbSJens Wiklander     if( mbedtls_mpi_cmp_mpi( &X, &U ) != 0 ||
2926817466cbSJens Wiklander         mbedtls_mpi_cmp_mpi( &Y, &V ) != 0 )
2927817466cbSJens Wiklander     {
2928817466cbSJens Wiklander         if( verbose != 0 )
2929817466cbSJens Wiklander             mbedtls_printf( "failed\n" );
2930817466cbSJens Wiklander 
2931817466cbSJens Wiklander         ret = 1;
2932817466cbSJens Wiklander         goto cleanup;
2933817466cbSJens Wiklander     }
2934817466cbSJens Wiklander 
2935817466cbSJens Wiklander     if( verbose != 0 )
2936817466cbSJens Wiklander         mbedtls_printf( "passed\n" );
2937817466cbSJens Wiklander 
2938817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &X, &A, &E, &N, NULL ) );
2939817466cbSJens Wiklander 
2940817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &U, 16,
2941817466cbSJens Wiklander         "36E139AEA55215609D2816998ED020BB" \
2942817466cbSJens Wiklander         "BD96C37890F65171D948E9BC7CBAA4D9" \
2943817466cbSJens Wiklander         "325D24D6A3C12710F10A09FA08AB87" ) );
2944817466cbSJens Wiklander 
2945817466cbSJens Wiklander     if( verbose != 0 )
2946817466cbSJens Wiklander         mbedtls_printf( "  MPI test #3 (exp_mod): " );
2947817466cbSJens Wiklander 
2948817466cbSJens Wiklander     if( mbedtls_mpi_cmp_mpi( &X, &U ) != 0 )
2949817466cbSJens Wiklander     {
2950817466cbSJens Wiklander         if( verbose != 0 )
2951817466cbSJens Wiklander             mbedtls_printf( "failed\n" );
2952817466cbSJens Wiklander 
2953817466cbSJens Wiklander         ret = 1;
2954817466cbSJens Wiklander         goto cleanup;
2955817466cbSJens Wiklander     }
2956817466cbSJens Wiklander 
2957817466cbSJens Wiklander     if( verbose != 0 )
2958817466cbSJens Wiklander         mbedtls_printf( "passed\n" );
2959817466cbSJens Wiklander 
2960817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &X, &A, &N ) );
2961817466cbSJens Wiklander 
2962817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &U, 16,
2963817466cbSJens Wiklander         "003A0AAEDD7E784FC07D8F9EC6E3BFD5" \
2964817466cbSJens Wiklander         "C3DBA76456363A10869622EAC2DD84EC" \
2965817466cbSJens Wiklander         "C5B8A74DAC4D09E03B5E0BE779F2DF61" ) );
2966817466cbSJens Wiklander 
2967817466cbSJens Wiklander     if( verbose != 0 )
2968817466cbSJens Wiklander         mbedtls_printf( "  MPI test #4 (inv_mod): " );
2969817466cbSJens Wiklander 
2970817466cbSJens Wiklander     if( mbedtls_mpi_cmp_mpi( &X, &U ) != 0 )
2971817466cbSJens Wiklander     {
2972817466cbSJens Wiklander         if( verbose != 0 )
2973817466cbSJens Wiklander             mbedtls_printf( "failed\n" );
2974817466cbSJens Wiklander 
2975817466cbSJens Wiklander         ret = 1;
2976817466cbSJens Wiklander         goto cleanup;
2977817466cbSJens Wiklander     }
2978817466cbSJens Wiklander 
2979817466cbSJens Wiklander     if( verbose != 0 )
2980817466cbSJens Wiklander         mbedtls_printf( "passed\n" );
2981817466cbSJens Wiklander 
2982817466cbSJens Wiklander     if( verbose != 0 )
2983817466cbSJens Wiklander         mbedtls_printf( "  MPI test #5 (simple gcd): " );
2984817466cbSJens Wiklander 
2985817466cbSJens Wiklander     for( i = 0; i < GCD_PAIR_COUNT; i++ )
2986817466cbSJens Wiklander     {
2987817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &X, gcd_pairs[i][0] ) );
2988817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &Y, gcd_pairs[i][1] ) );
2989817466cbSJens Wiklander 
2990817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &A, &X, &Y ) );
2991817466cbSJens Wiklander 
2992817466cbSJens Wiklander         if( mbedtls_mpi_cmp_int( &A, gcd_pairs[i][2] ) != 0 )
2993817466cbSJens Wiklander         {
2994817466cbSJens Wiklander             if( verbose != 0 )
2995817466cbSJens Wiklander                 mbedtls_printf( "failed at %d\n", i );
2996817466cbSJens Wiklander 
2997817466cbSJens Wiklander             ret = 1;
2998817466cbSJens Wiklander             goto cleanup;
2999817466cbSJens Wiklander         }
3000817466cbSJens Wiklander     }
3001817466cbSJens Wiklander 
3002817466cbSJens Wiklander     if( verbose != 0 )
3003817466cbSJens Wiklander         mbedtls_printf( "passed\n" );
3004817466cbSJens Wiklander 
3005817466cbSJens Wiklander cleanup:
3006817466cbSJens Wiklander 
3007817466cbSJens Wiklander     if( ret != 0 && verbose != 0 )
3008817466cbSJens Wiklander         mbedtls_printf( "Unexpected error, return code = %08X\n", ret );
3009817466cbSJens Wiklander 
3010817466cbSJens Wiklander     mbedtls_mpi_free( &A ); mbedtls_mpi_free( &E ); mbedtls_mpi_free( &N ); mbedtls_mpi_free( &X );
3011817466cbSJens Wiklander     mbedtls_mpi_free( &Y ); mbedtls_mpi_free( &U ); mbedtls_mpi_free( &V );
3012817466cbSJens Wiklander 
3013817466cbSJens Wiklander     if( verbose != 0 )
3014817466cbSJens Wiklander         mbedtls_printf( "\n" );
3015817466cbSJens Wiklander 
3016817466cbSJens Wiklander     return( ret );
3017817466cbSJens Wiklander }
3018817466cbSJens Wiklander 
3019817466cbSJens Wiklander #endif /* MBEDTLS_SELF_TEST */
3020817466cbSJens Wiklander 
3021817466cbSJens Wiklander #endif /* MBEDTLS_BIGNUM_C */
3022