xref: /optee_os/lib/libmbedtls/mbedtls/library/bignum.c (revision ad443200b69711ad9dc30f32847b6a0d7e2bddf2)
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 
193817466cbSJens Wiklander     /* Actually resize up in this case */
194817466cbSJens Wiklander     if( X->n <= nblimbs )
195817466cbSJens Wiklander         return( mbedtls_mpi_grow( X, nblimbs ) );
196817466cbSJens Wiklander 
197817466cbSJens Wiklander     for( i = X->n - 1; i > 0; i-- )
198817466cbSJens Wiklander         if( X->p[i] != 0 )
199817466cbSJens Wiklander             break;
200817466cbSJens Wiklander     i++;
201817466cbSJens Wiklander 
202817466cbSJens Wiklander     if( i < nblimbs )
203817466cbSJens Wiklander         i = nblimbs;
204817466cbSJens Wiklander 
2053d3b0591SJens Wiklander     if( X->use_mempool )
2063d3b0591SJens Wiklander     {
2073d3b0591SJens Wiklander         p = mempool_alloc( mbedtls_mpi_mempool, nblimbs * ciL );
2083d3b0591SJens Wiklander         if( p == NULL )
20998bd5fe3SJens Wiklander             return( MBEDTLS_ERR_MPI_ALLOC_FAILED );
2103d3b0591SJens Wiklander         memset( p, 0, nblimbs * ciL );
21198bd5fe3SJens Wiklander     }
2123d3b0591SJens Wiklander     else
2133d3b0591SJens Wiklander     {
2143d3b0591SJens Wiklander         p = (mbedtls_mpi_uint*)mbedtls_calloc( nblimbs, ciL );
2153d3b0591SJens Wiklander         if( p == NULL )
2163d3b0591SJens Wiklander             return( MBEDTLS_ERR_MPI_ALLOC_FAILED );
2173d3b0591SJens Wiklander     }
21818c5148dSJens Wiklander 
219817466cbSJens Wiklander     if( X->p != NULL )
220817466cbSJens Wiklander     {
221817466cbSJens Wiklander         memcpy( p, X->p, i * ciL );
222817466cbSJens Wiklander         mbedtls_mpi_zeroize( X->p, X->n );
2233d3b0591SJens Wiklander         if( X->use_mempool )
22418c5148dSJens Wiklander             mempool_free( mbedtls_mpi_mempool, X->p );
2253d3b0591SJens Wiklander         else
2263d3b0591SJens Wiklander             mbedtls_free( X->p );
227817466cbSJens Wiklander     }
228817466cbSJens Wiklander 
22918c5148dSJens Wiklander     X->n = i;
2303d3b0591SJens Wiklander     X->p = p;
231817466cbSJens Wiklander 
232817466cbSJens Wiklander     return( 0 );
233817466cbSJens Wiklander }
234817466cbSJens Wiklander 
235817466cbSJens Wiklander /*
236817466cbSJens Wiklander  * Copy the contents of Y into X
237817466cbSJens Wiklander  */
238817466cbSJens Wiklander int mbedtls_mpi_copy( mbedtls_mpi *X, const mbedtls_mpi *Y )
239817466cbSJens Wiklander {
2403d3b0591SJens Wiklander     int ret = 0;
241817466cbSJens Wiklander     size_t i;
2423d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
2433d3b0591SJens Wiklander     MPI_VALIDATE_RET( Y != NULL );
244817466cbSJens Wiklander 
245817466cbSJens Wiklander     if( X == Y )
246817466cbSJens Wiklander         return( 0 );
247817466cbSJens Wiklander 
248817466cbSJens Wiklander     if( Y->p == NULL )
249817466cbSJens Wiklander     {
250817466cbSJens Wiklander         mbedtls_mpi_free( X );
251817466cbSJens Wiklander         return( 0 );
252817466cbSJens Wiklander     }
253817466cbSJens Wiklander 
254817466cbSJens Wiklander     for( i = Y->n - 1; i > 0; i-- )
255817466cbSJens Wiklander         if( Y->p[i] != 0 )
256817466cbSJens Wiklander             break;
257817466cbSJens Wiklander     i++;
258817466cbSJens Wiklander 
259817466cbSJens Wiklander     X->s = Y->s;
260817466cbSJens Wiklander 
2613d3b0591SJens Wiklander     if( X->n < i )
2623d3b0591SJens Wiklander     {
263817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, i ) );
2643d3b0591SJens Wiklander     }
2653d3b0591SJens Wiklander     else
2663d3b0591SJens Wiklander     {
2673d3b0591SJens Wiklander         memset( X->p + i, 0, ( X->n - i ) * ciL );
2683d3b0591SJens Wiklander     }
269817466cbSJens Wiklander 
270817466cbSJens Wiklander     memcpy( X->p, Y->p, i * ciL );
271817466cbSJens Wiklander 
272817466cbSJens Wiklander cleanup:
273817466cbSJens Wiklander 
274817466cbSJens Wiklander     return( ret );
275817466cbSJens Wiklander }
276817466cbSJens Wiklander 
277817466cbSJens Wiklander /*
278817466cbSJens Wiklander  * Swap the contents of X and Y
279817466cbSJens Wiklander  */
280817466cbSJens Wiklander void mbedtls_mpi_swap( mbedtls_mpi *X, mbedtls_mpi *Y )
281817466cbSJens Wiklander {
282817466cbSJens Wiklander     mbedtls_mpi T;
2833d3b0591SJens Wiklander     MPI_VALIDATE( X != NULL );
2843d3b0591SJens Wiklander     MPI_VALIDATE( Y != NULL );
285817466cbSJens Wiklander 
286817466cbSJens Wiklander     memcpy( &T,  X, sizeof( mbedtls_mpi ) );
287817466cbSJens Wiklander     memcpy(  X,  Y, sizeof( mbedtls_mpi ) );
288817466cbSJens Wiklander     memcpy(  Y, &T, sizeof( mbedtls_mpi ) );
289817466cbSJens Wiklander }
290817466cbSJens Wiklander 
291817466cbSJens Wiklander /*
292817466cbSJens Wiklander  * Conditionally assign X = Y, without leaking information
293817466cbSJens Wiklander  * about whether the assignment was made or not.
294817466cbSJens Wiklander  * (Leaking information about the respective sizes of X and Y is ok however.)
295817466cbSJens Wiklander  */
296817466cbSJens Wiklander int mbedtls_mpi_safe_cond_assign( mbedtls_mpi *X, const mbedtls_mpi *Y, unsigned char assign )
297817466cbSJens Wiklander {
298817466cbSJens Wiklander     int ret = 0;
299817466cbSJens Wiklander     size_t i;
3003d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
3013d3b0591SJens Wiklander     MPI_VALIDATE_RET( Y != NULL );
302817466cbSJens Wiklander 
303817466cbSJens Wiklander     /* make sure assign is 0 or 1 in a time-constant manner */
304817466cbSJens Wiklander     assign = (assign | (unsigned char)-assign) >> 7;
305817466cbSJens Wiklander 
306817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, Y->n ) );
307817466cbSJens Wiklander 
308817466cbSJens Wiklander     X->s = X->s * ( 1 - assign ) + Y->s * assign;
309817466cbSJens Wiklander 
310817466cbSJens Wiklander     for( i = 0; i < Y->n; i++ )
311817466cbSJens Wiklander         X->p[i] = X->p[i] * ( 1 - assign ) + Y->p[i] * assign;
312817466cbSJens Wiklander 
313817466cbSJens Wiklander     for( ; i < X->n; i++ )
314817466cbSJens Wiklander         X->p[i] *= ( 1 - assign );
315817466cbSJens Wiklander 
316817466cbSJens Wiklander cleanup:
317817466cbSJens Wiklander     return( ret );
318817466cbSJens Wiklander }
319817466cbSJens Wiklander 
320817466cbSJens Wiklander /*
321817466cbSJens Wiklander  * Conditionally swap X and Y, without leaking information
322817466cbSJens Wiklander  * about whether the swap was made or not.
323817466cbSJens Wiklander  * Here it is not ok to simply swap the pointers, which whould lead to
324817466cbSJens Wiklander  * different memory access patterns when X and Y are used afterwards.
325817466cbSJens Wiklander  */
326817466cbSJens Wiklander int mbedtls_mpi_safe_cond_swap( mbedtls_mpi *X, mbedtls_mpi *Y, unsigned char swap )
327817466cbSJens Wiklander {
328817466cbSJens Wiklander     int ret, s;
329817466cbSJens Wiklander     size_t i;
330817466cbSJens Wiklander     mbedtls_mpi_uint tmp;
3313d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
3323d3b0591SJens Wiklander     MPI_VALIDATE_RET( Y != NULL );
333817466cbSJens Wiklander 
334817466cbSJens Wiklander     if( X == Y )
335817466cbSJens Wiklander         return( 0 );
336817466cbSJens Wiklander 
337817466cbSJens Wiklander     /* make sure swap is 0 or 1 in a time-constant manner */
338817466cbSJens Wiklander     swap = (swap | (unsigned char)-swap) >> 7;
339817466cbSJens Wiklander 
340817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, Y->n ) );
341817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( Y, X->n ) );
342817466cbSJens Wiklander 
343817466cbSJens Wiklander     s = X->s;
344817466cbSJens Wiklander     X->s = X->s * ( 1 - swap ) + Y->s * swap;
345817466cbSJens Wiklander     Y->s = Y->s * ( 1 - swap ) +    s * swap;
346817466cbSJens Wiklander 
347817466cbSJens Wiklander 
348817466cbSJens Wiklander     for( i = 0; i < X->n; i++ )
349817466cbSJens Wiklander     {
350817466cbSJens Wiklander         tmp = X->p[i];
351817466cbSJens Wiklander         X->p[i] = X->p[i] * ( 1 - swap ) + Y->p[i] * swap;
352817466cbSJens Wiklander         Y->p[i] = Y->p[i] * ( 1 - swap ) +     tmp * swap;
353817466cbSJens Wiklander     }
354817466cbSJens Wiklander 
355817466cbSJens Wiklander cleanup:
356817466cbSJens Wiklander     return( ret );
357817466cbSJens Wiklander }
358817466cbSJens Wiklander 
359817466cbSJens Wiklander /*
360817466cbSJens Wiklander  * Set value from integer
361817466cbSJens Wiklander  */
362817466cbSJens Wiklander int mbedtls_mpi_lset( mbedtls_mpi *X, mbedtls_mpi_sint z )
363817466cbSJens Wiklander {
364817466cbSJens Wiklander     int ret;
3653d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
366817466cbSJens Wiklander 
367817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, 1 ) );
368817466cbSJens Wiklander     memset( X->p, 0, X->n * ciL );
369817466cbSJens Wiklander 
370817466cbSJens Wiklander     X->p[0] = ( z < 0 ) ? -z : z;
371817466cbSJens Wiklander     X->s    = ( z < 0 ) ? -1 : 1;
372817466cbSJens Wiklander 
373817466cbSJens Wiklander cleanup:
374817466cbSJens Wiklander 
375817466cbSJens Wiklander     return( ret );
376817466cbSJens Wiklander }
377817466cbSJens Wiklander 
378817466cbSJens Wiklander /*
379817466cbSJens Wiklander  * Get a specific bit
380817466cbSJens Wiklander  */
381817466cbSJens Wiklander int mbedtls_mpi_get_bit( const mbedtls_mpi *X, size_t pos )
382817466cbSJens Wiklander {
3833d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
3843d3b0591SJens Wiklander 
385817466cbSJens Wiklander     if( X->n * biL <= pos )
386817466cbSJens Wiklander         return( 0 );
387817466cbSJens Wiklander 
388817466cbSJens Wiklander     return( ( X->p[pos / biL] >> ( pos % biL ) ) & 0x01 );
389817466cbSJens Wiklander }
390817466cbSJens Wiklander 
3913d3b0591SJens Wiklander /* Get a specific byte, without range checks. */
3923d3b0591SJens Wiklander #define GET_BYTE( X, i )                                \
3933d3b0591SJens Wiklander     ( ( ( X )->p[( i ) / ciL] >> ( ( ( i ) % ciL ) * 8 ) ) & 0xff )
3943d3b0591SJens Wiklander 
395817466cbSJens Wiklander /*
396817466cbSJens Wiklander  * Set a bit to a specific value of 0 or 1
397817466cbSJens Wiklander  */
398817466cbSJens Wiklander int mbedtls_mpi_set_bit( mbedtls_mpi *X, size_t pos, unsigned char val )
399817466cbSJens Wiklander {
400817466cbSJens Wiklander     int ret = 0;
401817466cbSJens Wiklander     size_t off = pos / biL;
402817466cbSJens Wiklander     size_t idx = pos % biL;
4033d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
404817466cbSJens Wiklander 
405817466cbSJens Wiklander     if( val != 0 && val != 1 )
406817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
407817466cbSJens Wiklander 
408817466cbSJens Wiklander     if( X->n * biL <= pos )
409817466cbSJens Wiklander     {
410817466cbSJens Wiklander         if( val == 0 )
411817466cbSJens Wiklander             return( 0 );
412817466cbSJens Wiklander 
413817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, off + 1 ) );
414817466cbSJens Wiklander     }
415817466cbSJens Wiklander 
416817466cbSJens Wiklander     X->p[off] &= ~( (mbedtls_mpi_uint) 0x01 << idx );
417817466cbSJens Wiklander     X->p[off] |= (mbedtls_mpi_uint) val << idx;
418817466cbSJens Wiklander 
419817466cbSJens Wiklander cleanup:
420817466cbSJens Wiklander 
421817466cbSJens Wiklander     return( ret );
422817466cbSJens Wiklander }
423817466cbSJens Wiklander 
424817466cbSJens Wiklander /*
425817466cbSJens Wiklander  * Return the number of less significant zero-bits
426817466cbSJens Wiklander  */
427817466cbSJens Wiklander size_t mbedtls_mpi_lsb( const mbedtls_mpi *X )
428817466cbSJens Wiklander {
429817466cbSJens Wiklander     size_t i, j, count = 0;
4303d3b0591SJens Wiklander     MBEDTLS_INTERNAL_VALIDATE_RET( X != NULL, 0 );
431817466cbSJens Wiklander 
432817466cbSJens Wiklander     for( i = 0; i < X->n; i++ )
433817466cbSJens Wiklander         for( j = 0; j < biL; j++, count++ )
434817466cbSJens Wiklander             if( ( ( X->p[i] >> j ) & 1 ) != 0 )
435817466cbSJens Wiklander                 return( count );
436817466cbSJens Wiklander 
437817466cbSJens Wiklander     return( 0 );
438817466cbSJens Wiklander }
439817466cbSJens Wiklander 
440817466cbSJens Wiklander /*
441817466cbSJens Wiklander  * Count leading zero bits in a given integer
442817466cbSJens Wiklander  */
443817466cbSJens Wiklander static size_t mbedtls_clz( const mbedtls_mpi_uint x )
444817466cbSJens Wiklander {
445817466cbSJens Wiklander     size_t j;
446817466cbSJens Wiklander     mbedtls_mpi_uint mask = (mbedtls_mpi_uint) 1 << (biL - 1);
447817466cbSJens Wiklander 
448817466cbSJens Wiklander     for( j = 0; j < biL; j++ )
449817466cbSJens Wiklander     {
450817466cbSJens Wiklander         if( x & mask ) break;
451817466cbSJens Wiklander 
452817466cbSJens Wiklander         mask >>= 1;
453817466cbSJens Wiklander     }
454817466cbSJens Wiklander 
455817466cbSJens Wiklander     return j;
456817466cbSJens Wiklander }
457817466cbSJens Wiklander 
458817466cbSJens Wiklander /*
459817466cbSJens Wiklander  * Return the number of bits
460817466cbSJens Wiklander  */
461817466cbSJens Wiklander size_t mbedtls_mpi_bitlen( const mbedtls_mpi *X )
462817466cbSJens Wiklander {
463817466cbSJens Wiklander     size_t i, j;
464817466cbSJens Wiklander 
465817466cbSJens Wiklander     if( X->n == 0 )
466817466cbSJens Wiklander         return( 0 );
467817466cbSJens Wiklander 
468817466cbSJens Wiklander     for( i = X->n - 1; i > 0; i-- )
469817466cbSJens Wiklander         if( X->p[i] != 0 )
470817466cbSJens Wiklander             break;
471817466cbSJens Wiklander 
472817466cbSJens Wiklander     j = biL - mbedtls_clz( X->p[i] );
473817466cbSJens Wiklander 
474817466cbSJens Wiklander     return( ( i * biL ) + j );
475817466cbSJens Wiklander }
476817466cbSJens Wiklander 
477817466cbSJens Wiklander /*
478817466cbSJens Wiklander  * Return the total size in bytes
479817466cbSJens Wiklander  */
480817466cbSJens Wiklander size_t mbedtls_mpi_size( const mbedtls_mpi *X )
481817466cbSJens Wiklander {
482817466cbSJens Wiklander     return( ( mbedtls_mpi_bitlen( X ) + 7 ) >> 3 );
483817466cbSJens Wiklander }
484817466cbSJens Wiklander 
485817466cbSJens Wiklander /*
486817466cbSJens Wiklander  * Convert an ASCII character to digit value
487817466cbSJens Wiklander  */
488817466cbSJens Wiklander static int mpi_get_digit( mbedtls_mpi_uint *d, int radix, char c )
489817466cbSJens Wiklander {
490817466cbSJens Wiklander     *d = 255;
491817466cbSJens Wiklander 
492817466cbSJens Wiklander     if( c >= 0x30 && c <= 0x39 ) *d = c - 0x30;
493817466cbSJens Wiklander     if( c >= 0x41 && c <= 0x46 ) *d = c - 0x37;
494817466cbSJens Wiklander     if( c >= 0x61 && c <= 0x66 ) *d = c - 0x57;
495817466cbSJens Wiklander 
496817466cbSJens Wiklander     if( *d >= (mbedtls_mpi_uint) radix )
497817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_INVALID_CHARACTER );
498817466cbSJens Wiklander 
499817466cbSJens Wiklander     return( 0 );
500817466cbSJens Wiklander }
501817466cbSJens Wiklander 
502817466cbSJens Wiklander /*
503817466cbSJens Wiklander  * Import from an ASCII string
504817466cbSJens Wiklander  */
505817466cbSJens Wiklander int mbedtls_mpi_read_string( mbedtls_mpi *X, int radix, const char *s )
506817466cbSJens Wiklander {
507817466cbSJens Wiklander     int ret;
508817466cbSJens Wiklander     size_t i, j, slen, n;
509817466cbSJens Wiklander     mbedtls_mpi_uint d;
510817466cbSJens Wiklander     mbedtls_mpi T;
5113d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
5123d3b0591SJens Wiklander     MPI_VALIDATE_RET( s != NULL );
513817466cbSJens Wiklander 
514817466cbSJens Wiklander     if( radix < 2 || radix > 16 )
515817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
516817466cbSJens Wiklander 
51798bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &T );
518817466cbSJens Wiklander 
519817466cbSJens Wiklander     slen = strlen( s );
520817466cbSJens Wiklander 
521817466cbSJens Wiklander     if( radix == 16 )
522817466cbSJens Wiklander     {
523817466cbSJens Wiklander         if( slen > MPI_SIZE_T_MAX >> 2 )
524817466cbSJens Wiklander             return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
525817466cbSJens Wiklander 
526817466cbSJens Wiklander         n = BITS_TO_LIMBS( slen << 2 );
527817466cbSJens Wiklander 
528817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, n ) );
529817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) );
530817466cbSJens Wiklander 
531817466cbSJens Wiklander         for( i = slen, j = 0; i > 0; i--, j++ )
532817466cbSJens Wiklander         {
533817466cbSJens Wiklander             if( i == 1 && s[i - 1] == '-' )
534817466cbSJens Wiklander             {
535817466cbSJens Wiklander                 X->s = -1;
536817466cbSJens Wiklander                 break;
537817466cbSJens Wiklander             }
538817466cbSJens Wiklander 
539817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mpi_get_digit( &d, radix, s[i - 1] ) );
540817466cbSJens Wiklander             X->p[j / ( 2 * ciL )] |= d << ( ( j % ( 2 * ciL ) ) << 2 );
541817466cbSJens Wiklander         }
542817466cbSJens Wiklander     }
543817466cbSJens Wiklander     else
544817466cbSJens Wiklander     {
545817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) );
546817466cbSJens Wiklander 
547817466cbSJens Wiklander         for( i = 0; i < slen; i++ )
548817466cbSJens Wiklander         {
549817466cbSJens Wiklander             if( i == 0 && s[i] == '-' )
550817466cbSJens Wiklander             {
551817466cbSJens Wiklander                 X->s = -1;
552817466cbSJens Wiklander                 continue;
553817466cbSJens Wiklander             }
554817466cbSJens Wiklander 
555817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mpi_get_digit( &d, radix, s[i] ) );
556817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &T, X, radix ) );
557817466cbSJens Wiklander 
558817466cbSJens Wiklander             if( X->s == 1 )
559817466cbSJens Wiklander             {
560817466cbSJens Wiklander                 MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, &T, d ) );
561817466cbSJens Wiklander             }
562817466cbSJens Wiklander             else
563817466cbSJens Wiklander             {
564817466cbSJens Wiklander                 MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( X, &T, d ) );
565817466cbSJens Wiklander             }
566817466cbSJens Wiklander         }
567817466cbSJens Wiklander     }
568817466cbSJens Wiklander 
569817466cbSJens Wiklander cleanup:
570817466cbSJens Wiklander 
571817466cbSJens Wiklander     mbedtls_mpi_free( &T );
572817466cbSJens Wiklander 
573817466cbSJens Wiklander     return( ret );
574817466cbSJens Wiklander }
575817466cbSJens Wiklander 
576817466cbSJens Wiklander /*
577817466cbSJens Wiklander  * Helper to write the digits high-order first
578817466cbSJens Wiklander  */
579817466cbSJens Wiklander static int mpi_write_hlp( mbedtls_mpi *X, int radix, char **p )
580817466cbSJens Wiklander {
581817466cbSJens Wiklander     int ret;
582817466cbSJens Wiklander     mbedtls_mpi_uint r;
583817466cbSJens Wiklander 
584817466cbSJens Wiklander     if( radix < 2 || radix > 16 )
585817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
586817466cbSJens Wiklander 
587817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mod_int( &r, X, radix ) );
588817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_div_int( X, NULL, X, radix ) );
589817466cbSJens Wiklander 
590817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( X, 0 ) != 0 )
591817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mpi_write_hlp( X, radix, p ) );
592817466cbSJens Wiklander 
593817466cbSJens Wiklander     if( r < 10 )
594817466cbSJens Wiklander         *(*p)++ = (char)( r + 0x30 );
595817466cbSJens Wiklander     else
596817466cbSJens Wiklander         *(*p)++ = (char)( r + 0x37 );
597817466cbSJens Wiklander 
598817466cbSJens Wiklander cleanup:
599817466cbSJens Wiklander 
600817466cbSJens Wiklander     return( ret );
601817466cbSJens Wiklander }
602817466cbSJens Wiklander 
603817466cbSJens Wiklander /*
604817466cbSJens Wiklander  * Export into an ASCII string
605817466cbSJens Wiklander  */
606817466cbSJens Wiklander int mbedtls_mpi_write_string( const mbedtls_mpi *X, int radix,
607817466cbSJens Wiklander                               char *buf, size_t buflen, size_t *olen )
608817466cbSJens Wiklander {
609817466cbSJens Wiklander     int ret = 0;
610817466cbSJens Wiklander     size_t n;
611817466cbSJens Wiklander     char *p;
612817466cbSJens Wiklander     mbedtls_mpi T;
6133d3b0591SJens Wiklander     MPI_VALIDATE_RET( X    != NULL );
6143d3b0591SJens Wiklander     MPI_VALIDATE_RET( olen != NULL );
6153d3b0591SJens Wiklander     MPI_VALIDATE_RET( buflen == 0 || buf != NULL );
616817466cbSJens Wiklander 
617817466cbSJens Wiklander     if( radix < 2 || radix > 16 )
618817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
619817466cbSJens Wiklander 
620817466cbSJens Wiklander     n = mbedtls_mpi_bitlen( X );
621817466cbSJens Wiklander     if( radix >=  4 ) n >>= 1;
622817466cbSJens Wiklander     if( radix >= 16 ) n >>= 1;
623817466cbSJens Wiklander     /*
624817466cbSJens Wiklander      * Round up the buffer length to an even value to ensure that there is
625817466cbSJens Wiklander      * enough room for hexadecimal values that can be represented in an odd
626817466cbSJens Wiklander      * number of digits.
627817466cbSJens Wiklander      */
628817466cbSJens Wiklander     n += 3 + ( ( n + 1 ) & 1 );
629817466cbSJens Wiklander 
630817466cbSJens Wiklander     if( buflen < n )
631817466cbSJens Wiklander     {
632817466cbSJens Wiklander         *olen = n;
633817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL );
634817466cbSJens Wiklander     }
635817466cbSJens Wiklander 
636817466cbSJens Wiklander     p = buf;
63798bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &T );
638817466cbSJens Wiklander 
639817466cbSJens Wiklander     if( X->s == -1 )
640817466cbSJens Wiklander         *p++ = '-';
641817466cbSJens Wiklander 
642817466cbSJens Wiklander     if( radix == 16 )
643817466cbSJens Wiklander     {
644817466cbSJens Wiklander         int c;
645817466cbSJens Wiklander         size_t i, j, k;
646817466cbSJens Wiklander 
647817466cbSJens Wiklander         for( i = X->n, k = 0; i > 0; i-- )
648817466cbSJens Wiklander         {
649817466cbSJens Wiklander             for( j = ciL; j > 0; j-- )
650817466cbSJens Wiklander             {
651817466cbSJens Wiklander                 c = ( X->p[i - 1] >> ( ( j - 1 ) << 3) ) & 0xFF;
652817466cbSJens Wiklander 
653817466cbSJens Wiklander                 if( c == 0 && k == 0 && ( i + j ) != 2 )
654817466cbSJens Wiklander                     continue;
655817466cbSJens Wiklander 
656817466cbSJens Wiklander                 *(p++) = "0123456789ABCDEF" [c / 16];
657817466cbSJens Wiklander                 *(p++) = "0123456789ABCDEF" [c % 16];
658817466cbSJens Wiklander                 k = 1;
659817466cbSJens Wiklander             }
660817466cbSJens Wiklander         }
661817466cbSJens Wiklander     }
662817466cbSJens Wiklander     else
663817466cbSJens Wiklander     {
664817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &T, X ) );
665817466cbSJens Wiklander 
666817466cbSJens Wiklander         if( T.s == -1 )
667817466cbSJens Wiklander             T.s = 1;
668817466cbSJens Wiklander 
669817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mpi_write_hlp( &T, radix, &p ) );
670817466cbSJens Wiklander     }
671817466cbSJens Wiklander 
672817466cbSJens Wiklander     *p++ = '\0';
673817466cbSJens Wiklander     *olen = p - buf;
674817466cbSJens Wiklander 
675817466cbSJens Wiklander cleanup:
676817466cbSJens Wiklander 
677817466cbSJens Wiklander     mbedtls_mpi_free( &T );
678817466cbSJens Wiklander 
679817466cbSJens Wiklander     return( ret );
680817466cbSJens Wiklander }
681817466cbSJens Wiklander 
682817466cbSJens Wiklander #if defined(MBEDTLS_FS_IO)
683817466cbSJens Wiklander /*
684817466cbSJens Wiklander  * Read X from an opened file
685817466cbSJens Wiklander  */
686817466cbSJens Wiklander int mbedtls_mpi_read_file( mbedtls_mpi *X, int radix, FILE *fin )
687817466cbSJens Wiklander {
688817466cbSJens Wiklander     mbedtls_mpi_uint d;
689817466cbSJens Wiklander     size_t slen;
690817466cbSJens Wiklander     char *p;
691817466cbSJens Wiklander     /*
692817466cbSJens Wiklander      * Buffer should have space for (short) label and decimal formatted MPI,
693817466cbSJens Wiklander      * newline characters and '\0'
694817466cbSJens Wiklander      */
695817466cbSJens Wiklander     char s[ MBEDTLS_MPI_RW_BUFFER_SIZE ];
696817466cbSJens Wiklander 
6973d3b0591SJens Wiklander     MPI_VALIDATE_RET( X   != NULL );
6983d3b0591SJens Wiklander     MPI_VALIDATE_RET( fin != NULL );
6993d3b0591SJens Wiklander 
7003d3b0591SJens Wiklander     if( radix < 2 || radix > 16 )
7013d3b0591SJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
7023d3b0591SJens Wiklander 
703817466cbSJens Wiklander     memset( s, 0, sizeof( s ) );
704817466cbSJens Wiklander     if( fgets( s, sizeof( s ) - 1, fin ) == NULL )
705817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_FILE_IO_ERROR );
706817466cbSJens Wiklander 
707817466cbSJens Wiklander     slen = strlen( s );
708817466cbSJens Wiklander     if( slen == sizeof( s ) - 2 )
709817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL );
710817466cbSJens Wiklander 
711817466cbSJens Wiklander     if( slen > 0 && s[slen - 1] == '\n' ) { slen--; s[slen] = '\0'; }
712817466cbSJens Wiklander     if( slen > 0 && s[slen - 1] == '\r' ) { slen--; s[slen] = '\0'; }
713817466cbSJens Wiklander 
714817466cbSJens Wiklander     p = s + slen;
715817466cbSJens Wiklander     while( p-- > s )
716817466cbSJens Wiklander         if( mpi_get_digit( &d, radix, *p ) != 0 )
717817466cbSJens Wiklander             break;
718817466cbSJens Wiklander 
719817466cbSJens Wiklander     return( mbedtls_mpi_read_string( X, radix, p + 1 ) );
720817466cbSJens Wiklander }
721817466cbSJens Wiklander 
722817466cbSJens Wiklander /*
723817466cbSJens Wiklander  * Write X into an opened file (or stdout if fout == NULL)
724817466cbSJens Wiklander  */
725817466cbSJens Wiklander int mbedtls_mpi_write_file( const char *p, const mbedtls_mpi *X, int radix, FILE *fout )
726817466cbSJens Wiklander {
727817466cbSJens Wiklander     int ret;
728817466cbSJens Wiklander     size_t n, slen, plen;
729817466cbSJens Wiklander     /*
730817466cbSJens Wiklander      * Buffer should have space for (short) label and decimal formatted MPI,
731817466cbSJens Wiklander      * newline characters and '\0'
732817466cbSJens Wiklander      */
733817466cbSJens Wiklander     char s[ MBEDTLS_MPI_RW_BUFFER_SIZE ];
7343d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
7353d3b0591SJens Wiklander 
7363d3b0591SJens Wiklander     if( radix < 2 || radix > 16 )
7373d3b0591SJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
738817466cbSJens Wiklander 
739817466cbSJens Wiklander     memset( s, 0, sizeof( s ) );
740817466cbSJens Wiklander 
741817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_write_string( X, radix, s, sizeof( s ) - 2, &n ) );
742817466cbSJens Wiklander 
743817466cbSJens Wiklander     if( p == NULL ) p = "";
744817466cbSJens Wiklander 
745817466cbSJens Wiklander     plen = strlen( p );
746817466cbSJens Wiklander     slen = strlen( s );
747817466cbSJens Wiklander     s[slen++] = '\r';
748817466cbSJens Wiklander     s[slen++] = '\n';
749817466cbSJens Wiklander 
750817466cbSJens Wiklander     if( fout != NULL )
751817466cbSJens Wiklander     {
752817466cbSJens Wiklander         if( fwrite( p, 1, plen, fout ) != plen ||
753817466cbSJens Wiklander             fwrite( s, 1, slen, fout ) != slen )
754817466cbSJens Wiklander             return( MBEDTLS_ERR_MPI_FILE_IO_ERROR );
755817466cbSJens Wiklander     }
756817466cbSJens Wiklander     else
757817466cbSJens Wiklander         mbedtls_printf( "%s%s", p, s );
758817466cbSJens Wiklander 
759817466cbSJens Wiklander cleanup:
760817466cbSJens Wiklander 
761817466cbSJens Wiklander     return( ret );
762817466cbSJens Wiklander }
763817466cbSJens Wiklander #endif /* MBEDTLS_FS_IO */
764817466cbSJens Wiklander 
765817466cbSJens Wiklander /*
766817466cbSJens Wiklander  * Import X from unsigned binary data, big endian
767817466cbSJens Wiklander  */
768817466cbSJens Wiklander int mbedtls_mpi_read_binary( mbedtls_mpi *X, const unsigned char *buf, size_t buflen )
769817466cbSJens Wiklander {
770817466cbSJens Wiklander     int ret;
7713d3b0591SJens Wiklander     size_t i, j;
7723d3b0591SJens Wiklander     size_t const limbs = CHARS_TO_LIMBS( buflen );
773817466cbSJens Wiklander 
7743d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
7753d3b0591SJens Wiklander     MPI_VALIDATE_RET( buflen == 0 || buf != NULL );
776817466cbSJens Wiklander 
7773d3b0591SJens Wiklander     /* Ensure that target MPI has exactly the necessary number of limbs */
7783d3b0591SJens Wiklander     if( X->n != limbs )
7793d3b0591SJens Wiklander     {
7802976273fSJens Wiklander         short use_mempool = X->use_mempool;
7812976273fSJens Wiklander 
7823d3b0591SJens Wiklander         mbedtls_mpi_free( X );
7832976273fSJens Wiklander         mpi_init( X, use_mempool );
7843d3b0591SJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, limbs ) );
7853d3b0591SJens Wiklander     }
7863d3b0591SJens Wiklander 
787817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) );
788817466cbSJens Wiklander 
7893d3b0591SJens Wiklander     for( i = buflen, j = 0; i > 0; i--, j++ )
790817466cbSJens Wiklander         X->p[j / ciL] |= ((mbedtls_mpi_uint) buf[i - 1]) << ((j % ciL) << 3);
791817466cbSJens Wiklander 
792817466cbSJens Wiklander cleanup:
793817466cbSJens Wiklander 
794817466cbSJens Wiklander     return( ret );
795817466cbSJens Wiklander }
796817466cbSJens Wiklander 
797817466cbSJens Wiklander /*
798817466cbSJens Wiklander  * Export X into unsigned binary data, big endian
799817466cbSJens Wiklander  */
8003d3b0591SJens Wiklander int mbedtls_mpi_write_binary( const mbedtls_mpi *X,
8013d3b0591SJens Wiklander                               unsigned char *buf, size_t buflen )
802817466cbSJens Wiklander {
8033d3b0591SJens Wiklander     size_t stored_bytes;
8043d3b0591SJens Wiklander     size_t bytes_to_copy;
8053d3b0591SJens Wiklander     unsigned char *p;
8063d3b0591SJens Wiklander     size_t i;
807817466cbSJens Wiklander 
8083d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
8093d3b0591SJens Wiklander     MPI_VALIDATE_RET( buflen == 0 || buf != NULL );
810817466cbSJens Wiklander 
8113d3b0591SJens Wiklander     stored_bytes = X->n * ciL;
8123d3b0591SJens Wiklander 
8133d3b0591SJens Wiklander     if( stored_bytes < buflen )
8143d3b0591SJens Wiklander     {
8153d3b0591SJens Wiklander         /* There is enough space in the output buffer. Write initial
8163d3b0591SJens Wiklander          * null bytes and record the position at which to start
8173d3b0591SJens Wiklander          * writing the significant bytes. In this case, the execution
8183d3b0591SJens Wiklander          * trace of this function does not depend on the value of the
8193d3b0591SJens Wiklander          * number. */
8203d3b0591SJens Wiklander         bytes_to_copy = stored_bytes;
8213d3b0591SJens Wiklander         p = buf + buflen - stored_bytes;
8223d3b0591SJens Wiklander         memset( buf, 0, buflen - stored_bytes );
8233d3b0591SJens Wiklander     }
8243d3b0591SJens Wiklander     else
8253d3b0591SJens Wiklander     {
8263d3b0591SJens Wiklander         /* The output buffer is smaller than the allocated size of X.
8273d3b0591SJens Wiklander          * However X may fit if its leading bytes are zero. */
8283d3b0591SJens Wiklander         bytes_to_copy = buflen;
8293d3b0591SJens Wiklander         p = buf;
8303d3b0591SJens Wiklander         for( i = bytes_to_copy; i < stored_bytes; i++ )
8313d3b0591SJens Wiklander         {
8323d3b0591SJens Wiklander             if( GET_BYTE( X, i ) != 0 )
833817466cbSJens Wiklander                 return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL );
8343d3b0591SJens Wiklander         }
8353d3b0591SJens Wiklander     }
836817466cbSJens Wiklander 
8373d3b0591SJens Wiklander     for( i = 0; i < bytes_to_copy; i++ )
8383d3b0591SJens Wiklander         p[bytes_to_copy - i - 1] = GET_BYTE( X, i );
839817466cbSJens Wiklander 
840817466cbSJens Wiklander     return( 0 );
841817466cbSJens Wiklander }
842817466cbSJens Wiklander 
843817466cbSJens Wiklander /*
844817466cbSJens Wiklander  * Left-shift: X <<= count
845817466cbSJens Wiklander  */
846817466cbSJens Wiklander int mbedtls_mpi_shift_l( mbedtls_mpi *X, size_t count )
847817466cbSJens Wiklander {
848817466cbSJens Wiklander     int ret;
849817466cbSJens Wiklander     size_t i, v0, t1;
850817466cbSJens Wiklander     mbedtls_mpi_uint r0 = 0, r1;
8513d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
852817466cbSJens Wiklander 
853817466cbSJens Wiklander     v0 = count / (biL    );
854817466cbSJens Wiklander     t1 = count & (biL - 1);
855817466cbSJens Wiklander 
856817466cbSJens Wiklander     i = mbedtls_mpi_bitlen( X ) + count;
857817466cbSJens Wiklander 
858817466cbSJens Wiklander     if( X->n * biL < i )
859817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, BITS_TO_LIMBS( i ) ) );
860817466cbSJens Wiklander 
861817466cbSJens Wiklander     ret = 0;
862817466cbSJens Wiklander 
863817466cbSJens Wiklander     /*
864817466cbSJens Wiklander      * shift by count / limb_size
865817466cbSJens Wiklander      */
866817466cbSJens Wiklander     if( v0 > 0 )
867817466cbSJens Wiklander     {
868817466cbSJens Wiklander         for( i = X->n; i > v0; i-- )
869817466cbSJens Wiklander             X->p[i - 1] = X->p[i - v0 - 1];
870817466cbSJens Wiklander 
871817466cbSJens Wiklander         for( ; i > 0; i-- )
872817466cbSJens Wiklander             X->p[i - 1] = 0;
873817466cbSJens Wiklander     }
874817466cbSJens Wiklander 
875817466cbSJens Wiklander     /*
876817466cbSJens Wiklander      * shift by count % limb_size
877817466cbSJens Wiklander      */
878817466cbSJens Wiklander     if( t1 > 0 )
879817466cbSJens Wiklander     {
880817466cbSJens Wiklander         for( i = v0; i < X->n; i++ )
881817466cbSJens Wiklander         {
882817466cbSJens Wiklander             r1 = X->p[i] >> (biL - t1);
883817466cbSJens Wiklander             X->p[i] <<= t1;
884817466cbSJens Wiklander             X->p[i] |= r0;
885817466cbSJens Wiklander             r0 = r1;
886817466cbSJens Wiklander         }
887817466cbSJens Wiklander     }
888817466cbSJens Wiklander 
889817466cbSJens Wiklander cleanup:
890817466cbSJens Wiklander 
891817466cbSJens Wiklander     return( ret );
892817466cbSJens Wiklander }
893817466cbSJens Wiklander 
894817466cbSJens Wiklander /*
895817466cbSJens Wiklander  * Right-shift: X >>= count
896817466cbSJens Wiklander  */
897817466cbSJens Wiklander int mbedtls_mpi_shift_r( mbedtls_mpi *X, size_t count )
898817466cbSJens Wiklander {
899817466cbSJens Wiklander     size_t i, v0, v1;
900817466cbSJens Wiklander     mbedtls_mpi_uint r0 = 0, r1;
9013d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
902817466cbSJens Wiklander 
903817466cbSJens Wiklander     v0 = count /  biL;
904817466cbSJens Wiklander     v1 = count & (biL - 1);
905817466cbSJens Wiklander 
906817466cbSJens Wiklander     if( v0 > X->n || ( v0 == X->n && v1 > 0 ) )
907817466cbSJens Wiklander         return mbedtls_mpi_lset( X, 0 );
908817466cbSJens Wiklander 
909817466cbSJens Wiklander     /*
910817466cbSJens Wiklander      * shift by count / limb_size
911817466cbSJens Wiklander      */
912817466cbSJens Wiklander     if( v0 > 0 )
913817466cbSJens Wiklander     {
914817466cbSJens Wiklander         for( i = 0; i < X->n - v0; i++ )
915817466cbSJens Wiklander             X->p[i] = X->p[i + v0];
916817466cbSJens Wiklander 
917817466cbSJens Wiklander         for( ; i < X->n; i++ )
918817466cbSJens Wiklander             X->p[i] = 0;
919817466cbSJens Wiklander     }
920817466cbSJens Wiklander 
921817466cbSJens Wiklander     /*
922817466cbSJens Wiklander      * shift by count % limb_size
923817466cbSJens Wiklander      */
924817466cbSJens Wiklander     if( v1 > 0 )
925817466cbSJens Wiklander     {
926817466cbSJens Wiklander         for( i = X->n; i > 0; i-- )
927817466cbSJens Wiklander         {
928817466cbSJens Wiklander             r1 = X->p[i - 1] << (biL - v1);
929817466cbSJens Wiklander             X->p[i - 1] >>= v1;
930817466cbSJens Wiklander             X->p[i - 1] |= r0;
931817466cbSJens Wiklander             r0 = r1;
932817466cbSJens Wiklander         }
933817466cbSJens Wiklander     }
934817466cbSJens Wiklander 
935817466cbSJens Wiklander     return( 0 );
936817466cbSJens Wiklander }
937817466cbSJens Wiklander 
938817466cbSJens Wiklander /*
939817466cbSJens Wiklander  * Compare unsigned values
940817466cbSJens Wiklander  */
941817466cbSJens Wiklander int mbedtls_mpi_cmp_abs( const mbedtls_mpi *X, const mbedtls_mpi *Y )
942817466cbSJens Wiklander {
943817466cbSJens Wiklander     size_t i, j;
9443d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
9453d3b0591SJens Wiklander     MPI_VALIDATE_RET( Y != NULL );
946817466cbSJens Wiklander 
947817466cbSJens Wiklander     for( i = X->n; i > 0; i-- )
948817466cbSJens Wiklander         if( X->p[i - 1] != 0 )
949817466cbSJens Wiklander             break;
950817466cbSJens Wiklander 
951817466cbSJens Wiklander     for( j = Y->n; j > 0; j-- )
952817466cbSJens Wiklander         if( Y->p[j - 1] != 0 )
953817466cbSJens Wiklander             break;
954817466cbSJens Wiklander 
955817466cbSJens Wiklander     if( i == 0 && j == 0 )
956817466cbSJens Wiklander         return( 0 );
957817466cbSJens Wiklander 
958817466cbSJens Wiklander     if( i > j ) return(  1 );
959817466cbSJens Wiklander     if( j > i ) return( -1 );
960817466cbSJens Wiklander 
961817466cbSJens Wiklander     for( ; i > 0; i-- )
962817466cbSJens Wiklander     {
963817466cbSJens Wiklander         if( X->p[i - 1] > Y->p[i - 1] ) return(  1 );
964817466cbSJens Wiklander         if( X->p[i - 1] < Y->p[i - 1] ) return( -1 );
965817466cbSJens Wiklander     }
966817466cbSJens Wiklander 
967817466cbSJens Wiklander     return( 0 );
968817466cbSJens Wiklander }
969817466cbSJens Wiklander 
970817466cbSJens Wiklander /*
971817466cbSJens Wiklander  * Compare signed values
972817466cbSJens Wiklander  */
973817466cbSJens Wiklander int mbedtls_mpi_cmp_mpi( const mbedtls_mpi *X, const mbedtls_mpi *Y )
974817466cbSJens Wiklander {
975817466cbSJens Wiklander     size_t i, j;
9763d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
9773d3b0591SJens Wiklander     MPI_VALIDATE_RET( Y != NULL );
978817466cbSJens Wiklander 
979817466cbSJens Wiklander     for( i = X->n; i > 0; i-- )
980817466cbSJens Wiklander         if( X->p[i - 1] != 0 )
981817466cbSJens Wiklander             break;
982817466cbSJens Wiklander 
983817466cbSJens Wiklander     for( j = Y->n; j > 0; j-- )
984817466cbSJens Wiklander         if( Y->p[j - 1] != 0 )
985817466cbSJens Wiklander             break;
986817466cbSJens Wiklander 
987817466cbSJens Wiklander     if( i == 0 && j == 0 )
988817466cbSJens Wiklander         return( 0 );
989817466cbSJens Wiklander 
990817466cbSJens Wiklander     if( i > j ) return(  X->s );
991817466cbSJens Wiklander     if( j > i ) return( -Y->s );
992817466cbSJens Wiklander 
993817466cbSJens Wiklander     if( X->s > 0 && Y->s < 0 ) return(  1 );
994817466cbSJens Wiklander     if( Y->s > 0 && X->s < 0 ) return( -1 );
995817466cbSJens Wiklander 
996817466cbSJens Wiklander     for( ; i > 0; i-- )
997817466cbSJens Wiklander     {
998817466cbSJens Wiklander         if( X->p[i - 1] > Y->p[i - 1] ) return(  X->s );
999817466cbSJens Wiklander         if( X->p[i - 1] < Y->p[i - 1] ) return( -X->s );
1000817466cbSJens Wiklander     }
1001817466cbSJens Wiklander 
1002817466cbSJens Wiklander     return( 0 );
1003817466cbSJens Wiklander }
1004817466cbSJens Wiklander 
1005817466cbSJens Wiklander /*
1006817466cbSJens Wiklander  * Compare signed values
1007817466cbSJens Wiklander  */
1008817466cbSJens Wiklander int mbedtls_mpi_cmp_int( const mbedtls_mpi *X, mbedtls_mpi_sint z )
1009817466cbSJens Wiklander {
1010817466cbSJens Wiklander     mbedtls_mpi Y;
1011817466cbSJens Wiklander     mbedtls_mpi_uint p[1];
10123d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
1013817466cbSJens Wiklander 
1014817466cbSJens Wiklander     *p  = ( z < 0 ) ? -z : z;
1015817466cbSJens Wiklander     Y.s = ( z < 0 ) ? -1 : 1;
1016817466cbSJens Wiklander     Y.n = 1;
1017817466cbSJens Wiklander     Y.p = p;
1018817466cbSJens Wiklander 
1019817466cbSJens Wiklander     return( mbedtls_mpi_cmp_mpi( X, &Y ) );
1020817466cbSJens Wiklander }
1021817466cbSJens Wiklander 
1022817466cbSJens Wiklander /*
1023817466cbSJens Wiklander  * Unsigned addition: X = |A| + |B|  (HAC 14.7)
1024817466cbSJens Wiklander  */
1025817466cbSJens Wiklander int mbedtls_mpi_add_abs( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B )
1026817466cbSJens Wiklander {
1027817466cbSJens Wiklander     int ret;
1028817466cbSJens Wiklander     size_t i, j;
1029817466cbSJens Wiklander     mbedtls_mpi_uint *o, *p, c, tmp;
10303d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
10313d3b0591SJens Wiklander     MPI_VALIDATE_RET( A != NULL );
10323d3b0591SJens Wiklander     MPI_VALIDATE_RET( B != NULL );
1033817466cbSJens Wiklander 
1034817466cbSJens Wiklander     if( X == B )
1035817466cbSJens Wiklander     {
1036817466cbSJens Wiklander         const mbedtls_mpi *T = A; A = X; B = T;
1037817466cbSJens Wiklander     }
1038817466cbSJens Wiklander 
1039817466cbSJens Wiklander     if( X != A )
1040817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, A ) );
1041817466cbSJens Wiklander 
1042817466cbSJens Wiklander     /*
1043817466cbSJens Wiklander      * X should always be positive as a result of unsigned additions.
1044817466cbSJens Wiklander      */
1045817466cbSJens Wiklander     X->s = 1;
1046817466cbSJens Wiklander 
1047817466cbSJens Wiklander     for( j = B->n; j > 0; j-- )
1048817466cbSJens Wiklander         if( B->p[j - 1] != 0 )
1049817466cbSJens Wiklander             break;
1050817466cbSJens Wiklander 
1051817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, j ) );
1052817466cbSJens Wiklander 
1053817466cbSJens Wiklander     o = B->p; p = X->p; c = 0;
1054817466cbSJens Wiklander 
1055817466cbSJens Wiklander     /*
1056817466cbSJens Wiklander      * tmp is used because it might happen that p == o
1057817466cbSJens Wiklander      */
1058817466cbSJens Wiklander     for( i = 0; i < j; i++, o++, p++ )
1059817466cbSJens Wiklander     {
1060817466cbSJens Wiklander         tmp= *o;
1061817466cbSJens Wiklander         *p +=  c; c  = ( *p <  c );
1062817466cbSJens Wiklander         *p += tmp; c += ( *p < tmp );
1063817466cbSJens Wiklander     }
1064817466cbSJens Wiklander 
1065817466cbSJens Wiklander     while( c != 0 )
1066817466cbSJens Wiklander     {
1067817466cbSJens Wiklander         if( i >= X->n )
1068817466cbSJens Wiklander         {
1069817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, i + 1 ) );
1070817466cbSJens Wiklander             p = X->p + i;
1071817466cbSJens Wiklander         }
1072817466cbSJens Wiklander 
1073817466cbSJens Wiklander         *p += c; c = ( *p < c ); i++; p++;
1074817466cbSJens Wiklander     }
1075817466cbSJens Wiklander 
1076817466cbSJens Wiklander cleanup:
1077817466cbSJens Wiklander 
1078817466cbSJens Wiklander     return( ret );
1079817466cbSJens Wiklander }
1080817466cbSJens Wiklander 
1081817466cbSJens Wiklander /*
1082817466cbSJens Wiklander  * Helper for mbedtls_mpi subtraction
1083817466cbSJens Wiklander  */
1084817466cbSJens Wiklander static void mpi_sub_hlp( size_t n, mbedtls_mpi_uint *s, mbedtls_mpi_uint *d )
1085817466cbSJens Wiklander {
1086817466cbSJens Wiklander     size_t i;
1087817466cbSJens Wiklander     mbedtls_mpi_uint c, z;
1088817466cbSJens Wiklander 
1089817466cbSJens Wiklander     for( i = c = 0; i < n; i++, s++, d++ )
1090817466cbSJens Wiklander     {
1091817466cbSJens Wiklander         z = ( *d <  c );     *d -=  c;
1092817466cbSJens Wiklander         c = ( *d < *s ) + z; *d -= *s;
1093817466cbSJens Wiklander     }
1094817466cbSJens Wiklander 
1095817466cbSJens Wiklander     while( c != 0 )
1096817466cbSJens Wiklander     {
1097817466cbSJens Wiklander         z = ( *d < c ); *d -= c;
10983d3b0591SJens Wiklander         c = z; d++;
1099817466cbSJens Wiklander     }
1100817466cbSJens Wiklander }
1101817466cbSJens Wiklander 
1102817466cbSJens Wiklander /*
1103817466cbSJens Wiklander  * Unsigned subtraction: X = |A| - |B|  (HAC 14.9)
1104817466cbSJens Wiklander  */
1105817466cbSJens Wiklander int mbedtls_mpi_sub_abs( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B )
1106817466cbSJens Wiklander {
1107817466cbSJens Wiklander     mbedtls_mpi TB;
1108817466cbSJens Wiklander     int ret;
1109817466cbSJens Wiklander     size_t n;
11103d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
11113d3b0591SJens Wiklander     MPI_VALIDATE_RET( A != NULL );
11123d3b0591SJens Wiklander     MPI_VALIDATE_RET( B != NULL );
1113817466cbSJens Wiklander 
1114817466cbSJens Wiklander     if( mbedtls_mpi_cmp_abs( A, B ) < 0 )
1115817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_NEGATIVE_VALUE );
1116817466cbSJens Wiklander 
111798bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &TB );
1118817466cbSJens Wiklander 
1119817466cbSJens Wiklander     if( X == B )
1120817466cbSJens Wiklander     {
1121817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, B ) );
1122817466cbSJens Wiklander         B = &TB;
1123817466cbSJens Wiklander     }
1124817466cbSJens Wiklander 
1125817466cbSJens Wiklander     if( X != A )
1126817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, A ) );
1127817466cbSJens Wiklander 
1128817466cbSJens Wiklander     /*
1129817466cbSJens Wiklander      * X should always be positive as a result of unsigned subtractions.
1130817466cbSJens Wiklander      */
1131817466cbSJens Wiklander     X->s = 1;
1132817466cbSJens Wiklander 
1133817466cbSJens Wiklander     ret = 0;
1134817466cbSJens Wiklander 
1135817466cbSJens Wiklander     for( n = B->n; n > 0; n-- )
1136817466cbSJens Wiklander         if( B->p[n - 1] != 0 )
1137817466cbSJens Wiklander             break;
1138817466cbSJens Wiklander 
1139817466cbSJens Wiklander     mpi_sub_hlp( n, B->p, X->p );
1140817466cbSJens Wiklander 
1141817466cbSJens Wiklander cleanup:
1142817466cbSJens Wiklander 
1143817466cbSJens Wiklander     mbedtls_mpi_free( &TB );
1144817466cbSJens Wiklander 
1145817466cbSJens Wiklander     return( ret );
1146817466cbSJens Wiklander }
1147817466cbSJens Wiklander 
1148817466cbSJens Wiklander /*
1149817466cbSJens Wiklander  * Signed addition: X = A + B
1150817466cbSJens Wiklander  */
1151817466cbSJens Wiklander int mbedtls_mpi_add_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B )
1152817466cbSJens Wiklander {
11533d3b0591SJens Wiklander     int ret, s;
11543d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
11553d3b0591SJens Wiklander     MPI_VALIDATE_RET( A != NULL );
11563d3b0591SJens Wiklander     MPI_VALIDATE_RET( B != NULL );
1157817466cbSJens Wiklander 
11583d3b0591SJens Wiklander     s = A->s;
1159817466cbSJens Wiklander     if( A->s * B->s < 0 )
1160817466cbSJens Wiklander     {
1161817466cbSJens Wiklander         if( mbedtls_mpi_cmp_abs( A, B ) >= 0 )
1162817466cbSJens Wiklander         {
1163817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, A, B ) );
1164817466cbSJens Wiklander             X->s =  s;
1165817466cbSJens Wiklander         }
1166817466cbSJens Wiklander         else
1167817466cbSJens Wiklander         {
1168817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, B, A ) );
1169817466cbSJens Wiklander             X->s = -s;
1170817466cbSJens Wiklander         }
1171817466cbSJens Wiklander     }
1172817466cbSJens Wiklander     else
1173817466cbSJens Wiklander     {
1174817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_add_abs( X, A, B ) );
1175817466cbSJens Wiklander         X->s = s;
1176817466cbSJens Wiklander     }
1177817466cbSJens Wiklander 
1178817466cbSJens Wiklander cleanup:
1179817466cbSJens Wiklander 
1180817466cbSJens Wiklander     return( ret );
1181817466cbSJens Wiklander }
1182817466cbSJens Wiklander 
1183817466cbSJens Wiklander /*
1184817466cbSJens Wiklander  * Signed subtraction: X = A - B
1185817466cbSJens Wiklander  */
1186817466cbSJens Wiklander int mbedtls_mpi_sub_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B )
1187817466cbSJens Wiklander {
11883d3b0591SJens Wiklander     int ret, s;
11893d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
11903d3b0591SJens Wiklander     MPI_VALIDATE_RET( A != NULL );
11913d3b0591SJens Wiklander     MPI_VALIDATE_RET( B != NULL );
1192817466cbSJens Wiklander 
11933d3b0591SJens Wiklander     s = A->s;
1194817466cbSJens Wiklander     if( A->s * B->s > 0 )
1195817466cbSJens Wiklander     {
1196817466cbSJens Wiklander         if( mbedtls_mpi_cmp_abs( A, B ) >= 0 )
1197817466cbSJens Wiklander         {
1198817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, A, B ) );
1199817466cbSJens Wiklander             X->s =  s;
1200817466cbSJens Wiklander         }
1201817466cbSJens Wiklander         else
1202817466cbSJens Wiklander         {
1203817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, B, A ) );
1204817466cbSJens Wiklander             X->s = -s;
1205817466cbSJens Wiklander         }
1206817466cbSJens Wiklander     }
1207817466cbSJens Wiklander     else
1208817466cbSJens Wiklander     {
1209817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_add_abs( X, A, B ) );
1210817466cbSJens Wiklander         X->s = s;
1211817466cbSJens Wiklander     }
1212817466cbSJens Wiklander 
1213817466cbSJens Wiklander cleanup:
1214817466cbSJens Wiklander 
1215817466cbSJens Wiklander     return( ret );
1216817466cbSJens Wiklander }
1217817466cbSJens Wiklander 
1218817466cbSJens Wiklander /*
1219817466cbSJens Wiklander  * Signed addition: X = A + b
1220817466cbSJens Wiklander  */
1221817466cbSJens Wiklander int mbedtls_mpi_add_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b )
1222817466cbSJens Wiklander {
1223817466cbSJens Wiklander     mbedtls_mpi _B;
1224817466cbSJens Wiklander     mbedtls_mpi_uint p[1];
12253d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
12263d3b0591SJens Wiklander     MPI_VALIDATE_RET( A != NULL );
1227817466cbSJens Wiklander 
1228817466cbSJens Wiklander     p[0] = ( b < 0 ) ? -b : b;
1229817466cbSJens Wiklander     _B.s = ( b < 0 ) ? -1 : 1;
1230817466cbSJens Wiklander     _B.n = 1;
1231817466cbSJens Wiklander     _B.p = p;
1232817466cbSJens Wiklander 
1233817466cbSJens Wiklander     return( mbedtls_mpi_add_mpi( X, A, &_B ) );
1234817466cbSJens Wiklander }
1235817466cbSJens Wiklander 
1236817466cbSJens Wiklander /*
1237817466cbSJens Wiklander  * Signed subtraction: X = A - b
1238817466cbSJens Wiklander  */
1239817466cbSJens Wiklander int mbedtls_mpi_sub_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b )
1240817466cbSJens Wiklander {
1241817466cbSJens Wiklander     mbedtls_mpi _B;
1242817466cbSJens Wiklander     mbedtls_mpi_uint p[1];
12433d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
12443d3b0591SJens Wiklander     MPI_VALIDATE_RET( A != NULL );
1245817466cbSJens Wiklander 
1246817466cbSJens Wiklander     p[0] = ( b < 0 ) ? -b : b;
1247817466cbSJens Wiklander     _B.s = ( b < 0 ) ? -1 : 1;
1248817466cbSJens Wiklander     _B.n = 1;
1249817466cbSJens Wiklander     _B.p = p;
1250817466cbSJens Wiklander 
1251817466cbSJens Wiklander     return( mbedtls_mpi_sub_mpi( X, A, &_B ) );
1252817466cbSJens Wiklander }
1253817466cbSJens Wiklander 
1254817466cbSJens Wiklander /*
1255817466cbSJens Wiklander  * Helper for mbedtls_mpi multiplication
1256817466cbSJens Wiklander  */
1257817466cbSJens Wiklander static
1258817466cbSJens Wiklander #if defined(__APPLE__) && defined(__arm__)
1259817466cbSJens Wiklander /*
1260817466cbSJens Wiklander  * Apple LLVM version 4.2 (clang-425.0.24) (based on LLVM 3.2svn)
1261817466cbSJens Wiklander  * appears to need this to prevent bad ARM code generation at -O3.
1262817466cbSJens Wiklander  */
1263817466cbSJens Wiklander __attribute__ ((noinline))
1264817466cbSJens Wiklander #endif
1265817466cbSJens Wiklander void mpi_mul_hlp( size_t i, mbedtls_mpi_uint *s, mbedtls_mpi_uint *d, mbedtls_mpi_uint b )
1266817466cbSJens Wiklander {
1267817466cbSJens Wiklander     mbedtls_mpi_uint c = 0, t = 0;
1268817466cbSJens Wiklander 
1269817466cbSJens Wiklander #if defined(MULADDC_HUIT)
1270817466cbSJens Wiklander     for( ; i >= 8; i -= 8 )
1271817466cbSJens Wiklander     {
1272817466cbSJens Wiklander         MULADDC_INIT
1273817466cbSJens Wiklander         MULADDC_HUIT
1274817466cbSJens Wiklander         MULADDC_STOP
1275817466cbSJens Wiklander     }
1276817466cbSJens Wiklander 
1277817466cbSJens Wiklander     for( ; i > 0; i-- )
1278817466cbSJens Wiklander     {
1279817466cbSJens Wiklander         MULADDC_INIT
1280817466cbSJens Wiklander         MULADDC_CORE
1281817466cbSJens Wiklander         MULADDC_STOP
1282817466cbSJens Wiklander     }
1283817466cbSJens Wiklander #else /* MULADDC_HUIT */
1284817466cbSJens Wiklander     for( ; i >= 16; i -= 16 )
1285817466cbSJens Wiklander     {
1286817466cbSJens Wiklander         MULADDC_INIT
1287817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1288817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1289817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1290817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1291817466cbSJens Wiklander 
1292817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1293817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1294817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1295817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1296817466cbSJens Wiklander         MULADDC_STOP
1297817466cbSJens Wiklander     }
1298817466cbSJens Wiklander 
1299817466cbSJens Wiklander     for( ; i >= 8; i -= 8 )
1300817466cbSJens Wiklander     {
1301817466cbSJens Wiklander         MULADDC_INIT
1302817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1303817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1304817466cbSJens Wiklander 
1305817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1306817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1307817466cbSJens Wiklander         MULADDC_STOP
1308817466cbSJens Wiklander     }
1309817466cbSJens Wiklander 
1310817466cbSJens Wiklander     for( ; i > 0; i-- )
1311817466cbSJens Wiklander     {
1312817466cbSJens Wiklander         MULADDC_INIT
1313817466cbSJens Wiklander         MULADDC_CORE
1314817466cbSJens Wiklander         MULADDC_STOP
1315817466cbSJens Wiklander     }
1316817466cbSJens Wiklander #endif /* MULADDC_HUIT */
1317817466cbSJens Wiklander 
1318817466cbSJens Wiklander     t++;
1319817466cbSJens Wiklander 
1320817466cbSJens Wiklander     do {
1321817466cbSJens Wiklander         *d += c; c = ( *d < c ); d++;
1322817466cbSJens Wiklander     }
1323817466cbSJens Wiklander     while( c != 0 );
1324817466cbSJens Wiklander }
1325817466cbSJens Wiklander 
1326817466cbSJens Wiklander /*
1327817466cbSJens Wiklander  * Baseline multiplication: X = A * B  (HAC 14.12)
1328817466cbSJens Wiklander  */
1329817466cbSJens Wiklander int mbedtls_mpi_mul_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B )
1330817466cbSJens Wiklander {
1331817466cbSJens Wiklander     int ret;
1332817466cbSJens Wiklander     size_t i, j;
1333817466cbSJens Wiklander     mbedtls_mpi TA, TB;
13343d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
13353d3b0591SJens Wiklander     MPI_VALIDATE_RET( A != NULL );
13363d3b0591SJens Wiklander     MPI_VALIDATE_RET( B != NULL );
1337817466cbSJens Wiklander 
133898bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &TA ); mbedtls_mpi_init_mempool( &TB );
1339817466cbSJens Wiklander 
1340817466cbSJens Wiklander     if( X == A ) { MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TA, A ) ); A = &TA; }
1341817466cbSJens Wiklander     if( X == B ) { MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, B ) ); B = &TB; }
1342817466cbSJens Wiklander 
1343817466cbSJens Wiklander     for( i = A->n; i > 0; i-- )
1344817466cbSJens Wiklander         if( A->p[i - 1] != 0 )
1345817466cbSJens Wiklander             break;
1346817466cbSJens Wiklander 
1347817466cbSJens Wiklander     for( j = B->n; j > 0; j-- )
1348817466cbSJens Wiklander         if( B->p[j - 1] != 0 )
1349817466cbSJens Wiklander             break;
1350817466cbSJens Wiklander 
1351817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, i + j ) );
1352817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) );
1353817466cbSJens Wiklander 
13543d3b0591SJens Wiklander     for( ; j > 0; j-- )
13553d3b0591SJens Wiklander         mpi_mul_hlp( i, A->p, X->p + j - 1, B->p[j - 1] );
1356817466cbSJens Wiklander 
1357817466cbSJens Wiklander     X->s = A->s * B->s;
1358817466cbSJens Wiklander 
1359817466cbSJens Wiklander cleanup:
1360817466cbSJens Wiklander 
1361817466cbSJens Wiklander     mbedtls_mpi_free( &TB ); mbedtls_mpi_free( &TA );
1362817466cbSJens Wiklander 
1363817466cbSJens Wiklander     return( ret );
1364817466cbSJens Wiklander }
1365817466cbSJens Wiklander 
1366817466cbSJens Wiklander /*
1367817466cbSJens Wiklander  * Baseline multiplication: X = A * b
1368817466cbSJens Wiklander  */
1369817466cbSJens Wiklander int mbedtls_mpi_mul_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_uint b )
1370817466cbSJens Wiklander {
1371817466cbSJens Wiklander     mbedtls_mpi _B;
1372817466cbSJens Wiklander     mbedtls_mpi_uint p[1];
13733d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
13743d3b0591SJens Wiklander     MPI_VALIDATE_RET( A != NULL );
1375817466cbSJens Wiklander 
1376817466cbSJens Wiklander     _B.s = 1;
1377817466cbSJens Wiklander     _B.n = 1;
1378817466cbSJens Wiklander     _B.p = p;
1379817466cbSJens Wiklander     p[0] = b;
1380817466cbSJens Wiklander 
1381817466cbSJens Wiklander     return( mbedtls_mpi_mul_mpi( X, A, &_B ) );
1382817466cbSJens Wiklander }
1383817466cbSJens Wiklander 
1384817466cbSJens Wiklander /*
1385817466cbSJens Wiklander  * Unsigned integer divide - double mbedtls_mpi_uint dividend, u1/u0, and
1386817466cbSJens Wiklander  * mbedtls_mpi_uint divisor, d
1387817466cbSJens Wiklander  */
1388817466cbSJens Wiklander static mbedtls_mpi_uint mbedtls_int_div_int( mbedtls_mpi_uint u1,
1389817466cbSJens Wiklander             mbedtls_mpi_uint u0, mbedtls_mpi_uint d, mbedtls_mpi_uint *r )
1390817466cbSJens Wiklander {
1391817466cbSJens Wiklander #if defined(MBEDTLS_HAVE_UDBL)
1392817466cbSJens Wiklander     mbedtls_t_udbl dividend, quotient;
1393817466cbSJens Wiklander #else
1394817466cbSJens Wiklander     const mbedtls_mpi_uint radix = (mbedtls_mpi_uint) 1 << biH;
1395817466cbSJens Wiklander     const mbedtls_mpi_uint uint_halfword_mask = ( (mbedtls_mpi_uint) 1 << biH ) - 1;
1396817466cbSJens Wiklander     mbedtls_mpi_uint d0, d1, q0, q1, rAX, r0, quotient;
1397817466cbSJens Wiklander     mbedtls_mpi_uint u0_msw, u0_lsw;
1398817466cbSJens Wiklander     size_t s;
1399817466cbSJens Wiklander #endif
1400817466cbSJens Wiklander 
1401817466cbSJens Wiklander     /*
1402817466cbSJens Wiklander      * Check for overflow
1403817466cbSJens Wiklander      */
1404817466cbSJens Wiklander     if( 0 == d || u1 >= d )
1405817466cbSJens Wiklander     {
1406817466cbSJens Wiklander         if (r != NULL) *r = ~0;
1407817466cbSJens Wiklander 
1408817466cbSJens Wiklander         return ( ~0 );
1409817466cbSJens Wiklander     }
1410817466cbSJens Wiklander 
1411817466cbSJens Wiklander #if defined(MBEDTLS_HAVE_UDBL)
1412817466cbSJens Wiklander     dividend  = (mbedtls_t_udbl) u1 << biL;
1413817466cbSJens Wiklander     dividend |= (mbedtls_t_udbl) u0;
1414817466cbSJens Wiklander     quotient = dividend / d;
1415817466cbSJens Wiklander     if( quotient > ( (mbedtls_t_udbl) 1 << biL ) - 1 )
1416817466cbSJens Wiklander         quotient = ( (mbedtls_t_udbl) 1 << biL ) - 1;
1417817466cbSJens Wiklander 
1418817466cbSJens Wiklander     if( r != NULL )
1419817466cbSJens Wiklander         *r = (mbedtls_mpi_uint)( dividend - (quotient * d ) );
1420817466cbSJens Wiklander 
1421817466cbSJens Wiklander     return (mbedtls_mpi_uint) quotient;
1422817466cbSJens Wiklander #else
1423817466cbSJens Wiklander 
1424817466cbSJens Wiklander     /*
1425817466cbSJens Wiklander      * Algorithm D, Section 4.3.1 - The Art of Computer Programming
1426817466cbSJens Wiklander      *   Vol. 2 - Seminumerical Algorithms, Knuth
1427817466cbSJens Wiklander      */
1428817466cbSJens Wiklander 
1429817466cbSJens Wiklander     /*
1430817466cbSJens Wiklander      * Normalize the divisor, d, and dividend, u0, u1
1431817466cbSJens Wiklander      */
1432817466cbSJens Wiklander     s = mbedtls_clz( d );
1433817466cbSJens Wiklander     d = d << s;
1434817466cbSJens Wiklander 
1435817466cbSJens Wiklander     u1 = u1 << s;
1436817466cbSJens Wiklander     u1 |= ( u0 >> ( biL - s ) ) & ( -(mbedtls_mpi_sint)s >> ( biL - 1 ) );
1437817466cbSJens Wiklander     u0 =  u0 << s;
1438817466cbSJens Wiklander 
1439817466cbSJens Wiklander     d1 = d >> biH;
1440817466cbSJens Wiklander     d0 = d & uint_halfword_mask;
1441817466cbSJens Wiklander 
1442817466cbSJens Wiklander     u0_msw = u0 >> biH;
1443817466cbSJens Wiklander     u0_lsw = u0 & uint_halfword_mask;
1444817466cbSJens Wiklander 
1445817466cbSJens Wiklander     /*
1446817466cbSJens Wiklander      * Find the first quotient and remainder
1447817466cbSJens Wiklander      */
1448817466cbSJens Wiklander     q1 = u1 / d1;
1449817466cbSJens Wiklander     r0 = u1 - d1 * q1;
1450817466cbSJens Wiklander 
1451817466cbSJens Wiklander     while( q1 >= radix || ( q1 * d0 > radix * r0 + u0_msw ) )
1452817466cbSJens Wiklander     {
1453817466cbSJens Wiklander         q1 -= 1;
1454817466cbSJens Wiklander         r0 += d1;
1455817466cbSJens Wiklander 
1456817466cbSJens Wiklander         if ( r0 >= radix ) break;
1457817466cbSJens Wiklander     }
1458817466cbSJens Wiklander 
1459817466cbSJens Wiklander     rAX = ( u1 * radix ) + ( u0_msw - q1 * d );
1460817466cbSJens Wiklander     q0 = rAX / d1;
1461817466cbSJens Wiklander     r0 = rAX - q0 * d1;
1462817466cbSJens Wiklander 
1463817466cbSJens Wiklander     while( q0 >= radix || ( q0 * d0 > radix * r0 + u0_lsw ) )
1464817466cbSJens Wiklander     {
1465817466cbSJens Wiklander         q0 -= 1;
1466817466cbSJens Wiklander         r0 += d1;
1467817466cbSJens Wiklander 
1468817466cbSJens Wiklander         if ( r0 >= radix ) break;
1469817466cbSJens Wiklander     }
1470817466cbSJens Wiklander 
1471817466cbSJens Wiklander     if (r != NULL)
1472817466cbSJens Wiklander         *r = ( rAX * radix + u0_lsw - q0 * d ) >> s;
1473817466cbSJens Wiklander 
1474817466cbSJens Wiklander     quotient = q1 * radix + q0;
1475817466cbSJens Wiklander 
1476817466cbSJens Wiklander     return quotient;
1477817466cbSJens Wiklander #endif
1478817466cbSJens Wiklander }
1479817466cbSJens Wiklander 
1480817466cbSJens Wiklander /*
1481817466cbSJens Wiklander  * Division by mbedtls_mpi: A = Q * B + R  (HAC 14.20)
1482817466cbSJens Wiklander  */
14833d3b0591SJens Wiklander int mbedtls_mpi_div_mpi( mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A,
14843d3b0591SJens Wiklander                          const mbedtls_mpi *B )
1485817466cbSJens Wiklander {
1486817466cbSJens Wiklander     int ret;
1487817466cbSJens Wiklander     size_t i, n, t, k;
1488817466cbSJens Wiklander     mbedtls_mpi X, Y, Z, T1, T2;
14893d3b0591SJens Wiklander     MPI_VALIDATE_RET( A != NULL );
14903d3b0591SJens Wiklander     MPI_VALIDATE_RET( B != NULL );
1491817466cbSJens Wiklander 
1492817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( B, 0 ) == 0 )
1493817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_DIVISION_BY_ZERO );
1494817466cbSJens Wiklander 
149598bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &X ); mbedtls_mpi_init_mempool( &Y );
149698bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &Z ); mbedtls_mpi_init_mempool( &T1 );
149798bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &T2 );
1498817466cbSJens Wiklander 
1499817466cbSJens Wiklander     if( mbedtls_mpi_cmp_abs( A, B ) < 0 )
1500817466cbSJens Wiklander     {
1501817466cbSJens Wiklander         if( Q != NULL ) MBEDTLS_MPI_CHK( mbedtls_mpi_lset( Q, 0 ) );
1502817466cbSJens Wiklander         if( R != NULL ) MBEDTLS_MPI_CHK( mbedtls_mpi_copy( R, A ) );
1503817466cbSJens Wiklander         return( 0 );
1504817466cbSJens Wiklander     }
1505817466cbSJens Wiklander 
1506817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &X, A ) );
1507817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &Y, B ) );
1508817466cbSJens Wiklander     X.s = Y.s = 1;
1509817466cbSJens Wiklander 
1510817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &Z, A->n + 2 ) );
1511817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &Z,  0 ) );
1512817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &T1, 2 ) );
1513817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &T2, 3 ) );
1514817466cbSJens Wiklander 
1515817466cbSJens Wiklander     k = mbedtls_mpi_bitlen( &Y ) % biL;
1516817466cbSJens Wiklander     if( k < biL - 1 )
1517817466cbSJens Wiklander     {
1518817466cbSJens Wiklander         k = biL - 1 - k;
1519817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &X, k ) );
1520817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &Y, k ) );
1521817466cbSJens Wiklander     }
1522817466cbSJens Wiklander     else k = 0;
1523817466cbSJens Wiklander 
1524817466cbSJens Wiklander     n = X.n - 1;
1525817466cbSJens Wiklander     t = Y.n - 1;
1526817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &Y, biL * ( n - t ) ) );
1527817466cbSJens Wiklander 
1528817466cbSJens Wiklander     while( mbedtls_mpi_cmp_mpi( &X, &Y ) >= 0 )
1529817466cbSJens Wiklander     {
1530817466cbSJens Wiklander         Z.p[n - t]++;
1531817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &X, &X, &Y ) );
1532817466cbSJens Wiklander     }
1533817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &Y, biL * ( n - t ) ) );
1534817466cbSJens Wiklander 
1535817466cbSJens Wiklander     for( i = n; i > t ; i-- )
1536817466cbSJens Wiklander     {
1537817466cbSJens Wiklander         if( X.p[i] >= Y.p[t] )
1538817466cbSJens Wiklander             Z.p[i - t - 1] = ~0;
1539817466cbSJens Wiklander         else
1540817466cbSJens Wiklander         {
1541817466cbSJens Wiklander             Z.p[i - t - 1] = mbedtls_int_div_int( X.p[i], X.p[i - 1],
1542817466cbSJens Wiklander                                                             Y.p[t], NULL);
1543817466cbSJens Wiklander         }
1544817466cbSJens Wiklander 
1545817466cbSJens Wiklander         Z.p[i - t - 1]++;
1546817466cbSJens Wiklander         do
1547817466cbSJens Wiklander         {
1548817466cbSJens Wiklander             Z.p[i - t - 1]--;
1549817466cbSJens Wiklander 
1550817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &T1, 0 ) );
1551817466cbSJens Wiklander             T1.p[0] = ( t < 1 ) ? 0 : Y.p[t - 1];
1552817466cbSJens Wiklander             T1.p[1] = Y.p[t];
1553817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &T1, &T1, Z.p[i - t - 1] ) );
1554817466cbSJens Wiklander 
1555817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &T2, 0 ) );
1556817466cbSJens Wiklander             T2.p[0] = ( i < 2 ) ? 0 : X.p[i - 2];
1557817466cbSJens Wiklander             T2.p[1] = ( i < 1 ) ? 0 : X.p[i - 1];
1558817466cbSJens Wiklander             T2.p[2] = X.p[i];
1559817466cbSJens Wiklander         }
1560817466cbSJens Wiklander         while( mbedtls_mpi_cmp_mpi( &T1, &T2 ) > 0 );
1561817466cbSJens Wiklander 
1562817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &T1, &Y, Z.p[i - t - 1] ) );
1563817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &T1,  biL * ( i - t - 1 ) ) );
1564817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &X, &X, &T1 ) );
1565817466cbSJens Wiklander 
1566817466cbSJens Wiklander         if( mbedtls_mpi_cmp_int( &X, 0 ) < 0 )
1567817466cbSJens Wiklander         {
1568817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &T1, &Y ) );
1569817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &T1, biL * ( i - t - 1 ) ) );
1570817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &X, &X, &T1 ) );
1571817466cbSJens Wiklander             Z.p[i - t - 1]--;
1572817466cbSJens Wiklander         }
1573817466cbSJens Wiklander     }
1574817466cbSJens Wiklander 
1575817466cbSJens Wiklander     if( Q != NULL )
1576817466cbSJens Wiklander     {
1577817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( Q, &Z ) );
1578817466cbSJens Wiklander         Q->s = A->s * B->s;
1579817466cbSJens Wiklander     }
1580817466cbSJens Wiklander 
1581817466cbSJens Wiklander     if( R != NULL )
1582817466cbSJens Wiklander     {
1583817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &X, k ) );
1584817466cbSJens Wiklander         X.s = A->s;
1585817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( R, &X ) );
1586817466cbSJens Wiklander 
1587817466cbSJens Wiklander         if( mbedtls_mpi_cmp_int( R, 0 ) == 0 )
1588817466cbSJens Wiklander             R->s = 1;
1589817466cbSJens Wiklander     }
1590817466cbSJens Wiklander 
1591817466cbSJens Wiklander cleanup:
1592817466cbSJens Wiklander 
1593817466cbSJens Wiklander     mbedtls_mpi_free( &X ); mbedtls_mpi_free( &Y ); mbedtls_mpi_free( &Z );
1594817466cbSJens Wiklander     mbedtls_mpi_free( &T1 ); mbedtls_mpi_free( &T2 );
1595817466cbSJens Wiklander 
1596817466cbSJens Wiklander     return( ret );
1597817466cbSJens Wiklander }
1598817466cbSJens Wiklander 
1599817466cbSJens Wiklander /*
1600817466cbSJens Wiklander  * Division by int: A = Q * b + R
1601817466cbSJens Wiklander  */
16023d3b0591SJens Wiklander int mbedtls_mpi_div_int( mbedtls_mpi *Q, mbedtls_mpi *R,
16033d3b0591SJens Wiklander                          const mbedtls_mpi *A,
16043d3b0591SJens Wiklander                          mbedtls_mpi_sint b )
1605817466cbSJens Wiklander {
1606817466cbSJens Wiklander     mbedtls_mpi _B;
1607817466cbSJens Wiklander     mbedtls_mpi_uint p[1];
16083d3b0591SJens Wiklander     MPI_VALIDATE_RET( A != NULL );
1609817466cbSJens Wiklander 
1610817466cbSJens Wiklander     p[0] = ( b < 0 ) ? -b : b;
1611817466cbSJens Wiklander     _B.s = ( b < 0 ) ? -1 : 1;
1612817466cbSJens Wiklander     _B.n = 1;
1613817466cbSJens Wiklander     _B.p = p;
1614817466cbSJens Wiklander 
1615817466cbSJens Wiklander     return( mbedtls_mpi_div_mpi( Q, R, A, &_B ) );
1616817466cbSJens Wiklander }
1617817466cbSJens Wiklander 
1618817466cbSJens Wiklander /*
1619817466cbSJens Wiklander  * Modulo: R = A mod B
1620817466cbSJens Wiklander  */
1621817466cbSJens Wiklander int mbedtls_mpi_mod_mpi( mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B )
1622817466cbSJens Wiklander {
1623817466cbSJens Wiklander     int ret;
16243d3b0591SJens Wiklander     MPI_VALIDATE_RET( R != NULL );
16253d3b0591SJens Wiklander     MPI_VALIDATE_RET( A != NULL );
16263d3b0591SJens Wiklander     MPI_VALIDATE_RET( B != NULL );
1627817466cbSJens Wiklander 
1628817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( B, 0 ) < 0 )
1629817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_NEGATIVE_VALUE );
1630817466cbSJens Wiklander 
1631817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_div_mpi( NULL, R, A, B ) );
1632817466cbSJens Wiklander 
1633817466cbSJens Wiklander     while( mbedtls_mpi_cmp_int( R, 0 ) < 0 )
1634817466cbSJens Wiklander       MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( R, R, B ) );
1635817466cbSJens Wiklander 
1636817466cbSJens Wiklander     while( mbedtls_mpi_cmp_mpi( R, B ) >= 0 )
1637817466cbSJens Wiklander       MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( R, R, B ) );
1638817466cbSJens Wiklander 
1639817466cbSJens Wiklander cleanup:
1640817466cbSJens Wiklander 
1641817466cbSJens Wiklander     return( ret );
1642817466cbSJens Wiklander }
1643817466cbSJens Wiklander 
1644817466cbSJens Wiklander /*
1645817466cbSJens Wiklander  * Modulo: r = A mod b
1646817466cbSJens Wiklander  */
1647817466cbSJens Wiklander int mbedtls_mpi_mod_int( mbedtls_mpi_uint *r, const mbedtls_mpi *A, mbedtls_mpi_sint b )
1648817466cbSJens Wiklander {
1649817466cbSJens Wiklander     size_t i;
1650817466cbSJens Wiklander     mbedtls_mpi_uint x, y, z;
16513d3b0591SJens Wiklander     MPI_VALIDATE_RET( r != NULL );
16523d3b0591SJens Wiklander     MPI_VALIDATE_RET( A != NULL );
1653817466cbSJens Wiklander 
1654817466cbSJens Wiklander     if( b == 0 )
1655817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_DIVISION_BY_ZERO );
1656817466cbSJens Wiklander 
1657817466cbSJens Wiklander     if( b < 0 )
1658817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_NEGATIVE_VALUE );
1659817466cbSJens Wiklander 
1660817466cbSJens Wiklander     /*
1661817466cbSJens Wiklander      * handle trivial cases
1662817466cbSJens Wiklander      */
1663817466cbSJens Wiklander     if( b == 1 )
1664817466cbSJens Wiklander     {
1665817466cbSJens Wiklander         *r = 0;
1666817466cbSJens Wiklander         return( 0 );
1667817466cbSJens Wiklander     }
1668817466cbSJens Wiklander 
1669817466cbSJens Wiklander     if( b == 2 )
1670817466cbSJens Wiklander     {
1671817466cbSJens Wiklander         *r = A->p[0] & 1;
1672817466cbSJens Wiklander         return( 0 );
1673817466cbSJens Wiklander     }
1674817466cbSJens Wiklander 
1675817466cbSJens Wiklander     /*
1676817466cbSJens Wiklander      * general case
1677817466cbSJens Wiklander      */
1678817466cbSJens Wiklander     for( i = A->n, y = 0; i > 0; i-- )
1679817466cbSJens Wiklander     {
1680817466cbSJens Wiklander         x  = A->p[i - 1];
1681817466cbSJens Wiklander         y  = ( y << biH ) | ( x >> biH );
1682817466cbSJens Wiklander         z  = y / b;
1683817466cbSJens Wiklander         y -= z * b;
1684817466cbSJens Wiklander 
1685817466cbSJens Wiklander         x <<= biH;
1686817466cbSJens Wiklander         y  = ( y << biH ) | ( x >> biH );
1687817466cbSJens Wiklander         z  = y / b;
1688817466cbSJens Wiklander         y -= z * b;
1689817466cbSJens Wiklander     }
1690817466cbSJens Wiklander 
1691817466cbSJens Wiklander     /*
1692817466cbSJens Wiklander      * If A is negative, then the current y represents a negative value.
1693817466cbSJens Wiklander      * Flipping it to the positive side.
1694817466cbSJens Wiklander      */
1695817466cbSJens Wiklander     if( A->s < 0 && y != 0 )
1696817466cbSJens Wiklander         y = b - y;
1697817466cbSJens Wiklander 
1698817466cbSJens Wiklander     *r = y;
1699817466cbSJens Wiklander 
1700817466cbSJens Wiklander     return( 0 );
1701817466cbSJens Wiklander }
1702817466cbSJens Wiklander 
1703817466cbSJens Wiklander /*
1704817466cbSJens Wiklander  * Fast Montgomery initialization (thanks to Tom St Denis)
1705817466cbSJens Wiklander  */
170662f21181SJens Wiklander void mbedtls_mpi_montg_init( mbedtls_mpi_uint *mm, const mbedtls_mpi *N )
1707817466cbSJens Wiklander {
1708817466cbSJens Wiklander     mbedtls_mpi_uint x, m0 = N->p[0];
1709817466cbSJens Wiklander     unsigned int i;
1710817466cbSJens Wiklander 
1711817466cbSJens Wiklander     x  = m0;
1712817466cbSJens Wiklander     x += ( ( m0 + 2 ) & 4 ) << 1;
1713817466cbSJens Wiklander 
1714817466cbSJens Wiklander     for( i = biL; i >= 8; i /= 2 )
1715817466cbSJens Wiklander         x *= ( 2 - ( m0 * x ) );
1716817466cbSJens Wiklander 
1717817466cbSJens Wiklander     *mm = ~x + 1;
1718817466cbSJens Wiklander }
1719817466cbSJens Wiklander 
1720817466cbSJens Wiklander /*
1721817466cbSJens Wiklander  * Montgomery multiplication: A = A * B * R^-1 mod N  (HAC 14.36)
1722817466cbSJens Wiklander  */
172362f21181SJens Wiklander int mbedtls_mpi_montmul( mbedtls_mpi *A, const mbedtls_mpi *B,
172462f21181SJens Wiklander 			 const mbedtls_mpi *N, mbedtls_mpi_uint mm,
1725817466cbSJens Wiklander                          const mbedtls_mpi *T )
1726817466cbSJens Wiklander {
1727817466cbSJens Wiklander     size_t i, n, m;
1728817466cbSJens Wiklander     mbedtls_mpi_uint u0, u1, *d;
1729817466cbSJens Wiklander 
1730817466cbSJens Wiklander     if( T->n < N->n + 1 || T->p == NULL )
1731817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
1732817466cbSJens Wiklander 
1733817466cbSJens Wiklander     memset( T->p, 0, T->n * ciL );
1734817466cbSJens Wiklander 
1735817466cbSJens Wiklander     d = T->p;
1736817466cbSJens Wiklander     n = N->n;
1737817466cbSJens Wiklander     m = ( B->n < n ) ? B->n : n;
1738817466cbSJens Wiklander 
1739817466cbSJens Wiklander     for( i = 0; i < n; i++ )
1740817466cbSJens Wiklander     {
1741817466cbSJens Wiklander         /*
1742817466cbSJens Wiklander          * T = (T + u0*B + u1*N) / 2^biL
1743817466cbSJens Wiklander          */
1744817466cbSJens Wiklander         u0 = A->p[i];
1745817466cbSJens Wiklander         u1 = ( d[0] + u0 * B->p[0] ) * mm;
1746817466cbSJens Wiklander 
1747817466cbSJens Wiklander         mpi_mul_hlp( m, B->p, d, u0 );
1748817466cbSJens Wiklander         mpi_mul_hlp( n, N->p, d, u1 );
1749817466cbSJens Wiklander 
1750817466cbSJens Wiklander         *d++ = u0; d[n + 1] = 0;
1751817466cbSJens Wiklander     }
1752817466cbSJens Wiklander 
1753817466cbSJens Wiklander     memcpy( A->p, d, ( n + 1 ) * ciL );
1754817466cbSJens Wiklander 
1755817466cbSJens Wiklander     if( mbedtls_mpi_cmp_abs( A, N ) >= 0 )
1756817466cbSJens Wiklander         mpi_sub_hlp( n, N->p, A->p );
1757817466cbSJens Wiklander     else
1758817466cbSJens Wiklander         /* prevent timing attacks */
1759817466cbSJens Wiklander         mpi_sub_hlp( n, A->p, T->p );
1760817466cbSJens Wiklander 
1761817466cbSJens Wiklander     return( 0 );
1762817466cbSJens Wiklander }
1763817466cbSJens Wiklander 
1764817466cbSJens Wiklander /*
1765817466cbSJens Wiklander  * Montgomery reduction: A = A * R^-1 mod N
1766817466cbSJens Wiklander  */
176762f21181SJens Wiklander int mbedtls_mpi_montred( mbedtls_mpi *A, const mbedtls_mpi *N,
176862f21181SJens Wiklander 			 mbedtls_mpi_uint mm, const mbedtls_mpi *T )
1769817466cbSJens Wiklander {
1770817466cbSJens Wiklander     mbedtls_mpi_uint z = 1;
1771817466cbSJens Wiklander     mbedtls_mpi U;
1772817466cbSJens Wiklander 
1773817466cbSJens Wiklander     U.n = U.s = (int) z;
1774817466cbSJens Wiklander     U.p = &z;
1775817466cbSJens Wiklander 
177662f21181SJens Wiklander     return( mbedtls_mpi_montmul( A, &U, N, mm, T ) );
1777817466cbSJens Wiklander }
1778817466cbSJens Wiklander 
1779817466cbSJens Wiklander /*
1780817466cbSJens Wiklander  * Sliding-window exponentiation: X = A^E mod N  (HAC 14.85)
1781817466cbSJens Wiklander  */
17823d3b0591SJens Wiklander int mbedtls_mpi_exp_mod( mbedtls_mpi *X, const mbedtls_mpi *A,
17833d3b0591SJens Wiklander                          const mbedtls_mpi *E, const mbedtls_mpi *N,
17843d3b0591SJens Wiklander                          mbedtls_mpi *_RR )
1785817466cbSJens Wiklander {
1786817466cbSJens Wiklander     int ret;
1787817466cbSJens Wiklander     size_t wbits, wsize, one = 1;
1788817466cbSJens Wiklander     size_t i, j, nblimbs;
1789817466cbSJens Wiklander     size_t bufsize, nbits;
1790817466cbSJens Wiklander     mbedtls_mpi_uint ei, mm, state;
179141e5aa8fSJens Wiklander     mbedtls_mpi RR, T, Apos;
1792*ad443200SJens Wiklander     mbedtls_mpi *W = NULL;
179341e5aa8fSJens Wiklander     const size_t array_size_W = 2 << MBEDTLS_MPI_WINDOW_SIZE;
1794817466cbSJens Wiklander     int neg;
1795817466cbSJens Wiklander 
17963d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
17973d3b0591SJens Wiklander     MPI_VALIDATE_RET( A != NULL );
17983d3b0591SJens Wiklander     MPI_VALIDATE_RET( E != NULL );
17993d3b0591SJens Wiklander     MPI_VALIDATE_RET( N != NULL );
18003d3b0591SJens Wiklander 
18013d3b0591SJens Wiklander     if( mbedtls_mpi_cmp_int( N, 0 ) <= 0 || ( N->p[0] & 1 ) == 0 )
1802817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
1803817466cbSJens Wiklander 
1804817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( E, 0 ) < 0 )
1805817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
1806817466cbSJens Wiklander 
1807817466cbSJens Wiklander     /*
1808817466cbSJens Wiklander      * Init temps and window size
1809817466cbSJens Wiklander      */
181062f21181SJens Wiklander     mbedtls_mpi_montg_init( &mm, N );
181198bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &RR ); mbedtls_mpi_init_mempool( &T );
181298bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &Apos );
1813817466cbSJens Wiklander 
1814817466cbSJens Wiklander     i = mbedtls_mpi_bitlen( E );
1815817466cbSJens Wiklander 
1816817466cbSJens Wiklander     wsize = ( i > 671 ) ? 6 : ( i > 239 ) ? 5 :
1817817466cbSJens Wiklander             ( i >  79 ) ? 4 : ( i >  23 ) ? 3 : 1;
1818817466cbSJens Wiklander 
1819817466cbSJens Wiklander     if( wsize > MBEDTLS_MPI_WINDOW_SIZE )
1820817466cbSJens Wiklander         wsize = MBEDTLS_MPI_WINDOW_SIZE;
1821817466cbSJens Wiklander 
1822817466cbSJens Wiklander     j = N->n + 1;
1823817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, j ) );
1824*ad443200SJens Wiklander 
1825817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &T, j * 2 ) );
1826817466cbSJens Wiklander 
1827817466cbSJens Wiklander     /*
1828817466cbSJens Wiklander      * Compensate for negative A (and correct at the end)
1829817466cbSJens Wiklander      */
1830817466cbSJens Wiklander     neg = ( A->s == -1 );
1831817466cbSJens Wiklander     if( neg )
1832817466cbSJens Wiklander     {
1833817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &Apos, A ) );
1834817466cbSJens Wiklander         Apos.s = 1;
1835817466cbSJens Wiklander         A = &Apos;
1836817466cbSJens Wiklander     }
1837817466cbSJens Wiklander 
1838817466cbSJens Wiklander     /*
1839817466cbSJens Wiklander      * If 1st call, pre-compute R^2 mod N
1840817466cbSJens Wiklander      */
1841817466cbSJens Wiklander     if( _RR == NULL || _RR->p == NULL )
1842817466cbSJens Wiklander     {
1843817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &RR, 1 ) );
1844817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &RR, N->n * 2 * biL ) );
1845817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &RR, &RR, N ) );
1846817466cbSJens Wiklander 
1847817466cbSJens Wiklander         if( _RR != NULL )
1848817466cbSJens Wiklander             memcpy( _RR, &RR, sizeof( mbedtls_mpi ) );
1849817466cbSJens Wiklander     }
1850817466cbSJens Wiklander     else
1851817466cbSJens Wiklander         memcpy( &RR, _RR, sizeof( mbedtls_mpi ) );
1852817466cbSJens Wiklander 
1853*ad443200SJens Wiklander     W = mempool_alloc( mbedtls_mpi_mempool,
1854*ad443200SJens Wiklander                        sizeof( mbedtls_mpi ) * array_size_W );
1855*ad443200SJens Wiklander     if( W == NULL ) {
1856*ad443200SJens Wiklander         ret = MBEDTLS_ERR_MPI_ALLOC_FAILED;
1857*ad443200SJens Wiklander         goto cleanup;
1858*ad443200SJens Wiklander     }
1859*ad443200SJens Wiklander     for( i = 0; i < array_size_W; i++ )
1860*ad443200SJens Wiklander         mbedtls_mpi_init_mempool( W + i );
1861*ad443200SJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[1],  j ) );
1862*ad443200SJens Wiklander 
1863817466cbSJens Wiklander     /*
1864817466cbSJens Wiklander      * W[1] = A * R^2 * R^-1 mod N = A * R mod N
1865817466cbSJens Wiklander      */
1866817466cbSJens Wiklander     if( mbedtls_mpi_cmp_mpi( A, N ) >= 0 )
1867817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &W[1], A, N ) );
1868817466cbSJens Wiklander     else
1869817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &W[1], A ) );
1870817466cbSJens Wiklander 
187162f21181SJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_montmul( &W[1], &RR, N, mm, &T ) );
1872817466cbSJens Wiklander 
1873817466cbSJens Wiklander     /*
1874817466cbSJens Wiklander      * X = R^2 * R^-1 mod N = R mod N
1875817466cbSJens Wiklander      */
1876817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, &RR ) );
187762f21181SJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_montred( X, N, mm, &T ) );
1878817466cbSJens Wiklander 
1879817466cbSJens Wiklander     if( wsize > 1 )
1880817466cbSJens Wiklander     {
1881817466cbSJens Wiklander         /*
1882817466cbSJens Wiklander          * W[1 << (wsize - 1)] = W[1] ^ (wsize - 1)
1883817466cbSJens Wiklander          */
1884817466cbSJens Wiklander         j =  one << ( wsize - 1 );
1885817466cbSJens Wiklander 
1886817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[j], N->n + 1 ) );
1887817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &W[j], &W[1]    ) );
1888817466cbSJens Wiklander 
1889817466cbSJens Wiklander         for( i = 0; i < wsize - 1; i++ )
189062f21181SJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_montmul( &W[j], &W[j], N, mm, &T ) );
1891817466cbSJens Wiklander 
1892817466cbSJens Wiklander         /*
1893817466cbSJens Wiklander          * W[i] = W[i - 1] * W[1]
1894817466cbSJens Wiklander          */
1895817466cbSJens Wiklander         for( i = j + 1; i < ( one << wsize ); i++ )
1896817466cbSJens Wiklander         {
1897817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[i], N->n + 1 ) );
1898817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &W[i], &W[i - 1] ) );
1899817466cbSJens Wiklander 
190062f21181SJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_montmul( &W[i], &W[1], N, mm, &T ) );
1901817466cbSJens Wiklander         }
1902817466cbSJens Wiklander     }
1903817466cbSJens Wiklander 
1904817466cbSJens Wiklander     nblimbs = E->n;
1905817466cbSJens Wiklander     bufsize = 0;
1906817466cbSJens Wiklander     nbits   = 0;
1907817466cbSJens Wiklander     wbits   = 0;
1908817466cbSJens Wiklander     state   = 0;
1909817466cbSJens Wiklander 
1910817466cbSJens Wiklander     while( 1 )
1911817466cbSJens Wiklander     {
1912817466cbSJens Wiklander         if( bufsize == 0 )
1913817466cbSJens Wiklander         {
1914817466cbSJens Wiklander             if( nblimbs == 0 )
1915817466cbSJens Wiklander                 break;
1916817466cbSJens Wiklander 
1917817466cbSJens Wiklander             nblimbs--;
1918817466cbSJens Wiklander 
1919817466cbSJens Wiklander             bufsize = sizeof( mbedtls_mpi_uint ) << 3;
1920817466cbSJens Wiklander         }
1921817466cbSJens Wiklander 
1922817466cbSJens Wiklander         bufsize--;
1923817466cbSJens Wiklander 
1924817466cbSJens Wiklander         ei = (E->p[nblimbs] >> bufsize) & 1;
1925817466cbSJens Wiklander 
1926817466cbSJens Wiklander         /*
1927817466cbSJens Wiklander          * skip leading 0s
1928817466cbSJens Wiklander          */
1929817466cbSJens Wiklander         if( ei == 0 && state == 0 )
1930817466cbSJens Wiklander             continue;
1931817466cbSJens Wiklander 
1932817466cbSJens Wiklander         if( ei == 0 && state == 1 )
1933817466cbSJens Wiklander         {
1934817466cbSJens Wiklander             /*
1935817466cbSJens Wiklander              * out of window, square X
1936817466cbSJens Wiklander              */
193762f21181SJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_montmul( X, X, N, mm, &T ) );
1938817466cbSJens Wiklander             continue;
1939817466cbSJens Wiklander         }
1940817466cbSJens Wiklander 
1941817466cbSJens Wiklander         /*
1942817466cbSJens Wiklander          * add ei to current window
1943817466cbSJens Wiklander          */
1944817466cbSJens Wiklander         state = 2;
1945817466cbSJens Wiklander 
1946817466cbSJens Wiklander         nbits++;
1947817466cbSJens Wiklander         wbits |= ( ei << ( wsize - nbits ) );
1948817466cbSJens Wiklander 
1949817466cbSJens Wiklander         if( nbits == wsize )
1950817466cbSJens Wiklander         {
1951817466cbSJens Wiklander             /*
1952817466cbSJens Wiklander              * X = X^wsize R^-1 mod N
1953817466cbSJens Wiklander              */
1954817466cbSJens Wiklander             for( i = 0; i < wsize; i++ )
195562f21181SJens Wiklander                 MBEDTLS_MPI_CHK( mbedtls_mpi_montmul( X, X, N, mm, &T ) );
1956817466cbSJens Wiklander 
1957817466cbSJens Wiklander             /*
1958817466cbSJens Wiklander              * X = X * W[wbits] R^-1 mod N
1959817466cbSJens Wiklander              */
196062f21181SJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_montmul( X, &W[wbits], N, mm, &T ) );
1961817466cbSJens Wiklander 
1962817466cbSJens Wiklander             state--;
1963817466cbSJens Wiklander             nbits = 0;
1964817466cbSJens Wiklander             wbits = 0;
1965817466cbSJens Wiklander         }
1966817466cbSJens Wiklander     }
1967817466cbSJens Wiklander 
1968817466cbSJens Wiklander     /*
1969817466cbSJens Wiklander      * process the remaining bits
1970817466cbSJens Wiklander      */
1971817466cbSJens Wiklander     for( i = 0; i < nbits; i++ )
1972817466cbSJens Wiklander     {
197362f21181SJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_montmul( X, X, N, mm, &T ) );
1974817466cbSJens Wiklander 
1975817466cbSJens Wiklander         wbits <<= 1;
1976817466cbSJens Wiklander 
1977817466cbSJens Wiklander         if( ( wbits & ( one << wsize ) ) != 0 )
197862f21181SJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_montmul( X, &W[1], N, mm, &T ) );
1979817466cbSJens Wiklander     }
1980817466cbSJens Wiklander 
1981817466cbSJens Wiklander     /*
1982817466cbSJens Wiklander      * X = A^E * R * R^-1 mod N = A^E mod N
1983817466cbSJens Wiklander      */
198462f21181SJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_montred( X, N, mm, &T ) );
1985817466cbSJens Wiklander 
1986817466cbSJens Wiklander     if( neg && E->n != 0 && ( E->p[0] & 1 ) != 0 )
1987817466cbSJens Wiklander     {
1988817466cbSJens Wiklander         X->s = -1;
1989817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( X, N, X ) );
1990817466cbSJens Wiklander     }
1991817466cbSJens Wiklander 
1992817466cbSJens Wiklander cleanup:
1993817466cbSJens Wiklander 
1994*ad443200SJens Wiklander     if( W )
199541e5aa8fSJens Wiklander         for( i = 0; i < array_size_W; i++ )
1996b99a4a18SJens Wiklander             mbedtls_mpi_free( W + i );
199741e5aa8fSJens Wiklander     mempool_free( mbedtls_mpi_mempool , W );
1998817466cbSJens Wiklander 
1999b99a4a18SJens Wiklander     mbedtls_mpi_free( &T ); mbedtls_mpi_free( &Apos );
2000817466cbSJens Wiklander 
2001817466cbSJens Wiklander     if( _RR == NULL || _RR->p == NULL )
2002817466cbSJens Wiklander         mbedtls_mpi_free( &RR );
2003817466cbSJens Wiklander 
2004817466cbSJens Wiklander     return( ret );
2005817466cbSJens Wiklander }
2006817466cbSJens Wiklander 
2007817466cbSJens Wiklander /*
2008817466cbSJens Wiklander  * Greatest common divisor: G = gcd(A, B)  (HAC 14.54)
2009817466cbSJens Wiklander  */
2010817466cbSJens Wiklander int mbedtls_mpi_gcd( mbedtls_mpi *G, const mbedtls_mpi *A, const mbedtls_mpi *B )
2011817466cbSJens Wiklander {
2012817466cbSJens Wiklander     int ret;
2013817466cbSJens Wiklander     size_t lz, lzt;
2014817466cbSJens Wiklander     mbedtls_mpi TG, TA, TB;
2015817466cbSJens Wiklander 
20163d3b0591SJens Wiklander     MPI_VALIDATE_RET( G != NULL );
20173d3b0591SJens Wiklander     MPI_VALIDATE_RET( A != NULL );
20183d3b0591SJens Wiklander     MPI_VALIDATE_RET( B != NULL );
20193d3b0591SJens Wiklander 
202098bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &TG ); mbedtls_mpi_init_mempool( &TA );
202198bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &TB );
2022817466cbSJens Wiklander 
2023817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TA, A ) );
2024817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, B ) );
2025817466cbSJens Wiklander 
2026817466cbSJens Wiklander     lz = mbedtls_mpi_lsb( &TA );
2027817466cbSJens Wiklander     lzt = mbedtls_mpi_lsb( &TB );
2028817466cbSJens Wiklander 
2029817466cbSJens Wiklander     if( lzt < lz )
2030817466cbSJens Wiklander         lz = lzt;
2031817466cbSJens Wiklander 
2032817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TA, lz ) );
2033817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TB, lz ) );
2034817466cbSJens Wiklander 
2035817466cbSJens Wiklander     TA.s = TB.s = 1;
2036817466cbSJens Wiklander 
2037817466cbSJens Wiklander     while( mbedtls_mpi_cmp_int( &TA, 0 ) != 0 )
2038817466cbSJens Wiklander     {
2039817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TA, mbedtls_mpi_lsb( &TA ) ) );
2040817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TB, mbedtls_mpi_lsb( &TB ) ) );
2041817466cbSJens Wiklander 
2042817466cbSJens Wiklander         if( mbedtls_mpi_cmp_mpi( &TA, &TB ) >= 0 )
2043817466cbSJens Wiklander         {
2044817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( &TA, &TA, &TB ) );
2045817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TA, 1 ) );
2046817466cbSJens Wiklander         }
2047817466cbSJens Wiklander         else
2048817466cbSJens Wiklander         {
2049817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( &TB, &TB, &TA ) );
2050817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TB, 1 ) );
2051817466cbSJens Wiklander         }
2052817466cbSJens Wiklander     }
2053817466cbSJens Wiklander 
2054817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &TB, lz ) );
2055817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( G, &TB ) );
2056817466cbSJens Wiklander 
2057817466cbSJens Wiklander cleanup:
2058817466cbSJens Wiklander 
2059817466cbSJens Wiklander     mbedtls_mpi_free( &TG ); mbedtls_mpi_free( &TA ); mbedtls_mpi_free( &TB );
2060817466cbSJens Wiklander 
2061817466cbSJens Wiklander     return( ret );
2062817466cbSJens Wiklander }
2063817466cbSJens Wiklander 
2064817466cbSJens Wiklander /*
2065817466cbSJens Wiklander  * Fill X with size bytes of random.
2066817466cbSJens Wiklander  *
2067817466cbSJens Wiklander  * Use a temporary bytes representation to make sure the result is the same
2068817466cbSJens Wiklander  * regardless of the platform endianness (useful when f_rng is actually
2069817466cbSJens Wiklander  * deterministic, eg for tests).
2070817466cbSJens Wiklander  */
2071817466cbSJens Wiklander int mbedtls_mpi_fill_random( mbedtls_mpi *X, size_t size,
2072817466cbSJens Wiklander                      int (*f_rng)(void *, unsigned char *, size_t),
2073817466cbSJens Wiklander                      void *p_rng )
2074817466cbSJens Wiklander {
2075817466cbSJens Wiklander     int ret;
2076817466cbSJens Wiklander     unsigned char buf[MBEDTLS_MPI_MAX_SIZE];
20773d3b0591SJens Wiklander     MPI_VALIDATE_RET( X     != NULL );
20783d3b0591SJens Wiklander     MPI_VALIDATE_RET( f_rng != NULL );
2079817466cbSJens Wiklander 
2080817466cbSJens Wiklander     if( size > MBEDTLS_MPI_MAX_SIZE )
2081817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
2082817466cbSJens Wiklander 
2083817466cbSJens Wiklander     MBEDTLS_MPI_CHK( f_rng( p_rng, buf, size ) );
2084817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( X, buf, size ) );
2085817466cbSJens Wiklander 
2086817466cbSJens Wiklander cleanup:
20873d3b0591SJens Wiklander     mbedtls_platform_zeroize( buf, sizeof( buf ) );
2088817466cbSJens Wiklander     return( ret );
2089817466cbSJens Wiklander }
2090817466cbSJens Wiklander 
2091817466cbSJens Wiklander /*
2092817466cbSJens Wiklander  * Modular inverse: X = A^-1 mod N  (HAC 14.61 / 14.64)
2093817466cbSJens Wiklander  */
2094817466cbSJens Wiklander int mbedtls_mpi_inv_mod( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *N )
2095817466cbSJens Wiklander {
2096817466cbSJens Wiklander     int ret;
2097817466cbSJens Wiklander     mbedtls_mpi G, TA, TU, U1, U2, TB, TV, V1, V2;
20983d3b0591SJens Wiklander     MPI_VALIDATE_RET( X != NULL );
20993d3b0591SJens Wiklander     MPI_VALIDATE_RET( A != NULL );
21003d3b0591SJens Wiklander     MPI_VALIDATE_RET( N != NULL );
2101817466cbSJens Wiklander 
2102817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( N, 1 ) <= 0 )
2103817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
2104817466cbSJens Wiklander 
210598bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &TA ); mbedtls_mpi_init_mempool( &TU );
210698bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &U1 ); mbedtls_mpi_init_mempool( &U2 );
210798bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &G ); mbedtls_mpi_init_mempool( &TB );
210898bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &TV ); mbedtls_mpi_init_mempool( &V1 );
210998bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &V2 );
2110817466cbSJens Wiklander 
2111817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &G, A, N ) );
2112817466cbSJens Wiklander 
2113817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( &G, 1 ) != 0 )
2114817466cbSJens Wiklander     {
2115817466cbSJens Wiklander         ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2116817466cbSJens Wiklander         goto cleanup;
2117817466cbSJens Wiklander     }
2118817466cbSJens Wiklander 
2119817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &TA, A, N ) );
2120817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TU, &TA ) );
2121817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, N ) );
2122817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TV, N ) );
2123817466cbSJens Wiklander 
2124817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &U1, 1 ) );
2125817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &U2, 0 ) );
2126817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &V1, 0 ) );
2127817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &V2, 1 ) );
2128817466cbSJens Wiklander 
2129817466cbSJens Wiklander     do
2130817466cbSJens Wiklander     {
2131817466cbSJens Wiklander         while( ( TU.p[0] & 1 ) == 0 )
2132817466cbSJens Wiklander         {
2133817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TU, 1 ) );
2134817466cbSJens Wiklander 
2135817466cbSJens Wiklander             if( ( U1.p[0] & 1 ) != 0 || ( U2.p[0] & 1 ) != 0 )
2136817466cbSJens Wiklander             {
2137817466cbSJens Wiklander                 MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &U1, &U1, &TB ) );
2138817466cbSJens Wiklander                 MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &U2, &U2, &TA ) );
2139817466cbSJens Wiklander             }
2140817466cbSJens Wiklander 
2141817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &U1, 1 ) );
2142817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &U2, 1 ) );
2143817466cbSJens Wiklander         }
2144817466cbSJens Wiklander 
2145817466cbSJens Wiklander         while( ( TV.p[0] & 1 ) == 0 )
2146817466cbSJens Wiklander         {
2147817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TV, 1 ) );
2148817466cbSJens Wiklander 
2149817466cbSJens Wiklander             if( ( V1.p[0] & 1 ) != 0 || ( V2.p[0] & 1 ) != 0 )
2150817466cbSJens Wiklander             {
2151817466cbSJens Wiklander                 MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &V1, &V1, &TB ) );
2152817466cbSJens Wiklander                 MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &V2, &V2, &TA ) );
2153817466cbSJens Wiklander             }
2154817466cbSJens Wiklander 
2155817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &V1, 1 ) );
2156817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &V2, 1 ) );
2157817466cbSJens Wiklander         }
2158817466cbSJens Wiklander 
2159817466cbSJens Wiklander         if( mbedtls_mpi_cmp_mpi( &TU, &TV ) >= 0 )
2160817466cbSJens Wiklander         {
2161817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &TU, &TU, &TV ) );
2162817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &U1, &U1, &V1 ) );
2163817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &U2, &U2, &V2 ) );
2164817466cbSJens Wiklander         }
2165817466cbSJens Wiklander         else
2166817466cbSJens Wiklander         {
2167817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &TV, &TV, &TU ) );
2168817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &V1, &V1, &U1 ) );
2169817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &V2, &V2, &U2 ) );
2170817466cbSJens Wiklander         }
2171817466cbSJens Wiklander     }
2172817466cbSJens Wiklander     while( mbedtls_mpi_cmp_int( &TU, 0 ) != 0 );
2173817466cbSJens Wiklander 
2174817466cbSJens Wiklander     while( mbedtls_mpi_cmp_int( &V1, 0 ) < 0 )
2175817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &V1, &V1, N ) );
2176817466cbSJens Wiklander 
2177817466cbSJens Wiklander     while( mbedtls_mpi_cmp_mpi( &V1, N ) >= 0 )
2178817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &V1, &V1, N ) );
2179817466cbSJens Wiklander 
2180817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, &V1 ) );
2181817466cbSJens Wiklander 
2182817466cbSJens Wiklander cleanup:
2183817466cbSJens Wiklander 
2184817466cbSJens Wiklander     mbedtls_mpi_free( &TA ); mbedtls_mpi_free( &TU ); mbedtls_mpi_free( &U1 ); mbedtls_mpi_free( &U2 );
2185817466cbSJens Wiklander     mbedtls_mpi_free( &G ); mbedtls_mpi_free( &TB ); mbedtls_mpi_free( &TV );
2186817466cbSJens Wiklander     mbedtls_mpi_free( &V1 ); mbedtls_mpi_free( &V2 );
2187817466cbSJens Wiklander 
2188817466cbSJens Wiklander     return( ret );
2189817466cbSJens Wiklander }
2190817466cbSJens Wiklander 
2191817466cbSJens Wiklander #if defined(MBEDTLS_GENPRIME)
2192817466cbSJens Wiklander 
2193817466cbSJens Wiklander static const int small_prime[] =
2194817466cbSJens Wiklander {
2195817466cbSJens Wiklander         3,    5,    7,   11,   13,   17,   19,   23,
2196817466cbSJens Wiklander        29,   31,   37,   41,   43,   47,   53,   59,
2197817466cbSJens Wiklander        61,   67,   71,   73,   79,   83,   89,   97,
2198817466cbSJens Wiklander       101,  103,  107,  109,  113,  127,  131,  137,
2199817466cbSJens Wiklander       139,  149,  151,  157,  163,  167,  173,  179,
2200817466cbSJens Wiklander       181,  191,  193,  197,  199,  211,  223,  227,
2201817466cbSJens Wiklander       229,  233,  239,  241,  251,  257,  263,  269,
2202817466cbSJens Wiklander       271,  277,  281,  283,  293,  307,  311,  313,
2203817466cbSJens Wiklander       317,  331,  337,  347,  349,  353,  359,  367,
2204817466cbSJens Wiklander       373,  379,  383,  389,  397,  401,  409,  419,
2205817466cbSJens Wiklander       421,  431,  433,  439,  443,  449,  457,  461,
2206817466cbSJens Wiklander       463,  467,  479,  487,  491,  499,  503,  509,
2207817466cbSJens Wiklander       521,  523,  541,  547,  557,  563,  569,  571,
2208817466cbSJens Wiklander       577,  587,  593,  599,  601,  607,  613,  617,
2209817466cbSJens Wiklander       619,  631,  641,  643,  647,  653,  659,  661,
2210817466cbSJens Wiklander       673,  677,  683,  691,  701,  709,  719,  727,
2211817466cbSJens Wiklander       733,  739,  743,  751,  757,  761,  769,  773,
2212817466cbSJens Wiklander       787,  797,  809,  811,  821,  823,  827,  829,
2213817466cbSJens Wiklander       839,  853,  857,  859,  863,  877,  881,  883,
2214817466cbSJens Wiklander       887,  907,  911,  919,  929,  937,  941,  947,
2215817466cbSJens Wiklander       953,  967,  971,  977,  983,  991,  997, -103
2216817466cbSJens Wiklander };
2217817466cbSJens Wiklander 
2218817466cbSJens Wiklander /*
2219817466cbSJens Wiklander  * Small divisors test (X must be positive)
2220817466cbSJens Wiklander  *
2221817466cbSJens Wiklander  * Return values:
2222817466cbSJens Wiklander  * 0: no small factor (possible prime, more tests needed)
2223817466cbSJens Wiklander  * 1: certain prime
2224817466cbSJens Wiklander  * MBEDTLS_ERR_MPI_NOT_ACCEPTABLE: certain non-prime
2225817466cbSJens Wiklander  * other negative: error
2226817466cbSJens Wiklander  */
2227817466cbSJens Wiklander static int mpi_check_small_factors( const mbedtls_mpi *X )
2228817466cbSJens Wiklander {
2229817466cbSJens Wiklander     int ret = 0;
2230817466cbSJens Wiklander     size_t i;
2231817466cbSJens Wiklander     mbedtls_mpi_uint r;
2232817466cbSJens Wiklander 
2233817466cbSJens Wiklander     if( ( X->p[0] & 1 ) == 0 )
2234817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE );
2235817466cbSJens Wiklander 
2236817466cbSJens Wiklander     for( i = 0; small_prime[i] > 0; i++ )
2237817466cbSJens Wiklander     {
2238817466cbSJens Wiklander         if( mbedtls_mpi_cmp_int( X, small_prime[i] ) <= 0 )
2239817466cbSJens Wiklander             return( 1 );
2240817466cbSJens Wiklander 
2241817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mod_int( &r, X, small_prime[i] ) );
2242817466cbSJens Wiklander 
2243817466cbSJens Wiklander         if( r == 0 )
2244817466cbSJens Wiklander             return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE );
2245817466cbSJens Wiklander     }
2246817466cbSJens Wiklander 
2247817466cbSJens Wiklander cleanup:
2248817466cbSJens Wiklander     return( ret );
2249817466cbSJens Wiklander }
2250817466cbSJens Wiklander 
2251817466cbSJens Wiklander /*
2252817466cbSJens Wiklander  * Miller-Rabin pseudo-primality test  (HAC 4.24)
2253817466cbSJens Wiklander  */
22543d3b0591SJens Wiklander static int mpi_miller_rabin( const mbedtls_mpi *X, size_t rounds,
2255817466cbSJens Wiklander                              int (*f_rng)(void *, unsigned char *, size_t),
2256817466cbSJens Wiklander                              void *p_rng )
2257817466cbSJens Wiklander {
2258817466cbSJens Wiklander     int ret, count;
22593d3b0591SJens Wiklander     size_t i, j, k, s;
2260817466cbSJens Wiklander     mbedtls_mpi W, R, T, A, RR;
2261817466cbSJens Wiklander 
22623d3b0591SJens Wiklander     MPI_VALIDATE_RET( X     != NULL );
22633d3b0591SJens Wiklander     MPI_VALIDATE_RET( f_rng != NULL );
22643d3b0591SJens Wiklander 
226598bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &W ); mbedtls_mpi_init_mempool( &R );
226698bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &T ); mbedtls_mpi_init_mempool( &A );
226798bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &RR );
2268817466cbSJens Wiklander 
2269817466cbSJens Wiklander     /*
2270817466cbSJens Wiklander      * W = |X| - 1
2271817466cbSJens Wiklander      * R = W >> lsb( W )
2272817466cbSJens Wiklander      */
2273817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &W, X, 1 ) );
2274817466cbSJens Wiklander     s = mbedtls_mpi_lsb( &W );
2275817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &R, &W ) );
2276817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &R, s ) );
2277817466cbSJens Wiklander 
2278817466cbSJens Wiklander     i = mbedtls_mpi_bitlen( X );
2279817466cbSJens Wiklander 
22803d3b0591SJens Wiklander     for( i = 0; i < rounds; i++ )
2281817466cbSJens Wiklander     {
2282817466cbSJens Wiklander         /*
2283817466cbSJens Wiklander          * pick a random A, 1 < A < |X| - 1
2284817466cbSJens Wiklander          */
2285817466cbSJens Wiklander         count = 0;
2286817466cbSJens Wiklander         do {
2287817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &A, X->n * ciL, f_rng, p_rng ) );
2288817466cbSJens Wiklander 
2289817466cbSJens Wiklander             j = mbedtls_mpi_bitlen( &A );
2290817466cbSJens Wiklander             k = mbedtls_mpi_bitlen( &W );
2291817466cbSJens Wiklander             if (j > k) {
22923d3b0591SJens Wiklander                 A.p[A.n - 1] &= ( (mbedtls_mpi_uint) 1 << ( k - ( A.n - 1 ) * biL - 1 ) ) - 1;
2293817466cbSJens Wiklander             }
2294817466cbSJens Wiklander 
2295117cce93SJens Wiklander             if (count++ > 300) {
2296336e3299SJens Wiklander                 ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2297336e3299SJens Wiklander                 goto cleanup;
2298817466cbSJens Wiklander             }
2299817466cbSJens Wiklander 
2300817466cbSJens Wiklander         } while ( mbedtls_mpi_cmp_mpi( &A, &W ) >= 0 ||
2301817466cbSJens Wiklander                   mbedtls_mpi_cmp_int( &A, 1 )  <= 0    );
2302817466cbSJens Wiklander 
2303817466cbSJens Wiklander         /*
2304817466cbSJens Wiklander          * A = A^R mod |X|
2305817466cbSJens Wiklander          */
2306817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &A, &A, &R, X, &RR ) );
2307817466cbSJens Wiklander 
2308817466cbSJens Wiklander         if( mbedtls_mpi_cmp_mpi( &A, &W ) == 0 ||
2309817466cbSJens Wiklander             mbedtls_mpi_cmp_int( &A,  1 ) == 0 )
2310817466cbSJens Wiklander             continue;
2311817466cbSJens Wiklander 
2312817466cbSJens Wiklander         j = 1;
2313817466cbSJens Wiklander         while( j < s && mbedtls_mpi_cmp_mpi( &A, &W ) != 0 )
2314817466cbSJens Wiklander         {
2315817466cbSJens Wiklander             /*
2316817466cbSJens Wiklander              * A = A * A mod |X|
2317817466cbSJens Wiklander              */
2318817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T, &A, &A ) );
2319817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &A, &T, X  ) );
2320817466cbSJens Wiklander 
2321817466cbSJens Wiklander             if( mbedtls_mpi_cmp_int( &A, 1 ) == 0 )
2322817466cbSJens Wiklander                 break;
2323817466cbSJens Wiklander 
2324817466cbSJens Wiklander             j++;
2325817466cbSJens Wiklander         }
2326817466cbSJens Wiklander 
2327817466cbSJens Wiklander         /*
2328817466cbSJens Wiklander          * not prime if A != |X| - 1 or A == 1
2329817466cbSJens Wiklander          */
2330817466cbSJens Wiklander         if( mbedtls_mpi_cmp_mpi( &A, &W ) != 0 ||
2331817466cbSJens Wiklander             mbedtls_mpi_cmp_int( &A,  1 ) == 0 )
2332817466cbSJens Wiklander         {
2333817466cbSJens Wiklander             ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2334817466cbSJens Wiklander             break;
2335817466cbSJens Wiklander         }
2336817466cbSJens Wiklander     }
2337817466cbSJens Wiklander 
2338817466cbSJens Wiklander cleanup:
23393d3b0591SJens Wiklander     mbedtls_mpi_free( &W ); mbedtls_mpi_free( &R );
23403d3b0591SJens Wiklander     mbedtls_mpi_free( &T ); mbedtls_mpi_free( &A );
2341817466cbSJens Wiklander     mbedtls_mpi_free( &RR );
2342817466cbSJens Wiklander 
2343817466cbSJens Wiklander     return( ret );
2344817466cbSJens Wiklander }
2345817466cbSJens Wiklander 
2346817466cbSJens Wiklander /*
2347817466cbSJens Wiklander  * Pseudo-primality test: small factors, then Miller-Rabin
2348817466cbSJens Wiklander  */
23493d3b0591SJens Wiklander int mbedtls_mpi_is_prime_ext( const mbedtls_mpi *X, int rounds,
2350817466cbSJens Wiklander                               int (*f_rng)(void *, unsigned char *, size_t),
2351817466cbSJens Wiklander                               void *p_rng )
2352817466cbSJens Wiklander {
2353817466cbSJens Wiklander     int ret;
2354817466cbSJens Wiklander     mbedtls_mpi XX;
23553d3b0591SJens Wiklander     MPI_VALIDATE_RET( X     != NULL );
23563d3b0591SJens Wiklander     MPI_VALIDATE_RET( f_rng != NULL );
2357817466cbSJens Wiklander 
2358817466cbSJens Wiklander     XX.s = 1;
2359817466cbSJens Wiklander     XX.n = X->n;
2360817466cbSJens Wiklander     XX.p = X->p;
2361817466cbSJens Wiklander 
2362817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( &XX, 0 ) == 0 ||
2363817466cbSJens Wiklander         mbedtls_mpi_cmp_int( &XX, 1 ) == 0 )
2364817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE );
2365817466cbSJens Wiklander 
2366817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( &XX, 2 ) == 0 )
2367817466cbSJens Wiklander         return( 0 );
2368817466cbSJens Wiklander 
2369817466cbSJens Wiklander     if( ( ret = mpi_check_small_factors( &XX ) ) != 0 )
2370817466cbSJens Wiklander     {
2371817466cbSJens Wiklander         if( ret == 1 )
2372817466cbSJens Wiklander             return( 0 );
2373817466cbSJens Wiklander 
2374817466cbSJens Wiklander         return( ret );
2375817466cbSJens Wiklander     }
2376817466cbSJens Wiklander 
23773d3b0591SJens Wiklander     return( mpi_miller_rabin( &XX, rounds, f_rng, p_rng ) );
2378817466cbSJens Wiklander }
2379817466cbSJens Wiklander 
23803d3b0591SJens Wiklander #if !defined(MBEDTLS_DEPRECATED_REMOVED)
2381817466cbSJens Wiklander /*
23823d3b0591SJens Wiklander  * Pseudo-primality test, error probability 2^-80
2383817466cbSJens Wiklander  */
23843d3b0591SJens Wiklander int mbedtls_mpi_is_prime( const mbedtls_mpi *X,
2385817466cbSJens Wiklander                   int (*f_rng)(void *, unsigned char *, size_t),
2386817466cbSJens Wiklander                   void *p_rng )
2387817466cbSJens Wiklander {
23883d3b0591SJens Wiklander     MPI_VALIDATE_RET( X     != NULL );
23893d3b0591SJens Wiklander     MPI_VALIDATE_RET( f_rng != NULL );
23903d3b0591SJens Wiklander 
23913d3b0591SJens Wiklander     /*
23923d3b0591SJens Wiklander      * In the past our key generation aimed for an error rate of at most
23933d3b0591SJens Wiklander      * 2^-80. Since this function is deprecated, aim for the same certainty
23943d3b0591SJens Wiklander      * here as well.
23953d3b0591SJens Wiklander      */
23963d3b0591SJens Wiklander     return( mbedtls_mpi_is_prime_ext( X, 40, f_rng, p_rng ) );
23973d3b0591SJens Wiklander }
23983d3b0591SJens Wiklander #endif
23993d3b0591SJens Wiklander 
24003d3b0591SJens Wiklander /*
24013d3b0591SJens Wiklander  * Prime number generation
24023d3b0591SJens Wiklander  *
24033d3b0591SJens Wiklander  * To generate an RSA key in a way recommended by FIPS 186-4, both primes must
24043d3b0591SJens Wiklander  * be either 1024 bits or 1536 bits long, and flags must contain
24053d3b0591SJens Wiklander  * MBEDTLS_MPI_GEN_PRIME_FLAG_LOW_ERR.
24063d3b0591SJens Wiklander  */
24073d3b0591SJens Wiklander int mbedtls_mpi_gen_prime( mbedtls_mpi *X, size_t nbits, int flags,
24083d3b0591SJens Wiklander                    int (*f_rng)(void *, unsigned char *, size_t),
24093d3b0591SJens Wiklander                    void *p_rng )
24103d3b0591SJens Wiklander {
24113d3b0591SJens Wiklander #ifdef MBEDTLS_HAVE_INT64
24123d3b0591SJens Wiklander // ceil(2^63.5)
24133d3b0591SJens Wiklander #define CEIL_MAXUINT_DIV_SQRT2 0xb504f333f9de6485ULL
24143d3b0591SJens Wiklander #else
24153d3b0591SJens Wiklander // ceil(2^31.5)
24163d3b0591SJens Wiklander #define CEIL_MAXUINT_DIV_SQRT2 0xb504f334U
24173d3b0591SJens Wiklander #endif
24183d3b0591SJens Wiklander     int ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2419817466cbSJens Wiklander     size_t k, n;
24203d3b0591SJens Wiklander     int rounds;
2421817466cbSJens Wiklander     mbedtls_mpi_uint r;
2422817466cbSJens Wiklander     mbedtls_mpi Y;
2423817466cbSJens Wiklander 
24243d3b0591SJens Wiklander     MPI_VALIDATE_RET( X     != NULL );
24253d3b0591SJens Wiklander     MPI_VALIDATE_RET( f_rng != NULL );
24263d3b0591SJens Wiklander 
2427817466cbSJens Wiklander     if( nbits < 3 || nbits > MBEDTLS_MPI_MAX_BITS )
2428817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
2429817466cbSJens Wiklander 
243098bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &Y );
2431817466cbSJens Wiklander 
2432817466cbSJens Wiklander     n = BITS_TO_LIMBS( nbits );
2433817466cbSJens Wiklander 
24343d3b0591SJens Wiklander     if( ( flags & MBEDTLS_MPI_GEN_PRIME_FLAG_LOW_ERR ) == 0 )
24353d3b0591SJens Wiklander     {
24363d3b0591SJens Wiklander         /*
24373d3b0591SJens Wiklander          * 2^-80 error probability, number of rounds chosen per HAC, table 4.4
24383d3b0591SJens Wiklander          */
24393d3b0591SJens Wiklander         rounds = ( ( nbits >= 1300 ) ?  2 : ( nbits >=  850 ) ?  3 :
24403d3b0591SJens Wiklander                    ( nbits >=  650 ) ?  4 : ( nbits >=  350 ) ?  8 :
24413d3b0591SJens Wiklander                    ( nbits >=  250 ) ? 12 : ( nbits >=  150 ) ? 18 : 27 );
24423d3b0591SJens Wiklander     }
24433d3b0591SJens Wiklander     else
24443d3b0591SJens Wiklander     {
24453d3b0591SJens Wiklander         /*
24463d3b0591SJens Wiklander          * 2^-100 error probability, number of rounds computed based on HAC,
24473d3b0591SJens Wiklander          * fact 4.48
24483d3b0591SJens Wiklander          */
24493d3b0591SJens Wiklander         rounds = ( ( nbits >= 1450 ) ?  4 : ( nbits >=  1150 ) ?  5 :
24503d3b0591SJens Wiklander                    ( nbits >= 1000 ) ?  6 : ( nbits >=   850 ) ?  7 :
24513d3b0591SJens Wiklander                    ( nbits >=  750 ) ?  8 : ( nbits >=   500 ) ? 13 :
24523d3b0591SJens Wiklander                    ( nbits >=  250 ) ? 28 : ( nbits >=   150 ) ? 40 : 51 );
24533d3b0591SJens Wiklander     }
24543d3b0591SJens Wiklander 
24553d3b0591SJens Wiklander     while( 1 )
24563d3b0591SJens Wiklander     {
2457817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( X, n * ciL, f_rng, p_rng ) );
24583d3b0591SJens Wiklander         /* make sure generated number is at least (nbits-1)+0.5 bits (FIPS 186-4 §B.3.3 steps 4.4, 5.5) */
24593d3b0591SJens Wiklander         if( X->p[n-1] < CEIL_MAXUINT_DIV_SQRT2 ) continue;
2460817466cbSJens Wiklander 
24613d3b0591SJens Wiklander         k = n * biL;
24623d3b0591SJens Wiklander         if( k > nbits ) MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( X, k - nbits ) );
2463817466cbSJens Wiklander         X->p[0] |= 1;
2464817466cbSJens Wiklander 
24653d3b0591SJens Wiklander         if( ( flags & MBEDTLS_MPI_GEN_PRIME_FLAG_DH ) == 0 )
2466817466cbSJens Wiklander         {
24673d3b0591SJens Wiklander             ret = mbedtls_mpi_is_prime_ext( X, rounds, f_rng, p_rng );
24683d3b0591SJens Wiklander 
2469817466cbSJens Wiklander             if( ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE )
2470817466cbSJens Wiklander                 goto cleanup;
2471817466cbSJens Wiklander         }
2472817466cbSJens Wiklander         else
2473817466cbSJens Wiklander         {
2474817466cbSJens Wiklander             /*
2475817466cbSJens Wiklander              * An necessary condition for Y and X = 2Y + 1 to be prime
2476817466cbSJens Wiklander              * is X = 2 mod 3 (which is equivalent to Y = 2 mod 3).
2477817466cbSJens Wiklander              * Make sure it is satisfied, while keeping X = 3 mod 4
2478817466cbSJens Wiklander              */
2479817466cbSJens Wiklander 
2480817466cbSJens Wiklander             X->p[0] |= 2;
2481817466cbSJens Wiklander 
2482817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_mod_int( &r, X, 3 ) );
2483817466cbSJens Wiklander             if( r == 0 )
2484817466cbSJens Wiklander                 MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, X, 8 ) );
2485817466cbSJens Wiklander             else if( r == 1 )
2486817466cbSJens Wiklander                 MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, X, 4 ) );
2487817466cbSJens Wiklander 
2488817466cbSJens Wiklander             /* Set Y = (X-1) / 2, which is X / 2 because X is odd */
2489817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &Y, X ) );
2490817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &Y, 1 ) );
2491817466cbSJens Wiklander 
2492817466cbSJens Wiklander             while( 1 )
2493817466cbSJens Wiklander             {
2494817466cbSJens Wiklander                 /*
2495817466cbSJens Wiklander                  * First, check small factors for X and Y
2496817466cbSJens Wiklander                  * before doing Miller-Rabin on any of them
2497817466cbSJens Wiklander                  */
2498817466cbSJens Wiklander                 if( ( ret = mpi_check_small_factors(  X         ) ) == 0 &&
2499817466cbSJens Wiklander                     ( ret = mpi_check_small_factors( &Y         ) ) == 0 &&
25003d3b0591SJens Wiklander                     ( ret = mpi_miller_rabin(  X, rounds, f_rng, p_rng  ) )
25013d3b0591SJens Wiklander                                                                     == 0 &&
25023d3b0591SJens Wiklander                     ( ret = mpi_miller_rabin( &Y, rounds, f_rng, p_rng  ) )
25033d3b0591SJens Wiklander                                                                     == 0 )
25043d3b0591SJens Wiklander                     goto cleanup;
2505817466cbSJens Wiklander 
2506817466cbSJens Wiklander                 if( ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE )
2507817466cbSJens Wiklander                     goto cleanup;
2508817466cbSJens Wiklander 
2509817466cbSJens Wiklander                 /*
2510817466cbSJens Wiklander                  * Next candidates. We want to preserve Y = (X-1) / 2 and
2511817466cbSJens Wiklander                  * Y = 1 mod 2 and Y = 2 mod 3 (eq X = 3 mod 4 and X = 2 mod 3)
2512817466cbSJens Wiklander                  * so up Y by 6 and X by 12.
2513817466cbSJens Wiklander                  */
2514817466cbSJens Wiklander                 MBEDTLS_MPI_CHK( mbedtls_mpi_add_int(  X,  X, 12 ) );
2515817466cbSJens Wiklander                 MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( &Y, &Y, 6  ) );
2516817466cbSJens Wiklander             }
2517817466cbSJens Wiklander         }
25183d3b0591SJens Wiklander     }
2519817466cbSJens Wiklander 
2520817466cbSJens Wiklander cleanup:
2521817466cbSJens Wiklander 
2522817466cbSJens Wiklander     mbedtls_mpi_free( &Y );
2523817466cbSJens Wiklander 
2524817466cbSJens Wiklander     return( ret );
2525817466cbSJens Wiklander }
2526817466cbSJens Wiklander 
2527817466cbSJens Wiklander #endif /* MBEDTLS_GENPRIME */
2528817466cbSJens Wiklander 
2529817466cbSJens Wiklander #if defined(MBEDTLS_SELF_TEST)
2530817466cbSJens Wiklander 
2531817466cbSJens Wiklander #define GCD_PAIR_COUNT  3
2532817466cbSJens Wiklander 
2533817466cbSJens Wiklander static const int gcd_pairs[GCD_PAIR_COUNT][3] =
2534817466cbSJens Wiklander {
2535817466cbSJens Wiklander     { 693, 609, 21 },
2536817466cbSJens Wiklander     { 1764, 868, 28 },
2537817466cbSJens Wiklander     { 768454923, 542167814, 1 }
2538817466cbSJens Wiklander };
2539817466cbSJens Wiklander 
2540817466cbSJens Wiklander /*
2541817466cbSJens Wiklander  * Checkup routine
2542817466cbSJens Wiklander  */
2543817466cbSJens Wiklander int mbedtls_mpi_self_test( int verbose )
2544817466cbSJens Wiklander {
2545817466cbSJens Wiklander     int ret, i;
2546817466cbSJens Wiklander     mbedtls_mpi A, E, N, X, Y, U, V;
2547817466cbSJens Wiklander 
254898bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &A ); mbedtls_mpi_init_mempool( &E );
254998bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &N ); mbedtls_mpi_init_mempool( &X );
255098bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &Y ); mbedtls_mpi_init_mempool( &U );
255198bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &V );
2552817466cbSJens Wiklander 
2553817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &A, 16,
2554817466cbSJens Wiklander         "EFE021C2645FD1DC586E69184AF4A31E" \
2555817466cbSJens Wiklander         "D5F53E93B5F123FA41680867BA110131" \
2556817466cbSJens Wiklander         "944FE7952E2517337780CB0DB80E61AA" \
2557817466cbSJens Wiklander         "E7C8DDC6C5C6AADEB34EB38A2F40D5E6" ) );
2558817466cbSJens Wiklander 
2559817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &E, 16,
2560817466cbSJens Wiklander         "B2E7EFD37075B9F03FF989C7C5051C20" \
2561817466cbSJens Wiklander         "34D2A323810251127E7BF8625A4F49A5" \
2562817466cbSJens Wiklander         "F3E27F4DA8BD59C47D6DAABA4C8127BD" \
2563817466cbSJens Wiklander         "5B5C25763222FEFCCFC38B832366C29E" ) );
2564817466cbSJens Wiklander 
2565817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &N, 16,
2566817466cbSJens Wiklander         "0066A198186C18C10B2F5ED9B522752A" \
2567817466cbSJens Wiklander         "9830B69916E535C8F047518A889A43A5" \
2568817466cbSJens Wiklander         "94B6BED27A168D31D4A52F88925AA8F5" ) );
2569817466cbSJens Wiklander 
2570817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &X, &A, &N ) );
2571817466cbSJens Wiklander 
2572817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &U, 16,
2573817466cbSJens Wiklander         "602AB7ECA597A3D6B56FF9829A5E8B85" \
2574817466cbSJens Wiklander         "9E857EA95A03512E2BAE7391688D264A" \
2575817466cbSJens Wiklander         "A5663B0341DB9CCFD2C4C5F421FEC814" \
2576817466cbSJens Wiklander         "8001B72E848A38CAE1C65F78E56ABDEF" \
2577817466cbSJens Wiklander         "E12D3C039B8A02D6BE593F0BBBDA56F1" \
2578817466cbSJens Wiklander         "ECF677152EF804370C1A305CAF3B5BF1" \
2579817466cbSJens Wiklander         "30879B56C61DE584A0F53A2447A51E" ) );
2580817466cbSJens Wiklander 
2581817466cbSJens Wiklander     if( verbose != 0 )
2582817466cbSJens Wiklander         mbedtls_printf( "  MPI test #1 (mul_mpi): " );
2583817466cbSJens Wiklander 
2584817466cbSJens Wiklander     if( mbedtls_mpi_cmp_mpi( &X, &U ) != 0 )
2585817466cbSJens Wiklander     {
2586817466cbSJens Wiklander         if( verbose != 0 )
2587817466cbSJens Wiklander             mbedtls_printf( "failed\n" );
2588817466cbSJens Wiklander 
2589817466cbSJens Wiklander         ret = 1;
2590817466cbSJens Wiklander         goto cleanup;
2591817466cbSJens Wiklander     }
2592817466cbSJens Wiklander 
2593817466cbSJens Wiklander     if( verbose != 0 )
2594817466cbSJens Wiklander         mbedtls_printf( "passed\n" );
2595817466cbSJens Wiklander 
2596817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_div_mpi( &X, &Y, &A, &N ) );
2597817466cbSJens Wiklander 
2598817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &U, 16,
2599817466cbSJens Wiklander         "256567336059E52CAE22925474705F39A94" ) );
2600817466cbSJens Wiklander 
2601817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &V, 16,
2602817466cbSJens Wiklander         "6613F26162223DF488E9CD48CC132C7A" \
2603817466cbSJens Wiklander         "0AC93C701B001B092E4E5B9F73BCD27B" \
2604817466cbSJens Wiklander         "9EE50D0657C77F374E903CDFA4C642" ) );
2605817466cbSJens Wiklander 
2606817466cbSJens Wiklander     if( verbose != 0 )
2607817466cbSJens Wiklander         mbedtls_printf( "  MPI test #2 (div_mpi): " );
2608817466cbSJens Wiklander 
2609817466cbSJens Wiklander     if( mbedtls_mpi_cmp_mpi( &X, &U ) != 0 ||
2610817466cbSJens Wiklander         mbedtls_mpi_cmp_mpi( &Y, &V ) != 0 )
2611817466cbSJens Wiklander     {
2612817466cbSJens Wiklander         if( verbose != 0 )
2613817466cbSJens Wiklander             mbedtls_printf( "failed\n" );
2614817466cbSJens Wiklander 
2615817466cbSJens Wiklander         ret = 1;
2616817466cbSJens Wiklander         goto cleanup;
2617817466cbSJens Wiklander     }
2618817466cbSJens Wiklander 
2619817466cbSJens Wiklander     if( verbose != 0 )
2620817466cbSJens Wiklander         mbedtls_printf( "passed\n" );
2621817466cbSJens Wiklander 
2622817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &X, &A, &E, &N, NULL ) );
2623817466cbSJens Wiklander 
2624817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &U, 16,
2625817466cbSJens Wiklander         "36E139AEA55215609D2816998ED020BB" \
2626817466cbSJens Wiklander         "BD96C37890F65171D948E9BC7CBAA4D9" \
2627817466cbSJens Wiklander         "325D24D6A3C12710F10A09FA08AB87" ) );
2628817466cbSJens Wiklander 
2629817466cbSJens Wiklander     if( verbose != 0 )
2630817466cbSJens Wiklander         mbedtls_printf( "  MPI test #3 (exp_mod): " );
2631817466cbSJens Wiklander 
2632817466cbSJens Wiklander     if( mbedtls_mpi_cmp_mpi( &X, &U ) != 0 )
2633817466cbSJens Wiklander     {
2634817466cbSJens Wiklander         if( verbose != 0 )
2635817466cbSJens Wiklander             mbedtls_printf( "failed\n" );
2636817466cbSJens Wiklander 
2637817466cbSJens Wiklander         ret = 1;
2638817466cbSJens Wiklander         goto cleanup;
2639817466cbSJens Wiklander     }
2640817466cbSJens Wiklander 
2641817466cbSJens Wiklander     if( verbose != 0 )
2642817466cbSJens Wiklander         mbedtls_printf( "passed\n" );
2643817466cbSJens Wiklander 
2644817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &X, &A, &N ) );
2645817466cbSJens Wiklander 
2646817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &U, 16,
2647817466cbSJens Wiklander         "003A0AAEDD7E784FC07D8F9EC6E3BFD5" \
2648817466cbSJens Wiklander         "C3DBA76456363A10869622EAC2DD84EC" \
2649817466cbSJens Wiklander         "C5B8A74DAC4D09E03B5E0BE779F2DF61" ) );
2650817466cbSJens Wiklander 
2651817466cbSJens Wiklander     if( verbose != 0 )
2652817466cbSJens Wiklander         mbedtls_printf( "  MPI test #4 (inv_mod): " );
2653817466cbSJens Wiklander 
2654817466cbSJens Wiklander     if( mbedtls_mpi_cmp_mpi( &X, &U ) != 0 )
2655817466cbSJens Wiklander     {
2656817466cbSJens Wiklander         if( verbose != 0 )
2657817466cbSJens Wiklander             mbedtls_printf( "failed\n" );
2658817466cbSJens Wiklander 
2659817466cbSJens Wiklander         ret = 1;
2660817466cbSJens Wiklander         goto cleanup;
2661817466cbSJens Wiklander     }
2662817466cbSJens Wiklander 
2663817466cbSJens Wiklander     if( verbose != 0 )
2664817466cbSJens Wiklander         mbedtls_printf( "passed\n" );
2665817466cbSJens Wiklander 
2666817466cbSJens Wiklander     if( verbose != 0 )
2667817466cbSJens Wiklander         mbedtls_printf( "  MPI test #5 (simple gcd): " );
2668817466cbSJens Wiklander 
2669817466cbSJens Wiklander     for( i = 0; i < GCD_PAIR_COUNT; i++ )
2670817466cbSJens Wiklander     {
2671817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &X, gcd_pairs[i][0] ) );
2672817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &Y, gcd_pairs[i][1] ) );
2673817466cbSJens Wiklander 
2674817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &A, &X, &Y ) );
2675817466cbSJens Wiklander 
2676817466cbSJens Wiklander         if( mbedtls_mpi_cmp_int( &A, gcd_pairs[i][2] ) != 0 )
2677817466cbSJens Wiklander         {
2678817466cbSJens Wiklander             if( verbose != 0 )
2679817466cbSJens Wiklander                 mbedtls_printf( "failed at %d\n", i );
2680817466cbSJens Wiklander 
2681817466cbSJens Wiklander             ret = 1;
2682817466cbSJens Wiklander             goto cleanup;
2683817466cbSJens Wiklander         }
2684817466cbSJens Wiklander     }
2685817466cbSJens Wiklander 
2686817466cbSJens Wiklander     if( verbose != 0 )
2687817466cbSJens Wiklander         mbedtls_printf( "passed\n" );
2688817466cbSJens Wiklander 
2689817466cbSJens Wiklander cleanup:
2690817466cbSJens Wiklander 
2691817466cbSJens Wiklander     if( ret != 0 && verbose != 0 )
2692817466cbSJens Wiklander         mbedtls_printf( "Unexpected error, return code = %08X\n", ret );
2693817466cbSJens Wiklander 
2694817466cbSJens Wiklander     mbedtls_mpi_free( &A ); mbedtls_mpi_free( &E ); mbedtls_mpi_free( &N ); mbedtls_mpi_free( &X );
2695817466cbSJens Wiklander     mbedtls_mpi_free( &Y ); mbedtls_mpi_free( &U ); mbedtls_mpi_free( &V );
2696817466cbSJens Wiklander 
2697817466cbSJens Wiklander     if( verbose != 0 )
2698817466cbSJens Wiklander         mbedtls_printf( "\n" );
2699817466cbSJens Wiklander 
2700817466cbSJens Wiklander     return( ret );
2701817466cbSJens Wiklander }
2702817466cbSJens Wiklander 
2703817466cbSJens Wiklander #endif /* MBEDTLS_SELF_TEST */
2704817466cbSJens Wiklander 
2705817466cbSJens Wiklander #endif /* MBEDTLS_BIGNUM_C */
2706