xref: /optee_os/lib/libmbedtls/mbedtls/library/bignum.c (revision 5b25c76ac40f830867e3d60800120ffd7874e8dc)
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"
49817466cbSJens Wiklander 
50817466cbSJens Wiklander #include <string.h>
51817466cbSJens Wiklander 
52817466cbSJens Wiklander #if defined(MBEDTLS_PLATFORM_C)
53817466cbSJens Wiklander #include "mbedtls/platform.h"
54817466cbSJens Wiklander #else
55817466cbSJens Wiklander #include <stdio.h>
56817466cbSJens Wiklander #include <stdlib.h>
57817466cbSJens Wiklander #define mbedtls_printf     printf
58817466cbSJens Wiklander #define mbedtls_calloc    calloc
59817466cbSJens Wiklander #define mbedtls_free       free
60817466cbSJens Wiklander #endif
61817466cbSJens Wiklander 
6298bd5fe3SJens Wiklander #include <mempool.h>
63b99a4a18SJens Wiklander #include <util.h>
6498bd5fe3SJens Wiklander 
653d3b0591SJens Wiklander #define MPI_VALIDATE_RET( cond )                                       \
663d3b0591SJens Wiklander     MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_MPI_BAD_INPUT_DATA )
673d3b0591SJens Wiklander #define MPI_VALIDATE( cond )                                           \
683d3b0591SJens Wiklander     MBEDTLS_INTERNAL_VALIDATE( cond )
69817466cbSJens Wiklander 
70817466cbSJens Wiklander #define ciL    (sizeof(mbedtls_mpi_uint))         /* chars in limb  */
71817466cbSJens Wiklander #define biL    (ciL << 3)               /* bits  in limb  */
72817466cbSJens Wiklander #define biH    (ciL << 2)               /* half limb size */
73817466cbSJens Wiklander 
74817466cbSJens Wiklander #define MPI_SIZE_T_MAX  ( (size_t) -1 ) /* SIZE_T_MAX is not standard */
75817466cbSJens Wiklander 
76817466cbSJens Wiklander /*
77817466cbSJens Wiklander  * Convert between bits/chars and number of limbs
78817466cbSJens Wiklander  * Divide first in order to avoid potential overflows
79817466cbSJens Wiklander  */
80817466cbSJens Wiklander #define BITS_TO_LIMBS(i)  ( (i) / biL + ( (i) % biL != 0 ) )
81817466cbSJens Wiklander #define CHARS_TO_LIMBS(i) ( (i) / ciL + ( (i) % ciL != 0 ) )
82817466cbSJens Wiklander 
8398bd5fe3SJens Wiklander void *mbedtls_mpi_mempool;
8498bd5fe3SJens Wiklander 
853d3b0591SJens Wiklander /* Implementation that should never be optimized out by the compiler */
863d3b0591SJens Wiklander static void mbedtls_mpi_zeroize( mbedtls_mpi_uint *v, size_t n )
873d3b0591SJens Wiklander {
883d3b0591SJens Wiklander     mbedtls_platform_zeroize( v, ciL * n );
893d3b0591SJens Wiklander }
903d3b0591SJens Wiklander 
91817466cbSJens Wiklander /*
92817466cbSJens Wiklander  * Initialize one MPI
93817466cbSJens Wiklander  */
943d3b0591SJens Wiklander static void mpi_init( mbedtls_mpi *X, short use_mempool )
95817466cbSJens Wiklander {
963d3b0591SJens Wiklander     MPI_VALIDATE( X != NULL );
97817466cbSJens Wiklander 
983d3b0591SJens Wiklander     X->s = 1;
993d3b0591SJens Wiklander     X->use_mempool = use_mempool;
1003d3b0591SJens Wiklander     X->n = 0;
1013d3b0591SJens Wiklander     X->p = NULL;
102817466cbSJens Wiklander }
103817466cbSJens Wiklander 
10498bd5fe3SJens Wiklander void mbedtls_mpi_init( mbedtls_mpi *X )
10598bd5fe3SJens Wiklander {
1063d3b0591SJens Wiklander     mpi_init( X, 0 /*use_mempool*/ );
10798bd5fe3SJens Wiklander }
10898bd5fe3SJens Wiklander 
10998bd5fe3SJens Wiklander void mbedtls_mpi_init_mempool( mbedtls_mpi *X )
11098bd5fe3SJens Wiklander {
1113d3b0591SJens Wiklander     mpi_init( X, !!mbedtls_mpi_mempool /*use_mempool*/ );
11298bd5fe3SJens Wiklander }
11398bd5fe3SJens Wiklander 
114817466cbSJens Wiklander /*
115817466cbSJens Wiklander  * Unallocate one MPI
116817466cbSJens Wiklander  */
117817466cbSJens Wiklander void mbedtls_mpi_free( mbedtls_mpi *X )
118817466cbSJens Wiklander {
119817466cbSJens Wiklander     if( X == NULL )
120817466cbSJens Wiklander         return;
121817466cbSJens Wiklander 
122817466cbSJens Wiklander     if( X->p != NULL )
123817466cbSJens Wiklander     {
124817466cbSJens Wiklander         mbedtls_mpi_zeroize( X->p, X->n );
1253d3b0591SJens Wiklander         if( X->use_mempool )
12618c5148dSJens Wiklander             mempool_free( mbedtls_mpi_mempool, X->p );
1273d3b0591SJens Wiklander         else
1283d3b0591SJens Wiklander             mbedtls_free( X->p );
129817466cbSJens Wiklander     }
130817466cbSJens Wiklander 
131817466cbSJens Wiklander     X->s = 1;
132817466cbSJens Wiklander     X->n = 0;
1333d3b0591SJens Wiklander     X->p = NULL;
134817466cbSJens Wiklander }
135817466cbSJens Wiklander 
136817466cbSJens Wiklander /*
137817466cbSJens Wiklander  * Enlarge to the specified number of limbs
138817466cbSJens Wiklander  */
139817466cbSJens Wiklander int mbedtls_mpi_grow( mbedtls_mpi *X, size_t nblimbs )
140817466cbSJens Wiklander {
141817466cbSJens Wiklander     mbedtls_mpi_uint *p;
1423d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
143817466cbSJens Wiklander 
144817466cbSJens Wiklander     if( nblimbs > MBEDTLS_MPI_MAX_LIMBS )
145817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_ALLOC_FAILED );
146817466cbSJens Wiklander 
1473d3b0591SJens Wiklander     if( X->n < nblimbs )
1483d3b0591SJens Wiklander     {
1493d3b0591SJens Wiklander         if( X->use_mempool )
1503d3b0591SJens Wiklander         {
1513d3b0591SJens Wiklander             p = mempool_alloc( mbedtls_mpi_mempool, nblimbs * ciL );
15218c5148dSJens Wiklander             if( p == NULL )
15318c5148dSJens Wiklander                 return( MBEDTLS_ERR_MPI_ALLOC_FAILED );
1543d3b0591SJens Wiklander             memset( p, 0, nblimbs * ciL );
1553d3b0591SJens Wiklander         }
1563d3b0591SJens Wiklander         else
1573d3b0591SJens Wiklander         {
1583d3b0591SJens Wiklander             p = (mbedtls_mpi_uint*)mbedtls_calloc( nblimbs, ciL );
1593d3b0591SJens Wiklander             if( p == NULL )
1603d3b0591SJens Wiklander                 return( MBEDTLS_ERR_MPI_ALLOC_FAILED );
161817466cbSJens Wiklander         }
162817466cbSJens Wiklander 
1633d3b0591SJens Wiklander         if( X->p != NULL )
1643d3b0591SJens Wiklander         {
1653d3b0591SJens Wiklander             memcpy( p, X->p, X->n * ciL );
1663d3b0591SJens Wiklander             mbedtls_mpi_zeroize( X->p, X->n );
1673d3b0591SJens Wiklander             if( X->use_mempool )
16818c5148dSJens Wiklander                 mempool_free( mbedtls_mpi_mempool, X->p);
1693d3b0591SJens Wiklander             else
1703d3b0591SJens Wiklander                 mbedtls_free( X->p );
1713d3b0591SJens Wiklander         }
17218c5148dSJens Wiklander 
17318c5148dSJens Wiklander         X->n = nblimbs;
1743d3b0591SJens Wiklander         X->p = p;
1753d3b0591SJens Wiklander     }
176817466cbSJens Wiklander 
177817466cbSJens Wiklander     return( 0 );
178817466cbSJens Wiklander }
179817466cbSJens Wiklander 
180817466cbSJens Wiklander /*
181817466cbSJens Wiklander  * Resize down as much as possible,
182817466cbSJens Wiklander  * while keeping at least the specified number of limbs
183817466cbSJens Wiklander  */
184817466cbSJens Wiklander int mbedtls_mpi_shrink( mbedtls_mpi *X, size_t nblimbs )
185817466cbSJens Wiklander {
186817466cbSJens Wiklander     mbedtls_mpi_uint *p;
187817466cbSJens Wiklander     size_t i;
1883d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
1893d3b0591SJens Wiklander 
1903d3b0591SJens Wiklander     if( nblimbs > MBEDTLS_MPI_MAX_LIMBS )
1913d3b0591SJens Wiklander         return( MBEDTLS_ERR_MPI_ALLOC_FAILED );
192817466cbSJens Wiklander 
193*5b25c76aSJerome Forissier     /* Actually resize up if there are currently fewer than nblimbs limbs. */
194817466cbSJens Wiklander     if( X->n <= nblimbs )
195817466cbSJens Wiklander         return( mbedtls_mpi_grow( X, nblimbs ) );
196*5b25c76aSJerome Forissier     /* After this point, then X->n > nblimbs and in particular X->n > 0. */
197817466cbSJens Wiklander 
198817466cbSJens Wiklander     for( i = X->n - 1; i > 0; i-- )
199817466cbSJens Wiklander         if( X->p[i] != 0 )
200817466cbSJens Wiklander             break;
201817466cbSJens Wiklander     i++;
202817466cbSJens Wiklander 
203817466cbSJens Wiklander     if( i < nblimbs )
204817466cbSJens Wiklander         i = nblimbs;
205817466cbSJens Wiklander 
2063d3b0591SJens Wiklander     if( X->use_mempool )
2073d3b0591SJens Wiklander     {
2083d3b0591SJens Wiklander         p = mempool_alloc( mbedtls_mpi_mempool, nblimbs * ciL );
2093d3b0591SJens Wiklander         if( p == NULL )
21098bd5fe3SJens Wiklander             return( MBEDTLS_ERR_MPI_ALLOC_FAILED );
2113d3b0591SJens Wiklander         memset( p, 0, nblimbs * ciL );
21298bd5fe3SJens Wiklander     }
2133d3b0591SJens Wiklander     else
2143d3b0591SJens Wiklander     {
2153d3b0591SJens Wiklander         p = (mbedtls_mpi_uint*)mbedtls_calloc( nblimbs, ciL );
2163d3b0591SJens Wiklander         if( p == NULL )
2173d3b0591SJens Wiklander             return( MBEDTLS_ERR_MPI_ALLOC_FAILED );
2183d3b0591SJens Wiklander     }
21918c5148dSJens Wiklander 
220817466cbSJens Wiklander     if( X->p != NULL )
221817466cbSJens Wiklander     {
222817466cbSJens Wiklander         memcpy( p, X->p, i * ciL );
223817466cbSJens Wiklander         mbedtls_mpi_zeroize( X->p, X->n );
2243d3b0591SJens Wiklander         if( X->use_mempool )
22518c5148dSJens Wiklander             mempool_free( mbedtls_mpi_mempool, X->p );
2263d3b0591SJens Wiklander         else
2273d3b0591SJens Wiklander             mbedtls_free( X->p );
228817466cbSJens Wiklander     }
229817466cbSJens Wiklander 
23018c5148dSJens Wiklander     X->n = i;
2313d3b0591SJens Wiklander     X->p = p;
232817466cbSJens Wiklander 
233817466cbSJens Wiklander     return( 0 );
234817466cbSJens Wiklander }
235817466cbSJens Wiklander 
236817466cbSJens Wiklander /*
237817466cbSJens Wiklander  * Copy the contents of Y into X
238817466cbSJens Wiklander  */
239817466cbSJens Wiklander int mbedtls_mpi_copy( mbedtls_mpi *X, const mbedtls_mpi *Y )
240817466cbSJens Wiklander {
2413d3b0591SJens Wiklander     int ret = 0;
242817466cbSJens Wiklander     size_t i;
2433d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
2443d3b0591SJens Wiklander     MPI_VALIDATE_RET( Y != NULL );
245817466cbSJens Wiklander 
246817466cbSJens Wiklander     if( X == Y )
247817466cbSJens Wiklander         return( 0 );
248817466cbSJens Wiklander 
249*5b25c76aSJerome Forissier     if( Y->n == 0 )
250817466cbSJens Wiklander     {
251817466cbSJens Wiklander         mbedtls_mpi_free( X );
252817466cbSJens Wiklander         return( 0 );
253817466cbSJens Wiklander     }
254817466cbSJens Wiklander 
255817466cbSJens Wiklander     for( i = Y->n - 1; i > 0; i-- )
256817466cbSJens Wiklander         if( Y->p[i] != 0 )
257817466cbSJens Wiklander             break;
258817466cbSJens Wiklander     i++;
259817466cbSJens Wiklander 
260817466cbSJens Wiklander     X->s = Y->s;
261817466cbSJens Wiklander 
2623d3b0591SJens Wiklander     if( X->n < i )
2633d3b0591SJens Wiklander     {
264817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, i ) );
2653d3b0591SJens Wiklander     }
2663d3b0591SJens Wiklander     else
2673d3b0591SJens Wiklander     {
2683d3b0591SJens Wiklander         memset( X->p + i, 0, ( X->n - i ) * ciL );
2693d3b0591SJens Wiklander     }
270817466cbSJens Wiklander 
271817466cbSJens Wiklander     memcpy( X->p, Y->p, i * ciL );
272817466cbSJens Wiklander 
273817466cbSJens Wiklander cleanup:
274817466cbSJens Wiklander 
275817466cbSJens Wiklander     return( ret );
276817466cbSJens Wiklander }
277817466cbSJens Wiklander 
278817466cbSJens Wiklander /*
279817466cbSJens Wiklander  * Swap the contents of X and Y
280817466cbSJens Wiklander  */
281817466cbSJens Wiklander void mbedtls_mpi_swap( mbedtls_mpi *X, mbedtls_mpi *Y )
282817466cbSJens Wiklander {
283817466cbSJens Wiklander     mbedtls_mpi T;
2843d3b0591SJens Wiklander     MPI_VALIDATE( X != NULL );
2853d3b0591SJens Wiklander     MPI_VALIDATE( Y != NULL );
286817466cbSJens Wiklander 
287817466cbSJens Wiklander     memcpy( &T,  X, sizeof( mbedtls_mpi ) );
288817466cbSJens Wiklander     memcpy(  X,  Y, sizeof( mbedtls_mpi ) );
289817466cbSJens Wiklander     memcpy(  Y, &T, sizeof( mbedtls_mpi ) );
290817466cbSJens Wiklander }
291817466cbSJens Wiklander 
292817466cbSJens Wiklander /*
293817466cbSJens Wiklander  * Conditionally assign X = Y, without leaking information
294817466cbSJens Wiklander  * about whether the assignment was made or not.
295817466cbSJens Wiklander  * (Leaking information about the respective sizes of X and Y is ok however.)
296817466cbSJens Wiklander  */
297817466cbSJens Wiklander int mbedtls_mpi_safe_cond_assign( mbedtls_mpi *X, const mbedtls_mpi *Y, unsigned char assign )
298817466cbSJens Wiklander {
299817466cbSJens Wiklander     int ret = 0;
300817466cbSJens Wiklander     size_t i;
3013d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
3023d3b0591SJens Wiklander     MPI_VALIDATE_RET( Y != NULL );
303817466cbSJens Wiklander 
304817466cbSJens Wiklander     /* make sure assign is 0 or 1 in a time-constant manner */
305817466cbSJens Wiklander     assign = (assign | (unsigned char)-assign) >> 7;
306817466cbSJens Wiklander 
307817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, Y->n ) );
308817466cbSJens Wiklander 
309817466cbSJens Wiklander     X->s = X->s * ( 1 - assign ) + Y->s * assign;
310817466cbSJens Wiklander 
311817466cbSJens Wiklander     for( i = 0; i < Y->n; i++ )
312817466cbSJens Wiklander         X->p[i] = X->p[i] * ( 1 - assign ) + Y->p[i] * assign;
313817466cbSJens Wiklander 
314817466cbSJens Wiklander     for( ; i < X->n; i++ )
315817466cbSJens Wiklander         X->p[i] *= ( 1 - assign );
316817466cbSJens Wiklander 
317817466cbSJens Wiklander cleanup:
318817466cbSJens Wiklander     return( ret );
319817466cbSJens Wiklander }
320817466cbSJens Wiklander 
321817466cbSJens Wiklander /*
322817466cbSJens Wiklander  * Conditionally swap X and Y, without leaking information
323817466cbSJens Wiklander  * about whether the swap was made or not.
324817466cbSJens Wiklander  * Here it is not ok to simply swap the pointers, which whould lead to
325817466cbSJens Wiklander  * different memory access patterns when X and Y are used afterwards.
326817466cbSJens Wiklander  */
327817466cbSJens Wiklander int mbedtls_mpi_safe_cond_swap( mbedtls_mpi *X, mbedtls_mpi *Y, unsigned char swap )
328817466cbSJens Wiklander {
329817466cbSJens Wiklander     int ret, s;
330817466cbSJens Wiklander     size_t i;
331817466cbSJens Wiklander     mbedtls_mpi_uint tmp;
3323d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
3333d3b0591SJens Wiklander     MPI_VALIDATE_RET( Y != NULL );
334817466cbSJens Wiklander 
335817466cbSJens Wiklander     if( X == Y )
336817466cbSJens Wiklander         return( 0 );
337817466cbSJens Wiklander 
338817466cbSJens Wiklander     /* make sure swap is 0 or 1 in a time-constant manner */
339817466cbSJens Wiklander     swap = (swap | (unsigned char)-swap) >> 7;
340817466cbSJens Wiklander 
341817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, Y->n ) );
342817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( Y, X->n ) );
343817466cbSJens Wiklander 
344817466cbSJens Wiklander     s = X->s;
345817466cbSJens Wiklander     X->s = X->s * ( 1 - swap ) + Y->s * swap;
346817466cbSJens Wiklander     Y->s = Y->s * ( 1 - swap ) +    s * swap;
347817466cbSJens Wiklander 
348817466cbSJens Wiklander 
349817466cbSJens Wiklander     for( i = 0; i < X->n; i++ )
350817466cbSJens Wiklander     {
351817466cbSJens Wiklander         tmp = X->p[i];
352817466cbSJens Wiklander         X->p[i] = X->p[i] * ( 1 - swap ) + Y->p[i] * swap;
353817466cbSJens Wiklander         Y->p[i] = Y->p[i] * ( 1 - swap ) +     tmp * swap;
354817466cbSJens Wiklander     }
355817466cbSJens Wiklander 
356817466cbSJens Wiklander cleanup:
357817466cbSJens Wiklander     return( ret );
358817466cbSJens Wiklander }
359817466cbSJens Wiklander 
360817466cbSJens Wiklander /*
361817466cbSJens Wiklander  * Set value from integer
362817466cbSJens Wiklander  */
363817466cbSJens Wiklander int mbedtls_mpi_lset( mbedtls_mpi *X, mbedtls_mpi_sint z )
364817466cbSJens Wiklander {
365817466cbSJens Wiklander     int ret;
3663d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
367817466cbSJens Wiklander 
368817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, 1 ) );
369817466cbSJens Wiklander     memset( X->p, 0, X->n * ciL );
370817466cbSJens Wiklander 
371817466cbSJens Wiklander     X->p[0] = ( z < 0 ) ? -z : z;
372817466cbSJens Wiklander     X->s    = ( z < 0 ) ? -1 : 1;
373817466cbSJens Wiklander 
374817466cbSJens Wiklander cleanup:
375817466cbSJens Wiklander 
376817466cbSJens Wiklander     return( ret );
377817466cbSJens Wiklander }
378817466cbSJens Wiklander 
379817466cbSJens Wiklander /*
380817466cbSJens Wiklander  * Get a specific bit
381817466cbSJens Wiklander  */
382817466cbSJens Wiklander int mbedtls_mpi_get_bit( const mbedtls_mpi *X, size_t pos )
383817466cbSJens Wiklander {
3843d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
3853d3b0591SJens Wiklander 
386817466cbSJens Wiklander     if( X->n * biL <= pos )
387817466cbSJens Wiklander         return( 0 );
388817466cbSJens Wiklander 
389817466cbSJens Wiklander     return( ( X->p[pos / biL] >> ( pos % biL ) ) & 0x01 );
390817466cbSJens Wiklander }
391817466cbSJens Wiklander 
3923d3b0591SJens Wiklander /* Get a specific byte, without range checks. */
3933d3b0591SJens Wiklander #define GET_BYTE( X, i )                                \
3943d3b0591SJens Wiklander     ( ( ( X )->p[( i ) / ciL] >> ( ( ( i ) % ciL ) * 8 ) ) & 0xff )
3953d3b0591SJens Wiklander 
396817466cbSJens Wiklander /*
397817466cbSJens Wiklander  * Set a bit to a specific value of 0 or 1
398817466cbSJens Wiklander  */
399817466cbSJens Wiklander int mbedtls_mpi_set_bit( mbedtls_mpi *X, size_t pos, unsigned char val )
400817466cbSJens Wiklander {
401817466cbSJens Wiklander     int ret = 0;
402817466cbSJens Wiklander     size_t off = pos / biL;
403817466cbSJens Wiklander     size_t idx = pos % biL;
4043d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
405817466cbSJens Wiklander 
406817466cbSJens Wiklander     if( val != 0 && val != 1 )
407817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
408817466cbSJens Wiklander 
409817466cbSJens Wiklander     if( X->n * biL <= pos )
410817466cbSJens Wiklander     {
411817466cbSJens Wiklander         if( val == 0 )
412817466cbSJens Wiklander             return( 0 );
413817466cbSJens Wiklander 
414817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, off + 1 ) );
415817466cbSJens Wiklander     }
416817466cbSJens Wiklander 
417817466cbSJens Wiklander     X->p[off] &= ~( (mbedtls_mpi_uint) 0x01 << idx );
418817466cbSJens Wiklander     X->p[off] |= (mbedtls_mpi_uint) val << idx;
419817466cbSJens Wiklander 
420817466cbSJens Wiklander cleanup:
421817466cbSJens Wiklander 
422817466cbSJens Wiklander     return( ret );
423817466cbSJens Wiklander }
424817466cbSJens Wiklander 
425817466cbSJens Wiklander /*
426817466cbSJens Wiklander  * Return the number of less significant zero-bits
427817466cbSJens Wiklander  */
428817466cbSJens Wiklander size_t mbedtls_mpi_lsb( const mbedtls_mpi *X )
429817466cbSJens Wiklander {
430817466cbSJens Wiklander     size_t i, j, count = 0;
4313d3b0591SJens Wiklander     MBEDTLS_INTERNAL_VALIDATE_RET( X != NULL, 0 );
432817466cbSJens Wiklander 
433817466cbSJens Wiklander     for( i = 0; i < X->n; i++ )
434817466cbSJens Wiklander         for( j = 0; j < biL; j++, count++ )
435817466cbSJens Wiklander             if( ( ( X->p[i] >> j ) & 1 ) != 0 )
436817466cbSJens Wiklander                 return( count );
437817466cbSJens Wiklander 
438817466cbSJens Wiklander     return( 0 );
439817466cbSJens Wiklander }
440817466cbSJens Wiklander 
441817466cbSJens Wiklander /*
442817466cbSJens Wiklander  * Count leading zero bits in a given integer
443817466cbSJens Wiklander  */
444817466cbSJens Wiklander static size_t mbedtls_clz( const mbedtls_mpi_uint x )
445817466cbSJens Wiklander {
446817466cbSJens Wiklander     size_t j;
447817466cbSJens Wiklander     mbedtls_mpi_uint mask = (mbedtls_mpi_uint) 1 << (biL - 1);
448817466cbSJens Wiklander 
449817466cbSJens Wiklander     for( j = 0; j < biL; j++ )
450817466cbSJens Wiklander     {
451817466cbSJens Wiklander         if( x & mask ) break;
452817466cbSJens Wiklander 
453817466cbSJens Wiklander         mask >>= 1;
454817466cbSJens Wiklander     }
455817466cbSJens Wiklander 
456817466cbSJens Wiklander     return j;
457817466cbSJens Wiklander }
458817466cbSJens Wiklander 
459817466cbSJens Wiklander /*
460817466cbSJens Wiklander  * Return the number of bits
461817466cbSJens Wiklander  */
462817466cbSJens Wiklander size_t mbedtls_mpi_bitlen( const mbedtls_mpi *X )
463817466cbSJens Wiklander {
464817466cbSJens Wiklander     size_t i, j;
465817466cbSJens Wiklander 
466817466cbSJens Wiklander     if( X->n == 0 )
467817466cbSJens Wiklander         return( 0 );
468817466cbSJens Wiklander 
469817466cbSJens Wiklander     for( i = X->n - 1; i > 0; i-- )
470817466cbSJens Wiklander         if( X->p[i] != 0 )
471817466cbSJens Wiklander             break;
472817466cbSJens Wiklander 
473817466cbSJens Wiklander     j = biL - mbedtls_clz( X->p[i] );
474817466cbSJens Wiklander 
475817466cbSJens Wiklander     return( ( i * biL ) + j );
476817466cbSJens Wiklander }
477817466cbSJens Wiklander 
478817466cbSJens Wiklander /*
479817466cbSJens Wiklander  * Return the total size in bytes
480817466cbSJens Wiklander  */
481817466cbSJens Wiklander size_t mbedtls_mpi_size( const mbedtls_mpi *X )
482817466cbSJens Wiklander {
483817466cbSJens Wiklander     return( ( mbedtls_mpi_bitlen( X ) + 7 ) >> 3 );
484817466cbSJens Wiklander }
485817466cbSJens Wiklander 
486817466cbSJens Wiklander /*
487817466cbSJens Wiklander  * Convert an ASCII character to digit value
488817466cbSJens Wiklander  */
489817466cbSJens Wiklander static int mpi_get_digit( mbedtls_mpi_uint *d, int radix, char c )
490817466cbSJens Wiklander {
491817466cbSJens Wiklander     *d = 255;
492817466cbSJens Wiklander 
493817466cbSJens Wiklander     if( c >= 0x30 && c <= 0x39 ) *d = c - 0x30;
494817466cbSJens Wiklander     if( c >= 0x41 && c <= 0x46 ) *d = c - 0x37;
495817466cbSJens Wiklander     if( c >= 0x61 && c <= 0x66 ) *d = c - 0x57;
496817466cbSJens Wiklander 
497817466cbSJens Wiklander     if( *d >= (mbedtls_mpi_uint) radix )
498817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_INVALID_CHARACTER );
499817466cbSJens Wiklander 
500817466cbSJens Wiklander     return( 0 );
501817466cbSJens Wiklander }
502817466cbSJens Wiklander 
503817466cbSJens Wiklander /*
504817466cbSJens Wiklander  * Import from an ASCII string
505817466cbSJens Wiklander  */
506817466cbSJens Wiklander int mbedtls_mpi_read_string( mbedtls_mpi *X, int radix, const char *s )
507817466cbSJens Wiklander {
508817466cbSJens Wiklander     int ret;
509817466cbSJens Wiklander     size_t i, j, slen, n;
510817466cbSJens Wiklander     mbedtls_mpi_uint d;
511817466cbSJens Wiklander     mbedtls_mpi T;
5123d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
5133d3b0591SJens Wiklander     MPI_VALIDATE_RET( s != NULL );
514817466cbSJens Wiklander 
515817466cbSJens Wiklander     if( radix < 2 || radix > 16 )
516817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
517817466cbSJens Wiklander 
51898bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &T );
519817466cbSJens Wiklander 
520817466cbSJens Wiklander     slen = strlen( s );
521817466cbSJens Wiklander 
522817466cbSJens Wiklander     if( radix == 16 )
523817466cbSJens Wiklander     {
524817466cbSJens Wiklander         if( slen > MPI_SIZE_T_MAX >> 2 )
525817466cbSJens Wiklander             return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
526817466cbSJens Wiklander 
527817466cbSJens Wiklander         n = BITS_TO_LIMBS( slen << 2 );
528817466cbSJens Wiklander 
529817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, n ) );
530817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) );
531817466cbSJens Wiklander 
532817466cbSJens Wiklander         for( i = slen, j = 0; i > 0; i--, j++ )
533817466cbSJens Wiklander         {
534817466cbSJens Wiklander             if( i == 1 && s[i - 1] == '-' )
535817466cbSJens Wiklander             {
536817466cbSJens Wiklander                 X->s = -1;
537817466cbSJens Wiklander                 break;
538817466cbSJens Wiklander             }
539817466cbSJens Wiklander 
540817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mpi_get_digit( &d, radix, s[i - 1] ) );
541817466cbSJens Wiklander             X->p[j / ( 2 * ciL )] |= d << ( ( j % ( 2 * ciL ) ) << 2 );
542817466cbSJens Wiklander         }
543817466cbSJens Wiklander     }
544817466cbSJens Wiklander     else
545817466cbSJens Wiklander     {
546817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) );
547817466cbSJens Wiklander 
548817466cbSJens Wiklander         for( i = 0; i < slen; i++ )
549817466cbSJens Wiklander         {
550817466cbSJens Wiklander             if( i == 0 && s[i] == '-' )
551817466cbSJens Wiklander             {
552817466cbSJens Wiklander                 X->s = -1;
553817466cbSJens Wiklander                 continue;
554817466cbSJens Wiklander             }
555817466cbSJens Wiklander 
556817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mpi_get_digit( &d, radix, s[i] ) );
557817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &T, X, radix ) );
558817466cbSJens Wiklander 
559817466cbSJens Wiklander             if( X->s == 1 )
560817466cbSJens Wiklander             {
561817466cbSJens Wiklander                 MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, &T, d ) );
562817466cbSJens Wiklander             }
563817466cbSJens Wiklander             else
564817466cbSJens Wiklander             {
565817466cbSJens Wiklander                 MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( X, &T, d ) );
566817466cbSJens Wiklander             }
567817466cbSJens Wiklander         }
568817466cbSJens Wiklander     }
569817466cbSJens Wiklander 
570817466cbSJens Wiklander cleanup:
571817466cbSJens Wiklander 
572817466cbSJens Wiklander     mbedtls_mpi_free( &T );
573817466cbSJens Wiklander 
574817466cbSJens Wiklander     return( ret );
575817466cbSJens Wiklander }
576817466cbSJens Wiklander 
577817466cbSJens Wiklander /*
578*5b25c76aSJerome Forissier  * Helper to write the digits high-order first.
579817466cbSJens Wiklander  */
580*5b25c76aSJerome Forissier static int mpi_write_hlp( mbedtls_mpi *X, int radix,
581*5b25c76aSJerome Forissier                           char **p, const size_t buflen )
582817466cbSJens Wiklander {
583817466cbSJens Wiklander     int ret;
584817466cbSJens Wiklander     mbedtls_mpi_uint r;
585*5b25c76aSJerome Forissier     size_t length = 0;
586*5b25c76aSJerome Forissier     char *p_end = *p + buflen;
587817466cbSJens Wiklander 
588*5b25c76aSJerome Forissier     do
589*5b25c76aSJerome Forissier     {
590*5b25c76aSJerome Forissier         if( length >= buflen )
591*5b25c76aSJerome Forissier         {
592*5b25c76aSJerome Forissier             return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL );
593*5b25c76aSJerome Forissier         }
594817466cbSJens Wiklander 
595817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mod_int( &r, X, radix ) );
596817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_div_int( X, NULL, X, radix ) );
597*5b25c76aSJerome Forissier         /*
598*5b25c76aSJerome Forissier          * Write the residue in the current position, as an ASCII character.
599*5b25c76aSJerome Forissier          */
600*5b25c76aSJerome Forissier         if( r < 0xA )
601*5b25c76aSJerome Forissier             *(--p_end) = (char)( '0' + r );
602817466cbSJens Wiklander         else
603*5b25c76aSJerome Forissier             *(--p_end) = (char)( 'A' + ( r - 0xA ) );
604*5b25c76aSJerome Forissier 
605*5b25c76aSJerome Forissier         length++;
606*5b25c76aSJerome Forissier     } while( mbedtls_mpi_cmp_int( X, 0 ) != 0 );
607*5b25c76aSJerome Forissier 
608*5b25c76aSJerome Forissier     memmove( *p, p_end, length );
609*5b25c76aSJerome Forissier     *p += length;
610817466cbSJens Wiklander 
611817466cbSJens Wiklander cleanup:
612817466cbSJens Wiklander 
613817466cbSJens Wiklander     return( ret );
614817466cbSJens Wiklander }
615817466cbSJens Wiklander 
616817466cbSJens Wiklander /*
617817466cbSJens Wiklander  * Export into an ASCII string
618817466cbSJens Wiklander  */
619817466cbSJens Wiklander int mbedtls_mpi_write_string( const mbedtls_mpi *X, int radix,
620817466cbSJens Wiklander                               char *buf, size_t buflen, size_t *olen )
621817466cbSJens Wiklander {
622817466cbSJens Wiklander     int ret = 0;
623817466cbSJens Wiklander     size_t n;
624817466cbSJens Wiklander     char *p;
625817466cbSJens Wiklander     mbedtls_mpi T;
6263d3b0591SJens Wiklander     MPI_VALIDATE_RET( X    != NULL );
6273d3b0591SJens Wiklander     MPI_VALIDATE_RET( olen != NULL );
6283d3b0591SJens Wiklander     MPI_VALIDATE_RET( buflen == 0 || buf != NULL );
629817466cbSJens Wiklander 
630817466cbSJens Wiklander     if( radix < 2 || radix > 16 )
631817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
632817466cbSJens Wiklander 
633*5b25c76aSJerome Forissier     n = mbedtls_mpi_bitlen( X ); /* Number of bits necessary to present `n`. */
634*5b25c76aSJerome Forissier     if( radix >=  4 ) n >>= 1;   /* Number of 4-adic digits necessary to present
635*5b25c76aSJerome Forissier                                   * `n`. If radix > 4, this might be a strict
636*5b25c76aSJerome Forissier                                   * overapproximation of the number of
637*5b25c76aSJerome Forissier                                   * radix-adic digits needed to present `n`. */
638*5b25c76aSJerome Forissier     if( radix >= 16 ) n >>= 1;   /* Number of hexadecimal digits necessary to
639*5b25c76aSJerome Forissier                                   * present `n`. */
640*5b25c76aSJerome Forissier 
641*5b25c76aSJerome Forissier     n += 1; /* Terminating null byte */
642*5b25c76aSJerome Forissier     n += 1; /* Compensate for the divisions above, which round down `n`
643*5b25c76aSJerome Forissier              * in case it's not even. */
644*5b25c76aSJerome Forissier     n += 1; /* Potential '-'-sign. */
645*5b25c76aSJerome Forissier     n += ( n & 1 ); /* Make n even to have enough space for hexadecimal writing,
646*5b25c76aSJerome Forissier                      * which always uses an even number of hex-digits. */
647817466cbSJens Wiklander 
648817466cbSJens Wiklander     if( buflen < n )
649817466cbSJens Wiklander     {
650817466cbSJens Wiklander         *olen = n;
651817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL );
652817466cbSJens Wiklander     }
653817466cbSJens Wiklander 
654817466cbSJens Wiklander     p = buf;
65598bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &T );
656817466cbSJens Wiklander 
657817466cbSJens Wiklander     if( X->s == -1 )
658*5b25c76aSJerome Forissier     {
659817466cbSJens Wiklander         *p++ = '-';
660*5b25c76aSJerome Forissier         buflen--;
661*5b25c76aSJerome Forissier     }
662817466cbSJens Wiklander 
663817466cbSJens Wiklander     if( radix == 16 )
664817466cbSJens Wiklander     {
665817466cbSJens Wiklander         int c;
666817466cbSJens Wiklander         size_t i, j, k;
667817466cbSJens Wiklander 
668817466cbSJens Wiklander         for( i = X->n, k = 0; i > 0; i-- )
669817466cbSJens Wiklander         {
670817466cbSJens Wiklander             for( j = ciL; j > 0; j-- )
671817466cbSJens Wiklander             {
672817466cbSJens Wiklander                 c = ( X->p[i - 1] >> ( ( j - 1 ) << 3) ) & 0xFF;
673817466cbSJens Wiklander 
674817466cbSJens Wiklander                 if( c == 0 && k == 0 && ( i + j ) != 2 )
675817466cbSJens Wiklander                     continue;
676817466cbSJens Wiklander 
677817466cbSJens Wiklander                 *(p++) = "0123456789ABCDEF" [c / 16];
678817466cbSJens Wiklander                 *(p++) = "0123456789ABCDEF" [c % 16];
679817466cbSJens Wiklander                 k = 1;
680817466cbSJens Wiklander             }
681817466cbSJens Wiklander         }
682817466cbSJens Wiklander     }
683817466cbSJens Wiklander     else
684817466cbSJens Wiklander     {
685817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &T, X ) );
686817466cbSJens Wiklander 
687817466cbSJens Wiklander         if( T.s == -1 )
688817466cbSJens Wiklander             T.s = 1;
689817466cbSJens Wiklander 
690*5b25c76aSJerome Forissier         MBEDTLS_MPI_CHK( mpi_write_hlp( &T, radix, &p, buflen ) );
691817466cbSJens Wiklander     }
692817466cbSJens Wiklander 
693817466cbSJens Wiklander     *p++ = '\0';
694817466cbSJens Wiklander     *olen = p - buf;
695817466cbSJens Wiklander 
696817466cbSJens Wiklander cleanup:
697817466cbSJens Wiklander 
698817466cbSJens Wiklander     mbedtls_mpi_free( &T );
699817466cbSJens Wiklander 
700817466cbSJens Wiklander     return( ret );
701817466cbSJens Wiklander }
702817466cbSJens Wiklander 
703817466cbSJens Wiklander #if defined(MBEDTLS_FS_IO)
704817466cbSJens Wiklander /*
705817466cbSJens Wiklander  * Read X from an opened file
706817466cbSJens Wiklander  */
707817466cbSJens Wiklander int mbedtls_mpi_read_file( mbedtls_mpi *X, int radix, FILE *fin )
708817466cbSJens Wiklander {
709817466cbSJens Wiklander     mbedtls_mpi_uint d;
710817466cbSJens Wiklander     size_t slen;
711817466cbSJens Wiklander     char *p;
712817466cbSJens Wiklander     /*
713817466cbSJens Wiklander      * Buffer should have space for (short) label and decimal formatted MPI,
714817466cbSJens Wiklander      * newline characters and '\0'
715817466cbSJens Wiklander      */
716817466cbSJens Wiklander     char s[ MBEDTLS_MPI_RW_BUFFER_SIZE ];
717817466cbSJens Wiklander 
7183d3b0591SJens Wiklander     MPI_VALIDATE_RET( X   != NULL );
7193d3b0591SJens Wiklander     MPI_VALIDATE_RET( fin != NULL );
7203d3b0591SJens Wiklander 
7213d3b0591SJens Wiklander     if( radix < 2 || radix > 16 )
7223d3b0591SJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
7233d3b0591SJens Wiklander 
724817466cbSJens Wiklander     memset( s, 0, sizeof( s ) );
725817466cbSJens Wiklander     if( fgets( s, sizeof( s ) - 1, fin ) == NULL )
726817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_FILE_IO_ERROR );
727817466cbSJens Wiklander 
728817466cbSJens Wiklander     slen = strlen( s );
729817466cbSJens Wiklander     if( slen == sizeof( s ) - 2 )
730817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL );
731817466cbSJens Wiklander 
732817466cbSJens Wiklander     if( slen > 0 && s[slen - 1] == '\n' ) { slen--; s[slen] = '\0'; }
733817466cbSJens Wiklander     if( slen > 0 && s[slen - 1] == '\r' ) { slen--; s[slen] = '\0'; }
734817466cbSJens Wiklander 
735817466cbSJens Wiklander     p = s + slen;
736817466cbSJens Wiklander     while( p-- > s )
737817466cbSJens Wiklander         if( mpi_get_digit( &d, radix, *p ) != 0 )
738817466cbSJens Wiklander             break;
739817466cbSJens Wiklander 
740817466cbSJens Wiklander     return( mbedtls_mpi_read_string( X, radix, p + 1 ) );
741817466cbSJens Wiklander }
742817466cbSJens Wiklander 
743817466cbSJens Wiklander /*
744817466cbSJens Wiklander  * Write X into an opened file (or stdout if fout == NULL)
745817466cbSJens Wiklander  */
746817466cbSJens Wiklander int mbedtls_mpi_write_file( const char *p, const mbedtls_mpi *X, int radix, FILE *fout )
747817466cbSJens Wiklander {
748817466cbSJens Wiklander     int ret;
749817466cbSJens Wiklander     size_t n, slen, plen;
750817466cbSJens Wiklander     /*
751817466cbSJens Wiklander      * Buffer should have space for (short) label and decimal formatted MPI,
752817466cbSJens Wiklander      * newline characters and '\0'
753817466cbSJens Wiklander      */
754817466cbSJens Wiklander     char s[ MBEDTLS_MPI_RW_BUFFER_SIZE ];
7553d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
7563d3b0591SJens Wiklander 
7573d3b0591SJens Wiklander     if( radix < 2 || radix > 16 )
7583d3b0591SJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
759817466cbSJens Wiklander 
760817466cbSJens Wiklander     memset( s, 0, sizeof( s ) );
761817466cbSJens Wiklander 
762817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_write_string( X, radix, s, sizeof( s ) - 2, &n ) );
763817466cbSJens Wiklander 
764817466cbSJens Wiklander     if( p == NULL ) p = "";
765817466cbSJens Wiklander 
766817466cbSJens Wiklander     plen = strlen( p );
767817466cbSJens Wiklander     slen = strlen( s );
768817466cbSJens Wiklander     s[slen++] = '\r';
769817466cbSJens Wiklander     s[slen++] = '\n';
770817466cbSJens Wiklander 
771817466cbSJens Wiklander     if( fout != NULL )
772817466cbSJens Wiklander     {
773817466cbSJens Wiklander         if( fwrite( p, 1, plen, fout ) != plen ||
774817466cbSJens Wiklander             fwrite( s, 1, slen, fout ) != slen )
775817466cbSJens Wiklander             return( MBEDTLS_ERR_MPI_FILE_IO_ERROR );
776817466cbSJens Wiklander     }
777817466cbSJens Wiklander     else
778817466cbSJens Wiklander         mbedtls_printf( "%s%s", p, s );
779817466cbSJens Wiklander 
780817466cbSJens Wiklander cleanup:
781817466cbSJens Wiklander 
782817466cbSJens Wiklander     return( ret );
783817466cbSJens Wiklander }
784817466cbSJens Wiklander #endif /* MBEDTLS_FS_IO */
785817466cbSJens Wiklander 
786*5b25c76aSJerome Forissier 
787*5b25c76aSJerome Forissier /* Convert a big-endian byte array aligned to the size of mbedtls_mpi_uint
788*5b25c76aSJerome Forissier  * into the storage form used by mbedtls_mpi. */
789*5b25c76aSJerome Forissier 
790*5b25c76aSJerome Forissier static mbedtls_mpi_uint mpi_uint_bigendian_to_host_c( mbedtls_mpi_uint x )
791*5b25c76aSJerome Forissier {
792*5b25c76aSJerome Forissier     uint8_t i;
793*5b25c76aSJerome Forissier     unsigned char *x_ptr;
794*5b25c76aSJerome Forissier     mbedtls_mpi_uint tmp = 0;
795*5b25c76aSJerome Forissier 
796*5b25c76aSJerome Forissier     for( i = 0, x_ptr = (unsigned char*) &x; i < ciL; i++, x_ptr++ )
797*5b25c76aSJerome Forissier     {
798*5b25c76aSJerome Forissier         tmp <<= CHAR_BIT;
799*5b25c76aSJerome Forissier         tmp |= (mbedtls_mpi_uint) *x_ptr;
800*5b25c76aSJerome Forissier     }
801*5b25c76aSJerome Forissier 
802*5b25c76aSJerome Forissier     return( tmp );
803*5b25c76aSJerome Forissier }
804*5b25c76aSJerome Forissier 
805*5b25c76aSJerome Forissier static mbedtls_mpi_uint mpi_uint_bigendian_to_host( mbedtls_mpi_uint x )
806*5b25c76aSJerome Forissier {
807*5b25c76aSJerome Forissier #if defined(__BYTE_ORDER__)
808*5b25c76aSJerome Forissier 
809*5b25c76aSJerome Forissier /* Nothing to do on bigendian systems. */
810*5b25c76aSJerome Forissier #if ( __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ )
811*5b25c76aSJerome Forissier     return( x );
812*5b25c76aSJerome Forissier #endif /* __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ */
813*5b25c76aSJerome Forissier 
814*5b25c76aSJerome Forissier #if ( __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ )
815*5b25c76aSJerome Forissier 
816*5b25c76aSJerome Forissier /* For GCC and Clang, have builtins for byte swapping. */
817*5b25c76aSJerome Forissier #if defined(__GNUC__) && defined(__GNUC_PREREQ)
818*5b25c76aSJerome Forissier #if __GNUC_PREREQ(4,3)
819*5b25c76aSJerome Forissier #define have_bswap
820*5b25c76aSJerome Forissier #endif
821*5b25c76aSJerome Forissier #endif
822*5b25c76aSJerome Forissier 
823*5b25c76aSJerome Forissier #if defined(__clang__) && defined(__has_builtin)
824*5b25c76aSJerome Forissier #if __has_builtin(__builtin_bswap32)  &&                 \
825*5b25c76aSJerome Forissier     __has_builtin(__builtin_bswap64)
826*5b25c76aSJerome Forissier #define have_bswap
827*5b25c76aSJerome Forissier #endif
828*5b25c76aSJerome Forissier #endif
829*5b25c76aSJerome Forissier 
830*5b25c76aSJerome Forissier #if defined(have_bswap)
831*5b25c76aSJerome Forissier     /* The compiler is hopefully able to statically evaluate this! */
832*5b25c76aSJerome Forissier     switch( sizeof(mbedtls_mpi_uint) )
833*5b25c76aSJerome Forissier     {
834*5b25c76aSJerome Forissier         case 4:
835*5b25c76aSJerome Forissier             return( __builtin_bswap32(x) );
836*5b25c76aSJerome Forissier         case 8:
837*5b25c76aSJerome Forissier             return( __builtin_bswap64(x) );
838*5b25c76aSJerome Forissier     }
839*5b25c76aSJerome Forissier #endif
840*5b25c76aSJerome Forissier #endif /* __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ */
841*5b25c76aSJerome Forissier #endif /* __BYTE_ORDER__ */
842*5b25c76aSJerome Forissier 
843*5b25c76aSJerome Forissier     /* Fall back to C-based reordering if we don't know the byte order
844*5b25c76aSJerome Forissier      * or we couldn't use a compiler-specific builtin. */
845*5b25c76aSJerome Forissier     return( mpi_uint_bigendian_to_host_c( x ) );
846*5b25c76aSJerome Forissier }
847*5b25c76aSJerome Forissier 
848*5b25c76aSJerome Forissier static void mpi_bigendian_to_host( mbedtls_mpi_uint * const p, size_t limbs )
849*5b25c76aSJerome Forissier {
850*5b25c76aSJerome Forissier     mbedtls_mpi_uint *cur_limb_left;
851*5b25c76aSJerome Forissier     mbedtls_mpi_uint *cur_limb_right;
852*5b25c76aSJerome Forissier     if( limbs == 0 )
853*5b25c76aSJerome Forissier         return;
854*5b25c76aSJerome Forissier 
855*5b25c76aSJerome Forissier     /*
856*5b25c76aSJerome Forissier      * Traverse limbs and
857*5b25c76aSJerome Forissier      * - adapt byte-order in each limb
858*5b25c76aSJerome Forissier      * - swap the limbs themselves.
859*5b25c76aSJerome Forissier      * For that, simultaneously traverse the limbs from left to right
860*5b25c76aSJerome Forissier      * and from right to left, as long as the left index is not bigger
861*5b25c76aSJerome Forissier      * than the right index (it's not a problem if limbs is odd and the
862*5b25c76aSJerome Forissier      * indices coincide in the last iteration).
863*5b25c76aSJerome Forissier      */
864*5b25c76aSJerome Forissier     for( cur_limb_left = p, cur_limb_right = p + ( limbs - 1 );
865*5b25c76aSJerome Forissier          cur_limb_left <= cur_limb_right;
866*5b25c76aSJerome Forissier          cur_limb_left++, cur_limb_right-- )
867*5b25c76aSJerome Forissier     {
868*5b25c76aSJerome Forissier         mbedtls_mpi_uint tmp;
869*5b25c76aSJerome Forissier         /* Note that if cur_limb_left == cur_limb_right,
870*5b25c76aSJerome Forissier          * this code effectively swaps the bytes only once. */
871*5b25c76aSJerome Forissier         tmp             = mpi_uint_bigendian_to_host( *cur_limb_left  );
872*5b25c76aSJerome Forissier         *cur_limb_left  = mpi_uint_bigendian_to_host( *cur_limb_right );
873*5b25c76aSJerome Forissier         *cur_limb_right = tmp;
874*5b25c76aSJerome Forissier     }
875*5b25c76aSJerome Forissier }
876*5b25c76aSJerome Forissier 
877817466cbSJens Wiklander /*
878817466cbSJens Wiklander  * Import X from unsigned binary data, big endian
879817466cbSJens Wiklander  */
880817466cbSJens Wiklander int mbedtls_mpi_read_binary( mbedtls_mpi *X, const unsigned char *buf, size_t buflen )
881817466cbSJens Wiklander {
882817466cbSJens Wiklander     int ret;
8833d3b0591SJens Wiklander     size_t const limbs    = CHARS_TO_LIMBS( buflen );
884*5b25c76aSJerome Forissier     size_t const overhead = ( limbs * ciL ) - buflen;
885*5b25c76aSJerome Forissier     unsigned char *Xp;
886817466cbSJens Wiklander 
8873d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
8883d3b0591SJens Wiklander     MPI_VALIDATE_RET( buflen == 0 || buf != NULL );
889817466cbSJens Wiklander 
8903d3b0591SJens Wiklander     /* Ensure that target MPI has exactly the necessary number of limbs */
8913d3b0591SJens Wiklander     if( X->n != limbs )
8923d3b0591SJens Wiklander     {
8932976273fSJens Wiklander         short use_mempool = X->use_mempool;
8942976273fSJens Wiklander 
8953d3b0591SJens Wiklander         mbedtls_mpi_free( X );
8962976273fSJens Wiklander         mpi_init( X, use_mempool );
8973d3b0591SJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, limbs ) );
8983d3b0591SJens Wiklander     }
899817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) );
900817466cbSJens Wiklander 
901*5b25c76aSJerome Forissier     /* Avoid calling `memcpy` with NULL source argument,
902*5b25c76aSJerome Forissier      * even if buflen is 0. */
903*5b25c76aSJerome Forissier     if( buf != NULL )
904*5b25c76aSJerome Forissier     {
905*5b25c76aSJerome Forissier         Xp = (unsigned char*) X->p;
906*5b25c76aSJerome Forissier         memcpy( Xp + overhead, buf, buflen );
907*5b25c76aSJerome Forissier 
908*5b25c76aSJerome Forissier         mpi_bigendian_to_host( X->p, limbs );
909*5b25c76aSJerome Forissier     }
910817466cbSJens Wiklander 
911817466cbSJens Wiklander cleanup:
912817466cbSJens Wiklander 
913817466cbSJens Wiklander     return( ret );
914817466cbSJens Wiklander }
915817466cbSJens Wiklander 
916817466cbSJens Wiklander /*
917817466cbSJens Wiklander  * Export X into unsigned binary data, big endian
918817466cbSJens Wiklander  */
9193d3b0591SJens Wiklander int mbedtls_mpi_write_binary( const mbedtls_mpi *X,
9203d3b0591SJens Wiklander                               unsigned char *buf, size_t buflen )
921817466cbSJens Wiklander {
9223d3b0591SJens Wiklander     size_t stored_bytes;
9233d3b0591SJens Wiklander     size_t bytes_to_copy;
9243d3b0591SJens Wiklander     unsigned char *p;
9253d3b0591SJens Wiklander     size_t i;
926817466cbSJens Wiklander 
9273d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
9283d3b0591SJens Wiklander     MPI_VALIDATE_RET( buflen == 0 || buf != NULL );
929817466cbSJens Wiklander 
9303d3b0591SJens Wiklander     stored_bytes = X->n * ciL;
9313d3b0591SJens Wiklander 
9323d3b0591SJens Wiklander     if( stored_bytes < buflen )
9333d3b0591SJens Wiklander     {
9343d3b0591SJens Wiklander         /* There is enough space in the output buffer. Write initial
9353d3b0591SJens Wiklander          * null bytes and record the position at which to start
9363d3b0591SJens Wiklander          * writing the significant bytes. In this case, the execution
9373d3b0591SJens Wiklander          * trace of this function does not depend on the value of the
9383d3b0591SJens Wiklander          * number. */
9393d3b0591SJens Wiklander         bytes_to_copy = stored_bytes;
9403d3b0591SJens Wiklander         p = buf + buflen - stored_bytes;
9413d3b0591SJens Wiklander         memset( buf, 0, buflen - stored_bytes );
9423d3b0591SJens Wiklander     }
9433d3b0591SJens Wiklander     else
9443d3b0591SJens Wiklander     {
9453d3b0591SJens Wiklander         /* The output buffer is smaller than the allocated size of X.
9463d3b0591SJens Wiklander          * However X may fit if its leading bytes are zero. */
9473d3b0591SJens Wiklander         bytes_to_copy = buflen;
9483d3b0591SJens Wiklander         p = buf;
9493d3b0591SJens Wiklander         for( i = bytes_to_copy; i < stored_bytes; i++ )
9503d3b0591SJens Wiklander         {
9513d3b0591SJens Wiklander             if( GET_BYTE( X, i ) != 0 )
952817466cbSJens Wiklander                 return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL );
9533d3b0591SJens Wiklander         }
9543d3b0591SJens Wiklander     }
955817466cbSJens Wiklander 
9563d3b0591SJens Wiklander     for( i = 0; i < bytes_to_copy; i++ )
9573d3b0591SJens Wiklander         p[bytes_to_copy - i - 1] = GET_BYTE( X, i );
958817466cbSJens Wiklander 
959817466cbSJens Wiklander     return( 0 );
960817466cbSJens Wiklander }
961817466cbSJens Wiklander 
962817466cbSJens Wiklander /*
963817466cbSJens Wiklander  * Left-shift: X <<= count
964817466cbSJens Wiklander  */
965817466cbSJens Wiklander int mbedtls_mpi_shift_l( mbedtls_mpi *X, size_t count )
966817466cbSJens Wiklander {
967817466cbSJens Wiklander     int ret;
968817466cbSJens Wiklander     size_t i, v0, t1;
969817466cbSJens Wiklander     mbedtls_mpi_uint r0 = 0, r1;
9703d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
971817466cbSJens Wiklander 
972817466cbSJens Wiklander     v0 = count / (biL    );
973817466cbSJens Wiklander     t1 = count & (biL - 1);
974817466cbSJens Wiklander 
975817466cbSJens Wiklander     i = mbedtls_mpi_bitlen( X ) + count;
976817466cbSJens Wiklander 
977817466cbSJens Wiklander     if( X->n * biL < i )
978817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, BITS_TO_LIMBS( i ) ) );
979817466cbSJens Wiklander 
980817466cbSJens Wiklander     ret = 0;
981817466cbSJens Wiklander 
982817466cbSJens Wiklander     /*
983817466cbSJens Wiklander      * shift by count / limb_size
984817466cbSJens Wiklander      */
985817466cbSJens Wiklander     if( v0 > 0 )
986817466cbSJens Wiklander     {
987817466cbSJens Wiklander         for( i = X->n; i > v0; i-- )
988817466cbSJens Wiklander             X->p[i - 1] = X->p[i - v0 - 1];
989817466cbSJens Wiklander 
990817466cbSJens Wiklander         for( ; i > 0; i-- )
991817466cbSJens Wiklander             X->p[i - 1] = 0;
992817466cbSJens Wiklander     }
993817466cbSJens Wiklander 
994817466cbSJens Wiklander     /*
995817466cbSJens Wiklander      * shift by count % limb_size
996817466cbSJens Wiklander      */
997817466cbSJens Wiklander     if( t1 > 0 )
998817466cbSJens Wiklander     {
999817466cbSJens Wiklander         for( i = v0; i < X->n; i++ )
1000817466cbSJens Wiklander         {
1001817466cbSJens Wiklander             r1 = X->p[i] >> (biL - t1);
1002817466cbSJens Wiklander             X->p[i] <<= t1;
1003817466cbSJens Wiklander             X->p[i] |= r0;
1004817466cbSJens Wiklander             r0 = r1;
1005817466cbSJens Wiklander         }
1006817466cbSJens Wiklander     }
1007817466cbSJens Wiklander 
1008817466cbSJens Wiklander cleanup:
1009817466cbSJens Wiklander 
1010817466cbSJens Wiklander     return( ret );
1011817466cbSJens Wiklander }
1012817466cbSJens Wiklander 
1013817466cbSJens Wiklander /*
1014817466cbSJens Wiklander  * Right-shift: X >>= count
1015817466cbSJens Wiklander  */
1016817466cbSJens Wiklander int mbedtls_mpi_shift_r( mbedtls_mpi *X, size_t count )
1017817466cbSJens Wiklander {
1018817466cbSJens Wiklander     size_t i, v0, v1;
1019817466cbSJens Wiklander     mbedtls_mpi_uint r0 = 0, r1;
10203d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
1021817466cbSJens Wiklander 
1022817466cbSJens Wiklander     v0 = count /  biL;
1023817466cbSJens Wiklander     v1 = count & (biL - 1);
1024817466cbSJens Wiklander 
1025817466cbSJens Wiklander     if( v0 > X->n || ( v0 == X->n && v1 > 0 ) )
1026817466cbSJens Wiklander         return mbedtls_mpi_lset( X, 0 );
1027817466cbSJens Wiklander 
1028817466cbSJens Wiklander     /*
1029817466cbSJens Wiklander      * shift by count / limb_size
1030817466cbSJens Wiklander      */
1031817466cbSJens Wiklander     if( v0 > 0 )
1032817466cbSJens Wiklander     {
1033817466cbSJens Wiklander         for( i = 0; i < X->n - v0; i++ )
1034817466cbSJens Wiklander             X->p[i] = X->p[i + v0];
1035817466cbSJens Wiklander 
1036817466cbSJens Wiklander         for( ; i < X->n; i++ )
1037817466cbSJens Wiklander             X->p[i] = 0;
1038817466cbSJens Wiklander     }
1039817466cbSJens Wiklander 
1040817466cbSJens Wiklander     /*
1041817466cbSJens Wiklander      * shift by count % limb_size
1042817466cbSJens Wiklander      */
1043817466cbSJens Wiklander     if( v1 > 0 )
1044817466cbSJens Wiklander     {
1045817466cbSJens Wiklander         for( i = X->n; i > 0; i-- )
1046817466cbSJens Wiklander         {
1047817466cbSJens Wiklander             r1 = X->p[i - 1] << (biL - v1);
1048817466cbSJens Wiklander             X->p[i - 1] >>= v1;
1049817466cbSJens Wiklander             X->p[i - 1] |= r0;
1050817466cbSJens Wiklander             r0 = r1;
1051817466cbSJens Wiklander         }
1052817466cbSJens Wiklander     }
1053817466cbSJens Wiklander 
1054817466cbSJens Wiklander     return( 0 );
1055817466cbSJens Wiklander }
1056817466cbSJens Wiklander 
1057817466cbSJens Wiklander /*
1058817466cbSJens Wiklander  * Compare unsigned values
1059817466cbSJens Wiklander  */
1060817466cbSJens Wiklander int mbedtls_mpi_cmp_abs( const mbedtls_mpi *X, const mbedtls_mpi *Y )
1061817466cbSJens Wiklander {
1062817466cbSJens Wiklander     size_t i, j;
10633d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
10643d3b0591SJens Wiklander     MPI_VALIDATE_RET( Y != NULL );
1065817466cbSJens Wiklander 
1066817466cbSJens Wiklander     for( i = X->n; i > 0; i-- )
1067817466cbSJens Wiklander         if( X->p[i - 1] != 0 )
1068817466cbSJens Wiklander             break;
1069817466cbSJens Wiklander 
1070817466cbSJens Wiklander     for( j = Y->n; j > 0; j-- )
1071817466cbSJens Wiklander         if( Y->p[j - 1] != 0 )
1072817466cbSJens Wiklander             break;
1073817466cbSJens Wiklander 
1074817466cbSJens Wiklander     if( i == 0 && j == 0 )
1075817466cbSJens Wiklander         return( 0 );
1076817466cbSJens Wiklander 
1077817466cbSJens Wiklander     if( i > j ) return(  1 );
1078817466cbSJens Wiklander     if( j > i ) return( -1 );
1079817466cbSJens Wiklander 
1080817466cbSJens Wiklander     for( ; i > 0; i-- )
1081817466cbSJens Wiklander     {
1082817466cbSJens Wiklander         if( X->p[i - 1] > Y->p[i - 1] ) return(  1 );
1083817466cbSJens Wiklander         if( X->p[i - 1] < Y->p[i - 1] ) return( -1 );
1084817466cbSJens Wiklander     }
1085817466cbSJens Wiklander 
1086817466cbSJens Wiklander     return( 0 );
1087817466cbSJens Wiklander }
1088817466cbSJens Wiklander 
1089817466cbSJens Wiklander /*
1090817466cbSJens Wiklander  * Compare signed values
1091817466cbSJens Wiklander  */
1092817466cbSJens Wiklander int mbedtls_mpi_cmp_mpi( const mbedtls_mpi *X, const mbedtls_mpi *Y )
1093817466cbSJens Wiklander {
1094817466cbSJens Wiklander     size_t i, j;
10953d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
10963d3b0591SJens Wiklander     MPI_VALIDATE_RET( Y != NULL );
1097817466cbSJens Wiklander 
1098817466cbSJens Wiklander     for( i = X->n; i > 0; i-- )
1099817466cbSJens Wiklander         if( X->p[i - 1] != 0 )
1100817466cbSJens Wiklander             break;
1101817466cbSJens Wiklander 
1102817466cbSJens Wiklander     for( j = Y->n; j > 0; j-- )
1103817466cbSJens Wiklander         if( Y->p[j - 1] != 0 )
1104817466cbSJens Wiklander             break;
1105817466cbSJens Wiklander 
1106817466cbSJens Wiklander     if( i == 0 && j == 0 )
1107817466cbSJens Wiklander         return( 0 );
1108817466cbSJens Wiklander 
1109817466cbSJens Wiklander     if( i > j ) return(  X->s );
1110817466cbSJens Wiklander     if( j > i ) return( -Y->s );
1111817466cbSJens Wiklander 
1112817466cbSJens Wiklander     if( X->s > 0 && Y->s < 0 ) return(  1 );
1113817466cbSJens Wiklander     if( Y->s > 0 && X->s < 0 ) return( -1 );
1114817466cbSJens Wiklander 
1115817466cbSJens Wiklander     for( ; i > 0; i-- )
1116817466cbSJens Wiklander     {
1117817466cbSJens Wiklander         if( X->p[i - 1] > Y->p[i - 1] ) return(  X->s );
1118817466cbSJens Wiklander         if( X->p[i - 1] < Y->p[i - 1] ) return( -X->s );
1119817466cbSJens Wiklander     }
1120817466cbSJens Wiklander 
1121817466cbSJens Wiklander     return( 0 );
1122817466cbSJens Wiklander }
1123817466cbSJens Wiklander 
1124*5b25c76aSJerome Forissier /** Decide if an integer is less than the other, without branches.
1125*5b25c76aSJerome Forissier  *
1126*5b25c76aSJerome Forissier  * \param x         First integer.
1127*5b25c76aSJerome Forissier  * \param y         Second integer.
1128*5b25c76aSJerome Forissier  *
1129*5b25c76aSJerome Forissier  * \return          1 if \p x is less than \p y, 0 otherwise
1130*5b25c76aSJerome Forissier  */
1131*5b25c76aSJerome Forissier static unsigned ct_lt_mpi_uint( const mbedtls_mpi_uint x,
1132*5b25c76aSJerome Forissier         const mbedtls_mpi_uint y )
1133*5b25c76aSJerome Forissier {
1134*5b25c76aSJerome Forissier     mbedtls_mpi_uint ret;
1135*5b25c76aSJerome Forissier     mbedtls_mpi_uint cond;
1136*5b25c76aSJerome Forissier 
1137*5b25c76aSJerome Forissier     /*
1138*5b25c76aSJerome Forissier      * Check if the most significant bits (MSB) of the operands are different.
1139*5b25c76aSJerome Forissier      */
1140*5b25c76aSJerome Forissier     cond = ( x ^ y );
1141*5b25c76aSJerome Forissier     /*
1142*5b25c76aSJerome Forissier      * If the MSB are the same then the difference x-y will be negative (and
1143*5b25c76aSJerome Forissier      * have its MSB set to 1 during conversion to unsigned) if and only if x<y.
1144*5b25c76aSJerome Forissier      */
1145*5b25c76aSJerome Forissier     ret = ( x - y ) & ~cond;
1146*5b25c76aSJerome Forissier     /*
1147*5b25c76aSJerome Forissier      * If the MSB are different, then the operand with the MSB of 1 is the
1148*5b25c76aSJerome Forissier      * bigger. (That is if y has MSB of 1, then x<y is true and it is false if
1149*5b25c76aSJerome Forissier      * the MSB of y is 0.)
1150*5b25c76aSJerome Forissier      */
1151*5b25c76aSJerome Forissier     ret |= y & cond;
1152*5b25c76aSJerome Forissier 
1153*5b25c76aSJerome Forissier 
1154*5b25c76aSJerome Forissier     ret = ret >> ( biL - 1 );
1155*5b25c76aSJerome Forissier 
1156*5b25c76aSJerome Forissier     return (unsigned) ret;
1157*5b25c76aSJerome Forissier }
1158*5b25c76aSJerome Forissier 
1159*5b25c76aSJerome Forissier /*
1160*5b25c76aSJerome Forissier  * Compare signed values in constant time
1161*5b25c76aSJerome Forissier  */
1162*5b25c76aSJerome Forissier int mbedtls_mpi_lt_mpi_ct( const mbedtls_mpi *X, const mbedtls_mpi *Y,
1163*5b25c76aSJerome Forissier         unsigned *ret )
1164*5b25c76aSJerome Forissier {
1165*5b25c76aSJerome Forissier     size_t i;
1166*5b25c76aSJerome Forissier     /* The value of any of these variables is either 0 or 1 at all times. */
1167*5b25c76aSJerome Forissier     unsigned cond, done, X_is_negative, Y_is_negative;
1168*5b25c76aSJerome Forissier 
1169*5b25c76aSJerome Forissier     MPI_VALIDATE_RET( X != NULL );
1170*5b25c76aSJerome Forissier     MPI_VALIDATE_RET( Y != NULL );
1171*5b25c76aSJerome Forissier     MPI_VALIDATE_RET( ret != NULL );
1172*5b25c76aSJerome Forissier 
1173*5b25c76aSJerome Forissier     if( X->n != Y->n )
1174*5b25c76aSJerome Forissier         return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
1175*5b25c76aSJerome Forissier 
1176*5b25c76aSJerome Forissier     /*
1177*5b25c76aSJerome Forissier      * Set sign_N to 1 if N >= 0, 0 if N < 0.
1178*5b25c76aSJerome Forissier      * We know that N->s == 1 if N >= 0 and N->s == -1 if N < 0.
1179*5b25c76aSJerome Forissier      */
1180*5b25c76aSJerome Forissier     X_is_negative = ( X->s & 2 ) >> 1;
1181*5b25c76aSJerome Forissier     Y_is_negative = ( Y->s & 2 ) >> 1;
1182*5b25c76aSJerome Forissier 
1183*5b25c76aSJerome Forissier     /*
1184*5b25c76aSJerome Forissier      * If the signs are different, then the positive operand is the bigger.
1185*5b25c76aSJerome Forissier      * That is if X is negative (X_is_negative == 1), then X < Y is true and it
1186*5b25c76aSJerome Forissier      * is false if X is positive (X_is_negative == 0).
1187*5b25c76aSJerome Forissier      */
1188*5b25c76aSJerome Forissier     cond = ( X_is_negative ^ Y_is_negative );
1189*5b25c76aSJerome Forissier     *ret = cond & X_is_negative;
1190*5b25c76aSJerome Forissier 
1191*5b25c76aSJerome Forissier     /*
1192*5b25c76aSJerome Forissier      * This is a constant-time function. We might have the result, but we still
1193*5b25c76aSJerome Forissier      * need to go through the loop. Record if we have the result already.
1194*5b25c76aSJerome Forissier      */
1195*5b25c76aSJerome Forissier     done = cond;
1196*5b25c76aSJerome Forissier 
1197*5b25c76aSJerome Forissier     for( i = X->n; i > 0; i-- )
1198*5b25c76aSJerome Forissier     {
1199*5b25c76aSJerome Forissier         /*
1200*5b25c76aSJerome Forissier          * If Y->p[i - 1] < X->p[i - 1] then X < Y is true if and only if both
1201*5b25c76aSJerome Forissier          * X and Y are negative.
1202*5b25c76aSJerome Forissier          *
1203*5b25c76aSJerome Forissier          * Again even if we can make a decision, we just mark the result and
1204*5b25c76aSJerome Forissier          * the fact that we are done and continue looping.
1205*5b25c76aSJerome Forissier          */
1206*5b25c76aSJerome Forissier         cond = ct_lt_mpi_uint( Y->p[i - 1], X->p[i - 1] );
1207*5b25c76aSJerome Forissier         *ret |= cond & ( 1 - done ) & X_is_negative;
1208*5b25c76aSJerome Forissier         done |= cond;
1209*5b25c76aSJerome Forissier 
1210*5b25c76aSJerome Forissier         /*
1211*5b25c76aSJerome Forissier          * If X->p[i - 1] < Y->p[i - 1] then X < Y is true if and only if both
1212*5b25c76aSJerome Forissier          * X and Y are positive.
1213*5b25c76aSJerome Forissier          *
1214*5b25c76aSJerome Forissier          * Again even if we can make a decision, we just mark the result and
1215*5b25c76aSJerome Forissier          * the fact that we are done and continue looping.
1216*5b25c76aSJerome Forissier          */
1217*5b25c76aSJerome Forissier         cond = ct_lt_mpi_uint( X->p[i - 1], Y->p[i - 1] );
1218*5b25c76aSJerome Forissier         *ret |= cond & ( 1 - done ) & ( 1 - X_is_negative );
1219*5b25c76aSJerome Forissier         done |= cond;
1220*5b25c76aSJerome Forissier     }
1221*5b25c76aSJerome Forissier 
1222*5b25c76aSJerome Forissier     return( 0 );
1223*5b25c76aSJerome Forissier }
1224*5b25c76aSJerome Forissier 
1225817466cbSJens Wiklander /*
1226817466cbSJens Wiklander  * Compare signed values
1227817466cbSJens Wiklander  */
1228817466cbSJens Wiklander int mbedtls_mpi_cmp_int( const mbedtls_mpi *X, mbedtls_mpi_sint z )
1229817466cbSJens Wiklander {
1230817466cbSJens Wiklander     mbedtls_mpi Y;
1231817466cbSJens Wiklander     mbedtls_mpi_uint p[1];
12323d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
1233817466cbSJens Wiklander 
1234817466cbSJens Wiklander     *p  = ( z < 0 ) ? -z : z;
1235817466cbSJens Wiklander     Y.s = ( z < 0 ) ? -1 : 1;
1236817466cbSJens Wiklander     Y.n = 1;
1237817466cbSJens Wiklander     Y.p = p;
1238817466cbSJens Wiklander 
1239817466cbSJens Wiklander     return( mbedtls_mpi_cmp_mpi( X, &Y ) );
1240817466cbSJens Wiklander }
1241817466cbSJens Wiklander 
1242817466cbSJens Wiklander /*
1243817466cbSJens Wiklander  * Unsigned addition: X = |A| + |B|  (HAC 14.7)
1244817466cbSJens Wiklander  */
1245817466cbSJens Wiklander int mbedtls_mpi_add_abs( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B )
1246817466cbSJens Wiklander {
1247817466cbSJens Wiklander     int ret;
1248817466cbSJens Wiklander     size_t i, j;
1249817466cbSJens Wiklander     mbedtls_mpi_uint *o, *p, c, tmp;
12503d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
12513d3b0591SJens Wiklander     MPI_VALIDATE_RET( A != NULL );
12523d3b0591SJens Wiklander     MPI_VALIDATE_RET( B != NULL );
1253817466cbSJens Wiklander 
1254817466cbSJens Wiklander     if( X == B )
1255817466cbSJens Wiklander     {
1256817466cbSJens Wiklander         const mbedtls_mpi *T = A; A = X; B = T;
1257817466cbSJens Wiklander     }
1258817466cbSJens Wiklander 
1259817466cbSJens Wiklander     if( X != A )
1260817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, A ) );
1261817466cbSJens Wiklander 
1262817466cbSJens Wiklander     /*
1263817466cbSJens Wiklander      * X should always be positive as a result of unsigned additions.
1264817466cbSJens Wiklander      */
1265817466cbSJens Wiklander     X->s = 1;
1266817466cbSJens Wiklander 
1267817466cbSJens Wiklander     for( j = B->n; j > 0; j-- )
1268817466cbSJens Wiklander         if( B->p[j - 1] != 0 )
1269817466cbSJens Wiklander             break;
1270817466cbSJens Wiklander 
1271817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, j ) );
1272817466cbSJens Wiklander 
1273817466cbSJens Wiklander     o = B->p; p = X->p; c = 0;
1274817466cbSJens Wiklander 
1275817466cbSJens Wiklander     /*
1276817466cbSJens Wiklander      * tmp is used because it might happen that p == o
1277817466cbSJens Wiklander      */
1278817466cbSJens Wiklander     for( i = 0; i < j; i++, o++, p++ )
1279817466cbSJens Wiklander     {
1280817466cbSJens Wiklander         tmp= *o;
1281817466cbSJens Wiklander         *p +=  c; c  = ( *p <  c );
1282817466cbSJens Wiklander         *p += tmp; c += ( *p < tmp );
1283817466cbSJens Wiklander     }
1284817466cbSJens Wiklander 
1285817466cbSJens Wiklander     while( c != 0 )
1286817466cbSJens Wiklander     {
1287817466cbSJens Wiklander         if( i >= X->n )
1288817466cbSJens Wiklander         {
1289817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, i + 1 ) );
1290817466cbSJens Wiklander             p = X->p + i;
1291817466cbSJens Wiklander         }
1292817466cbSJens Wiklander 
1293817466cbSJens Wiklander         *p += c; c = ( *p < c ); i++; p++;
1294817466cbSJens Wiklander     }
1295817466cbSJens Wiklander 
1296817466cbSJens Wiklander cleanup:
1297817466cbSJens Wiklander 
1298817466cbSJens Wiklander     return( ret );
1299817466cbSJens Wiklander }
1300817466cbSJens Wiklander 
1301817466cbSJens Wiklander /*
1302817466cbSJens Wiklander  * Helper for mbedtls_mpi subtraction
1303817466cbSJens Wiklander  */
1304817466cbSJens Wiklander static void mpi_sub_hlp( size_t n, mbedtls_mpi_uint *s, mbedtls_mpi_uint *d )
1305817466cbSJens Wiklander {
1306817466cbSJens Wiklander     size_t i;
1307817466cbSJens Wiklander     mbedtls_mpi_uint c, z;
1308817466cbSJens Wiklander 
1309817466cbSJens Wiklander     for( i = c = 0; i < n; i++, s++, d++ )
1310817466cbSJens Wiklander     {
1311817466cbSJens Wiklander         z = ( *d <  c );     *d -=  c;
1312817466cbSJens Wiklander         c = ( *d < *s ) + z; *d -= *s;
1313817466cbSJens Wiklander     }
1314817466cbSJens Wiklander 
1315817466cbSJens Wiklander     while( c != 0 )
1316817466cbSJens Wiklander     {
1317817466cbSJens Wiklander         z = ( *d < c ); *d -= c;
13183d3b0591SJens Wiklander         c = z; d++;
1319817466cbSJens Wiklander     }
1320817466cbSJens Wiklander }
1321817466cbSJens Wiklander 
1322817466cbSJens Wiklander /*
1323817466cbSJens Wiklander  * Unsigned subtraction: X = |A| - |B|  (HAC 14.9)
1324817466cbSJens Wiklander  */
1325817466cbSJens Wiklander int mbedtls_mpi_sub_abs( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B )
1326817466cbSJens Wiklander {
1327817466cbSJens Wiklander     mbedtls_mpi TB;
1328817466cbSJens Wiklander     int ret;
1329817466cbSJens Wiklander     size_t n;
13303d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
13313d3b0591SJens Wiklander     MPI_VALIDATE_RET( A != NULL );
13323d3b0591SJens Wiklander     MPI_VALIDATE_RET( B != NULL );
1333817466cbSJens Wiklander 
1334817466cbSJens Wiklander     if( mbedtls_mpi_cmp_abs( A, B ) < 0 )
1335817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_NEGATIVE_VALUE );
1336817466cbSJens Wiklander 
133798bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &TB );
1338817466cbSJens Wiklander 
1339817466cbSJens Wiklander     if( X == B )
1340817466cbSJens Wiklander     {
1341817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, B ) );
1342817466cbSJens Wiklander         B = &TB;
1343817466cbSJens Wiklander     }
1344817466cbSJens Wiklander 
1345817466cbSJens Wiklander     if( X != A )
1346817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, A ) );
1347817466cbSJens Wiklander 
1348817466cbSJens Wiklander     /*
1349817466cbSJens Wiklander      * X should always be positive as a result of unsigned subtractions.
1350817466cbSJens Wiklander      */
1351817466cbSJens Wiklander     X->s = 1;
1352817466cbSJens Wiklander 
1353817466cbSJens Wiklander     ret = 0;
1354817466cbSJens Wiklander 
1355817466cbSJens Wiklander     for( n = B->n; n > 0; n-- )
1356817466cbSJens Wiklander         if( B->p[n - 1] != 0 )
1357817466cbSJens Wiklander             break;
1358817466cbSJens Wiklander 
1359817466cbSJens Wiklander     mpi_sub_hlp( n, B->p, X->p );
1360817466cbSJens Wiklander 
1361817466cbSJens Wiklander cleanup:
1362817466cbSJens Wiklander 
1363817466cbSJens Wiklander     mbedtls_mpi_free( &TB );
1364817466cbSJens Wiklander 
1365817466cbSJens Wiklander     return( ret );
1366817466cbSJens Wiklander }
1367817466cbSJens Wiklander 
1368817466cbSJens Wiklander /*
1369817466cbSJens Wiklander  * Signed addition: X = A + B
1370817466cbSJens Wiklander  */
1371817466cbSJens Wiklander int mbedtls_mpi_add_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B )
1372817466cbSJens Wiklander {
13733d3b0591SJens Wiklander     int ret, s;
13743d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
13753d3b0591SJens Wiklander     MPI_VALIDATE_RET( A != NULL );
13763d3b0591SJens Wiklander     MPI_VALIDATE_RET( B != NULL );
1377817466cbSJens Wiklander 
13783d3b0591SJens Wiklander     s = A->s;
1379817466cbSJens Wiklander     if( A->s * B->s < 0 )
1380817466cbSJens Wiklander     {
1381817466cbSJens Wiklander         if( mbedtls_mpi_cmp_abs( A, B ) >= 0 )
1382817466cbSJens Wiklander         {
1383817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, A, B ) );
1384817466cbSJens Wiklander             X->s =  s;
1385817466cbSJens Wiklander         }
1386817466cbSJens Wiklander         else
1387817466cbSJens Wiklander         {
1388817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, B, A ) );
1389817466cbSJens Wiklander             X->s = -s;
1390817466cbSJens Wiklander         }
1391817466cbSJens Wiklander     }
1392817466cbSJens Wiklander     else
1393817466cbSJens Wiklander     {
1394817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_add_abs( X, A, B ) );
1395817466cbSJens Wiklander         X->s = s;
1396817466cbSJens Wiklander     }
1397817466cbSJens Wiklander 
1398817466cbSJens Wiklander cleanup:
1399817466cbSJens Wiklander 
1400817466cbSJens Wiklander     return( ret );
1401817466cbSJens Wiklander }
1402817466cbSJens Wiklander 
1403817466cbSJens Wiklander /*
1404817466cbSJens Wiklander  * Signed subtraction: X = A - B
1405817466cbSJens Wiklander  */
1406817466cbSJens Wiklander int mbedtls_mpi_sub_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B )
1407817466cbSJens Wiklander {
14083d3b0591SJens Wiklander     int ret, s;
14093d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
14103d3b0591SJens Wiklander     MPI_VALIDATE_RET( A != NULL );
14113d3b0591SJens Wiklander     MPI_VALIDATE_RET( B != NULL );
1412817466cbSJens Wiklander 
14133d3b0591SJens Wiklander     s = A->s;
1414817466cbSJens Wiklander     if( A->s * B->s > 0 )
1415817466cbSJens Wiklander     {
1416817466cbSJens Wiklander         if( mbedtls_mpi_cmp_abs( A, B ) >= 0 )
1417817466cbSJens Wiklander         {
1418817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, A, B ) );
1419817466cbSJens Wiklander             X->s =  s;
1420817466cbSJens Wiklander         }
1421817466cbSJens Wiklander         else
1422817466cbSJens Wiklander         {
1423817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, B, A ) );
1424817466cbSJens Wiklander             X->s = -s;
1425817466cbSJens Wiklander         }
1426817466cbSJens Wiklander     }
1427817466cbSJens Wiklander     else
1428817466cbSJens Wiklander     {
1429817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_add_abs( X, A, B ) );
1430817466cbSJens Wiklander         X->s = s;
1431817466cbSJens Wiklander     }
1432817466cbSJens Wiklander 
1433817466cbSJens Wiklander cleanup:
1434817466cbSJens Wiklander 
1435817466cbSJens Wiklander     return( ret );
1436817466cbSJens Wiklander }
1437817466cbSJens Wiklander 
1438817466cbSJens Wiklander /*
1439817466cbSJens Wiklander  * Signed addition: X = A + b
1440817466cbSJens Wiklander  */
1441817466cbSJens Wiklander int mbedtls_mpi_add_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b )
1442817466cbSJens Wiklander {
1443817466cbSJens Wiklander     mbedtls_mpi _B;
1444817466cbSJens Wiklander     mbedtls_mpi_uint p[1];
14453d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
14463d3b0591SJens Wiklander     MPI_VALIDATE_RET( A != NULL );
1447817466cbSJens Wiklander 
1448817466cbSJens Wiklander     p[0] = ( b < 0 ) ? -b : b;
1449817466cbSJens Wiklander     _B.s = ( b < 0 ) ? -1 : 1;
1450817466cbSJens Wiklander     _B.n = 1;
1451817466cbSJens Wiklander     _B.p = p;
1452817466cbSJens Wiklander 
1453817466cbSJens Wiklander     return( mbedtls_mpi_add_mpi( X, A, &_B ) );
1454817466cbSJens Wiklander }
1455817466cbSJens Wiklander 
1456817466cbSJens Wiklander /*
1457817466cbSJens Wiklander  * Signed subtraction: X = A - b
1458817466cbSJens Wiklander  */
1459817466cbSJens Wiklander int mbedtls_mpi_sub_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b )
1460817466cbSJens Wiklander {
1461817466cbSJens Wiklander     mbedtls_mpi _B;
1462817466cbSJens Wiklander     mbedtls_mpi_uint p[1];
14633d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
14643d3b0591SJens Wiklander     MPI_VALIDATE_RET( A != NULL );
1465817466cbSJens Wiklander 
1466817466cbSJens Wiklander     p[0] = ( b < 0 ) ? -b : b;
1467817466cbSJens Wiklander     _B.s = ( b < 0 ) ? -1 : 1;
1468817466cbSJens Wiklander     _B.n = 1;
1469817466cbSJens Wiklander     _B.p = p;
1470817466cbSJens Wiklander 
1471817466cbSJens Wiklander     return( mbedtls_mpi_sub_mpi( X, A, &_B ) );
1472817466cbSJens Wiklander }
1473817466cbSJens Wiklander 
1474817466cbSJens Wiklander /*
1475817466cbSJens Wiklander  * Helper for mbedtls_mpi multiplication
1476817466cbSJens Wiklander  */
1477817466cbSJens Wiklander static
1478817466cbSJens Wiklander #if defined(__APPLE__) && defined(__arm__)
1479817466cbSJens Wiklander /*
1480817466cbSJens Wiklander  * Apple LLVM version 4.2 (clang-425.0.24) (based on LLVM 3.2svn)
1481817466cbSJens Wiklander  * appears to need this to prevent bad ARM code generation at -O3.
1482817466cbSJens Wiklander  */
1483817466cbSJens Wiklander __attribute__ ((noinline))
1484817466cbSJens Wiklander #endif
1485817466cbSJens Wiklander void mpi_mul_hlp( size_t i, mbedtls_mpi_uint *s, mbedtls_mpi_uint *d, mbedtls_mpi_uint b )
1486817466cbSJens Wiklander {
1487817466cbSJens Wiklander     mbedtls_mpi_uint c = 0, t = 0;
1488817466cbSJens Wiklander 
1489817466cbSJens Wiklander #if defined(MULADDC_HUIT)
1490817466cbSJens Wiklander     for( ; i >= 8; i -= 8 )
1491817466cbSJens Wiklander     {
1492817466cbSJens Wiklander         MULADDC_INIT
1493817466cbSJens Wiklander         MULADDC_HUIT
1494817466cbSJens Wiklander         MULADDC_STOP
1495817466cbSJens Wiklander     }
1496817466cbSJens Wiklander 
1497817466cbSJens Wiklander     for( ; i > 0; i-- )
1498817466cbSJens Wiklander     {
1499817466cbSJens Wiklander         MULADDC_INIT
1500817466cbSJens Wiklander         MULADDC_CORE
1501817466cbSJens Wiklander         MULADDC_STOP
1502817466cbSJens Wiklander     }
1503817466cbSJens Wiklander #else /* MULADDC_HUIT */
1504817466cbSJens Wiklander     for( ; i >= 16; i -= 16 )
1505817466cbSJens Wiklander     {
1506817466cbSJens Wiklander         MULADDC_INIT
1507817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1508817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1509817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1510817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1511817466cbSJens Wiklander 
1512817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1513817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1514817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1515817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1516817466cbSJens Wiklander         MULADDC_STOP
1517817466cbSJens Wiklander     }
1518817466cbSJens Wiklander 
1519817466cbSJens Wiklander     for( ; i >= 8; i -= 8 )
1520817466cbSJens Wiklander     {
1521817466cbSJens Wiklander         MULADDC_INIT
1522817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1523817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1524817466cbSJens Wiklander 
1525817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1526817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1527817466cbSJens Wiklander         MULADDC_STOP
1528817466cbSJens Wiklander     }
1529817466cbSJens Wiklander 
1530817466cbSJens Wiklander     for( ; i > 0; i-- )
1531817466cbSJens Wiklander     {
1532817466cbSJens Wiklander         MULADDC_INIT
1533817466cbSJens Wiklander         MULADDC_CORE
1534817466cbSJens Wiklander         MULADDC_STOP
1535817466cbSJens Wiklander     }
1536817466cbSJens Wiklander #endif /* MULADDC_HUIT */
1537817466cbSJens Wiklander 
1538817466cbSJens Wiklander     t++;
1539817466cbSJens Wiklander 
1540817466cbSJens Wiklander     do {
1541817466cbSJens Wiklander         *d += c; c = ( *d < c ); d++;
1542817466cbSJens Wiklander     }
1543817466cbSJens Wiklander     while( c != 0 );
1544817466cbSJens Wiklander }
1545817466cbSJens Wiklander 
1546817466cbSJens Wiklander /*
1547817466cbSJens Wiklander  * Baseline multiplication: X = A * B  (HAC 14.12)
1548817466cbSJens Wiklander  */
1549817466cbSJens Wiklander int mbedtls_mpi_mul_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B )
1550817466cbSJens Wiklander {
1551817466cbSJens Wiklander     int ret;
1552817466cbSJens Wiklander     size_t i, j;
1553817466cbSJens Wiklander     mbedtls_mpi TA, TB;
15543d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
15553d3b0591SJens Wiklander     MPI_VALIDATE_RET( A != NULL );
15563d3b0591SJens Wiklander     MPI_VALIDATE_RET( B != NULL );
1557817466cbSJens Wiklander 
155898bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &TA ); mbedtls_mpi_init_mempool( &TB );
1559817466cbSJens Wiklander 
1560817466cbSJens Wiklander     if( X == A ) { MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TA, A ) ); A = &TA; }
1561817466cbSJens Wiklander     if( X == B ) { MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, B ) ); B = &TB; }
1562817466cbSJens Wiklander 
1563817466cbSJens Wiklander     for( i = A->n; i > 0; i-- )
1564817466cbSJens Wiklander         if( A->p[i - 1] != 0 )
1565817466cbSJens Wiklander             break;
1566817466cbSJens Wiklander 
1567817466cbSJens Wiklander     for( j = B->n; j > 0; j-- )
1568817466cbSJens Wiklander         if( B->p[j - 1] != 0 )
1569817466cbSJens Wiklander             break;
1570817466cbSJens Wiklander 
1571817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, i + j ) );
1572817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) );
1573817466cbSJens Wiklander 
15743d3b0591SJens Wiklander     for( ; j > 0; j-- )
15753d3b0591SJens Wiklander         mpi_mul_hlp( i, A->p, X->p + j - 1, B->p[j - 1] );
1576817466cbSJens Wiklander 
1577817466cbSJens Wiklander     X->s = A->s * B->s;
1578817466cbSJens Wiklander 
1579817466cbSJens Wiklander cleanup:
1580817466cbSJens Wiklander 
1581817466cbSJens Wiklander     mbedtls_mpi_free( &TB ); mbedtls_mpi_free( &TA );
1582817466cbSJens Wiklander 
1583817466cbSJens Wiklander     return( ret );
1584817466cbSJens Wiklander }
1585817466cbSJens Wiklander 
1586817466cbSJens Wiklander /*
1587817466cbSJens Wiklander  * Baseline multiplication: X = A * b
1588817466cbSJens Wiklander  */
1589817466cbSJens Wiklander int mbedtls_mpi_mul_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_uint b )
1590817466cbSJens Wiklander {
1591817466cbSJens Wiklander     mbedtls_mpi _B;
1592817466cbSJens Wiklander     mbedtls_mpi_uint p[1];
15933d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
15943d3b0591SJens Wiklander     MPI_VALIDATE_RET( A != NULL );
1595817466cbSJens Wiklander 
1596817466cbSJens Wiklander     _B.s = 1;
1597817466cbSJens Wiklander     _B.n = 1;
1598817466cbSJens Wiklander     _B.p = p;
1599817466cbSJens Wiklander     p[0] = b;
1600817466cbSJens Wiklander 
1601817466cbSJens Wiklander     return( mbedtls_mpi_mul_mpi( X, A, &_B ) );
1602817466cbSJens Wiklander }
1603817466cbSJens Wiklander 
1604817466cbSJens Wiklander /*
1605817466cbSJens Wiklander  * Unsigned integer divide - double mbedtls_mpi_uint dividend, u1/u0, and
1606817466cbSJens Wiklander  * mbedtls_mpi_uint divisor, d
1607817466cbSJens Wiklander  */
1608817466cbSJens Wiklander static mbedtls_mpi_uint mbedtls_int_div_int( mbedtls_mpi_uint u1,
1609817466cbSJens Wiklander             mbedtls_mpi_uint u0, mbedtls_mpi_uint d, mbedtls_mpi_uint *r )
1610817466cbSJens Wiklander {
1611817466cbSJens Wiklander #if defined(MBEDTLS_HAVE_UDBL)
1612817466cbSJens Wiklander     mbedtls_t_udbl dividend, quotient;
1613817466cbSJens Wiklander #else
1614817466cbSJens Wiklander     const mbedtls_mpi_uint radix = (mbedtls_mpi_uint) 1 << biH;
1615817466cbSJens Wiklander     const mbedtls_mpi_uint uint_halfword_mask = ( (mbedtls_mpi_uint) 1 << biH ) - 1;
1616817466cbSJens Wiklander     mbedtls_mpi_uint d0, d1, q0, q1, rAX, r0, quotient;
1617817466cbSJens Wiklander     mbedtls_mpi_uint u0_msw, u0_lsw;
1618817466cbSJens Wiklander     size_t s;
1619817466cbSJens Wiklander #endif
1620817466cbSJens Wiklander 
1621817466cbSJens Wiklander     /*
1622817466cbSJens Wiklander      * Check for overflow
1623817466cbSJens Wiklander      */
1624817466cbSJens Wiklander     if( 0 == d || u1 >= d )
1625817466cbSJens Wiklander     {
1626817466cbSJens Wiklander         if (r != NULL) *r = ~0;
1627817466cbSJens Wiklander 
1628817466cbSJens Wiklander         return ( ~0 );
1629817466cbSJens Wiklander     }
1630817466cbSJens Wiklander 
1631817466cbSJens Wiklander #if defined(MBEDTLS_HAVE_UDBL)
1632817466cbSJens Wiklander     dividend  = (mbedtls_t_udbl) u1 << biL;
1633817466cbSJens Wiklander     dividend |= (mbedtls_t_udbl) u0;
1634817466cbSJens Wiklander     quotient = dividend / d;
1635817466cbSJens Wiklander     if( quotient > ( (mbedtls_t_udbl) 1 << biL ) - 1 )
1636817466cbSJens Wiklander         quotient = ( (mbedtls_t_udbl) 1 << biL ) - 1;
1637817466cbSJens Wiklander 
1638817466cbSJens Wiklander     if( r != NULL )
1639817466cbSJens Wiklander         *r = (mbedtls_mpi_uint)( dividend - (quotient * d ) );
1640817466cbSJens Wiklander 
1641817466cbSJens Wiklander     return (mbedtls_mpi_uint) quotient;
1642817466cbSJens Wiklander #else
1643817466cbSJens Wiklander 
1644817466cbSJens Wiklander     /*
1645817466cbSJens Wiklander      * Algorithm D, Section 4.3.1 - The Art of Computer Programming
1646817466cbSJens Wiklander      *   Vol. 2 - Seminumerical Algorithms, Knuth
1647817466cbSJens Wiklander      */
1648817466cbSJens Wiklander 
1649817466cbSJens Wiklander     /*
1650817466cbSJens Wiklander      * Normalize the divisor, d, and dividend, u0, u1
1651817466cbSJens Wiklander      */
1652817466cbSJens Wiklander     s = mbedtls_clz( d );
1653817466cbSJens Wiklander     d = d << s;
1654817466cbSJens Wiklander 
1655817466cbSJens Wiklander     u1 = u1 << s;
1656817466cbSJens Wiklander     u1 |= ( u0 >> ( biL - s ) ) & ( -(mbedtls_mpi_sint)s >> ( biL - 1 ) );
1657817466cbSJens Wiklander     u0 =  u0 << s;
1658817466cbSJens Wiklander 
1659817466cbSJens Wiklander     d1 = d >> biH;
1660817466cbSJens Wiklander     d0 = d & uint_halfword_mask;
1661817466cbSJens Wiklander 
1662817466cbSJens Wiklander     u0_msw = u0 >> biH;
1663817466cbSJens Wiklander     u0_lsw = u0 & uint_halfword_mask;
1664817466cbSJens Wiklander 
1665817466cbSJens Wiklander     /*
1666817466cbSJens Wiklander      * Find the first quotient and remainder
1667817466cbSJens Wiklander      */
1668817466cbSJens Wiklander     q1 = u1 / d1;
1669817466cbSJens Wiklander     r0 = u1 - d1 * q1;
1670817466cbSJens Wiklander 
1671817466cbSJens Wiklander     while( q1 >= radix || ( q1 * d0 > radix * r0 + u0_msw ) )
1672817466cbSJens Wiklander     {
1673817466cbSJens Wiklander         q1 -= 1;
1674817466cbSJens Wiklander         r0 += d1;
1675817466cbSJens Wiklander 
1676817466cbSJens Wiklander         if ( r0 >= radix ) break;
1677817466cbSJens Wiklander     }
1678817466cbSJens Wiklander 
1679817466cbSJens Wiklander     rAX = ( u1 * radix ) + ( u0_msw - q1 * d );
1680817466cbSJens Wiklander     q0 = rAX / d1;
1681817466cbSJens Wiklander     r0 = rAX - q0 * d1;
1682817466cbSJens Wiklander 
1683817466cbSJens Wiklander     while( q0 >= radix || ( q0 * d0 > radix * r0 + u0_lsw ) )
1684817466cbSJens Wiklander     {
1685817466cbSJens Wiklander         q0 -= 1;
1686817466cbSJens Wiklander         r0 += d1;
1687817466cbSJens Wiklander 
1688817466cbSJens Wiklander         if ( r0 >= radix ) break;
1689817466cbSJens Wiklander     }
1690817466cbSJens Wiklander 
1691817466cbSJens Wiklander     if (r != NULL)
1692817466cbSJens Wiklander         *r = ( rAX * radix + u0_lsw - q0 * d ) >> s;
1693817466cbSJens Wiklander 
1694817466cbSJens Wiklander     quotient = q1 * radix + q0;
1695817466cbSJens Wiklander 
1696817466cbSJens Wiklander     return quotient;
1697817466cbSJens Wiklander #endif
1698817466cbSJens Wiklander }
1699817466cbSJens Wiklander 
1700817466cbSJens Wiklander /*
1701817466cbSJens Wiklander  * Division by mbedtls_mpi: A = Q * B + R  (HAC 14.20)
1702817466cbSJens Wiklander  */
17033d3b0591SJens Wiklander int mbedtls_mpi_div_mpi( mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A,
17043d3b0591SJens Wiklander                          const mbedtls_mpi *B )
1705817466cbSJens Wiklander {
1706817466cbSJens Wiklander     int ret;
1707817466cbSJens Wiklander     size_t i, n, t, k;
1708817466cbSJens Wiklander     mbedtls_mpi X, Y, Z, T1, T2;
17093d3b0591SJens Wiklander     MPI_VALIDATE_RET( A != NULL );
17103d3b0591SJens Wiklander     MPI_VALIDATE_RET( B != NULL );
1711817466cbSJens Wiklander 
1712817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( B, 0 ) == 0 )
1713817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_DIVISION_BY_ZERO );
1714817466cbSJens Wiklander 
171598bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &X ); mbedtls_mpi_init_mempool( &Y );
171698bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &Z ); mbedtls_mpi_init_mempool( &T1 );
171798bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &T2 );
1718817466cbSJens Wiklander 
1719817466cbSJens Wiklander     if( mbedtls_mpi_cmp_abs( A, B ) < 0 )
1720817466cbSJens Wiklander     {
1721817466cbSJens Wiklander         if( Q != NULL ) MBEDTLS_MPI_CHK( mbedtls_mpi_lset( Q, 0 ) );
1722817466cbSJens Wiklander         if( R != NULL ) MBEDTLS_MPI_CHK( mbedtls_mpi_copy( R, A ) );
1723817466cbSJens Wiklander         return( 0 );
1724817466cbSJens Wiklander     }
1725817466cbSJens Wiklander 
1726817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &X, A ) );
1727817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &Y, B ) );
1728817466cbSJens Wiklander     X.s = Y.s = 1;
1729817466cbSJens Wiklander 
1730817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &Z, A->n + 2 ) );
1731817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &Z,  0 ) );
1732817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &T1, 2 ) );
1733817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &T2, 3 ) );
1734817466cbSJens Wiklander 
1735817466cbSJens Wiklander     k = mbedtls_mpi_bitlen( &Y ) % biL;
1736817466cbSJens Wiklander     if( k < biL - 1 )
1737817466cbSJens Wiklander     {
1738817466cbSJens Wiklander         k = biL - 1 - k;
1739817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &X, k ) );
1740817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &Y, k ) );
1741817466cbSJens Wiklander     }
1742817466cbSJens Wiklander     else k = 0;
1743817466cbSJens Wiklander 
1744817466cbSJens Wiklander     n = X.n - 1;
1745817466cbSJens Wiklander     t = Y.n - 1;
1746817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &Y, biL * ( n - t ) ) );
1747817466cbSJens Wiklander 
1748817466cbSJens Wiklander     while( mbedtls_mpi_cmp_mpi( &X, &Y ) >= 0 )
1749817466cbSJens Wiklander     {
1750817466cbSJens Wiklander         Z.p[n - t]++;
1751817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &X, &X, &Y ) );
1752817466cbSJens Wiklander     }
1753817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &Y, biL * ( n - t ) ) );
1754817466cbSJens Wiklander 
1755817466cbSJens Wiklander     for( i = n; i > t ; i-- )
1756817466cbSJens Wiklander     {
1757817466cbSJens Wiklander         if( X.p[i] >= Y.p[t] )
1758817466cbSJens Wiklander             Z.p[i - t - 1] = ~0;
1759817466cbSJens Wiklander         else
1760817466cbSJens Wiklander         {
1761817466cbSJens Wiklander             Z.p[i - t - 1] = mbedtls_int_div_int( X.p[i], X.p[i - 1],
1762817466cbSJens Wiklander                                                             Y.p[t], NULL);
1763817466cbSJens Wiklander         }
1764817466cbSJens Wiklander 
1765817466cbSJens Wiklander         Z.p[i - t - 1]++;
1766817466cbSJens Wiklander         do
1767817466cbSJens Wiklander         {
1768817466cbSJens Wiklander             Z.p[i - t - 1]--;
1769817466cbSJens Wiklander 
1770817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &T1, 0 ) );
1771817466cbSJens Wiklander             T1.p[0] = ( t < 1 ) ? 0 : Y.p[t - 1];
1772817466cbSJens Wiklander             T1.p[1] = Y.p[t];
1773817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &T1, &T1, Z.p[i - t - 1] ) );
1774817466cbSJens Wiklander 
1775817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &T2, 0 ) );
1776817466cbSJens Wiklander             T2.p[0] = ( i < 2 ) ? 0 : X.p[i - 2];
1777817466cbSJens Wiklander             T2.p[1] = ( i < 1 ) ? 0 : X.p[i - 1];
1778817466cbSJens Wiklander             T2.p[2] = X.p[i];
1779817466cbSJens Wiklander         }
1780817466cbSJens Wiklander         while( mbedtls_mpi_cmp_mpi( &T1, &T2 ) > 0 );
1781817466cbSJens Wiklander 
1782817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &T1, &Y, Z.p[i - t - 1] ) );
1783817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &T1,  biL * ( i - t - 1 ) ) );
1784817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &X, &X, &T1 ) );
1785817466cbSJens Wiklander 
1786817466cbSJens Wiklander         if( mbedtls_mpi_cmp_int( &X, 0 ) < 0 )
1787817466cbSJens Wiklander         {
1788817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &T1, &Y ) );
1789817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &T1, biL * ( i - t - 1 ) ) );
1790817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &X, &X, &T1 ) );
1791817466cbSJens Wiklander             Z.p[i - t - 1]--;
1792817466cbSJens Wiklander         }
1793817466cbSJens Wiklander     }
1794817466cbSJens Wiklander 
1795817466cbSJens Wiklander     if( Q != NULL )
1796817466cbSJens Wiklander     {
1797817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( Q, &Z ) );
1798817466cbSJens Wiklander         Q->s = A->s * B->s;
1799817466cbSJens Wiklander     }
1800817466cbSJens Wiklander 
1801817466cbSJens Wiklander     if( R != NULL )
1802817466cbSJens Wiklander     {
1803817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &X, k ) );
1804817466cbSJens Wiklander         X.s = A->s;
1805817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( R, &X ) );
1806817466cbSJens Wiklander 
1807817466cbSJens Wiklander         if( mbedtls_mpi_cmp_int( R, 0 ) == 0 )
1808817466cbSJens Wiklander             R->s = 1;
1809817466cbSJens Wiklander     }
1810817466cbSJens Wiklander 
1811817466cbSJens Wiklander cleanup:
1812817466cbSJens Wiklander 
1813817466cbSJens Wiklander     mbedtls_mpi_free( &X ); mbedtls_mpi_free( &Y ); mbedtls_mpi_free( &Z );
1814817466cbSJens Wiklander     mbedtls_mpi_free( &T1 ); mbedtls_mpi_free( &T2 );
1815817466cbSJens Wiklander 
1816817466cbSJens Wiklander     return( ret );
1817817466cbSJens Wiklander }
1818817466cbSJens Wiklander 
1819817466cbSJens Wiklander /*
1820817466cbSJens Wiklander  * Division by int: A = Q * b + R
1821817466cbSJens Wiklander  */
18223d3b0591SJens Wiklander int mbedtls_mpi_div_int( mbedtls_mpi *Q, mbedtls_mpi *R,
18233d3b0591SJens Wiklander                          const mbedtls_mpi *A,
18243d3b0591SJens Wiklander                          mbedtls_mpi_sint b )
1825817466cbSJens Wiklander {
1826817466cbSJens Wiklander     mbedtls_mpi _B;
1827817466cbSJens Wiklander     mbedtls_mpi_uint p[1];
18283d3b0591SJens Wiklander     MPI_VALIDATE_RET( A != NULL );
1829817466cbSJens Wiklander 
1830817466cbSJens Wiklander     p[0] = ( b < 0 ) ? -b : b;
1831817466cbSJens Wiklander     _B.s = ( b < 0 ) ? -1 : 1;
1832817466cbSJens Wiklander     _B.n = 1;
1833817466cbSJens Wiklander     _B.p = p;
1834817466cbSJens Wiklander 
1835817466cbSJens Wiklander     return( mbedtls_mpi_div_mpi( Q, R, A, &_B ) );
1836817466cbSJens Wiklander }
1837817466cbSJens Wiklander 
1838817466cbSJens Wiklander /*
1839817466cbSJens Wiklander  * Modulo: R = A mod B
1840817466cbSJens Wiklander  */
1841817466cbSJens Wiklander int mbedtls_mpi_mod_mpi( mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B )
1842817466cbSJens Wiklander {
1843817466cbSJens Wiklander     int ret;
18443d3b0591SJens Wiklander     MPI_VALIDATE_RET( R != NULL );
18453d3b0591SJens Wiklander     MPI_VALIDATE_RET( A != NULL );
18463d3b0591SJens Wiklander     MPI_VALIDATE_RET( B != NULL );
1847817466cbSJens Wiklander 
1848817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( B, 0 ) < 0 )
1849817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_NEGATIVE_VALUE );
1850817466cbSJens Wiklander 
1851817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_div_mpi( NULL, R, A, B ) );
1852817466cbSJens Wiklander 
1853817466cbSJens Wiklander     while( mbedtls_mpi_cmp_int( R, 0 ) < 0 )
1854817466cbSJens Wiklander       MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( R, R, B ) );
1855817466cbSJens Wiklander 
1856817466cbSJens Wiklander     while( mbedtls_mpi_cmp_mpi( R, B ) >= 0 )
1857817466cbSJens Wiklander       MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( R, R, B ) );
1858817466cbSJens Wiklander 
1859817466cbSJens Wiklander cleanup:
1860817466cbSJens Wiklander 
1861817466cbSJens Wiklander     return( ret );
1862817466cbSJens Wiklander }
1863817466cbSJens Wiklander 
1864817466cbSJens Wiklander /*
1865817466cbSJens Wiklander  * Modulo: r = A mod b
1866817466cbSJens Wiklander  */
1867817466cbSJens Wiklander int mbedtls_mpi_mod_int( mbedtls_mpi_uint *r, const mbedtls_mpi *A, mbedtls_mpi_sint b )
1868817466cbSJens Wiklander {
1869817466cbSJens Wiklander     size_t i;
1870817466cbSJens Wiklander     mbedtls_mpi_uint x, y, z;
18713d3b0591SJens Wiklander     MPI_VALIDATE_RET( r != NULL );
18723d3b0591SJens Wiklander     MPI_VALIDATE_RET( A != NULL );
1873817466cbSJens Wiklander 
1874817466cbSJens Wiklander     if( b == 0 )
1875817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_DIVISION_BY_ZERO );
1876817466cbSJens Wiklander 
1877817466cbSJens Wiklander     if( b < 0 )
1878817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_NEGATIVE_VALUE );
1879817466cbSJens Wiklander 
1880817466cbSJens Wiklander     /*
1881817466cbSJens Wiklander      * handle trivial cases
1882817466cbSJens Wiklander      */
1883817466cbSJens Wiklander     if( b == 1 )
1884817466cbSJens Wiklander     {
1885817466cbSJens Wiklander         *r = 0;
1886817466cbSJens Wiklander         return( 0 );
1887817466cbSJens Wiklander     }
1888817466cbSJens Wiklander 
1889817466cbSJens Wiklander     if( b == 2 )
1890817466cbSJens Wiklander     {
1891817466cbSJens Wiklander         *r = A->p[0] & 1;
1892817466cbSJens Wiklander         return( 0 );
1893817466cbSJens Wiklander     }
1894817466cbSJens Wiklander 
1895817466cbSJens Wiklander     /*
1896817466cbSJens Wiklander      * general case
1897817466cbSJens Wiklander      */
1898817466cbSJens Wiklander     for( i = A->n, y = 0; i > 0; i-- )
1899817466cbSJens Wiklander     {
1900817466cbSJens Wiklander         x  = A->p[i - 1];
1901817466cbSJens Wiklander         y  = ( y << biH ) | ( x >> biH );
1902817466cbSJens Wiklander         z  = y / b;
1903817466cbSJens Wiklander         y -= z * b;
1904817466cbSJens Wiklander 
1905817466cbSJens Wiklander         x <<= biH;
1906817466cbSJens Wiklander         y  = ( y << biH ) | ( x >> biH );
1907817466cbSJens Wiklander         z  = y / b;
1908817466cbSJens Wiklander         y -= z * b;
1909817466cbSJens Wiklander     }
1910817466cbSJens Wiklander 
1911817466cbSJens Wiklander     /*
1912817466cbSJens Wiklander      * If A is negative, then the current y represents a negative value.
1913817466cbSJens Wiklander      * Flipping it to the positive side.
1914817466cbSJens Wiklander      */
1915817466cbSJens Wiklander     if( A->s < 0 && y != 0 )
1916817466cbSJens Wiklander         y = b - y;
1917817466cbSJens Wiklander 
1918817466cbSJens Wiklander     *r = y;
1919817466cbSJens Wiklander 
1920817466cbSJens Wiklander     return( 0 );
1921817466cbSJens Wiklander }
1922817466cbSJens Wiklander 
1923817466cbSJens Wiklander /*
1924817466cbSJens Wiklander  * Fast Montgomery initialization (thanks to Tom St Denis)
1925817466cbSJens Wiklander  */
192662f21181SJens Wiklander void mbedtls_mpi_montg_init( mbedtls_mpi_uint *mm, const mbedtls_mpi *N )
1927817466cbSJens Wiklander {
1928817466cbSJens Wiklander     mbedtls_mpi_uint x, m0 = N->p[0];
1929817466cbSJens Wiklander     unsigned int i;
1930817466cbSJens Wiklander 
1931817466cbSJens Wiklander     x  = m0;
1932817466cbSJens Wiklander     x += ( ( m0 + 2 ) & 4 ) << 1;
1933817466cbSJens Wiklander 
1934817466cbSJens Wiklander     for( i = biL; i >= 8; i /= 2 )
1935817466cbSJens Wiklander         x *= ( 2 - ( m0 * x ) );
1936817466cbSJens Wiklander 
1937817466cbSJens Wiklander     *mm = ~x + 1;
1938817466cbSJens Wiklander }
1939817466cbSJens Wiklander 
1940817466cbSJens Wiklander /*
1941817466cbSJens Wiklander  * Montgomery multiplication: A = A * B * R^-1 mod N  (HAC 14.36)
1942817466cbSJens Wiklander  */
194362f21181SJens Wiklander int mbedtls_mpi_montmul( mbedtls_mpi *A, const mbedtls_mpi *B,
194462f21181SJens Wiklander 			 const mbedtls_mpi *N, mbedtls_mpi_uint mm,
1945817466cbSJens Wiklander                          const mbedtls_mpi *T )
1946817466cbSJens Wiklander {
1947817466cbSJens Wiklander     size_t i, n, m;
1948817466cbSJens Wiklander     mbedtls_mpi_uint u0, u1, *d;
1949817466cbSJens Wiklander 
1950817466cbSJens Wiklander     if( T->n < N->n + 1 || T->p == NULL )
1951817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
1952817466cbSJens Wiklander 
1953817466cbSJens Wiklander     memset( T->p, 0, T->n * ciL );
1954817466cbSJens Wiklander 
1955817466cbSJens Wiklander     d = T->p;
1956817466cbSJens Wiklander     n = N->n;
1957817466cbSJens Wiklander     m = ( B->n < n ) ? B->n : n;
1958817466cbSJens Wiklander 
1959817466cbSJens Wiklander     for( i = 0; i < n; i++ )
1960817466cbSJens Wiklander     {
1961817466cbSJens Wiklander         /*
1962817466cbSJens Wiklander          * T = (T + u0*B + u1*N) / 2^biL
1963817466cbSJens Wiklander          */
1964817466cbSJens Wiklander         u0 = A->p[i];
1965817466cbSJens Wiklander         u1 = ( d[0] + u0 * B->p[0] ) * mm;
1966817466cbSJens Wiklander 
1967817466cbSJens Wiklander         mpi_mul_hlp( m, B->p, d, u0 );
1968817466cbSJens Wiklander         mpi_mul_hlp( n, N->p, d, u1 );
1969817466cbSJens Wiklander 
1970817466cbSJens Wiklander         *d++ = u0; d[n + 1] = 0;
1971817466cbSJens Wiklander     }
1972817466cbSJens Wiklander 
1973817466cbSJens Wiklander     memcpy( A->p, d, ( n + 1 ) * ciL );
1974817466cbSJens Wiklander 
1975817466cbSJens Wiklander     if( mbedtls_mpi_cmp_abs( A, N ) >= 0 )
1976817466cbSJens Wiklander         mpi_sub_hlp( n, N->p, A->p );
1977817466cbSJens Wiklander     else
1978817466cbSJens Wiklander         /* prevent timing attacks */
1979817466cbSJens Wiklander         mpi_sub_hlp( n, A->p, T->p );
1980817466cbSJens Wiklander 
1981817466cbSJens Wiklander     return( 0 );
1982817466cbSJens Wiklander }
1983817466cbSJens Wiklander 
1984817466cbSJens Wiklander /*
1985817466cbSJens Wiklander  * Montgomery reduction: A = A * R^-1 mod N
1986817466cbSJens Wiklander  */
198762f21181SJens Wiklander int mbedtls_mpi_montred( mbedtls_mpi *A, const mbedtls_mpi *N,
198862f21181SJens Wiklander 			 mbedtls_mpi_uint mm, const mbedtls_mpi *T )
1989817466cbSJens Wiklander {
1990817466cbSJens Wiklander     mbedtls_mpi_uint z = 1;
1991817466cbSJens Wiklander     mbedtls_mpi U;
1992817466cbSJens Wiklander 
1993817466cbSJens Wiklander     U.n = U.s = (int) z;
1994817466cbSJens Wiklander     U.p = &z;
1995817466cbSJens Wiklander 
199662f21181SJens Wiklander     return( mbedtls_mpi_montmul( A, &U, N, mm, T ) );
1997817466cbSJens Wiklander }
1998817466cbSJens Wiklander 
1999817466cbSJens Wiklander /*
2000817466cbSJens Wiklander  * Sliding-window exponentiation: X = A^E mod N  (HAC 14.85)
2001817466cbSJens Wiklander  */
20023d3b0591SJens Wiklander int mbedtls_mpi_exp_mod( mbedtls_mpi *X, const mbedtls_mpi *A,
20033d3b0591SJens Wiklander                          const mbedtls_mpi *E, const mbedtls_mpi *N,
20043d3b0591SJens Wiklander                          mbedtls_mpi *_RR )
2005817466cbSJens Wiklander {
2006817466cbSJens Wiklander     int ret;
2007817466cbSJens Wiklander     size_t wbits, wsize, one = 1;
2008817466cbSJens Wiklander     size_t i, j, nblimbs;
2009817466cbSJens Wiklander     size_t bufsize, nbits;
2010817466cbSJens Wiklander     mbedtls_mpi_uint ei, mm, state;
201141e5aa8fSJens Wiklander     mbedtls_mpi RR, T, Apos;
2012ad443200SJens Wiklander     mbedtls_mpi *W = NULL;
201341e5aa8fSJens Wiklander     const size_t array_size_W = 2 << MBEDTLS_MPI_WINDOW_SIZE;
2014817466cbSJens Wiklander     int neg;
2015817466cbSJens Wiklander 
20163d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
20173d3b0591SJens Wiklander     MPI_VALIDATE_RET( A != NULL );
20183d3b0591SJens Wiklander     MPI_VALIDATE_RET( E != NULL );
20193d3b0591SJens Wiklander     MPI_VALIDATE_RET( N != NULL );
20203d3b0591SJens Wiklander 
20213d3b0591SJens Wiklander     if( mbedtls_mpi_cmp_int( N, 0 ) <= 0 || ( N->p[0] & 1 ) == 0 )
2022817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
2023817466cbSJens Wiklander 
2024817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( E, 0 ) < 0 )
2025817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
2026817466cbSJens Wiklander 
2027817466cbSJens Wiklander     /*
2028817466cbSJens Wiklander      * Init temps and window size
2029817466cbSJens Wiklander      */
203062f21181SJens Wiklander     mbedtls_mpi_montg_init( &mm, N );
203198bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &RR ); mbedtls_mpi_init_mempool( &T );
203298bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &Apos );
2033817466cbSJens Wiklander 
2034817466cbSJens Wiklander     i = mbedtls_mpi_bitlen( E );
2035817466cbSJens Wiklander 
2036817466cbSJens Wiklander     wsize = ( i > 671 ) ? 6 : ( i > 239 ) ? 5 :
2037817466cbSJens Wiklander             ( i >  79 ) ? 4 : ( i >  23 ) ? 3 : 1;
2038817466cbSJens Wiklander 
2039*5b25c76aSJerome Forissier #if( MBEDTLS_MPI_WINDOW_SIZE < 6 )
2040817466cbSJens Wiklander     if( wsize > MBEDTLS_MPI_WINDOW_SIZE )
2041817466cbSJens Wiklander         wsize = MBEDTLS_MPI_WINDOW_SIZE;
2042*5b25c76aSJerome Forissier #endif
2043817466cbSJens Wiklander 
2044817466cbSJens Wiklander     j = N->n + 1;
2045817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, j ) );
2046ad443200SJens Wiklander 
2047817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &T, j * 2 ) );
2048817466cbSJens Wiklander 
2049817466cbSJens Wiklander     /*
2050817466cbSJens Wiklander      * Compensate for negative A (and correct at the end)
2051817466cbSJens Wiklander      */
2052817466cbSJens Wiklander     neg = ( A->s == -1 );
2053817466cbSJens Wiklander     if( neg )
2054817466cbSJens Wiklander     {
2055817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &Apos, A ) );
2056817466cbSJens Wiklander         Apos.s = 1;
2057817466cbSJens Wiklander         A = &Apos;
2058817466cbSJens Wiklander     }
2059817466cbSJens Wiklander 
2060817466cbSJens Wiklander     /*
2061817466cbSJens Wiklander      * If 1st call, pre-compute R^2 mod N
2062817466cbSJens Wiklander      */
2063817466cbSJens Wiklander     if( _RR == NULL || _RR->p == NULL )
2064817466cbSJens Wiklander     {
2065817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &RR, 1 ) );
2066817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &RR, N->n * 2 * biL ) );
2067817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &RR, &RR, N ) );
2068817466cbSJens Wiklander 
2069817466cbSJens Wiklander         if( _RR != NULL )
2070817466cbSJens Wiklander             memcpy( _RR, &RR, sizeof( mbedtls_mpi ) );
2071817466cbSJens Wiklander     }
2072817466cbSJens Wiklander     else
2073817466cbSJens Wiklander         memcpy( &RR, _RR, sizeof( mbedtls_mpi ) );
2074817466cbSJens Wiklander 
2075ad443200SJens Wiklander     W = mempool_alloc( mbedtls_mpi_mempool,
2076ad443200SJens Wiklander                        sizeof( mbedtls_mpi ) * array_size_W );
2077ad443200SJens Wiklander     if( W == NULL ) {
2078ad443200SJens Wiklander         ret = MBEDTLS_ERR_MPI_ALLOC_FAILED;
2079ad443200SJens Wiklander         goto cleanup;
2080ad443200SJens Wiklander     }
2081ad443200SJens Wiklander     for( i = 0; i < array_size_W; i++ )
2082ad443200SJens Wiklander         mbedtls_mpi_init_mempool( W + i );
2083ad443200SJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[1],  j ) );
2084ad443200SJens Wiklander 
2085817466cbSJens Wiklander     /*
2086817466cbSJens Wiklander      * W[1] = A * R^2 * R^-1 mod N = A * R mod N
2087817466cbSJens Wiklander      */
2088817466cbSJens Wiklander     if( mbedtls_mpi_cmp_mpi( A, N ) >= 0 )
2089817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &W[1], A, N ) );
2090817466cbSJens Wiklander     else
2091817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &W[1], A ) );
2092817466cbSJens Wiklander 
209362f21181SJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_montmul( &W[1], &RR, N, mm, &T ) );
2094817466cbSJens Wiklander 
2095817466cbSJens Wiklander     /*
2096817466cbSJens Wiklander      * X = R^2 * R^-1 mod N = R mod N
2097817466cbSJens Wiklander      */
2098817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, &RR ) );
209962f21181SJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_montred( X, N, mm, &T ) );
2100817466cbSJens Wiklander 
2101817466cbSJens Wiklander     if( wsize > 1 )
2102817466cbSJens Wiklander     {
2103817466cbSJens Wiklander         /*
2104817466cbSJens Wiklander          * W[1 << (wsize - 1)] = W[1] ^ (wsize - 1)
2105817466cbSJens Wiklander          */
2106817466cbSJens Wiklander         j =  one << ( wsize - 1 );
2107817466cbSJens Wiklander 
2108817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[j], N->n + 1 ) );
2109817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &W[j], &W[1]    ) );
2110817466cbSJens Wiklander 
2111817466cbSJens Wiklander         for( i = 0; i < wsize - 1; i++ )
211262f21181SJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_montmul( &W[j], &W[j], N, mm, &T ) );
2113817466cbSJens Wiklander 
2114817466cbSJens Wiklander         /*
2115817466cbSJens Wiklander          * W[i] = W[i - 1] * W[1]
2116817466cbSJens Wiklander          */
2117817466cbSJens Wiklander         for( i = j + 1; i < ( one << wsize ); i++ )
2118817466cbSJens Wiklander         {
2119817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[i], N->n + 1 ) );
2120817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &W[i], &W[i - 1] ) );
2121817466cbSJens Wiklander 
212262f21181SJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_montmul( &W[i], &W[1], N, mm, &T ) );
2123817466cbSJens Wiklander         }
2124817466cbSJens Wiklander     }
2125817466cbSJens Wiklander 
2126817466cbSJens Wiklander     nblimbs = E->n;
2127817466cbSJens Wiklander     bufsize = 0;
2128817466cbSJens Wiklander     nbits   = 0;
2129817466cbSJens Wiklander     wbits   = 0;
2130817466cbSJens Wiklander     state   = 0;
2131817466cbSJens Wiklander 
2132817466cbSJens Wiklander     while( 1 )
2133817466cbSJens Wiklander     {
2134817466cbSJens Wiklander         if( bufsize == 0 )
2135817466cbSJens Wiklander         {
2136817466cbSJens Wiklander             if( nblimbs == 0 )
2137817466cbSJens Wiklander                 break;
2138817466cbSJens Wiklander 
2139817466cbSJens Wiklander             nblimbs--;
2140817466cbSJens Wiklander 
2141817466cbSJens Wiklander             bufsize = sizeof( mbedtls_mpi_uint ) << 3;
2142817466cbSJens Wiklander         }
2143817466cbSJens Wiklander 
2144817466cbSJens Wiklander         bufsize--;
2145817466cbSJens Wiklander 
2146817466cbSJens Wiklander         ei = (E->p[nblimbs] >> bufsize) & 1;
2147817466cbSJens Wiklander 
2148817466cbSJens Wiklander         /*
2149817466cbSJens Wiklander          * skip leading 0s
2150817466cbSJens Wiklander          */
2151817466cbSJens Wiklander         if( ei == 0 && state == 0 )
2152817466cbSJens Wiklander             continue;
2153817466cbSJens Wiklander 
2154817466cbSJens Wiklander         if( ei == 0 && state == 1 )
2155817466cbSJens Wiklander         {
2156817466cbSJens Wiklander             /*
2157817466cbSJens Wiklander              * out of window, square X
2158817466cbSJens Wiklander              */
215962f21181SJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_montmul( X, X, N, mm, &T ) );
2160817466cbSJens Wiklander             continue;
2161817466cbSJens Wiklander         }
2162817466cbSJens Wiklander 
2163817466cbSJens Wiklander         /*
2164817466cbSJens Wiklander          * add ei to current window
2165817466cbSJens Wiklander          */
2166817466cbSJens Wiklander         state = 2;
2167817466cbSJens Wiklander 
2168817466cbSJens Wiklander         nbits++;
2169817466cbSJens Wiklander         wbits |= ( ei << ( wsize - nbits ) );
2170817466cbSJens Wiklander 
2171817466cbSJens Wiklander         if( nbits == wsize )
2172817466cbSJens Wiklander         {
2173817466cbSJens Wiklander             /*
2174817466cbSJens Wiklander              * X = X^wsize R^-1 mod N
2175817466cbSJens Wiklander              */
2176817466cbSJens Wiklander             for( i = 0; i < wsize; i++ )
217762f21181SJens Wiklander                 MBEDTLS_MPI_CHK( mbedtls_mpi_montmul( X, X, N, mm, &T ) );
2178817466cbSJens Wiklander 
2179817466cbSJens Wiklander             /*
2180817466cbSJens Wiklander              * X = X * W[wbits] R^-1 mod N
2181817466cbSJens Wiklander              */
218262f21181SJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_montmul( X, &W[wbits], N, mm, &T ) );
2183817466cbSJens Wiklander 
2184817466cbSJens Wiklander             state--;
2185817466cbSJens Wiklander             nbits = 0;
2186817466cbSJens Wiklander             wbits = 0;
2187817466cbSJens Wiklander         }
2188817466cbSJens Wiklander     }
2189817466cbSJens Wiklander 
2190817466cbSJens Wiklander     /*
2191817466cbSJens Wiklander      * process the remaining bits
2192817466cbSJens Wiklander      */
2193817466cbSJens Wiklander     for( i = 0; i < nbits; i++ )
2194817466cbSJens Wiklander     {
219562f21181SJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_montmul( X, X, N, mm, &T ) );
2196817466cbSJens Wiklander 
2197817466cbSJens Wiklander         wbits <<= 1;
2198817466cbSJens Wiklander 
2199817466cbSJens Wiklander         if( ( wbits & ( one << wsize ) ) != 0 )
220062f21181SJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_montmul( X, &W[1], N, mm, &T ) );
2201817466cbSJens Wiklander     }
2202817466cbSJens Wiklander 
2203817466cbSJens Wiklander     /*
2204817466cbSJens Wiklander      * X = A^E * R * R^-1 mod N = A^E mod N
2205817466cbSJens Wiklander      */
220662f21181SJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_montred( X, N, mm, &T ) );
2207817466cbSJens Wiklander 
2208817466cbSJens Wiklander     if( neg && E->n != 0 && ( E->p[0] & 1 ) != 0 )
2209817466cbSJens Wiklander     {
2210817466cbSJens Wiklander         X->s = -1;
2211817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( X, N, X ) );
2212817466cbSJens Wiklander     }
2213817466cbSJens Wiklander 
2214817466cbSJens Wiklander cleanup:
2215817466cbSJens Wiklander 
2216ad443200SJens Wiklander     if( W )
221741e5aa8fSJens Wiklander         for( i = 0; i < array_size_W; i++ )
2218b99a4a18SJens Wiklander             mbedtls_mpi_free( W + i );
221941e5aa8fSJens Wiklander     mempool_free( mbedtls_mpi_mempool , W );
2220817466cbSJens Wiklander 
2221b99a4a18SJens Wiklander     mbedtls_mpi_free( &T ); mbedtls_mpi_free( &Apos );
2222817466cbSJens Wiklander 
2223817466cbSJens Wiklander     if( _RR == NULL || _RR->p == NULL )
2224817466cbSJens Wiklander         mbedtls_mpi_free( &RR );
2225817466cbSJens Wiklander 
2226817466cbSJens Wiklander     return( ret );
2227817466cbSJens Wiklander }
2228817466cbSJens Wiklander 
2229817466cbSJens Wiklander /*
2230817466cbSJens Wiklander  * Greatest common divisor: G = gcd(A, B)  (HAC 14.54)
2231817466cbSJens Wiklander  */
2232817466cbSJens Wiklander int mbedtls_mpi_gcd( mbedtls_mpi *G, const mbedtls_mpi *A, const mbedtls_mpi *B )
2233817466cbSJens Wiklander {
2234817466cbSJens Wiklander     int ret;
2235817466cbSJens Wiklander     size_t lz, lzt;
2236817466cbSJens Wiklander     mbedtls_mpi TG, TA, TB;
2237817466cbSJens Wiklander 
22383d3b0591SJens Wiklander     MPI_VALIDATE_RET( G != NULL );
22393d3b0591SJens Wiklander     MPI_VALIDATE_RET( A != NULL );
22403d3b0591SJens Wiklander     MPI_VALIDATE_RET( B != NULL );
22413d3b0591SJens Wiklander 
224298bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &TG ); mbedtls_mpi_init_mempool( &TA );
224398bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &TB );
2244817466cbSJens Wiklander 
2245817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TA, A ) );
2246817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, B ) );
2247817466cbSJens Wiklander 
2248817466cbSJens Wiklander     lz = mbedtls_mpi_lsb( &TA );
2249817466cbSJens Wiklander     lzt = mbedtls_mpi_lsb( &TB );
2250817466cbSJens Wiklander 
2251817466cbSJens Wiklander     if( lzt < lz )
2252817466cbSJens Wiklander         lz = lzt;
2253817466cbSJens Wiklander 
2254817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TA, lz ) );
2255817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TB, lz ) );
2256817466cbSJens Wiklander 
2257817466cbSJens Wiklander     TA.s = TB.s = 1;
2258817466cbSJens Wiklander 
2259817466cbSJens Wiklander     while( mbedtls_mpi_cmp_int( &TA, 0 ) != 0 )
2260817466cbSJens Wiklander     {
2261817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TA, mbedtls_mpi_lsb( &TA ) ) );
2262817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TB, mbedtls_mpi_lsb( &TB ) ) );
2263817466cbSJens Wiklander 
2264817466cbSJens Wiklander         if( mbedtls_mpi_cmp_mpi( &TA, &TB ) >= 0 )
2265817466cbSJens Wiklander         {
2266817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( &TA, &TA, &TB ) );
2267817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TA, 1 ) );
2268817466cbSJens Wiklander         }
2269817466cbSJens Wiklander         else
2270817466cbSJens Wiklander         {
2271817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( &TB, &TB, &TA ) );
2272817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TB, 1 ) );
2273817466cbSJens Wiklander         }
2274817466cbSJens Wiklander     }
2275817466cbSJens Wiklander 
2276817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &TB, lz ) );
2277817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( G, &TB ) );
2278817466cbSJens Wiklander 
2279817466cbSJens Wiklander cleanup:
2280817466cbSJens Wiklander 
2281817466cbSJens Wiklander     mbedtls_mpi_free( &TG ); mbedtls_mpi_free( &TA ); mbedtls_mpi_free( &TB );
2282817466cbSJens Wiklander 
2283817466cbSJens Wiklander     return( ret );
2284817466cbSJens Wiklander }
2285817466cbSJens Wiklander 
2286817466cbSJens Wiklander /*
2287817466cbSJens Wiklander  * Fill X with size bytes of random.
2288817466cbSJens Wiklander  *
2289817466cbSJens Wiklander  * Use a temporary bytes representation to make sure the result is the same
2290817466cbSJens Wiklander  * regardless of the platform endianness (useful when f_rng is actually
2291817466cbSJens Wiklander  * deterministic, eg for tests).
2292817466cbSJens Wiklander  */
2293817466cbSJens Wiklander int mbedtls_mpi_fill_random( mbedtls_mpi *X, size_t size,
2294817466cbSJens Wiklander                      int (*f_rng)(void *, unsigned char *, size_t),
2295817466cbSJens Wiklander                      void *p_rng )
2296817466cbSJens Wiklander {
2297817466cbSJens Wiklander     int ret;
2298*5b25c76aSJerome Forissier     size_t const limbs = CHARS_TO_LIMBS( size );
2299*5b25c76aSJerome Forissier     size_t const overhead = ( limbs * ciL ) - size;
2300*5b25c76aSJerome Forissier     unsigned char *Xp;
2301*5b25c76aSJerome Forissier 
23023d3b0591SJens Wiklander     MPI_VALIDATE_RET( X     != NULL );
23033d3b0591SJens Wiklander     MPI_VALIDATE_RET( f_rng != NULL );
2304817466cbSJens Wiklander 
2305*5b25c76aSJerome Forissier     /* Ensure that target MPI has exactly the necessary number of limbs */
2306*5b25c76aSJerome Forissier     if( X->n != limbs )
2307*5b25c76aSJerome Forissier     {
2308*5b25c76aSJerome Forissier         mbedtls_mpi_free( X );
2309*5b25c76aSJerome Forissier         mbedtls_mpi_init( X );
2310*5b25c76aSJerome Forissier         MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, limbs ) );
2311*5b25c76aSJerome Forissier     }
2312*5b25c76aSJerome Forissier     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) );
2313817466cbSJens Wiklander 
2314*5b25c76aSJerome Forissier     Xp = (unsigned char*) X->p;
2315*5b25c76aSJerome Forissier     f_rng( p_rng, Xp + overhead, size );
2316*5b25c76aSJerome Forissier 
2317*5b25c76aSJerome Forissier     mpi_bigendian_to_host( X->p, limbs );
2318817466cbSJens Wiklander 
2319817466cbSJens Wiklander cleanup:
2320817466cbSJens Wiklander     return( ret );
2321817466cbSJens Wiklander }
2322817466cbSJens Wiklander 
2323817466cbSJens Wiklander /*
2324817466cbSJens Wiklander  * Modular inverse: X = A^-1 mod N  (HAC 14.61 / 14.64)
2325817466cbSJens Wiklander  */
2326817466cbSJens Wiklander int mbedtls_mpi_inv_mod( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *N )
2327817466cbSJens Wiklander {
2328817466cbSJens Wiklander     int ret;
2329817466cbSJens Wiklander     mbedtls_mpi G, TA, TU, U1, U2, TB, TV, V1, V2;
23303d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
23313d3b0591SJens Wiklander     MPI_VALIDATE_RET( A != NULL );
23323d3b0591SJens Wiklander     MPI_VALIDATE_RET( N != NULL );
2333817466cbSJens Wiklander 
2334817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( N, 1 ) <= 0 )
2335817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
2336817466cbSJens Wiklander 
233798bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &TA ); mbedtls_mpi_init_mempool( &TU );
233898bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &U1 ); mbedtls_mpi_init_mempool( &U2 );
233998bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &G ); mbedtls_mpi_init_mempool( &TB );
234098bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &TV ); mbedtls_mpi_init_mempool( &V1 );
234198bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &V2 );
2342817466cbSJens Wiklander 
2343817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &G, A, N ) );
2344817466cbSJens Wiklander 
2345817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( &G, 1 ) != 0 )
2346817466cbSJens Wiklander     {
2347817466cbSJens Wiklander         ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2348817466cbSJens Wiklander         goto cleanup;
2349817466cbSJens Wiklander     }
2350817466cbSJens Wiklander 
2351817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &TA, A, N ) );
2352817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TU, &TA ) );
2353817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, N ) );
2354817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TV, N ) );
2355817466cbSJens Wiklander 
2356817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &U1, 1 ) );
2357817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &U2, 0 ) );
2358817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &V1, 0 ) );
2359817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &V2, 1 ) );
2360817466cbSJens Wiklander 
2361817466cbSJens Wiklander     do
2362817466cbSJens Wiklander     {
2363817466cbSJens Wiklander         while( ( TU.p[0] & 1 ) == 0 )
2364817466cbSJens Wiklander         {
2365817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TU, 1 ) );
2366817466cbSJens Wiklander 
2367817466cbSJens Wiklander             if( ( U1.p[0] & 1 ) != 0 || ( U2.p[0] & 1 ) != 0 )
2368817466cbSJens Wiklander             {
2369817466cbSJens Wiklander                 MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &U1, &U1, &TB ) );
2370817466cbSJens Wiklander                 MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &U2, &U2, &TA ) );
2371817466cbSJens Wiklander             }
2372817466cbSJens Wiklander 
2373817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &U1, 1 ) );
2374817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &U2, 1 ) );
2375817466cbSJens Wiklander         }
2376817466cbSJens Wiklander 
2377817466cbSJens Wiklander         while( ( TV.p[0] & 1 ) == 0 )
2378817466cbSJens Wiklander         {
2379817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TV, 1 ) );
2380817466cbSJens Wiklander 
2381817466cbSJens Wiklander             if( ( V1.p[0] & 1 ) != 0 || ( V2.p[0] & 1 ) != 0 )
2382817466cbSJens Wiklander             {
2383817466cbSJens Wiklander                 MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &V1, &V1, &TB ) );
2384817466cbSJens Wiklander                 MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &V2, &V2, &TA ) );
2385817466cbSJens Wiklander             }
2386817466cbSJens Wiklander 
2387817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &V1, 1 ) );
2388817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &V2, 1 ) );
2389817466cbSJens Wiklander         }
2390817466cbSJens Wiklander 
2391817466cbSJens Wiklander         if( mbedtls_mpi_cmp_mpi( &TU, &TV ) >= 0 )
2392817466cbSJens Wiklander         {
2393817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &TU, &TU, &TV ) );
2394817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &U1, &U1, &V1 ) );
2395817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &U2, &U2, &V2 ) );
2396817466cbSJens Wiklander         }
2397817466cbSJens Wiklander         else
2398817466cbSJens Wiklander         {
2399817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &TV, &TV, &TU ) );
2400817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &V1, &V1, &U1 ) );
2401817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &V2, &V2, &U2 ) );
2402817466cbSJens Wiklander         }
2403817466cbSJens Wiklander     }
2404817466cbSJens Wiklander     while( mbedtls_mpi_cmp_int( &TU, 0 ) != 0 );
2405817466cbSJens Wiklander 
2406817466cbSJens Wiklander     while( mbedtls_mpi_cmp_int( &V1, 0 ) < 0 )
2407817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &V1, &V1, N ) );
2408817466cbSJens Wiklander 
2409817466cbSJens Wiklander     while( mbedtls_mpi_cmp_mpi( &V1, N ) >= 0 )
2410817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &V1, &V1, N ) );
2411817466cbSJens Wiklander 
2412817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, &V1 ) );
2413817466cbSJens Wiklander 
2414817466cbSJens Wiklander cleanup:
2415817466cbSJens Wiklander 
2416817466cbSJens Wiklander     mbedtls_mpi_free( &TA ); mbedtls_mpi_free( &TU ); mbedtls_mpi_free( &U1 ); mbedtls_mpi_free( &U2 );
2417817466cbSJens Wiklander     mbedtls_mpi_free( &G ); mbedtls_mpi_free( &TB ); mbedtls_mpi_free( &TV );
2418817466cbSJens Wiklander     mbedtls_mpi_free( &V1 ); mbedtls_mpi_free( &V2 );
2419817466cbSJens Wiklander 
2420817466cbSJens Wiklander     return( ret );
2421817466cbSJens Wiklander }
2422817466cbSJens Wiklander 
2423817466cbSJens Wiklander #if defined(MBEDTLS_GENPRIME)
2424817466cbSJens Wiklander 
2425817466cbSJens Wiklander static const int small_prime[] =
2426817466cbSJens Wiklander {
2427817466cbSJens Wiklander         3,    5,    7,   11,   13,   17,   19,   23,
2428817466cbSJens Wiklander        29,   31,   37,   41,   43,   47,   53,   59,
2429817466cbSJens Wiklander        61,   67,   71,   73,   79,   83,   89,   97,
2430817466cbSJens Wiklander       101,  103,  107,  109,  113,  127,  131,  137,
2431817466cbSJens Wiklander       139,  149,  151,  157,  163,  167,  173,  179,
2432817466cbSJens Wiklander       181,  191,  193,  197,  199,  211,  223,  227,
2433817466cbSJens Wiklander       229,  233,  239,  241,  251,  257,  263,  269,
2434817466cbSJens Wiklander       271,  277,  281,  283,  293,  307,  311,  313,
2435817466cbSJens Wiklander       317,  331,  337,  347,  349,  353,  359,  367,
2436817466cbSJens Wiklander       373,  379,  383,  389,  397,  401,  409,  419,
2437817466cbSJens Wiklander       421,  431,  433,  439,  443,  449,  457,  461,
2438817466cbSJens Wiklander       463,  467,  479,  487,  491,  499,  503,  509,
2439817466cbSJens Wiklander       521,  523,  541,  547,  557,  563,  569,  571,
2440817466cbSJens Wiklander       577,  587,  593,  599,  601,  607,  613,  617,
2441817466cbSJens Wiklander       619,  631,  641,  643,  647,  653,  659,  661,
2442817466cbSJens Wiklander       673,  677,  683,  691,  701,  709,  719,  727,
2443817466cbSJens Wiklander       733,  739,  743,  751,  757,  761,  769,  773,
2444817466cbSJens Wiklander       787,  797,  809,  811,  821,  823,  827,  829,
2445817466cbSJens Wiklander       839,  853,  857,  859,  863,  877,  881,  883,
2446817466cbSJens Wiklander       887,  907,  911,  919,  929,  937,  941,  947,
2447817466cbSJens Wiklander       953,  967,  971,  977,  983,  991,  997, -103
2448817466cbSJens Wiklander };
2449817466cbSJens Wiklander 
2450817466cbSJens Wiklander /*
2451817466cbSJens Wiklander  * Small divisors test (X must be positive)
2452817466cbSJens Wiklander  *
2453817466cbSJens Wiklander  * Return values:
2454817466cbSJens Wiklander  * 0: no small factor (possible prime, more tests needed)
2455817466cbSJens Wiklander  * 1: certain prime
2456817466cbSJens Wiklander  * MBEDTLS_ERR_MPI_NOT_ACCEPTABLE: certain non-prime
2457817466cbSJens Wiklander  * other negative: error
2458817466cbSJens Wiklander  */
2459817466cbSJens Wiklander static int mpi_check_small_factors( const mbedtls_mpi *X )
2460817466cbSJens Wiklander {
2461817466cbSJens Wiklander     int ret = 0;
2462817466cbSJens Wiklander     size_t i;
2463817466cbSJens Wiklander     mbedtls_mpi_uint r;
2464817466cbSJens Wiklander 
2465817466cbSJens Wiklander     if( ( X->p[0] & 1 ) == 0 )
2466817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE );
2467817466cbSJens Wiklander 
2468817466cbSJens Wiklander     for( i = 0; small_prime[i] > 0; i++ )
2469817466cbSJens Wiklander     {
2470817466cbSJens Wiklander         if( mbedtls_mpi_cmp_int( X, small_prime[i] ) <= 0 )
2471817466cbSJens Wiklander             return( 1 );
2472817466cbSJens Wiklander 
2473817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mod_int( &r, X, small_prime[i] ) );
2474817466cbSJens Wiklander 
2475817466cbSJens Wiklander         if( r == 0 )
2476817466cbSJens Wiklander             return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE );
2477817466cbSJens Wiklander     }
2478817466cbSJens Wiklander 
2479817466cbSJens Wiklander cleanup:
2480817466cbSJens Wiklander     return( ret );
2481817466cbSJens Wiklander }
2482817466cbSJens Wiklander 
2483817466cbSJens Wiklander /*
2484817466cbSJens Wiklander  * Miller-Rabin pseudo-primality test  (HAC 4.24)
2485817466cbSJens Wiklander  */
24863d3b0591SJens Wiklander static int mpi_miller_rabin( const mbedtls_mpi *X, size_t rounds,
2487817466cbSJens Wiklander                              int (*f_rng)(void *, unsigned char *, size_t),
2488817466cbSJens Wiklander                              void *p_rng )
2489817466cbSJens Wiklander {
2490817466cbSJens Wiklander     int ret, count;
24913d3b0591SJens Wiklander     size_t i, j, k, s;
2492817466cbSJens Wiklander     mbedtls_mpi W, R, T, A, RR;
2493817466cbSJens Wiklander 
24943d3b0591SJens Wiklander     MPI_VALIDATE_RET( X     != NULL );
24953d3b0591SJens Wiklander     MPI_VALIDATE_RET( f_rng != NULL );
24963d3b0591SJens Wiklander 
249798bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &W ); mbedtls_mpi_init_mempool( &R );
249898bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &T ); mbedtls_mpi_init_mempool( &A );
249998bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &RR );
2500817466cbSJens Wiklander 
2501817466cbSJens Wiklander     /*
2502817466cbSJens Wiklander      * W = |X| - 1
2503817466cbSJens Wiklander      * R = W >> lsb( W )
2504817466cbSJens Wiklander      */
2505817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &W, X, 1 ) );
2506817466cbSJens Wiklander     s = mbedtls_mpi_lsb( &W );
2507817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &R, &W ) );
2508817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &R, s ) );
2509817466cbSJens Wiklander 
25103d3b0591SJens Wiklander     for( i = 0; i < rounds; i++ )
2511817466cbSJens Wiklander     {
2512817466cbSJens Wiklander         /*
2513817466cbSJens Wiklander          * pick a random A, 1 < A < |X| - 1
2514817466cbSJens Wiklander          */
2515817466cbSJens Wiklander         count = 0;
2516817466cbSJens Wiklander         do {
2517817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &A, X->n * ciL, f_rng, p_rng ) );
2518817466cbSJens Wiklander 
2519817466cbSJens Wiklander             j = mbedtls_mpi_bitlen( &A );
2520817466cbSJens Wiklander             k = mbedtls_mpi_bitlen( &W );
2521817466cbSJens Wiklander             if (j > k) {
25223d3b0591SJens Wiklander                 A.p[A.n - 1] &= ( (mbedtls_mpi_uint) 1 << ( k - ( A.n - 1 ) * biL - 1 ) ) - 1;
2523817466cbSJens Wiklander             }
2524817466cbSJens Wiklander 
2525117cce93SJens Wiklander             if (count++ > 300) {
2526336e3299SJens Wiklander                 ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2527336e3299SJens Wiklander                 goto cleanup;
2528817466cbSJens Wiklander             }
2529817466cbSJens Wiklander 
2530817466cbSJens Wiklander         } while ( mbedtls_mpi_cmp_mpi( &A, &W ) >= 0 ||
2531817466cbSJens Wiklander                   mbedtls_mpi_cmp_int( &A, 1 )  <= 0    );
2532817466cbSJens Wiklander 
2533817466cbSJens Wiklander         /*
2534817466cbSJens Wiklander          * A = A^R mod |X|
2535817466cbSJens Wiklander          */
2536817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &A, &A, &R, X, &RR ) );
2537817466cbSJens Wiklander 
2538817466cbSJens Wiklander         if( mbedtls_mpi_cmp_mpi( &A, &W ) == 0 ||
2539817466cbSJens Wiklander             mbedtls_mpi_cmp_int( &A,  1 ) == 0 )
2540817466cbSJens Wiklander             continue;
2541817466cbSJens Wiklander 
2542817466cbSJens Wiklander         j = 1;
2543817466cbSJens Wiklander         while( j < s && mbedtls_mpi_cmp_mpi( &A, &W ) != 0 )
2544817466cbSJens Wiklander         {
2545817466cbSJens Wiklander             /*
2546817466cbSJens Wiklander              * A = A * A mod |X|
2547817466cbSJens Wiklander              */
2548817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T, &A, &A ) );
2549817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &A, &T, X  ) );
2550817466cbSJens Wiklander 
2551817466cbSJens Wiklander             if( mbedtls_mpi_cmp_int( &A, 1 ) == 0 )
2552817466cbSJens Wiklander                 break;
2553817466cbSJens Wiklander 
2554817466cbSJens Wiklander             j++;
2555817466cbSJens Wiklander         }
2556817466cbSJens Wiklander 
2557817466cbSJens Wiklander         /*
2558817466cbSJens Wiklander          * not prime if A != |X| - 1 or A == 1
2559817466cbSJens Wiklander          */
2560817466cbSJens Wiklander         if( mbedtls_mpi_cmp_mpi( &A, &W ) != 0 ||
2561817466cbSJens Wiklander             mbedtls_mpi_cmp_int( &A,  1 ) == 0 )
2562817466cbSJens Wiklander         {
2563817466cbSJens Wiklander             ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2564817466cbSJens Wiklander             break;
2565817466cbSJens Wiklander         }
2566817466cbSJens Wiklander     }
2567817466cbSJens Wiklander 
2568817466cbSJens Wiklander cleanup:
25693d3b0591SJens Wiklander     mbedtls_mpi_free( &W ); mbedtls_mpi_free( &R );
25703d3b0591SJens Wiklander     mbedtls_mpi_free( &T ); mbedtls_mpi_free( &A );
2571817466cbSJens Wiklander     mbedtls_mpi_free( &RR );
2572817466cbSJens Wiklander 
2573817466cbSJens Wiklander     return( ret );
2574817466cbSJens Wiklander }
2575817466cbSJens Wiklander 
2576817466cbSJens Wiklander /*
2577817466cbSJens Wiklander  * Pseudo-primality test: small factors, then Miller-Rabin
2578817466cbSJens Wiklander  */
25793d3b0591SJens Wiklander int mbedtls_mpi_is_prime_ext( const mbedtls_mpi *X, int rounds,
2580817466cbSJens Wiklander                               int (*f_rng)(void *, unsigned char *, size_t),
2581817466cbSJens Wiklander                               void *p_rng )
2582817466cbSJens Wiklander {
2583817466cbSJens Wiklander     int ret;
2584817466cbSJens Wiklander     mbedtls_mpi XX;
25853d3b0591SJens Wiklander     MPI_VALIDATE_RET( X     != NULL );
25863d3b0591SJens Wiklander     MPI_VALIDATE_RET( f_rng != NULL );
2587817466cbSJens Wiklander 
2588817466cbSJens Wiklander     XX.s = 1;
2589817466cbSJens Wiklander     XX.n = X->n;
2590817466cbSJens Wiklander     XX.p = X->p;
2591817466cbSJens Wiklander 
2592817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( &XX, 0 ) == 0 ||
2593817466cbSJens Wiklander         mbedtls_mpi_cmp_int( &XX, 1 ) == 0 )
2594817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE );
2595817466cbSJens Wiklander 
2596817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( &XX, 2 ) == 0 )
2597817466cbSJens Wiklander         return( 0 );
2598817466cbSJens Wiklander 
2599817466cbSJens Wiklander     if( ( ret = mpi_check_small_factors( &XX ) ) != 0 )
2600817466cbSJens Wiklander     {
2601817466cbSJens Wiklander         if( ret == 1 )
2602817466cbSJens Wiklander             return( 0 );
2603817466cbSJens Wiklander 
2604817466cbSJens Wiklander         return( ret );
2605817466cbSJens Wiklander     }
2606817466cbSJens Wiklander 
26073d3b0591SJens Wiklander     return( mpi_miller_rabin( &XX, rounds, f_rng, p_rng ) );
2608817466cbSJens Wiklander }
2609817466cbSJens Wiklander 
26103d3b0591SJens Wiklander #if !defined(MBEDTLS_DEPRECATED_REMOVED)
2611817466cbSJens Wiklander /*
26123d3b0591SJens Wiklander  * Pseudo-primality test, error probability 2^-80
2613817466cbSJens Wiklander  */
26143d3b0591SJens Wiklander int mbedtls_mpi_is_prime( const mbedtls_mpi *X,
2615817466cbSJens Wiklander                   int (*f_rng)(void *, unsigned char *, size_t),
2616817466cbSJens Wiklander                   void *p_rng )
2617817466cbSJens Wiklander {
26183d3b0591SJens Wiklander     MPI_VALIDATE_RET( X     != NULL );
26193d3b0591SJens Wiklander     MPI_VALIDATE_RET( f_rng != NULL );
26203d3b0591SJens Wiklander 
26213d3b0591SJens Wiklander     /*
26223d3b0591SJens Wiklander      * In the past our key generation aimed for an error rate of at most
26233d3b0591SJens Wiklander      * 2^-80. Since this function is deprecated, aim for the same certainty
26243d3b0591SJens Wiklander      * here as well.
26253d3b0591SJens Wiklander      */
26263d3b0591SJens Wiklander     return( mbedtls_mpi_is_prime_ext( X, 40, f_rng, p_rng ) );
26273d3b0591SJens Wiklander }
26283d3b0591SJens Wiklander #endif
26293d3b0591SJens Wiklander 
26303d3b0591SJens Wiklander /*
26313d3b0591SJens Wiklander  * Prime number generation
26323d3b0591SJens Wiklander  *
26333d3b0591SJens Wiklander  * To generate an RSA key in a way recommended by FIPS 186-4, both primes must
26343d3b0591SJens Wiklander  * be either 1024 bits or 1536 bits long, and flags must contain
26353d3b0591SJens Wiklander  * MBEDTLS_MPI_GEN_PRIME_FLAG_LOW_ERR.
26363d3b0591SJens Wiklander  */
26373d3b0591SJens Wiklander int mbedtls_mpi_gen_prime( mbedtls_mpi *X, size_t nbits, int flags,
26383d3b0591SJens Wiklander                    int (*f_rng)(void *, unsigned char *, size_t),
26393d3b0591SJens Wiklander                    void *p_rng )
26403d3b0591SJens Wiklander {
26413d3b0591SJens Wiklander #ifdef MBEDTLS_HAVE_INT64
26423d3b0591SJens Wiklander // ceil(2^63.5)
26433d3b0591SJens Wiklander #define CEIL_MAXUINT_DIV_SQRT2 0xb504f333f9de6485ULL
26443d3b0591SJens Wiklander #else
26453d3b0591SJens Wiklander // ceil(2^31.5)
26463d3b0591SJens Wiklander #define CEIL_MAXUINT_DIV_SQRT2 0xb504f334U
26473d3b0591SJens Wiklander #endif
26483d3b0591SJens Wiklander     int ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2649817466cbSJens Wiklander     size_t k, n;
26503d3b0591SJens Wiklander     int rounds;
2651817466cbSJens Wiklander     mbedtls_mpi_uint r;
2652817466cbSJens Wiklander     mbedtls_mpi Y;
2653817466cbSJens Wiklander 
26543d3b0591SJens Wiklander     MPI_VALIDATE_RET( X     != NULL );
26553d3b0591SJens Wiklander     MPI_VALIDATE_RET( f_rng != NULL );
26563d3b0591SJens Wiklander 
2657817466cbSJens Wiklander     if( nbits < 3 || nbits > MBEDTLS_MPI_MAX_BITS )
2658817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
2659817466cbSJens Wiklander 
266098bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &Y );
2661817466cbSJens Wiklander 
2662817466cbSJens Wiklander     n = BITS_TO_LIMBS( nbits );
2663817466cbSJens Wiklander 
26643d3b0591SJens Wiklander     if( ( flags & MBEDTLS_MPI_GEN_PRIME_FLAG_LOW_ERR ) == 0 )
26653d3b0591SJens Wiklander     {
26663d3b0591SJens Wiklander         /*
26673d3b0591SJens Wiklander          * 2^-80 error probability, number of rounds chosen per HAC, table 4.4
26683d3b0591SJens Wiklander          */
26693d3b0591SJens Wiklander         rounds = ( ( nbits >= 1300 ) ?  2 : ( nbits >=  850 ) ?  3 :
26703d3b0591SJens Wiklander                    ( nbits >=  650 ) ?  4 : ( nbits >=  350 ) ?  8 :
26713d3b0591SJens Wiklander                    ( nbits >=  250 ) ? 12 : ( nbits >=  150 ) ? 18 : 27 );
26723d3b0591SJens Wiklander     }
26733d3b0591SJens Wiklander     else
26743d3b0591SJens Wiklander     {
26753d3b0591SJens Wiklander         /*
26763d3b0591SJens Wiklander          * 2^-100 error probability, number of rounds computed based on HAC,
26773d3b0591SJens Wiklander          * fact 4.48
26783d3b0591SJens Wiklander          */
26793d3b0591SJens Wiklander         rounds = ( ( nbits >= 1450 ) ?  4 : ( nbits >=  1150 ) ?  5 :
26803d3b0591SJens Wiklander                    ( nbits >= 1000 ) ?  6 : ( nbits >=   850 ) ?  7 :
26813d3b0591SJens Wiklander                    ( nbits >=  750 ) ?  8 : ( nbits >=   500 ) ? 13 :
26823d3b0591SJens Wiklander                    ( nbits >=  250 ) ? 28 : ( nbits >=   150 ) ? 40 : 51 );
26833d3b0591SJens Wiklander     }
26843d3b0591SJens Wiklander 
26853d3b0591SJens Wiklander     while( 1 )
26863d3b0591SJens Wiklander     {
2687817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( X, n * ciL, f_rng, p_rng ) );
26883d3b0591SJens Wiklander         /* make sure generated number is at least (nbits-1)+0.5 bits (FIPS 186-4 §B.3.3 steps 4.4, 5.5) */
26893d3b0591SJens Wiklander         if( X->p[n-1] < CEIL_MAXUINT_DIV_SQRT2 ) continue;
2690817466cbSJens Wiklander 
26913d3b0591SJens Wiklander         k = n * biL;
26923d3b0591SJens Wiklander         if( k > nbits ) MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( X, k - nbits ) );
2693817466cbSJens Wiklander         X->p[0] |= 1;
2694817466cbSJens Wiklander 
26953d3b0591SJens Wiklander         if( ( flags & MBEDTLS_MPI_GEN_PRIME_FLAG_DH ) == 0 )
2696817466cbSJens Wiklander         {
26973d3b0591SJens Wiklander             ret = mbedtls_mpi_is_prime_ext( X, rounds, f_rng, p_rng );
26983d3b0591SJens Wiklander 
2699817466cbSJens Wiklander             if( ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE )
2700817466cbSJens Wiklander                 goto cleanup;
2701817466cbSJens Wiklander         }
2702817466cbSJens Wiklander         else
2703817466cbSJens Wiklander         {
2704817466cbSJens Wiklander             /*
2705817466cbSJens Wiklander              * An necessary condition for Y and X = 2Y + 1 to be prime
2706817466cbSJens Wiklander              * is X = 2 mod 3 (which is equivalent to Y = 2 mod 3).
2707817466cbSJens Wiklander              * Make sure it is satisfied, while keeping X = 3 mod 4
2708817466cbSJens Wiklander              */
2709817466cbSJens Wiklander 
2710817466cbSJens Wiklander             X->p[0] |= 2;
2711817466cbSJens Wiklander 
2712817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_mod_int( &r, X, 3 ) );
2713817466cbSJens Wiklander             if( r == 0 )
2714817466cbSJens Wiklander                 MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, X, 8 ) );
2715817466cbSJens Wiklander             else if( r == 1 )
2716817466cbSJens Wiklander                 MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, X, 4 ) );
2717817466cbSJens Wiklander 
2718817466cbSJens Wiklander             /* Set Y = (X-1) / 2, which is X / 2 because X is odd */
2719817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &Y, X ) );
2720817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &Y, 1 ) );
2721817466cbSJens Wiklander 
2722817466cbSJens Wiklander             while( 1 )
2723817466cbSJens Wiklander             {
2724817466cbSJens Wiklander                 /*
2725817466cbSJens Wiklander                  * First, check small factors for X and Y
2726817466cbSJens Wiklander                  * before doing Miller-Rabin on any of them
2727817466cbSJens Wiklander                  */
2728817466cbSJens Wiklander                 if( ( ret = mpi_check_small_factors(  X         ) ) == 0 &&
2729817466cbSJens Wiklander                     ( ret = mpi_check_small_factors( &Y         ) ) == 0 &&
27303d3b0591SJens Wiklander                     ( ret = mpi_miller_rabin(  X, rounds, f_rng, p_rng  ) )
27313d3b0591SJens Wiklander                                                                     == 0 &&
27323d3b0591SJens Wiklander                     ( ret = mpi_miller_rabin( &Y, rounds, f_rng, p_rng  ) )
27333d3b0591SJens Wiklander                                                                     == 0 )
27343d3b0591SJens Wiklander                     goto cleanup;
2735817466cbSJens Wiklander 
2736817466cbSJens Wiklander                 if( ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE )
2737817466cbSJens Wiklander                     goto cleanup;
2738817466cbSJens Wiklander 
2739817466cbSJens Wiklander                 /*
2740817466cbSJens Wiklander                  * Next candidates. We want to preserve Y = (X-1) / 2 and
2741817466cbSJens Wiklander                  * Y = 1 mod 2 and Y = 2 mod 3 (eq X = 3 mod 4 and X = 2 mod 3)
2742817466cbSJens Wiklander                  * so up Y by 6 and X by 12.
2743817466cbSJens Wiklander                  */
2744817466cbSJens Wiklander                 MBEDTLS_MPI_CHK( mbedtls_mpi_add_int(  X,  X, 12 ) );
2745817466cbSJens Wiklander                 MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( &Y, &Y, 6  ) );
2746817466cbSJens Wiklander             }
2747817466cbSJens Wiklander         }
27483d3b0591SJens Wiklander     }
2749817466cbSJens Wiklander 
2750817466cbSJens Wiklander cleanup:
2751817466cbSJens Wiklander 
2752817466cbSJens Wiklander     mbedtls_mpi_free( &Y );
2753817466cbSJens Wiklander 
2754817466cbSJens Wiklander     return( ret );
2755817466cbSJens Wiklander }
2756817466cbSJens Wiklander 
2757817466cbSJens Wiklander #endif /* MBEDTLS_GENPRIME */
2758817466cbSJens Wiklander 
2759817466cbSJens Wiklander #if defined(MBEDTLS_SELF_TEST)
2760817466cbSJens Wiklander 
2761817466cbSJens Wiklander #define GCD_PAIR_COUNT  3
2762817466cbSJens Wiklander 
2763817466cbSJens Wiklander static const int gcd_pairs[GCD_PAIR_COUNT][3] =
2764817466cbSJens Wiklander {
2765817466cbSJens Wiklander     { 693, 609, 21 },
2766817466cbSJens Wiklander     { 1764, 868, 28 },
2767817466cbSJens Wiklander     { 768454923, 542167814, 1 }
2768817466cbSJens Wiklander };
2769817466cbSJens Wiklander 
2770817466cbSJens Wiklander /*
2771817466cbSJens Wiklander  * Checkup routine
2772817466cbSJens Wiklander  */
2773817466cbSJens Wiklander int mbedtls_mpi_self_test( int verbose )
2774817466cbSJens Wiklander {
2775817466cbSJens Wiklander     int ret, i;
2776817466cbSJens Wiklander     mbedtls_mpi A, E, N, X, Y, U, V;
2777817466cbSJens Wiklander 
277898bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &A ); mbedtls_mpi_init_mempool( &E );
277998bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &N ); mbedtls_mpi_init_mempool( &X );
278098bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &Y ); mbedtls_mpi_init_mempool( &U );
278198bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &V );
2782817466cbSJens Wiklander 
2783817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &A, 16,
2784817466cbSJens Wiklander         "EFE021C2645FD1DC586E69184AF4A31E" \
2785817466cbSJens Wiklander         "D5F53E93B5F123FA41680867BA110131" \
2786817466cbSJens Wiklander         "944FE7952E2517337780CB0DB80E61AA" \
2787817466cbSJens Wiklander         "E7C8DDC6C5C6AADEB34EB38A2F40D5E6" ) );
2788817466cbSJens Wiklander 
2789817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &E, 16,
2790817466cbSJens Wiklander         "B2E7EFD37075B9F03FF989C7C5051C20" \
2791817466cbSJens Wiklander         "34D2A323810251127E7BF8625A4F49A5" \
2792817466cbSJens Wiklander         "F3E27F4DA8BD59C47D6DAABA4C8127BD" \
2793817466cbSJens Wiklander         "5B5C25763222FEFCCFC38B832366C29E" ) );
2794817466cbSJens Wiklander 
2795817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &N, 16,
2796817466cbSJens Wiklander         "0066A198186C18C10B2F5ED9B522752A" \
2797817466cbSJens Wiklander         "9830B69916E535C8F047518A889A43A5" \
2798817466cbSJens Wiklander         "94B6BED27A168D31D4A52F88925AA8F5" ) );
2799817466cbSJens Wiklander 
2800817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &X, &A, &N ) );
2801817466cbSJens Wiklander 
2802817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &U, 16,
2803817466cbSJens Wiklander         "602AB7ECA597A3D6B56FF9829A5E8B85" \
2804817466cbSJens Wiklander         "9E857EA95A03512E2BAE7391688D264A" \
2805817466cbSJens Wiklander         "A5663B0341DB9CCFD2C4C5F421FEC814" \
2806817466cbSJens Wiklander         "8001B72E848A38CAE1C65F78E56ABDEF" \
2807817466cbSJens Wiklander         "E12D3C039B8A02D6BE593F0BBBDA56F1" \
2808817466cbSJens Wiklander         "ECF677152EF804370C1A305CAF3B5BF1" \
2809817466cbSJens Wiklander         "30879B56C61DE584A0F53A2447A51E" ) );
2810817466cbSJens Wiklander 
2811817466cbSJens Wiklander     if( verbose != 0 )
2812817466cbSJens Wiklander         mbedtls_printf( "  MPI test #1 (mul_mpi): " );
2813817466cbSJens Wiklander 
2814817466cbSJens Wiklander     if( mbedtls_mpi_cmp_mpi( &X, &U ) != 0 )
2815817466cbSJens Wiklander     {
2816817466cbSJens Wiklander         if( verbose != 0 )
2817817466cbSJens Wiklander             mbedtls_printf( "failed\n" );
2818817466cbSJens Wiklander 
2819817466cbSJens Wiklander         ret = 1;
2820817466cbSJens Wiklander         goto cleanup;
2821817466cbSJens Wiklander     }
2822817466cbSJens Wiklander 
2823817466cbSJens Wiklander     if( verbose != 0 )
2824817466cbSJens Wiklander         mbedtls_printf( "passed\n" );
2825817466cbSJens Wiklander 
2826817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_div_mpi( &X, &Y, &A, &N ) );
2827817466cbSJens Wiklander 
2828817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &U, 16,
2829817466cbSJens Wiklander         "256567336059E52CAE22925474705F39A94" ) );
2830817466cbSJens Wiklander 
2831817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &V, 16,
2832817466cbSJens Wiklander         "6613F26162223DF488E9CD48CC132C7A" \
2833817466cbSJens Wiklander         "0AC93C701B001B092E4E5B9F73BCD27B" \
2834817466cbSJens Wiklander         "9EE50D0657C77F374E903CDFA4C642" ) );
2835817466cbSJens Wiklander 
2836817466cbSJens Wiklander     if( verbose != 0 )
2837817466cbSJens Wiklander         mbedtls_printf( "  MPI test #2 (div_mpi): " );
2838817466cbSJens Wiklander 
2839817466cbSJens Wiklander     if( mbedtls_mpi_cmp_mpi( &X, &U ) != 0 ||
2840817466cbSJens Wiklander         mbedtls_mpi_cmp_mpi( &Y, &V ) != 0 )
2841817466cbSJens Wiklander     {
2842817466cbSJens Wiklander         if( verbose != 0 )
2843817466cbSJens Wiklander             mbedtls_printf( "failed\n" );
2844817466cbSJens Wiklander 
2845817466cbSJens Wiklander         ret = 1;
2846817466cbSJens Wiklander         goto cleanup;
2847817466cbSJens Wiklander     }
2848817466cbSJens Wiklander 
2849817466cbSJens Wiklander     if( verbose != 0 )
2850817466cbSJens Wiklander         mbedtls_printf( "passed\n" );
2851817466cbSJens Wiklander 
2852817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &X, &A, &E, &N, NULL ) );
2853817466cbSJens Wiklander 
2854817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &U, 16,
2855817466cbSJens Wiklander         "36E139AEA55215609D2816998ED020BB" \
2856817466cbSJens Wiklander         "BD96C37890F65171D948E9BC7CBAA4D9" \
2857817466cbSJens Wiklander         "325D24D6A3C12710F10A09FA08AB87" ) );
2858817466cbSJens Wiklander 
2859817466cbSJens Wiklander     if( verbose != 0 )
2860817466cbSJens Wiklander         mbedtls_printf( "  MPI test #3 (exp_mod): " );
2861817466cbSJens Wiklander 
2862817466cbSJens Wiklander     if( mbedtls_mpi_cmp_mpi( &X, &U ) != 0 )
2863817466cbSJens Wiklander     {
2864817466cbSJens Wiklander         if( verbose != 0 )
2865817466cbSJens Wiklander             mbedtls_printf( "failed\n" );
2866817466cbSJens Wiklander 
2867817466cbSJens Wiklander         ret = 1;
2868817466cbSJens Wiklander         goto cleanup;
2869817466cbSJens Wiklander     }
2870817466cbSJens Wiklander 
2871817466cbSJens Wiklander     if( verbose != 0 )
2872817466cbSJens Wiklander         mbedtls_printf( "passed\n" );
2873817466cbSJens Wiklander 
2874817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &X, &A, &N ) );
2875817466cbSJens Wiklander 
2876817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &U, 16,
2877817466cbSJens Wiklander         "003A0AAEDD7E784FC07D8F9EC6E3BFD5" \
2878817466cbSJens Wiklander         "C3DBA76456363A10869622EAC2DD84EC" \
2879817466cbSJens Wiklander         "C5B8A74DAC4D09E03B5E0BE779F2DF61" ) );
2880817466cbSJens Wiklander 
2881817466cbSJens Wiklander     if( verbose != 0 )
2882817466cbSJens Wiklander         mbedtls_printf( "  MPI test #4 (inv_mod): " );
2883817466cbSJens Wiklander 
2884817466cbSJens Wiklander     if( mbedtls_mpi_cmp_mpi( &X, &U ) != 0 )
2885817466cbSJens Wiklander     {
2886817466cbSJens Wiklander         if( verbose != 0 )
2887817466cbSJens Wiklander             mbedtls_printf( "failed\n" );
2888817466cbSJens Wiklander 
2889817466cbSJens Wiklander         ret = 1;
2890817466cbSJens Wiklander         goto cleanup;
2891817466cbSJens Wiklander     }
2892817466cbSJens Wiklander 
2893817466cbSJens Wiklander     if( verbose != 0 )
2894817466cbSJens Wiklander         mbedtls_printf( "passed\n" );
2895817466cbSJens Wiklander 
2896817466cbSJens Wiklander     if( verbose != 0 )
2897817466cbSJens Wiklander         mbedtls_printf( "  MPI test #5 (simple gcd): " );
2898817466cbSJens Wiklander 
2899817466cbSJens Wiklander     for( i = 0; i < GCD_PAIR_COUNT; i++ )
2900817466cbSJens Wiklander     {
2901817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &X, gcd_pairs[i][0] ) );
2902817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &Y, gcd_pairs[i][1] ) );
2903817466cbSJens Wiklander 
2904817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &A, &X, &Y ) );
2905817466cbSJens Wiklander 
2906817466cbSJens Wiklander         if( mbedtls_mpi_cmp_int( &A, gcd_pairs[i][2] ) != 0 )
2907817466cbSJens Wiklander         {
2908817466cbSJens Wiklander             if( verbose != 0 )
2909817466cbSJens Wiklander                 mbedtls_printf( "failed at %d\n", i );
2910817466cbSJens Wiklander 
2911817466cbSJens Wiklander             ret = 1;
2912817466cbSJens Wiklander             goto cleanup;
2913817466cbSJens Wiklander         }
2914817466cbSJens Wiklander     }
2915817466cbSJens Wiklander 
2916817466cbSJens Wiklander     if( verbose != 0 )
2917817466cbSJens Wiklander         mbedtls_printf( "passed\n" );
2918817466cbSJens Wiklander 
2919817466cbSJens Wiklander cleanup:
2920817466cbSJens Wiklander 
2921817466cbSJens Wiklander     if( ret != 0 && verbose != 0 )
2922817466cbSJens Wiklander         mbedtls_printf( "Unexpected error, return code = %08X\n", ret );
2923817466cbSJens Wiklander 
2924817466cbSJens Wiklander     mbedtls_mpi_free( &A ); mbedtls_mpi_free( &E ); mbedtls_mpi_free( &N ); mbedtls_mpi_free( &X );
2925817466cbSJens Wiklander     mbedtls_mpi_free( &Y ); mbedtls_mpi_free( &U ); mbedtls_mpi_free( &V );
2926817466cbSJens Wiklander 
2927817466cbSJens Wiklander     if( verbose != 0 )
2928817466cbSJens Wiklander         mbedtls_printf( "\n" );
2929817466cbSJens Wiklander 
2930817466cbSJens Wiklander     return( ret );
2931817466cbSJens Wiklander }
2932817466cbSJens Wiklander 
2933817466cbSJens Wiklander #endif /* MBEDTLS_SELF_TEST */
2934817466cbSJens Wiklander 
2935817466cbSJens Wiklander #endif /* MBEDTLS_BIGNUM_C */
2936