xref: /optee_os/lib/libmbedtls/mbedtls/library/bignum.c (revision 117cce93afaaf8beff411c9b29238825bfbdefd9)
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"
48817466cbSJens Wiklander 
49817466cbSJens Wiklander #include <string.h>
50817466cbSJens Wiklander 
51817466cbSJens Wiklander #if defined(MBEDTLS_PLATFORM_C)
52817466cbSJens Wiklander #include "mbedtls/platform.h"
53817466cbSJens Wiklander #else
54817466cbSJens Wiklander #include <stdio.h>
55817466cbSJens Wiklander #include <stdlib.h>
56817466cbSJens Wiklander #define mbedtls_printf     printf
57817466cbSJens Wiklander #define mbedtls_calloc    calloc
58817466cbSJens Wiklander #define mbedtls_free       free
59817466cbSJens Wiklander #endif
60817466cbSJens Wiklander 
6198bd5fe3SJens Wiklander #include <mempool.h>
6298bd5fe3SJens Wiklander 
63817466cbSJens Wiklander /* Implementation that should never be optimized out by the compiler */
64817466cbSJens Wiklander static void mbedtls_mpi_zeroize( mbedtls_mpi_uint *v, size_t n ) {
65817466cbSJens Wiklander     volatile mbedtls_mpi_uint *p = v; while( n-- ) *p++ = 0;
66817466cbSJens Wiklander }
67817466cbSJens Wiklander 
68817466cbSJens Wiklander #define ciL    (sizeof(mbedtls_mpi_uint))         /* chars in limb  */
69817466cbSJens Wiklander #define biL    (ciL << 3)               /* bits  in limb  */
70817466cbSJens Wiklander #define biH    (ciL << 2)               /* half limb size */
71817466cbSJens Wiklander 
72817466cbSJens Wiklander #define MPI_SIZE_T_MAX  ( (size_t) -1 ) /* SIZE_T_MAX is not standard */
73817466cbSJens Wiklander 
74817466cbSJens Wiklander /*
75817466cbSJens Wiklander  * Convert between bits/chars and number of limbs
76817466cbSJens Wiklander  * Divide first in order to avoid potential overflows
77817466cbSJens Wiklander  */
78817466cbSJens Wiklander #define BITS_TO_LIMBS(i)  ( (i) / biL + ( (i) % biL != 0 ) )
79817466cbSJens Wiklander #define CHARS_TO_LIMBS(i) ( (i) / ciL + ( (i) % ciL != 0 ) )
80817466cbSJens Wiklander 
8198bd5fe3SJens Wiklander void *mbedtls_mpi_mempool;
8298bd5fe3SJens Wiklander 
83817466cbSJens Wiklander /*
84817466cbSJens Wiklander  * Initialize one MPI
85817466cbSJens Wiklander  */
8618c5148dSJens Wiklander static void mpi_init( mbedtls_mpi *X, enum mbedtls_mpi_alloc_type alloc_type,
8718c5148dSJens Wiklander 		      mbedtls_mpi_uint *p, int sign, size_t alloc_size,
8818c5148dSJens Wiklander                       size_t nblimbs)
89817466cbSJens Wiklander {
90817466cbSJens Wiklander     if( X == NULL )
91817466cbSJens Wiklander         return;
92817466cbSJens Wiklander 
9318c5148dSJens Wiklander     X->s = sign;
9418c5148dSJens Wiklander     X->alloc_type = alloc_type;
9518c5148dSJens Wiklander     X->alloc_size = alloc_size;
9618c5148dSJens Wiklander     X->n = nblimbs;
9718c5148dSJens Wiklander     X->p = p;
98817466cbSJens Wiklander }
99817466cbSJens Wiklander 
10098bd5fe3SJens Wiklander void mbedtls_mpi_init( mbedtls_mpi *X )
10198bd5fe3SJens Wiklander {
10218c5148dSJens Wiklander     mpi_init(X, MBEDTLS_MPI_ALLOC_TYPE_MALLOC, NULL, 1, 0, 0);
10398bd5fe3SJens Wiklander }
10498bd5fe3SJens Wiklander 
10598bd5fe3SJens Wiklander void mbedtls_mpi_init_mempool( mbedtls_mpi *X )
10698bd5fe3SJens Wiklander {
10718c5148dSJens Wiklander     if( mbedtls_mpi_mempool )
10818c5148dSJens Wiklander         mpi_init(X, MBEDTLS_MPI_ALLOC_TYPE_MEMPOOL, NULL, 1, 0, 0);
10918c5148dSJens Wiklander     else
11018c5148dSJens Wiklander         mbedtls_mpi_init( X );
11118c5148dSJens Wiklander }
11218c5148dSJens Wiklander 
11318c5148dSJens Wiklander void mbedtls_mpi_init_static( mbedtls_mpi *X , mbedtls_mpi_uint *p,
11418c5148dSJens Wiklander                               int sign, size_t alloc_size, size_t nblimbs)
11518c5148dSJens Wiklander {
11618c5148dSJens Wiklander     mpi_init(X, MBEDTLS_MPI_ALLOC_TYPE_STATIC, p, sign, alloc_size, nblimbs);
11798bd5fe3SJens Wiklander }
11898bd5fe3SJens Wiklander 
119817466cbSJens Wiklander /*
120817466cbSJens Wiklander  * Unallocate one MPI
121817466cbSJens Wiklander  */
122817466cbSJens Wiklander void mbedtls_mpi_free( mbedtls_mpi *X )
123817466cbSJens Wiklander {
124817466cbSJens Wiklander     if( X == NULL )
125817466cbSJens Wiklander         return;
126817466cbSJens Wiklander 
127817466cbSJens Wiklander     if( X->p != NULL )
128817466cbSJens Wiklander     {
129817466cbSJens Wiklander         mbedtls_mpi_zeroize( X->p, X->n );
13018c5148dSJens Wiklander         switch (X->alloc_type) {
13118c5148dSJens Wiklander         case MBEDTLS_MPI_ALLOC_TYPE_MALLOC:
132817466cbSJens Wiklander             mbedtls_free( X->p );
13318c5148dSJens Wiklander             X->p = NULL;
13418c5148dSJens Wiklander             break;
13518c5148dSJens Wiklander         case MBEDTLS_MPI_ALLOC_TYPE_MEMPOOL:
13618c5148dSJens Wiklander             mempool_free( mbedtls_mpi_mempool, X->p );
13718c5148dSJens Wiklander             X->p = NULL;
13818c5148dSJens Wiklander             break;
13918c5148dSJens Wiklander         default:
14018c5148dSJens Wiklander             break;
14118c5148dSJens Wiklander         }
142817466cbSJens Wiklander     }
143817466cbSJens Wiklander 
144817466cbSJens Wiklander     X->s = 1;
145817466cbSJens Wiklander     X->n = 0;
146817466cbSJens Wiklander }
147817466cbSJens Wiklander 
148817466cbSJens Wiklander /*
149817466cbSJens Wiklander  * Enlarge to the specified number of limbs
150817466cbSJens Wiklander  */
151817466cbSJens Wiklander int mbedtls_mpi_grow( mbedtls_mpi *X, size_t nblimbs )
152817466cbSJens Wiklander {
153817466cbSJens Wiklander     mbedtls_mpi_uint *p;
154817466cbSJens Wiklander 
155817466cbSJens Wiklander     if( nblimbs > MBEDTLS_MPI_MAX_LIMBS )
156817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_ALLOC_FAILED );
157817466cbSJens Wiklander 
15818c5148dSJens Wiklander     if( X->n >= nblimbs )
15918c5148dSJens Wiklander         return( 0 );
16018c5148dSJens Wiklander 
16118c5148dSJens Wiklander     switch( X->alloc_type ) {
16218c5148dSJens Wiklander     case MBEDTLS_MPI_ALLOC_TYPE_MALLOC:
16398bd5fe3SJens Wiklander         p = (mbedtls_mpi_uint*)mbedtls_calloc( nblimbs, ciL );
16418c5148dSJens Wiklander         break;
16518c5148dSJens Wiklander     case MBEDTLS_MPI_ALLOC_TYPE_MEMPOOL:
16618c5148dSJens Wiklander         p = mempool_calloc( mbedtls_mpi_mempool, nblimbs, ciL );
16718c5148dSJens Wiklander         break;
16818c5148dSJens Wiklander     case MBEDTLS_MPI_ALLOC_TYPE_STATIC:
16918c5148dSJens Wiklander         if( nblimbs > X->alloc_size )
17098bd5fe3SJens Wiklander             return( MBEDTLS_ERR_MPI_ALLOC_FAILED );
17118c5148dSJens Wiklander         memset( X->p + X->n, 0, (nblimbs - X->n) * ciL );
17218c5148dSJens Wiklander 	goto out;
17318c5148dSJens Wiklander     default:
17418c5148dSJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
17598bd5fe3SJens Wiklander     }
176817466cbSJens Wiklander 
17718c5148dSJens Wiklander     if( p == NULL )
17818c5148dSJens Wiklander         return( MBEDTLS_ERR_MPI_ALLOC_FAILED );
17918c5148dSJens Wiklander 
18018c5148dSJens Wiklander     if( X->p != NULL ) {
181817466cbSJens Wiklander         memcpy( p, X->p, X->n * ciL );
182817466cbSJens Wiklander         mbedtls_mpi_zeroize( X->p, X->n );
183817466cbSJens Wiklander     }
184817466cbSJens Wiklander 
18518c5148dSJens Wiklander 
18618c5148dSJens Wiklander     if( X->alloc_type == MBEDTLS_MPI_ALLOC_TYPE_MALLOC)
18718c5148dSJens Wiklander         mbedtls_free( X->p );
18818c5148dSJens Wiklander     else
18918c5148dSJens Wiklander         mempool_free( mbedtls_mpi_mempool, X->p );
19018c5148dSJens Wiklander 
191817466cbSJens Wiklander     X->p = p;
19218c5148dSJens Wiklander out:
19318c5148dSJens Wiklander     X->n = nblimbs;
194817466cbSJens Wiklander 
195817466cbSJens Wiklander     return( 0 );
196817466cbSJens Wiklander }
197817466cbSJens Wiklander 
198817466cbSJens Wiklander /*
199817466cbSJens Wiklander  * Resize down as much as possible,
200817466cbSJens Wiklander  * while keeping at least the specified number of limbs
201817466cbSJens Wiklander  */
202817466cbSJens Wiklander int mbedtls_mpi_shrink( mbedtls_mpi *X, size_t nblimbs )
203817466cbSJens Wiklander {
204817466cbSJens Wiklander     mbedtls_mpi_uint *p;
205817466cbSJens Wiklander     size_t i;
206817466cbSJens Wiklander 
207817466cbSJens Wiklander     /* Actually resize up in this case */
208817466cbSJens Wiklander     if( X->n <= nblimbs )
209817466cbSJens Wiklander         return( mbedtls_mpi_grow( X, nblimbs ) );
210817466cbSJens Wiklander 
211817466cbSJens Wiklander     for( i = X->n - 1; i > 0; i-- )
212817466cbSJens Wiklander         if( X->p[i] != 0 )
213817466cbSJens Wiklander             break;
214817466cbSJens Wiklander     i++;
215817466cbSJens Wiklander 
216817466cbSJens Wiklander     if( i < nblimbs )
217817466cbSJens Wiklander         i = nblimbs;
218817466cbSJens Wiklander 
21918c5148dSJens Wiklander     switch (X->alloc_type) {
22018c5148dSJens Wiklander     case MBEDTLS_MPI_ALLOC_TYPE_MALLOC:
22198bd5fe3SJens Wiklander             p = (mbedtls_mpi_uint*)mbedtls_calloc( nblimbs, ciL );
22218c5148dSJens Wiklander             break;
22318c5148dSJens Wiklander     case MBEDTLS_MPI_ALLOC_TYPE_MEMPOOL:
22418c5148dSJens Wiklander             p = mempool_calloc(mbedtls_mpi_mempool, nblimbs, ciL);
22518c5148dSJens Wiklander             break;
22618c5148dSJens Wiklander     case MBEDTLS_MPI_ALLOC_TYPE_STATIC:
22718c5148dSJens Wiklander         if (nblimbs > X->alloc_size)
22898bd5fe3SJens Wiklander             return( MBEDTLS_ERR_MPI_ALLOC_FAILED );
22918c5148dSJens Wiklander         mbedtls_mpi_zeroize(X->p + i, X->n - i);
23018c5148dSJens Wiklander         goto out;
23118c5148dSJens Wiklander 
23218c5148dSJens Wiklander     default:
23318c5148dSJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
23498bd5fe3SJens Wiklander     }
235817466cbSJens Wiklander 
23618c5148dSJens Wiklander 
237817466cbSJens Wiklander     if( X->p != NULL )
238817466cbSJens Wiklander     {
239817466cbSJens Wiklander         memcpy( p, X->p, i * ciL );
240817466cbSJens Wiklander         mbedtls_mpi_zeroize( X->p, X->n );
24118c5148dSJens Wiklander         if (X->alloc_type == MBEDTLS_MPI_ALLOC_TYPE_MALLOC)
242817466cbSJens Wiklander             mbedtls_free( X->p );
24318c5148dSJens Wiklander         else
24418c5148dSJens Wiklander             mempool_free( mbedtls_mpi_mempool, X->p );
245817466cbSJens Wiklander     }
246817466cbSJens Wiklander 
247817466cbSJens Wiklander     X->p = p;
24818c5148dSJens Wiklander out:
24918c5148dSJens Wiklander     X->n = i;
250817466cbSJens Wiklander 
251817466cbSJens Wiklander     return( 0 );
252817466cbSJens Wiklander }
253817466cbSJens Wiklander 
254817466cbSJens Wiklander /*
255817466cbSJens Wiklander  * Copy the contents of Y into X
256817466cbSJens Wiklander  */
257817466cbSJens Wiklander int mbedtls_mpi_copy( mbedtls_mpi *X, const mbedtls_mpi *Y )
258817466cbSJens Wiklander {
259817466cbSJens Wiklander     int ret;
260817466cbSJens Wiklander     size_t i;
261817466cbSJens Wiklander 
262817466cbSJens Wiklander     if( X == Y )
263817466cbSJens Wiklander         return( 0 );
264817466cbSJens Wiklander 
265817466cbSJens Wiklander     if( Y->p == NULL )
266817466cbSJens Wiklander     {
267817466cbSJens Wiklander         mbedtls_mpi_free( X );
268817466cbSJens Wiklander         return( 0 );
269817466cbSJens Wiklander     }
270817466cbSJens Wiklander 
271817466cbSJens Wiklander     for( i = Y->n - 1; i > 0; i-- )
272817466cbSJens Wiklander         if( Y->p[i] != 0 )
273817466cbSJens Wiklander             break;
274817466cbSJens Wiklander     i++;
275817466cbSJens Wiklander 
276817466cbSJens Wiklander     X->s = Y->s;
277817466cbSJens Wiklander 
278817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, i ) );
279817466cbSJens Wiklander 
280817466cbSJens Wiklander     memset( X->p, 0, X->n * ciL );
281817466cbSJens Wiklander     memcpy( X->p, Y->p, i * ciL );
282817466cbSJens Wiklander 
283817466cbSJens Wiklander cleanup:
284817466cbSJens Wiklander 
285817466cbSJens Wiklander     return( ret );
286817466cbSJens Wiklander }
287817466cbSJens Wiklander 
288817466cbSJens Wiklander /*
289817466cbSJens Wiklander  * Swap the contents of X and Y
290817466cbSJens Wiklander  */
291817466cbSJens Wiklander void mbedtls_mpi_swap( mbedtls_mpi *X, mbedtls_mpi *Y )
292817466cbSJens Wiklander {
293817466cbSJens Wiklander     mbedtls_mpi T;
294817466cbSJens Wiklander 
295817466cbSJens Wiklander     memcpy( &T,  X, sizeof( mbedtls_mpi ) );
296817466cbSJens Wiklander     memcpy(  X,  Y, sizeof( mbedtls_mpi ) );
297817466cbSJens Wiklander     memcpy(  Y, &T, sizeof( mbedtls_mpi ) );
298817466cbSJens Wiklander }
299817466cbSJens Wiklander 
300817466cbSJens Wiklander /*
301817466cbSJens Wiklander  * Conditionally assign X = Y, without leaking information
302817466cbSJens Wiklander  * about whether the assignment was made or not.
303817466cbSJens Wiklander  * (Leaking information about the respective sizes of X and Y is ok however.)
304817466cbSJens Wiklander  */
305817466cbSJens Wiklander int mbedtls_mpi_safe_cond_assign( mbedtls_mpi *X, const mbedtls_mpi *Y, unsigned char assign )
306817466cbSJens Wiklander {
307817466cbSJens Wiklander     int ret = 0;
308817466cbSJens Wiklander     size_t i;
309817466cbSJens Wiklander 
310817466cbSJens Wiklander     /* make sure assign is 0 or 1 in a time-constant manner */
311817466cbSJens Wiklander     assign = (assign | (unsigned char)-assign) >> 7;
312817466cbSJens Wiklander 
313817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, Y->n ) );
314817466cbSJens Wiklander 
315817466cbSJens Wiklander     X->s = X->s * ( 1 - assign ) + Y->s * assign;
316817466cbSJens Wiklander 
317817466cbSJens Wiklander     for( i = 0; i < Y->n; i++ )
318817466cbSJens Wiklander         X->p[i] = X->p[i] * ( 1 - assign ) + Y->p[i] * assign;
319817466cbSJens Wiklander 
320817466cbSJens Wiklander     for( ; i < X->n; i++ )
321817466cbSJens Wiklander         X->p[i] *= ( 1 - assign );
322817466cbSJens Wiklander 
323817466cbSJens Wiklander cleanup:
324817466cbSJens Wiklander     return( ret );
325817466cbSJens Wiklander }
326817466cbSJens Wiklander 
327817466cbSJens Wiklander /*
328817466cbSJens Wiklander  * Conditionally swap X and Y, without leaking information
329817466cbSJens Wiklander  * about whether the swap was made or not.
330817466cbSJens Wiklander  * Here it is not ok to simply swap the pointers, which whould lead to
331817466cbSJens Wiklander  * different memory access patterns when X and Y are used afterwards.
332817466cbSJens Wiklander  */
333817466cbSJens Wiklander int mbedtls_mpi_safe_cond_swap( mbedtls_mpi *X, mbedtls_mpi *Y, unsigned char swap )
334817466cbSJens Wiklander {
335817466cbSJens Wiklander     int ret, s;
336817466cbSJens Wiklander     size_t i;
337817466cbSJens Wiklander     mbedtls_mpi_uint tmp;
338817466cbSJens Wiklander 
339817466cbSJens Wiklander     if( X == Y )
340817466cbSJens Wiklander         return( 0 );
341817466cbSJens Wiklander 
342817466cbSJens Wiklander     /* make sure swap is 0 or 1 in a time-constant manner */
343817466cbSJens Wiklander     swap = (swap | (unsigned char)-swap) >> 7;
344817466cbSJens Wiklander 
345817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, Y->n ) );
346817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( Y, X->n ) );
347817466cbSJens Wiklander 
348817466cbSJens Wiklander     s = X->s;
349817466cbSJens Wiklander     X->s = X->s * ( 1 - swap ) + Y->s * swap;
350817466cbSJens Wiklander     Y->s = Y->s * ( 1 - swap ) +    s * swap;
351817466cbSJens Wiklander 
352817466cbSJens Wiklander 
353817466cbSJens Wiklander     for( i = 0; i < X->n; i++ )
354817466cbSJens Wiklander     {
355817466cbSJens Wiklander         tmp = X->p[i];
356817466cbSJens Wiklander         X->p[i] = X->p[i] * ( 1 - swap ) + Y->p[i] * swap;
357817466cbSJens Wiklander         Y->p[i] = Y->p[i] * ( 1 - swap ) +     tmp * swap;
358817466cbSJens Wiklander     }
359817466cbSJens Wiklander 
360817466cbSJens Wiklander cleanup:
361817466cbSJens Wiklander     return( ret );
362817466cbSJens Wiklander }
363817466cbSJens Wiklander 
364817466cbSJens Wiklander /*
365817466cbSJens Wiklander  * Set value from integer
366817466cbSJens Wiklander  */
367817466cbSJens Wiklander int mbedtls_mpi_lset( mbedtls_mpi *X, mbedtls_mpi_sint z )
368817466cbSJens Wiklander {
369817466cbSJens Wiklander     int ret;
370817466cbSJens Wiklander 
371817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, 1 ) );
372817466cbSJens Wiklander     memset( X->p, 0, X->n * ciL );
373817466cbSJens Wiklander 
374817466cbSJens Wiklander     X->p[0] = ( z < 0 ) ? -z : z;
375817466cbSJens Wiklander     X->s    = ( z < 0 ) ? -1 : 1;
376817466cbSJens Wiklander 
377817466cbSJens Wiklander cleanup:
378817466cbSJens Wiklander 
379817466cbSJens Wiklander     return( ret );
380817466cbSJens Wiklander }
381817466cbSJens Wiklander 
382817466cbSJens Wiklander /*
383817466cbSJens Wiklander  * Get a specific bit
384817466cbSJens Wiklander  */
385817466cbSJens Wiklander int mbedtls_mpi_get_bit( const mbedtls_mpi *X, size_t pos )
386817466cbSJens Wiklander {
387817466cbSJens Wiklander     if( X->n * biL <= pos )
388817466cbSJens Wiklander         return( 0 );
389817466cbSJens Wiklander 
390817466cbSJens Wiklander     return( ( X->p[pos / biL] >> ( pos % biL ) ) & 0x01 );
391817466cbSJens Wiklander }
392817466cbSJens Wiklander 
393817466cbSJens Wiklander /*
394817466cbSJens Wiklander  * Set a bit to a specific value of 0 or 1
395817466cbSJens Wiklander  */
396817466cbSJens Wiklander int mbedtls_mpi_set_bit( mbedtls_mpi *X, size_t pos, unsigned char val )
397817466cbSJens Wiklander {
398817466cbSJens Wiklander     int ret = 0;
399817466cbSJens Wiklander     size_t off = pos / biL;
400817466cbSJens Wiklander     size_t idx = pos % biL;
401817466cbSJens Wiklander 
402817466cbSJens Wiklander     if( val != 0 && val != 1 )
403817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
404817466cbSJens Wiklander 
405817466cbSJens Wiklander     if( X->n * biL <= pos )
406817466cbSJens Wiklander     {
407817466cbSJens Wiklander         if( val == 0 )
408817466cbSJens Wiklander             return( 0 );
409817466cbSJens Wiklander 
410817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, off + 1 ) );
411817466cbSJens Wiklander     }
412817466cbSJens Wiklander 
413817466cbSJens Wiklander     X->p[off] &= ~( (mbedtls_mpi_uint) 0x01 << idx );
414817466cbSJens Wiklander     X->p[off] |= (mbedtls_mpi_uint) val << idx;
415817466cbSJens Wiklander 
416817466cbSJens Wiklander cleanup:
417817466cbSJens Wiklander 
418817466cbSJens Wiklander     return( ret );
419817466cbSJens Wiklander }
420817466cbSJens Wiklander 
421817466cbSJens Wiklander /*
422817466cbSJens Wiklander  * Return the number of less significant zero-bits
423817466cbSJens Wiklander  */
424817466cbSJens Wiklander size_t mbedtls_mpi_lsb( const mbedtls_mpi *X )
425817466cbSJens Wiklander {
426817466cbSJens Wiklander     size_t i, j, count = 0;
427817466cbSJens Wiklander 
428817466cbSJens Wiklander     for( i = 0; i < X->n; i++ )
429817466cbSJens Wiklander         for( j = 0; j < biL; j++, count++ )
430817466cbSJens Wiklander             if( ( ( X->p[i] >> j ) & 1 ) != 0 )
431817466cbSJens Wiklander                 return( count );
432817466cbSJens Wiklander 
433817466cbSJens Wiklander     return( 0 );
434817466cbSJens Wiklander }
435817466cbSJens Wiklander 
436817466cbSJens Wiklander /*
437817466cbSJens Wiklander  * Count leading zero bits in a given integer
438817466cbSJens Wiklander  */
439817466cbSJens Wiklander static size_t mbedtls_clz( const mbedtls_mpi_uint x )
440817466cbSJens Wiklander {
441817466cbSJens Wiklander     size_t j;
442817466cbSJens Wiklander     mbedtls_mpi_uint mask = (mbedtls_mpi_uint) 1 << (biL - 1);
443817466cbSJens Wiklander 
444817466cbSJens Wiklander     for( j = 0; j < biL; j++ )
445817466cbSJens Wiklander     {
446817466cbSJens Wiklander         if( x & mask ) break;
447817466cbSJens Wiklander 
448817466cbSJens Wiklander         mask >>= 1;
449817466cbSJens Wiklander     }
450817466cbSJens Wiklander 
451817466cbSJens Wiklander     return j;
452817466cbSJens Wiklander }
453817466cbSJens Wiklander 
454817466cbSJens Wiklander /*
455817466cbSJens Wiklander  * Return the number of bits
456817466cbSJens Wiklander  */
457817466cbSJens Wiklander size_t mbedtls_mpi_bitlen( const mbedtls_mpi *X )
458817466cbSJens Wiklander {
459817466cbSJens Wiklander     size_t i, j;
460817466cbSJens Wiklander 
461817466cbSJens Wiklander     if( X->n == 0 )
462817466cbSJens Wiklander         return( 0 );
463817466cbSJens Wiklander 
464817466cbSJens Wiklander     for( i = X->n - 1; i > 0; i-- )
465817466cbSJens Wiklander         if( X->p[i] != 0 )
466817466cbSJens Wiklander             break;
467817466cbSJens Wiklander 
468817466cbSJens Wiklander     j = biL - mbedtls_clz( X->p[i] );
469817466cbSJens Wiklander 
470817466cbSJens Wiklander     return( ( i * biL ) + j );
471817466cbSJens Wiklander }
472817466cbSJens Wiklander 
473817466cbSJens Wiklander /*
474817466cbSJens Wiklander  * Return the total size in bytes
475817466cbSJens Wiklander  */
476817466cbSJens Wiklander size_t mbedtls_mpi_size( const mbedtls_mpi *X )
477817466cbSJens Wiklander {
478817466cbSJens Wiklander     return( ( mbedtls_mpi_bitlen( X ) + 7 ) >> 3 );
479817466cbSJens Wiklander }
480817466cbSJens Wiklander 
481817466cbSJens Wiklander /*
482817466cbSJens Wiklander  * Convert an ASCII character to digit value
483817466cbSJens Wiklander  */
484817466cbSJens Wiklander static int mpi_get_digit( mbedtls_mpi_uint *d, int radix, char c )
485817466cbSJens Wiklander {
486817466cbSJens Wiklander     *d = 255;
487817466cbSJens Wiklander 
488817466cbSJens Wiklander     if( c >= 0x30 && c <= 0x39 ) *d = c - 0x30;
489817466cbSJens Wiklander     if( c >= 0x41 && c <= 0x46 ) *d = c - 0x37;
490817466cbSJens Wiklander     if( c >= 0x61 && c <= 0x66 ) *d = c - 0x57;
491817466cbSJens Wiklander 
492817466cbSJens Wiklander     if( *d >= (mbedtls_mpi_uint) radix )
493817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_INVALID_CHARACTER );
494817466cbSJens Wiklander 
495817466cbSJens Wiklander     return( 0 );
496817466cbSJens Wiklander }
497817466cbSJens Wiklander 
498817466cbSJens Wiklander /*
499817466cbSJens Wiklander  * Import from an ASCII string
500817466cbSJens Wiklander  */
501817466cbSJens Wiklander int mbedtls_mpi_read_string( mbedtls_mpi *X, int radix, const char *s )
502817466cbSJens Wiklander {
503817466cbSJens Wiklander     int ret;
504817466cbSJens Wiklander     size_t i, j, slen, n;
505817466cbSJens Wiklander     mbedtls_mpi_uint d;
506817466cbSJens Wiklander     mbedtls_mpi T;
507817466cbSJens Wiklander 
508817466cbSJens Wiklander     if( radix < 2 || radix > 16 )
509817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
510817466cbSJens Wiklander 
51198bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &T );
512817466cbSJens Wiklander 
513817466cbSJens Wiklander     slen = strlen( s );
514817466cbSJens Wiklander 
515817466cbSJens Wiklander     if( radix == 16 )
516817466cbSJens Wiklander     {
517817466cbSJens Wiklander         if( slen > MPI_SIZE_T_MAX >> 2 )
518817466cbSJens Wiklander             return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
519817466cbSJens Wiklander 
520817466cbSJens Wiklander         n = BITS_TO_LIMBS( slen << 2 );
521817466cbSJens Wiklander 
522817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, n ) );
523817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) );
524817466cbSJens Wiklander 
525817466cbSJens Wiklander         for( i = slen, j = 0; i > 0; i--, j++ )
526817466cbSJens Wiklander         {
527817466cbSJens Wiklander             if( i == 1 && s[i - 1] == '-' )
528817466cbSJens Wiklander             {
529817466cbSJens Wiklander                 X->s = -1;
530817466cbSJens Wiklander                 break;
531817466cbSJens Wiklander             }
532817466cbSJens Wiklander 
533817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mpi_get_digit( &d, radix, s[i - 1] ) );
534817466cbSJens Wiklander             X->p[j / ( 2 * ciL )] |= d << ( ( j % ( 2 * ciL ) ) << 2 );
535817466cbSJens Wiklander         }
536817466cbSJens Wiklander     }
537817466cbSJens Wiklander     else
538817466cbSJens Wiklander     {
539817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) );
540817466cbSJens Wiklander 
541817466cbSJens Wiklander         for( i = 0; i < slen; i++ )
542817466cbSJens Wiklander         {
543817466cbSJens Wiklander             if( i == 0 && s[i] == '-' )
544817466cbSJens Wiklander             {
545817466cbSJens Wiklander                 X->s = -1;
546817466cbSJens Wiklander                 continue;
547817466cbSJens Wiklander             }
548817466cbSJens Wiklander 
549817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mpi_get_digit( &d, radix, s[i] ) );
550817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &T, X, radix ) );
551817466cbSJens Wiklander 
552817466cbSJens Wiklander             if( X->s == 1 )
553817466cbSJens Wiklander             {
554817466cbSJens Wiklander                 MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, &T, d ) );
555817466cbSJens Wiklander             }
556817466cbSJens Wiklander             else
557817466cbSJens Wiklander             {
558817466cbSJens Wiklander                 MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( X, &T, d ) );
559817466cbSJens Wiklander             }
560817466cbSJens Wiklander         }
561817466cbSJens Wiklander     }
562817466cbSJens Wiklander 
563817466cbSJens Wiklander cleanup:
564817466cbSJens Wiklander 
565817466cbSJens Wiklander     mbedtls_mpi_free( &T );
566817466cbSJens Wiklander 
567817466cbSJens Wiklander     return( ret );
568817466cbSJens Wiklander }
569817466cbSJens Wiklander 
570817466cbSJens Wiklander /*
571817466cbSJens Wiklander  * Helper to write the digits high-order first
572817466cbSJens Wiklander  */
573817466cbSJens Wiklander static int mpi_write_hlp( mbedtls_mpi *X, int radix, char **p )
574817466cbSJens Wiklander {
575817466cbSJens Wiklander     int ret;
576817466cbSJens Wiklander     mbedtls_mpi_uint r;
577817466cbSJens Wiklander 
578817466cbSJens Wiklander     if( radix < 2 || radix > 16 )
579817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
580817466cbSJens Wiklander 
581817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mod_int( &r, X, radix ) );
582817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_div_int( X, NULL, X, radix ) );
583817466cbSJens Wiklander 
584817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( X, 0 ) != 0 )
585817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mpi_write_hlp( X, radix, p ) );
586817466cbSJens Wiklander 
587817466cbSJens Wiklander     if( r < 10 )
588817466cbSJens Wiklander         *(*p)++ = (char)( r + 0x30 );
589817466cbSJens Wiklander     else
590817466cbSJens Wiklander         *(*p)++ = (char)( r + 0x37 );
591817466cbSJens Wiklander 
592817466cbSJens Wiklander cleanup:
593817466cbSJens Wiklander 
594817466cbSJens Wiklander     return( ret );
595817466cbSJens Wiklander }
596817466cbSJens Wiklander 
597817466cbSJens Wiklander /*
598817466cbSJens Wiklander  * Export into an ASCII string
599817466cbSJens Wiklander  */
600817466cbSJens Wiklander int mbedtls_mpi_write_string( const mbedtls_mpi *X, int radix,
601817466cbSJens Wiklander                               char *buf, size_t buflen, size_t *olen )
602817466cbSJens Wiklander {
603817466cbSJens Wiklander     int ret = 0;
604817466cbSJens Wiklander     size_t n;
605817466cbSJens Wiklander     char *p;
606817466cbSJens Wiklander     mbedtls_mpi T;
607817466cbSJens Wiklander 
608817466cbSJens Wiklander     if( radix < 2 || radix > 16 )
609817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
610817466cbSJens Wiklander 
611817466cbSJens Wiklander     n = mbedtls_mpi_bitlen( X );
612817466cbSJens Wiklander     if( radix >=  4 ) n >>= 1;
613817466cbSJens Wiklander     if( radix >= 16 ) n >>= 1;
614817466cbSJens Wiklander     /*
615817466cbSJens Wiklander      * Round up the buffer length to an even value to ensure that there is
616817466cbSJens Wiklander      * enough room for hexadecimal values that can be represented in an odd
617817466cbSJens Wiklander      * number of digits.
618817466cbSJens Wiklander      */
619817466cbSJens Wiklander     n += 3 + ( ( n + 1 ) & 1 );
620817466cbSJens Wiklander 
621817466cbSJens Wiklander     if( buflen < n )
622817466cbSJens Wiklander     {
623817466cbSJens Wiklander         *olen = n;
624817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL );
625817466cbSJens Wiklander     }
626817466cbSJens Wiklander 
627817466cbSJens Wiklander     p = buf;
62898bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &T );
629817466cbSJens Wiklander 
630817466cbSJens Wiklander     if( X->s == -1 )
631817466cbSJens Wiklander         *p++ = '-';
632817466cbSJens Wiklander 
633817466cbSJens Wiklander     if( radix == 16 )
634817466cbSJens Wiklander     {
635817466cbSJens Wiklander         int c;
636817466cbSJens Wiklander         size_t i, j, k;
637817466cbSJens Wiklander 
638817466cbSJens Wiklander         for( i = X->n, k = 0; i > 0; i-- )
639817466cbSJens Wiklander         {
640817466cbSJens Wiklander             for( j = ciL; j > 0; j-- )
641817466cbSJens Wiklander             {
642817466cbSJens Wiklander                 c = ( X->p[i - 1] >> ( ( j - 1 ) << 3) ) & 0xFF;
643817466cbSJens Wiklander 
644817466cbSJens Wiklander                 if( c == 0 && k == 0 && ( i + j ) != 2 )
645817466cbSJens Wiklander                     continue;
646817466cbSJens Wiklander 
647817466cbSJens Wiklander                 *(p++) = "0123456789ABCDEF" [c / 16];
648817466cbSJens Wiklander                 *(p++) = "0123456789ABCDEF" [c % 16];
649817466cbSJens Wiklander                 k = 1;
650817466cbSJens Wiklander             }
651817466cbSJens Wiklander         }
652817466cbSJens Wiklander     }
653817466cbSJens Wiklander     else
654817466cbSJens Wiklander     {
655817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &T, X ) );
656817466cbSJens Wiklander 
657817466cbSJens Wiklander         if( T.s == -1 )
658817466cbSJens Wiklander             T.s = 1;
659817466cbSJens Wiklander 
660817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mpi_write_hlp( &T, radix, &p ) );
661817466cbSJens Wiklander     }
662817466cbSJens Wiklander 
663817466cbSJens Wiklander     *p++ = '\0';
664817466cbSJens Wiklander     *olen = p - buf;
665817466cbSJens Wiklander 
666817466cbSJens Wiklander cleanup:
667817466cbSJens Wiklander 
668817466cbSJens Wiklander     mbedtls_mpi_free( &T );
669817466cbSJens Wiklander 
670817466cbSJens Wiklander     return( ret );
671817466cbSJens Wiklander }
672817466cbSJens Wiklander 
673817466cbSJens Wiklander #if defined(MBEDTLS_FS_IO)
674817466cbSJens Wiklander /*
675817466cbSJens Wiklander  * Read X from an opened file
676817466cbSJens Wiklander  */
677817466cbSJens Wiklander int mbedtls_mpi_read_file( mbedtls_mpi *X, int radix, FILE *fin )
678817466cbSJens Wiklander {
679817466cbSJens Wiklander     mbedtls_mpi_uint d;
680817466cbSJens Wiklander     size_t slen;
681817466cbSJens Wiklander     char *p;
682817466cbSJens Wiklander     /*
683817466cbSJens Wiklander      * Buffer should have space for (short) label and decimal formatted MPI,
684817466cbSJens Wiklander      * newline characters and '\0'
685817466cbSJens Wiklander      */
686817466cbSJens Wiklander     char s[ MBEDTLS_MPI_RW_BUFFER_SIZE ];
687817466cbSJens Wiklander 
688817466cbSJens Wiklander     memset( s, 0, sizeof( s ) );
689817466cbSJens Wiklander     if( fgets( s, sizeof( s ) - 1, fin ) == NULL )
690817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_FILE_IO_ERROR );
691817466cbSJens Wiklander 
692817466cbSJens Wiklander     slen = strlen( s );
693817466cbSJens Wiklander     if( slen == sizeof( s ) - 2 )
694817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL );
695817466cbSJens Wiklander 
696817466cbSJens Wiklander     if( slen > 0 && s[slen - 1] == '\n' ) { slen--; s[slen] = '\0'; }
697817466cbSJens Wiklander     if( slen > 0 && s[slen - 1] == '\r' ) { slen--; s[slen] = '\0'; }
698817466cbSJens Wiklander 
699817466cbSJens Wiklander     p = s + slen;
700817466cbSJens Wiklander     while( p-- > s )
701817466cbSJens Wiklander         if( mpi_get_digit( &d, radix, *p ) != 0 )
702817466cbSJens Wiklander             break;
703817466cbSJens Wiklander 
704817466cbSJens Wiklander     return( mbedtls_mpi_read_string( X, radix, p + 1 ) );
705817466cbSJens Wiklander }
706817466cbSJens Wiklander 
707817466cbSJens Wiklander /*
708817466cbSJens Wiklander  * Write X into an opened file (or stdout if fout == NULL)
709817466cbSJens Wiklander  */
710817466cbSJens Wiklander int mbedtls_mpi_write_file( const char *p, const mbedtls_mpi *X, int radix, FILE *fout )
711817466cbSJens Wiklander {
712817466cbSJens Wiklander     int ret;
713817466cbSJens Wiklander     size_t n, slen, plen;
714817466cbSJens Wiklander     /*
715817466cbSJens Wiklander      * Buffer should have space for (short) label and decimal formatted MPI,
716817466cbSJens Wiklander      * newline characters and '\0'
717817466cbSJens Wiklander      */
718817466cbSJens Wiklander     char s[ MBEDTLS_MPI_RW_BUFFER_SIZE ];
719817466cbSJens Wiklander 
720817466cbSJens Wiklander     memset( s, 0, sizeof( s ) );
721817466cbSJens Wiklander 
722817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_write_string( X, radix, s, sizeof( s ) - 2, &n ) );
723817466cbSJens Wiklander 
724817466cbSJens Wiklander     if( p == NULL ) p = "";
725817466cbSJens Wiklander 
726817466cbSJens Wiklander     plen = strlen( p );
727817466cbSJens Wiklander     slen = strlen( s );
728817466cbSJens Wiklander     s[slen++] = '\r';
729817466cbSJens Wiklander     s[slen++] = '\n';
730817466cbSJens Wiklander 
731817466cbSJens Wiklander     if( fout != NULL )
732817466cbSJens Wiklander     {
733817466cbSJens Wiklander         if( fwrite( p, 1, plen, fout ) != plen ||
734817466cbSJens Wiklander             fwrite( s, 1, slen, fout ) != slen )
735817466cbSJens Wiklander             return( MBEDTLS_ERR_MPI_FILE_IO_ERROR );
736817466cbSJens Wiklander     }
737817466cbSJens Wiklander     else
738817466cbSJens Wiklander         mbedtls_printf( "%s%s", p, s );
739817466cbSJens Wiklander 
740817466cbSJens Wiklander cleanup:
741817466cbSJens Wiklander 
742817466cbSJens Wiklander     return( ret );
743817466cbSJens Wiklander }
744817466cbSJens Wiklander #endif /* MBEDTLS_FS_IO */
745817466cbSJens Wiklander 
746817466cbSJens Wiklander /*
747817466cbSJens Wiklander  * Import X from unsigned binary data, big endian
748817466cbSJens Wiklander  */
749817466cbSJens Wiklander int mbedtls_mpi_read_binary( mbedtls_mpi *X, const unsigned char *buf, size_t buflen )
750817466cbSJens Wiklander {
751817466cbSJens Wiklander     int ret;
752817466cbSJens Wiklander     size_t i, j, n;
753817466cbSJens Wiklander 
754817466cbSJens Wiklander     for( n = 0; n < buflen; n++ )
755817466cbSJens Wiklander         if( buf[n] != 0 )
756817466cbSJens Wiklander             break;
757817466cbSJens Wiklander 
758817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, CHARS_TO_LIMBS( buflen - n ) ) );
759817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) );
760817466cbSJens Wiklander 
761817466cbSJens Wiklander     for( i = buflen, j = 0; i > n; i--, j++ )
762817466cbSJens Wiklander         X->p[j / ciL] |= ((mbedtls_mpi_uint) buf[i - 1]) << ((j % ciL) << 3);
763817466cbSJens Wiklander 
764817466cbSJens Wiklander cleanup:
765817466cbSJens Wiklander 
766817466cbSJens Wiklander     return( ret );
767817466cbSJens Wiklander }
768817466cbSJens Wiklander 
769817466cbSJens Wiklander /*
770817466cbSJens Wiklander  * Export X into unsigned binary data, big endian
771817466cbSJens Wiklander  */
772817466cbSJens Wiklander int mbedtls_mpi_write_binary( const mbedtls_mpi *X, unsigned char *buf, size_t buflen )
773817466cbSJens Wiklander {
774817466cbSJens Wiklander     size_t i, j, n;
775817466cbSJens Wiklander 
776817466cbSJens Wiklander     n = mbedtls_mpi_size( X );
777817466cbSJens Wiklander 
778817466cbSJens Wiklander     if( buflen < n )
779817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL );
780817466cbSJens Wiklander 
781817466cbSJens Wiklander     memset( buf, 0, buflen );
782817466cbSJens Wiklander 
783817466cbSJens Wiklander     for( i = buflen - 1, j = 0; n > 0; i--, j++, n-- )
784817466cbSJens Wiklander         buf[i] = (unsigned char)( X->p[j / ciL] >> ((j % ciL) << 3) );
785817466cbSJens Wiklander 
786817466cbSJens Wiklander     return( 0 );
787817466cbSJens Wiklander }
788817466cbSJens Wiklander 
789817466cbSJens Wiklander /*
790817466cbSJens Wiklander  * Left-shift: X <<= count
791817466cbSJens Wiklander  */
792817466cbSJens Wiklander int mbedtls_mpi_shift_l( mbedtls_mpi *X, size_t count )
793817466cbSJens Wiklander {
794817466cbSJens Wiklander     int ret;
795817466cbSJens Wiklander     size_t i, v0, t1;
796817466cbSJens Wiklander     mbedtls_mpi_uint r0 = 0, r1;
797817466cbSJens Wiklander 
798817466cbSJens Wiklander     v0 = count / (biL    );
799817466cbSJens Wiklander     t1 = count & (biL - 1);
800817466cbSJens Wiklander 
801817466cbSJens Wiklander     i = mbedtls_mpi_bitlen( X ) + count;
802817466cbSJens Wiklander 
803817466cbSJens Wiklander     if( X->n * biL < i )
804817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, BITS_TO_LIMBS( i ) ) );
805817466cbSJens Wiklander 
806817466cbSJens Wiklander     ret = 0;
807817466cbSJens Wiklander 
808817466cbSJens Wiklander     /*
809817466cbSJens Wiklander      * shift by count / limb_size
810817466cbSJens Wiklander      */
811817466cbSJens Wiklander     if( v0 > 0 )
812817466cbSJens Wiklander     {
813817466cbSJens Wiklander         for( i = X->n; i > v0; i-- )
814817466cbSJens Wiklander             X->p[i - 1] = X->p[i - v0 - 1];
815817466cbSJens Wiklander 
816817466cbSJens Wiklander         for( ; i > 0; i-- )
817817466cbSJens Wiklander             X->p[i - 1] = 0;
818817466cbSJens Wiklander     }
819817466cbSJens Wiklander 
820817466cbSJens Wiklander     /*
821817466cbSJens Wiklander      * shift by count % limb_size
822817466cbSJens Wiklander      */
823817466cbSJens Wiklander     if( t1 > 0 )
824817466cbSJens Wiklander     {
825817466cbSJens Wiklander         for( i = v0; i < X->n; i++ )
826817466cbSJens Wiklander         {
827817466cbSJens Wiklander             r1 = X->p[i] >> (biL - t1);
828817466cbSJens Wiklander             X->p[i] <<= t1;
829817466cbSJens Wiklander             X->p[i] |= r0;
830817466cbSJens Wiklander             r0 = r1;
831817466cbSJens Wiklander         }
832817466cbSJens Wiklander     }
833817466cbSJens Wiklander 
834817466cbSJens Wiklander cleanup:
835817466cbSJens Wiklander 
836817466cbSJens Wiklander     return( ret );
837817466cbSJens Wiklander }
838817466cbSJens Wiklander 
839817466cbSJens Wiklander /*
840817466cbSJens Wiklander  * Right-shift: X >>= count
841817466cbSJens Wiklander  */
842817466cbSJens Wiklander int mbedtls_mpi_shift_r( mbedtls_mpi *X, size_t count )
843817466cbSJens Wiklander {
844817466cbSJens Wiklander     size_t i, v0, v1;
845817466cbSJens Wiklander     mbedtls_mpi_uint r0 = 0, r1;
846817466cbSJens Wiklander 
847817466cbSJens Wiklander     v0 = count /  biL;
848817466cbSJens Wiklander     v1 = count & (biL - 1);
849817466cbSJens Wiklander 
850817466cbSJens Wiklander     if( v0 > X->n || ( v0 == X->n && v1 > 0 ) )
851817466cbSJens Wiklander         return mbedtls_mpi_lset( X, 0 );
852817466cbSJens Wiklander 
853817466cbSJens Wiklander     /*
854817466cbSJens Wiklander      * shift by count / limb_size
855817466cbSJens Wiklander      */
856817466cbSJens Wiklander     if( v0 > 0 )
857817466cbSJens Wiklander     {
858817466cbSJens Wiklander         for( i = 0; i < X->n - v0; i++ )
859817466cbSJens Wiklander             X->p[i] = X->p[i + v0];
860817466cbSJens Wiklander 
861817466cbSJens Wiklander         for( ; i < X->n; i++ )
862817466cbSJens Wiklander             X->p[i] = 0;
863817466cbSJens Wiklander     }
864817466cbSJens Wiklander 
865817466cbSJens Wiklander     /*
866817466cbSJens Wiklander      * shift by count % limb_size
867817466cbSJens Wiklander      */
868817466cbSJens Wiklander     if( v1 > 0 )
869817466cbSJens Wiklander     {
870817466cbSJens Wiklander         for( i = X->n; i > 0; i-- )
871817466cbSJens Wiklander         {
872817466cbSJens Wiklander             r1 = X->p[i - 1] << (biL - v1);
873817466cbSJens Wiklander             X->p[i - 1] >>= v1;
874817466cbSJens Wiklander             X->p[i - 1] |= r0;
875817466cbSJens Wiklander             r0 = r1;
876817466cbSJens Wiklander         }
877817466cbSJens Wiklander     }
878817466cbSJens Wiklander 
879817466cbSJens Wiklander     return( 0 );
880817466cbSJens Wiklander }
881817466cbSJens Wiklander 
882817466cbSJens Wiklander /*
883817466cbSJens Wiklander  * Compare unsigned values
884817466cbSJens Wiklander  */
885817466cbSJens Wiklander int mbedtls_mpi_cmp_abs( const mbedtls_mpi *X, const mbedtls_mpi *Y )
886817466cbSJens Wiklander {
887817466cbSJens Wiklander     size_t i, j;
888817466cbSJens Wiklander 
889817466cbSJens Wiklander     for( i = X->n; i > 0; i-- )
890817466cbSJens Wiklander         if( X->p[i - 1] != 0 )
891817466cbSJens Wiklander             break;
892817466cbSJens Wiklander 
893817466cbSJens Wiklander     for( j = Y->n; j > 0; j-- )
894817466cbSJens Wiklander         if( Y->p[j - 1] != 0 )
895817466cbSJens Wiklander             break;
896817466cbSJens Wiklander 
897817466cbSJens Wiklander     if( i == 0 && j == 0 )
898817466cbSJens Wiklander         return( 0 );
899817466cbSJens Wiklander 
900817466cbSJens Wiklander     if( i > j ) return(  1 );
901817466cbSJens Wiklander     if( j > i ) return( -1 );
902817466cbSJens Wiklander 
903817466cbSJens Wiklander     for( ; i > 0; i-- )
904817466cbSJens Wiklander     {
905817466cbSJens Wiklander         if( X->p[i - 1] > Y->p[i - 1] ) return(  1 );
906817466cbSJens Wiklander         if( X->p[i - 1] < Y->p[i - 1] ) return( -1 );
907817466cbSJens Wiklander     }
908817466cbSJens Wiklander 
909817466cbSJens Wiklander     return( 0 );
910817466cbSJens Wiklander }
911817466cbSJens Wiklander 
912817466cbSJens Wiklander /*
913817466cbSJens Wiklander  * Compare signed values
914817466cbSJens Wiklander  */
915817466cbSJens Wiklander int mbedtls_mpi_cmp_mpi( const mbedtls_mpi *X, const mbedtls_mpi *Y )
916817466cbSJens Wiklander {
917817466cbSJens Wiklander     size_t i, j;
918817466cbSJens Wiklander 
919817466cbSJens Wiklander     for( i = X->n; i > 0; i-- )
920817466cbSJens Wiklander         if( X->p[i - 1] != 0 )
921817466cbSJens Wiklander             break;
922817466cbSJens Wiklander 
923817466cbSJens Wiklander     for( j = Y->n; j > 0; j-- )
924817466cbSJens Wiklander         if( Y->p[j - 1] != 0 )
925817466cbSJens Wiklander             break;
926817466cbSJens Wiklander 
927817466cbSJens Wiklander     if( i == 0 && j == 0 )
928817466cbSJens Wiklander         return( 0 );
929817466cbSJens Wiklander 
930817466cbSJens Wiklander     if( i > j ) return(  X->s );
931817466cbSJens Wiklander     if( j > i ) return( -Y->s );
932817466cbSJens Wiklander 
933817466cbSJens Wiklander     if( X->s > 0 && Y->s < 0 ) return(  1 );
934817466cbSJens Wiklander     if( Y->s > 0 && X->s < 0 ) return( -1 );
935817466cbSJens Wiklander 
936817466cbSJens Wiklander     for( ; i > 0; i-- )
937817466cbSJens Wiklander     {
938817466cbSJens Wiklander         if( X->p[i - 1] > Y->p[i - 1] ) return(  X->s );
939817466cbSJens Wiklander         if( X->p[i - 1] < Y->p[i - 1] ) return( -X->s );
940817466cbSJens Wiklander     }
941817466cbSJens Wiklander 
942817466cbSJens Wiklander     return( 0 );
943817466cbSJens Wiklander }
944817466cbSJens Wiklander 
945817466cbSJens Wiklander /*
946817466cbSJens Wiklander  * Compare signed values
947817466cbSJens Wiklander  */
948817466cbSJens Wiklander int mbedtls_mpi_cmp_int( const mbedtls_mpi *X, mbedtls_mpi_sint z )
949817466cbSJens Wiklander {
950817466cbSJens Wiklander     mbedtls_mpi Y;
951817466cbSJens Wiklander     mbedtls_mpi_uint p[1];
952817466cbSJens Wiklander 
953817466cbSJens Wiklander     *p  = ( z < 0 ) ? -z : z;
954817466cbSJens Wiklander     Y.s = ( z < 0 ) ? -1 : 1;
955817466cbSJens Wiklander     Y.n = 1;
956817466cbSJens Wiklander     Y.p = p;
957817466cbSJens Wiklander 
958817466cbSJens Wiklander     return( mbedtls_mpi_cmp_mpi( X, &Y ) );
959817466cbSJens Wiklander }
960817466cbSJens Wiklander 
961817466cbSJens Wiklander /*
962817466cbSJens Wiklander  * Unsigned addition: X = |A| + |B|  (HAC 14.7)
963817466cbSJens Wiklander  */
964817466cbSJens Wiklander int mbedtls_mpi_add_abs( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B )
965817466cbSJens Wiklander {
966817466cbSJens Wiklander     int ret;
967817466cbSJens Wiklander     size_t i, j;
968817466cbSJens Wiklander     mbedtls_mpi_uint *o, *p, c, tmp;
969817466cbSJens Wiklander 
970817466cbSJens Wiklander     if( X == B )
971817466cbSJens Wiklander     {
972817466cbSJens Wiklander         const mbedtls_mpi *T = A; A = X; B = T;
973817466cbSJens Wiklander     }
974817466cbSJens Wiklander 
975817466cbSJens Wiklander     if( X != A )
976817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, A ) );
977817466cbSJens Wiklander 
978817466cbSJens Wiklander     /*
979817466cbSJens Wiklander      * X should always be positive as a result of unsigned additions.
980817466cbSJens Wiklander      */
981817466cbSJens Wiklander     X->s = 1;
982817466cbSJens Wiklander 
983817466cbSJens Wiklander     for( j = B->n; j > 0; j-- )
984817466cbSJens Wiklander         if( B->p[j - 1] != 0 )
985817466cbSJens Wiklander             break;
986817466cbSJens Wiklander 
987817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, j ) );
988817466cbSJens Wiklander 
989817466cbSJens Wiklander     o = B->p; p = X->p; c = 0;
990817466cbSJens Wiklander 
991817466cbSJens Wiklander     /*
992817466cbSJens Wiklander      * tmp is used because it might happen that p == o
993817466cbSJens Wiklander      */
994817466cbSJens Wiklander     for( i = 0; i < j; i++, o++, p++ )
995817466cbSJens Wiklander     {
996817466cbSJens Wiklander         tmp= *o;
997817466cbSJens Wiklander         *p +=  c; c  = ( *p <  c );
998817466cbSJens Wiklander         *p += tmp; c += ( *p < tmp );
999817466cbSJens Wiklander     }
1000817466cbSJens Wiklander 
1001817466cbSJens Wiklander     while( c != 0 )
1002817466cbSJens Wiklander     {
1003817466cbSJens Wiklander         if( i >= X->n )
1004817466cbSJens Wiklander         {
1005817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, i + 1 ) );
1006817466cbSJens Wiklander             p = X->p + i;
1007817466cbSJens Wiklander         }
1008817466cbSJens Wiklander 
1009817466cbSJens Wiklander         *p += c; c = ( *p < c ); i++; p++;
1010817466cbSJens Wiklander     }
1011817466cbSJens Wiklander 
1012817466cbSJens Wiklander cleanup:
1013817466cbSJens Wiklander 
1014817466cbSJens Wiklander     return( ret );
1015817466cbSJens Wiklander }
1016817466cbSJens Wiklander 
1017817466cbSJens Wiklander /*
1018817466cbSJens Wiklander  * Helper for mbedtls_mpi subtraction
1019817466cbSJens Wiklander  */
1020817466cbSJens Wiklander static void mpi_sub_hlp( size_t n, mbedtls_mpi_uint *s, mbedtls_mpi_uint *d )
1021817466cbSJens Wiklander {
1022817466cbSJens Wiklander     size_t i;
1023817466cbSJens Wiklander     mbedtls_mpi_uint c, z;
1024817466cbSJens Wiklander 
1025817466cbSJens Wiklander     for( i = c = 0; i < n; i++, s++, d++ )
1026817466cbSJens Wiklander     {
1027817466cbSJens Wiklander         z = ( *d <  c );     *d -=  c;
1028817466cbSJens Wiklander         c = ( *d < *s ) + z; *d -= *s;
1029817466cbSJens Wiklander     }
1030817466cbSJens Wiklander 
1031817466cbSJens Wiklander     while( c != 0 )
1032817466cbSJens Wiklander     {
1033817466cbSJens Wiklander         z = ( *d < c ); *d -= c;
1034817466cbSJens Wiklander         c = z; i++; d++;
1035817466cbSJens Wiklander     }
1036817466cbSJens Wiklander }
1037817466cbSJens Wiklander 
1038817466cbSJens Wiklander /*
1039817466cbSJens Wiklander  * Unsigned subtraction: X = |A| - |B|  (HAC 14.9)
1040817466cbSJens Wiklander  */
1041817466cbSJens Wiklander int mbedtls_mpi_sub_abs( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B )
1042817466cbSJens Wiklander {
1043817466cbSJens Wiklander     mbedtls_mpi TB;
1044817466cbSJens Wiklander     int ret;
1045817466cbSJens Wiklander     size_t n;
1046817466cbSJens Wiklander 
1047817466cbSJens Wiklander     if( mbedtls_mpi_cmp_abs( A, B ) < 0 )
1048817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_NEGATIVE_VALUE );
1049817466cbSJens Wiklander 
105098bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &TB );
1051817466cbSJens Wiklander 
1052817466cbSJens Wiklander     if( X == B )
1053817466cbSJens Wiklander     {
1054817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, B ) );
1055817466cbSJens Wiklander         B = &TB;
1056817466cbSJens Wiklander     }
1057817466cbSJens Wiklander 
1058817466cbSJens Wiklander     if( X != A )
1059817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, A ) );
1060817466cbSJens Wiklander 
1061817466cbSJens Wiklander     /*
1062817466cbSJens Wiklander      * X should always be positive as a result of unsigned subtractions.
1063817466cbSJens Wiklander      */
1064817466cbSJens Wiklander     X->s = 1;
1065817466cbSJens Wiklander 
1066817466cbSJens Wiklander     ret = 0;
1067817466cbSJens Wiklander 
1068817466cbSJens Wiklander     for( n = B->n; n > 0; n-- )
1069817466cbSJens Wiklander         if( B->p[n - 1] != 0 )
1070817466cbSJens Wiklander             break;
1071817466cbSJens Wiklander 
1072817466cbSJens Wiklander     mpi_sub_hlp( n, B->p, X->p );
1073817466cbSJens Wiklander 
1074817466cbSJens Wiklander cleanup:
1075817466cbSJens Wiklander 
1076817466cbSJens Wiklander     mbedtls_mpi_free( &TB );
1077817466cbSJens Wiklander 
1078817466cbSJens Wiklander     return( ret );
1079817466cbSJens Wiklander }
1080817466cbSJens Wiklander 
1081817466cbSJens Wiklander /*
1082817466cbSJens Wiklander  * Signed addition: X = A + B
1083817466cbSJens Wiklander  */
1084817466cbSJens Wiklander int mbedtls_mpi_add_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B )
1085817466cbSJens Wiklander {
1086817466cbSJens Wiklander     int ret, s = A->s;
1087817466cbSJens Wiklander 
1088817466cbSJens Wiklander     if( A->s * B->s < 0 )
1089817466cbSJens Wiklander     {
1090817466cbSJens Wiklander         if( mbedtls_mpi_cmp_abs( A, B ) >= 0 )
1091817466cbSJens Wiklander         {
1092817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, A, B ) );
1093817466cbSJens Wiklander             X->s =  s;
1094817466cbSJens Wiklander         }
1095817466cbSJens Wiklander         else
1096817466cbSJens Wiklander         {
1097817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, B, A ) );
1098817466cbSJens Wiklander             X->s = -s;
1099817466cbSJens Wiklander         }
1100817466cbSJens Wiklander     }
1101817466cbSJens Wiklander     else
1102817466cbSJens Wiklander     {
1103817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_add_abs( X, A, B ) );
1104817466cbSJens Wiklander         X->s = s;
1105817466cbSJens Wiklander     }
1106817466cbSJens Wiklander 
1107817466cbSJens Wiklander cleanup:
1108817466cbSJens Wiklander 
1109817466cbSJens Wiklander     return( ret );
1110817466cbSJens Wiklander }
1111817466cbSJens Wiklander 
1112817466cbSJens Wiklander /*
1113817466cbSJens Wiklander  * Signed subtraction: X = A - B
1114817466cbSJens Wiklander  */
1115817466cbSJens Wiklander int mbedtls_mpi_sub_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B )
1116817466cbSJens Wiklander {
1117817466cbSJens Wiklander     int ret, s = A->s;
1118817466cbSJens Wiklander 
1119817466cbSJens Wiklander     if( A->s * B->s > 0 )
1120817466cbSJens Wiklander     {
1121817466cbSJens Wiklander         if( mbedtls_mpi_cmp_abs( A, B ) >= 0 )
1122817466cbSJens Wiklander         {
1123817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, A, B ) );
1124817466cbSJens Wiklander             X->s =  s;
1125817466cbSJens Wiklander         }
1126817466cbSJens Wiklander         else
1127817466cbSJens Wiklander         {
1128817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, B, A ) );
1129817466cbSJens Wiklander             X->s = -s;
1130817466cbSJens Wiklander         }
1131817466cbSJens Wiklander     }
1132817466cbSJens Wiklander     else
1133817466cbSJens Wiklander     {
1134817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_add_abs( X, A, B ) );
1135817466cbSJens Wiklander         X->s = s;
1136817466cbSJens Wiklander     }
1137817466cbSJens Wiklander 
1138817466cbSJens Wiklander cleanup:
1139817466cbSJens Wiklander 
1140817466cbSJens Wiklander     return( ret );
1141817466cbSJens Wiklander }
1142817466cbSJens Wiklander 
1143817466cbSJens Wiklander /*
1144817466cbSJens Wiklander  * Signed addition: X = A + b
1145817466cbSJens Wiklander  */
1146817466cbSJens Wiklander int mbedtls_mpi_add_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b )
1147817466cbSJens Wiklander {
1148817466cbSJens Wiklander     mbedtls_mpi _B;
1149817466cbSJens Wiklander     mbedtls_mpi_uint p[1];
1150817466cbSJens Wiklander 
1151817466cbSJens Wiklander     p[0] = ( b < 0 ) ? -b : b;
1152817466cbSJens Wiklander     _B.s = ( b < 0 ) ? -1 : 1;
1153817466cbSJens Wiklander     _B.n = 1;
1154817466cbSJens Wiklander     _B.p = p;
1155817466cbSJens Wiklander 
1156817466cbSJens Wiklander     return( mbedtls_mpi_add_mpi( X, A, &_B ) );
1157817466cbSJens Wiklander }
1158817466cbSJens Wiklander 
1159817466cbSJens Wiklander /*
1160817466cbSJens Wiklander  * Signed subtraction: X = A - b
1161817466cbSJens Wiklander  */
1162817466cbSJens Wiklander int mbedtls_mpi_sub_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b )
1163817466cbSJens Wiklander {
1164817466cbSJens Wiklander     mbedtls_mpi _B;
1165817466cbSJens Wiklander     mbedtls_mpi_uint p[1];
1166817466cbSJens Wiklander 
1167817466cbSJens Wiklander     p[0] = ( b < 0 ) ? -b : b;
1168817466cbSJens Wiklander     _B.s = ( b < 0 ) ? -1 : 1;
1169817466cbSJens Wiklander     _B.n = 1;
1170817466cbSJens Wiklander     _B.p = p;
1171817466cbSJens Wiklander 
1172817466cbSJens Wiklander     return( mbedtls_mpi_sub_mpi( X, A, &_B ) );
1173817466cbSJens Wiklander }
1174817466cbSJens Wiklander 
1175817466cbSJens Wiklander /*
1176817466cbSJens Wiklander  * Helper for mbedtls_mpi multiplication
1177817466cbSJens Wiklander  */
1178817466cbSJens Wiklander static
1179817466cbSJens Wiklander #if defined(__APPLE__) && defined(__arm__)
1180817466cbSJens Wiklander /*
1181817466cbSJens Wiklander  * Apple LLVM version 4.2 (clang-425.0.24) (based on LLVM 3.2svn)
1182817466cbSJens Wiklander  * appears to need this to prevent bad ARM code generation at -O3.
1183817466cbSJens Wiklander  */
1184817466cbSJens Wiklander __attribute__ ((noinline))
1185817466cbSJens Wiklander #endif
1186817466cbSJens Wiklander void mpi_mul_hlp( size_t i, mbedtls_mpi_uint *s, mbedtls_mpi_uint *d, mbedtls_mpi_uint b )
1187817466cbSJens Wiklander {
1188817466cbSJens Wiklander     mbedtls_mpi_uint c = 0, t = 0;
1189817466cbSJens Wiklander 
1190817466cbSJens Wiklander #if defined(MULADDC_HUIT)
1191817466cbSJens Wiklander     for( ; i >= 8; i -= 8 )
1192817466cbSJens Wiklander     {
1193817466cbSJens Wiklander         MULADDC_INIT
1194817466cbSJens Wiklander         MULADDC_HUIT
1195817466cbSJens Wiklander         MULADDC_STOP
1196817466cbSJens Wiklander     }
1197817466cbSJens Wiklander 
1198817466cbSJens Wiklander     for( ; i > 0; i-- )
1199817466cbSJens Wiklander     {
1200817466cbSJens Wiklander         MULADDC_INIT
1201817466cbSJens Wiklander         MULADDC_CORE
1202817466cbSJens Wiklander         MULADDC_STOP
1203817466cbSJens Wiklander     }
1204817466cbSJens Wiklander #else /* MULADDC_HUIT */
1205817466cbSJens Wiklander     for( ; i >= 16; i -= 16 )
1206817466cbSJens Wiklander     {
1207817466cbSJens Wiklander         MULADDC_INIT
1208817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1209817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1210817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1211817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1212817466cbSJens Wiklander 
1213817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1214817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1215817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1216817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1217817466cbSJens Wiklander         MULADDC_STOP
1218817466cbSJens Wiklander     }
1219817466cbSJens Wiklander 
1220817466cbSJens Wiklander     for( ; i >= 8; i -= 8 )
1221817466cbSJens Wiklander     {
1222817466cbSJens Wiklander         MULADDC_INIT
1223817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1224817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1225817466cbSJens Wiklander 
1226817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1227817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1228817466cbSJens Wiklander         MULADDC_STOP
1229817466cbSJens Wiklander     }
1230817466cbSJens Wiklander 
1231817466cbSJens Wiklander     for( ; i > 0; i-- )
1232817466cbSJens Wiklander     {
1233817466cbSJens Wiklander         MULADDC_INIT
1234817466cbSJens Wiklander         MULADDC_CORE
1235817466cbSJens Wiklander         MULADDC_STOP
1236817466cbSJens Wiklander     }
1237817466cbSJens Wiklander #endif /* MULADDC_HUIT */
1238817466cbSJens Wiklander 
1239817466cbSJens Wiklander     t++;
1240817466cbSJens Wiklander 
1241817466cbSJens Wiklander     do {
1242817466cbSJens Wiklander         *d += c; c = ( *d < c ); d++;
1243817466cbSJens Wiklander     }
1244817466cbSJens Wiklander     while( c != 0 );
1245817466cbSJens Wiklander }
1246817466cbSJens Wiklander 
1247817466cbSJens Wiklander /*
1248817466cbSJens Wiklander  * Baseline multiplication: X = A * B  (HAC 14.12)
1249817466cbSJens Wiklander  */
1250817466cbSJens Wiklander int mbedtls_mpi_mul_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B )
1251817466cbSJens Wiklander {
1252817466cbSJens Wiklander     int ret;
1253817466cbSJens Wiklander     size_t i, j;
1254817466cbSJens Wiklander     mbedtls_mpi TA, TB;
1255817466cbSJens Wiklander 
125698bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &TA ); mbedtls_mpi_init_mempool( &TB );
1257817466cbSJens Wiklander 
1258817466cbSJens Wiklander     if( X == A ) { MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TA, A ) ); A = &TA; }
1259817466cbSJens Wiklander     if( X == B ) { MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, B ) ); B = &TB; }
1260817466cbSJens Wiklander 
1261817466cbSJens Wiklander     for( i = A->n; i > 0; i-- )
1262817466cbSJens Wiklander         if( A->p[i - 1] != 0 )
1263817466cbSJens Wiklander             break;
1264817466cbSJens Wiklander 
1265817466cbSJens Wiklander     for( j = B->n; j > 0; j-- )
1266817466cbSJens Wiklander         if( B->p[j - 1] != 0 )
1267817466cbSJens Wiklander             break;
1268817466cbSJens Wiklander 
1269817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, i + j ) );
1270817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) );
1271817466cbSJens Wiklander 
1272817466cbSJens Wiklander     for( i++; j > 0; j-- )
1273817466cbSJens Wiklander         mpi_mul_hlp( i - 1, A->p, X->p + j - 1, B->p[j - 1] );
1274817466cbSJens Wiklander 
1275817466cbSJens Wiklander     X->s = A->s * B->s;
1276817466cbSJens Wiklander 
1277817466cbSJens Wiklander cleanup:
1278817466cbSJens Wiklander 
1279817466cbSJens Wiklander     mbedtls_mpi_free( &TB ); mbedtls_mpi_free( &TA );
1280817466cbSJens Wiklander 
1281817466cbSJens Wiklander     return( ret );
1282817466cbSJens Wiklander }
1283817466cbSJens Wiklander 
1284817466cbSJens Wiklander /*
1285817466cbSJens Wiklander  * Baseline multiplication: X = A * b
1286817466cbSJens Wiklander  */
1287817466cbSJens Wiklander int mbedtls_mpi_mul_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_uint b )
1288817466cbSJens Wiklander {
1289817466cbSJens Wiklander     mbedtls_mpi _B;
1290817466cbSJens Wiklander     mbedtls_mpi_uint p[1];
1291817466cbSJens Wiklander 
1292817466cbSJens Wiklander     _B.s = 1;
1293817466cbSJens Wiklander     _B.n = 1;
1294817466cbSJens Wiklander     _B.p = p;
1295817466cbSJens Wiklander     p[0] = b;
1296817466cbSJens Wiklander 
1297817466cbSJens Wiklander     return( mbedtls_mpi_mul_mpi( X, A, &_B ) );
1298817466cbSJens Wiklander }
1299817466cbSJens Wiklander 
1300817466cbSJens Wiklander /*
1301817466cbSJens Wiklander  * Unsigned integer divide - double mbedtls_mpi_uint dividend, u1/u0, and
1302817466cbSJens Wiklander  * mbedtls_mpi_uint divisor, d
1303817466cbSJens Wiklander  */
1304817466cbSJens Wiklander static mbedtls_mpi_uint mbedtls_int_div_int( mbedtls_mpi_uint u1,
1305817466cbSJens Wiklander             mbedtls_mpi_uint u0, mbedtls_mpi_uint d, mbedtls_mpi_uint *r )
1306817466cbSJens Wiklander {
1307817466cbSJens Wiklander #if defined(MBEDTLS_HAVE_UDBL)
1308817466cbSJens Wiklander     mbedtls_t_udbl dividend, quotient;
1309817466cbSJens Wiklander #else
1310817466cbSJens Wiklander     const mbedtls_mpi_uint radix = (mbedtls_mpi_uint) 1 << biH;
1311817466cbSJens Wiklander     const mbedtls_mpi_uint uint_halfword_mask = ( (mbedtls_mpi_uint) 1 << biH ) - 1;
1312817466cbSJens Wiklander     mbedtls_mpi_uint d0, d1, q0, q1, rAX, r0, quotient;
1313817466cbSJens Wiklander     mbedtls_mpi_uint u0_msw, u0_lsw;
1314817466cbSJens Wiklander     size_t s;
1315817466cbSJens Wiklander #endif
1316817466cbSJens Wiklander 
1317817466cbSJens Wiklander     /*
1318817466cbSJens Wiklander      * Check for overflow
1319817466cbSJens Wiklander      */
1320817466cbSJens Wiklander     if( 0 == d || u1 >= d )
1321817466cbSJens Wiklander     {
1322817466cbSJens Wiklander         if (r != NULL) *r = ~0;
1323817466cbSJens Wiklander 
1324817466cbSJens Wiklander         return ( ~0 );
1325817466cbSJens Wiklander     }
1326817466cbSJens Wiklander 
1327817466cbSJens Wiklander #if defined(MBEDTLS_HAVE_UDBL)
1328817466cbSJens Wiklander     dividend  = (mbedtls_t_udbl) u1 << biL;
1329817466cbSJens Wiklander     dividend |= (mbedtls_t_udbl) u0;
1330817466cbSJens Wiklander     quotient = dividend / d;
1331817466cbSJens Wiklander     if( quotient > ( (mbedtls_t_udbl) 1 << biL ) - 1 )
1332817466cbSJens Wiklander         quotient = ( (mbedtls_t_udbl) 1 << biL ) - 1;
1333817466cbSJens Wiklander 
1334817466cbSJens Wiklander     if( r != NULL )
1335817466cbSJens Wiklander         *r = (mbedtls_mpi_uint)( dividend - (quotient * d ) );
1336817466cbSJens Wiklander 
1337817466cbSJens Wiklander     return (mbedtls_mpi_uint) quotient;
1338817466cbSJens Wiklander #else
1339817466cbSJens Wiklander 
1340817466cbSJens Wiklander     /*
1341817466cbSJens Wiklander      * Algorithm D, Section 4.3.1 - The Art of Computer Programming
1342817466cbSJens Wiklander      *   Vol. 2 - Seminumerical Algorithms, Knuth
1343817466cbSJens Wiklander      */
1344817466cbSJens Wiklander 
1345817466cbSJens Wiklander     /*
1346817466cbSJens Wiklander      * Normalize the divisor, d, and dividend, u0, u1
1347817466cbSJens Wiklander      */
1348817466cbSJens Wiklander     s = mbedtls_clz( d );
1349817466cbSJens Wiklander     d = d << s;
1350817466cbSJens Wiklander 
1351817466cbSJens Wiklander     u1 = u1 << s;
1352817466cbSJens Wiklander     u1 |= ( u0 >> ( biL - s ) ) & ( -(mbedtls_mpi_sint)s >> ( biL - 1 ) );
1353817466cbSJens Wiklander     u0 =  u0 << s;
1354817466cbSJens Wiklander 
1355817466cbSJens Wiklander     d1 = d >> biH;
1356817466cbSJens Wiklander     d0 = d & uint_halfword_mask;
1357817466cbSJens Wiklander 
1358817466cbSJens Wiklander     u0_msw = u0 >> biH;
1359817466cbSJens Wiklander     u0_lsw = u0 & uint_halfword_mask;
1360817466cbSJens Wiklander 
1361817466cbSJens Wiklander     /*
1362817466cbSJens Wiklander      * Find the first quotient and remainder
1363817466cbSJens Wiklander      */
1364817466cbSJens Wiklander     q1 = u1 / d1;
1365817466cbSJens Wiklander     r0 = u1 - d1 * q1;
1366817466cbSJens Wiklander 
1367817466cbSJens Wiklander     while( q1 >= radix || ( q1 * d0 > radix * r0 + u0_msw ) )
1368817466cbSJens Wiklander     {
1369817466cbSJens Wiklander         q1 -= 1;
1370817466cbSJens Wiklander         r0 += d1;
1371817466cbSJens Wiklander 
1372817466cbSJens Wiklander         if ( r0 >= radix ) break;
1373817466cbSJens Wiklander     }
1374817466cbSJens Wiklander 
1375817466cbSJens Wiklander     rAX = ( u1 * radix ) + ( u0_msw - q1 * d );
1376817466cbSJens Wiklander     q0 = rAX / d1;
1377817466cbSJens Wiklander     r0 = rAX - q0 * d1;
1378817466cbSJens Wiklander 
1379817466cbSJens Wiklander     while( q0 >= radix || ( q0 * d0 > radix * r0 + u0_lsw ) )
1380817466cbSJens Wiklander     {
1381817466cbSJens Wiklander         q0 -= 1;
1382817466cbSJens Wiklander         r0 += d1;
1383817466cbSJens Wiklander 
1384817466cbSJens Wiklander         if ( r0 >= radix ) break;
1385817466cbSJens Wiklander     }
1386817466cbSJens Wiklander 
1387817466cbSJens Wiklander     if (r != NULL)
1388817466cbSJens Wiklander         *r = ( rAX * radix + u0_lsw - q0 * d ) >> s;
1389817466cbSJens Wiklander 
1390817466cbSJens Wiklander     quotient = q1 * radix + q0;
1391817466cbSJens Wiklander 
1392817466cbSJens Wiklander     return quotient;
1393817466cbSJens Wiklander #endif
1394817466cbSJens Wiklander }
1395817466cbSJens Wiklander 
1396817466cbSJens Wiklander /*
1397817466cbSJens Wiklander  * Division by mbedtls_mpi: A = Q * B + R  (HAC 14.20)
1398817466cbSJens Wiklander  */
1399817466cbSJens Wiklander int mbedtls_mpi_div_mpi( mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B )
1400817466cbSJens Wiklander {
1401817466cbSJens Wiklander     int ret;
1402817466cbSJens Wiklander     size_t i, n, t, k;
1403817466cbSJens Wiklander     mbedtls_mpi X, Y, Z, T1, T2;
1404817466cbSJens Wiklander 
1405817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( B, 0 ) == 0 )
1406817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_DIVISION_BY_ZERO );
1407817466cbSJens Wiklander 
140898bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &X ); mbedtls_mpi_init_mempool( &Y );
140998bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &Z ); mbedtls_mpi_init_mempool( &T1 );
141098bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &T2 );
1411817466cbSJens Wiklander 
1412817466cbSJens Wiklander     if( mbedtls_mpi_cmp_abs( A, B ) < 0 )
1413817466cbSJens Wiklander     {
1414817466cbSJens Wiklander         if( Q != NULL ) MBEDTLS_MPI_CHK( mbedtls_mpi_lset( Q, 0 ) );
1415817466cbSJens Wiklander         if( R != NULL ) MBEDTLS_MPI_CHK( mbedtls_mpi_copy( R, A ) );
1416817466cbSJens Wiklander         return( 0 );
1417817466cbSJens Wiklander     }
1418817466cbSJens Wiklander 
1419817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &X, A ) );
1420817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &Y, B ) );
1421817466cbSJens Wiklander     X.s = Y.s = 1;
1422817466cbSJens Wiklander 
1423817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &Z, A->n + 2 ) );
1424817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &Z,  0 ) );
1425817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &T1, 2 ) );
1426817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &T2, 3 ) );
1427817466cbSJens Wiklander 
1428817466cbSJens Wiklander     k = mbedtls_mpi_bitlen( &Y ) % biL;
1429817466cbSJens Wiklander     if( k < biL - 1 )
1430817466cbSJens Wiklander     {
1431817466cbSJens Wiklander         k = biL - 1 - k;
1432817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &X, k ) );
1433817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &Y, k ) );
1434817466cbSJens Wiklander     }
1435817466cbSJens Wiklander     else k = 0;
1436817466cbSJens Wiklander 
1437817466cbSJens Wiklander     n = X.n - 1;
1438817466cbSJens Wiklander     t = Y.n - 1;
1439817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &Y, biL * ( n - t ) ) );
1440817466cbSJens Wiklander 
1441817466cbSJens Wiklander     while( mbedtls_mpi_cmp_mpi( &X, &Y ) >= 0 )
1442817466cbSJens Wiklander     {
1443817466cbSJens Wiklander         Z.p[n - t]++;
1444817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &X, &X, &Y ) );
1445817466cbSJens Wiklander     }
1446817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &Y, biL * ( n - t ) ) );
1447817466cbSJens Wiklander 
1448817466cbSJens Wiklander     for( i = n; i > t ; i-- )
1449817466cbSJens Wiklander     {
1450817466cbSJens Wiklander         if( X.p[i] >= Y.p[t] )
1451817466cbSJens Wiklander             Z.p[i - t - 1] = ~0;
1452817466cbSJens Wiklander         else
1453817466cbSJens Wiklander         {
1454817466cbSJens Wiklander             Z.p[i - t - 1] = mbedtls_int_div_int( X.p[i], X.p[i - 1],
1455817466cbSJens Wiklander                                                             Y.p[t], NULL);
1456817466cbSJens Wiklander         }
1457817466cbSJens Wiklander 
1458817466cbSJens Wiklander         Z.p[i - t - 1]++;
1459817466cbSJens Wiklander         do
1460817466cbSJens Wiklander         {
1461817466cbSJens Wiklander             Z.p[i - t - 1]--;
1462817466cbSJens Wiklander 
1463817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &T1, 0 ) );
1464817466cbSJens Wiklander             T1.p[0] = ( t < 1 ) ? 0 : Y.p[t - 1];
1465817466cbSJens Wiklander             T1.p[1] = Y.p[t];
1466817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &T1, &T1, Z.p[i - t - 1] ) );
1467817466cbSJens Wiklander 
1468817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &T2, 0 ) );
1469817466cbSJens Wiklander             T2.p[0] = ( i < 2 ) ? 0 : X.p[i - 2];
1470817466cbSJens Wiklander             T2.p[1] = ( i < 1 ) ? 0 : X.p[i - 1];
1471817466cbSJens Wiklander             T2.p[2] = X.p[i];
1472817466cbSJens Wiklander         }
1473817466cbSJens Wiklander         while( mbedtls_mpi_cmp_mpi( &T1, &T2 ) > 0 );
1474817466cbSJens Wiklander 
1475817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &T1, &Y, Z.p[i - t - 1] ) );
1476817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &T1,  biL * ( i - t - 1 ) ) );
1477817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &X, &X, &T1 ) );
1478817466cbSJens Wiklander 
1479817466cbSJens Wiklander         if( mbedtls_mpi_cmp_int( &X, 0 ) < 0 )
1480817466cbSJens Wiklander         {
1481817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &T1, &Y ) );
1482817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &T1, biL * ( i - t - 1 ) ) );
1483817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &X, &X, &T1 ) );
1484817466cbSJens Wiklander             Z.p[i - t - 1]--;
1485817466cbSJens Wiklander         }
1486817466cbSJens Wiklander     }
1487817466cbSJens Wiklander 
1488817466cbSJens Wiklander     if( Q != NULL )
1489817466cbSJens Wiklander     {
1490817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( Q, &Z ) );
1491817466cbSJens Wiklander         Q->s = A->s * B->s;
1492817466cbSJens Wiklander     }
1493817466cbSJens Wiklander 
1494817466cbSJens Wiklander     if( R != NULL )
1495817466cbSJens Wiklander     {
1496817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &X, k ) );
1497817466cbSJens Wiklander         X.s = A->s;
1498817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( R, &X ) );
1499817466cbSJens Wiklander 
1500817466cbSJens Wiklander         if( mbedtls_mpi_cmp_int( R, 0 ) == 0 )
1501817466cbSJens Wiklander             R->s = 1;
1502817466cbSJens Wiklander     }
1503817466cbSJens Wiklander 
1504817466cbSJens Wiklander cleanup:
1505817466cbSJens Wiklander 
1506817466cbSJens Wiklander     mbedtls_mpi_free( &X ); mbedtls_mpi_free( &Y ); mbedtls_mpi_free( &Z );
1507817466cbSJens Wiklander     mbedtls_mpi_free( &T1 ); mbedtls_mpi_free( &T2 );
1508817466cbSJens Wiklander 
1509817466cbSJens Wiklander     return( ret );
1510817466cbSJens Wiklander }
1511817466cbSJens Wiklander 
1512817466cbSJens Wiklander /*
1513817466cbSJens Wiklander  * Division by int: A = Q * b + R
1514817466cbSJens Wiklander  */
1515817466cbSJens Wiklander int mbedtls_mpi_div_int( mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A, mbedtls_mpi_sint b )
1516817466cbSJens Wiklander {
1517817466cbSJens Wiklander     mbedtls_mpi _B;
1518817466cbSJens Wiklander     mbedtls_mpi_uint p[1];
1519817466cbSJens Wiklander 
1520817466cbSJens Wiklander     p[0] = ( b < 0 ) ? -b : b;
1521817466cbSJens Wiklander     _B.s = ( b < 0 ) ? -1 : 1;
1522817466cbSJens Wiklander     _B.n = 1;
1523817466cbSJens Wiklander     _B.p = p;
1524817466cbSJens Wiklander 
1525817466cbSJens Wiklander     return( mbedtls_mpi_div_mpi( Q, R, A, &_B ) );
1526817466cbSJens Wiklander }
1527817466cbSJens Wiklander 
1528817466cbSJens Wiklander /*
1529817466cbSJens Wiklander  * Modulo: R = A mod B
1530817466cbSJens Wiklander  */
1531817466cbSJens Wiklander int mbedtls_mpi_mod_mpi( mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B )
1532817466cbSJens Wiklander {
1533817466cbSJens Wiklander     int ret;
1534817466cbSJens Wiklander 
1535817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( B, 0 ) < 0 )
1536817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_NEGATIVE_VALUE );
1537817466cbSJens Wiklander 
1538817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_div_mpi( NULL, R, A, B ) );
1539817466cbSJens Wiklander 
1540817466cbSJens Wiklander     while( mbedtls_mpi_cmp_int( R, 0 ) < 0 )
1541817466cbSJens Wiklander       MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( R, R, B ) );
1542817466cbSJens Wiklander 
1543817466cbSJens Wiklander     while( mbedtls_mpi_cmp_mpi( R, B ) >= 0 )
1544817466cbSJens Wiklander       MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( R, R, B ) );
1545817466cbSJens Wiklander 
1546817466cbSJens Wiklander cleanup:
1547817466cbSJens Wiklander 
1548817466cbSJens Wiklander     return( ret );
1549817466cbSJens Wiklander }
1550817466cbSJens Wiklander 
1551817466cbSJens Wiklander /*
1552817466cbSJens Wiklander  * Modulo: r = A mod b
1553817466cbSJens Wiklander  */
1554817466cbSJens Wiklander int mbedtls_mpi_mod_int( mbedtls_mpi_uint *r, const mbedtls_mpi *A, mbedtls_mpi_sint b )
1555817466cbSJens Wiklander {
1556817466cbSJens Wiklander     size_t i;
1557817466cbSJens Wiklander     mbedtls_mpi_uint x, y, z;
1558817466cbSJens Wiklander 
1559817466cbSJens Wiklander     if( b == 0 )
1560817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_DIVISION_BY_ZERO );
1561817466cbSJens Wiklander 
1562817466cbSJens Wiklander     if( b < 0 )
1563817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_NEGATIVE_VALUE );
1564817466cbSJens Wiklander 
1565817466cbSJens Wiklander     /*
1566817466cbSJens Wiklander      * handle trivial cases
1567817466cbSJens Wiklander      */
1568817466cbSJens Wiklander     if( b == 1 )
1569817466cbSJens Wiklander     {
1570817466cbSJens Wiklander         *r = 0;
1571817466cbSJens Wiklander         return( 0 );
1572817466cbSJens Wiklander     }
1573817466cbSJens Wiklander 
1574817466cbSJens Wiklander     if( b == 2 )
1575817466cbSJens Wiklander     {
1576817466cbSJens Wiklander         *r = A->p[0] & 1;
1577817466cbSJens Wiklander         return( 0 );
1578817466cbSJens Wiklander     }
1579817466cbSJens Wiklander 
1580817466cbSJens Wiklander     /*
1581817466cbSJens Wiklander      * general case
1582817466cbSJens Wiklander      */
1583817466cbSJens Wiklander     for( i = A->n, y = 0; i > 0; i-- )
1584817466cbSJens Wiklander     {
1585817466cbSJens Wiklander         x  = A->p[i - 1];
1586817466cbSJens Wiklander         y  = ( y << biH ) | ( x >> biH );
1587817466cbSJens Wiklander         z  = y / b;
1588817466cbSJens Wiklander         y -= z * b;
1589817466cbSJens Wiklander 
1590817466cbSJens Wiklander         x <<= biH;
1591817466cbSJens Wiklander         y  = ( y << biH ) | ( x >> biH );
1592817466cbSJens Wiklander         z  = y / b;
1593817466cbSJens Wiklander         y -= z * b;
1594817466cbSJens Wiklander     }
1595817466cbSJens Wiklander 
1596817466cbSJens Wiklander     /*
1597817466cbSJens Wiklander      * If A is negative, then the current y represents a negative value.
1598817466cbSJens Wiklander      * Flipping it to the positive side.
1599817466cbSJens Wiklander      */
1600817466cbSJens Wiklander     if( A->s < 0 && y != 0 )
1601817466cbSJens Wiklander         y = b - y;
1602817466cbSJens Wiklander 
1603817466cbSJens Wiklander     *r = y;
1604817466cbSJens Wiklander 
1605817466cbSJens Wiklander     return( 0 );
1606817466cbSJens Wiklander }
1607817466cbSJens Wiklander 
1608817466cbSJens Wiklander /*
1609817466cbSJens Wiklander  * Fast Montgomery initialization (thanks to Tom St Denis)
1610817466cbSJens Wiklander  */
161162f21181SJens Wiklander void mbedtls_mpi_montg_init( mbedtls_mpi_uint *mm, const mbedtls_mpi *N )
1612817466cbSJens Wiklander {
1613817466cbSJens Wiklander     mbedtls_mpi_uint x, m0 = N->p[0];
1614817466cbSJens Wiklander     unsigned int i;
1615817466cbSJens Wiklander 
1616817466cbSJens Wiklander     x  = m0;
1617817466cbSJens Wiklander     x += ( ( m0 + 2 ) & 4 ) << 1;
1618817466cbSJens Wiklander 
1619817466cbSJens Wiklander     for( i = biL; i >= 8; i /= 2 )
1620817466cbSJens Wiklander         x *= ( 2 - ( m0 * x ) );
1621817466cbSJens Wiklander 
1622817466cbSJens Wiklander     *mm = ~x + 1;
1623817466cbSJens Wiklander }
1624817466cbSJens Wiklander 
1625817466cbSJens Wiklander /*
1626817466cbSJens Wiklander  * Montgomery multiplication: A = A * B * R^-1 mod N  (HAC 14.36)
1627817466cbSJens Wiklander  */
162862f21181SJens Wiklander int mbedtls_mpi_montmul( mbedtls_mpi *A, const mbedtls_mpi *B,
162962f21181SJens Wiklander 			 const mbedtls_mpi *N, mbedtls_mpi_uint mm,
1630817466cbSJens Wiklander                          const mbedtls_mpi *T )
1631817466cbSJens Wiklander {
1632817466cbSJens Wiklander     size_t i, n, m;
1633817466cbSJens Wiklander     mbedtls_mpi_uint u0, u1, *d;
1634817466cbSJens Wiklander 
1635817466cbSJens Wiklander     if( T->n < N->n + 1 || T->p == NULL )
1636817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
1637817466cbSJens Wiklander 
1638817466cbSJens Wiklander     memset( T->p, 0, T->n * ciL );
1639817466cbSJens Wiklander 
1640817466cbSJens Wiklander     d = T->p;
1641817466cbSJens Wiklander     n = N->n;
1642817466cbSJens Wiklander     m = ( B->n < n ) ? B->n : n;
1643817466cbSJens Wiklander 
1644817466cbSJens Wiklander     for( i = 0; i < n; i++ )
1645817466cbSJens Wiklander     {
1646817466cbSJens Wiklander         /*
1647817466cbSJens Wiklander          * T = (T + u0*B + u1*N) / 2^biL
1648817466cbSJens Wiklander          */
1649817466cbSJens Wiklander         u0 = A->p[i];
1650817466cbSJens Wiklander         u1 = ( d[0] + u0 * B->p[0] ) * mm;
1651817466cbSJens Wiklander 
1652817466cbSJens Wiklander         mpi_mul_hlp( m, B->p, d, u0 );
1653817466cbSJens Wiklander         mpi_mul_hlp( n, N->p, d, u1 );
1654817466cbSJens Wiklander 
1655817466cbSJens Wiklander         *d++ = u0; d[n + 1] = 0;
1656817466cbSJens Wiklander     }
1657817466cbSJens Wiklander 
1658817466cbSJens Wiklander     memcpy( A->p, d, ( n + 1 ) * ciL );
1659817466cbSJens Wiklander 
1660817466cbSJens Wiklander     if( mbedtls_mpi_cmp_abs( A, N ) >= 0 )
1661817466cbSJens Wiklander         mpi_sub_hlp( n, N->p, A->p );
1662817466cbSJens Wiklander     else
1663817466cbSJens Wiklander         /* prevent timing attacks */
1664817466cbSJens Wiklander         mpi_sub_hlp( n, A->p, T->p );
1665817466cbSJens Wiklander 
1666817466cbSJens Wiklander     return( 0 );
1667817466cbSJens Wiklander }
1668817466cbSJens Wiklander 
1669817466cbSJens Wiklander /*
1670817466cbSJens Wiklander  * Montgomery reduction: A = A * R^-1 mod N
1671817466cbSJens Wiklander  */
167262f21181SJens Wiklander int mbedtls_mpi_montred( mbedtls_mpi *A, const mbedtls_mpi *N,
167362f21181SJens Wiklander 			 mbedtls_mpi_uint mm, const mbedtls_mpi *T )
1674817466cbSJens Wiklander {
1675817466cbSJens Wiklander     mbedtls_mpi_uint z = 1;
1676817466cbSJens Wiklander     mbedtls_mpi U;
1677817466cbSJens Wiklander 
1678817466cbSJens Wiklander     U.n = U.s = (int) z;
1679817466cbSJens Wiklander     U.p = &z;
1680817466cbSJens Wiklander 
168162f21181SJens Wiklander     return( mbedtls_mpi_montmul( A, &U, N, mm, T ) );
1682817466cbSJens Wiklander }
1683817466cbSJens Wiklander 
1684817466cbSJens Wiklander /*
1685817466cbSJens Wiklander  * Sliding-window exponentiation: X = A^E mod N  (HAC 14.85)
1686817466cbSJens Wiklander  */
1687817466cbSJens Wiklander int mbedtls_mpi_exp_mod( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *E, const mbedtls_mpi *N, mbedtls_mpi *_RR )
1688817466cbSJens Wiklander {
1689817466cbSJens Wiklander     int ret;
1690817466cbSJens Wiklander     size_t wbits, wsize, one = 1;
1691817466cbSJens Wiklander     size_t i, j, nblimbs;
1692817466cbSJens Wiklander     size_t bufsize, nbits;
1693817466cbSJens Wiklander     mbedtls_mpi_uint ei, mm, state;
1694817466cbSJens Wiklander     mbedtls_mpi RR, T, W[ 2 << MBEDTLS_MPI_WINDOW_SIZE ], Apos;
1695817466cbSJens Wiklander     int neg;
1696817466cbSJens Wiklander 
1697817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( N, 0 ) < 0 || ( N->p[0] & 1 ) == 0 )
1698817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
1699817466cbSJens Wiklander 
1700817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( E, 0 ) < 0 )
1701817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
1702817466cbSJens Wiklander 
1703817466cbSJens Wiklander     /*
1704817466cbSJens Wiklander      * Init temps and window size
1705817466cbSJens Wiklander      */
170662f21181SJens Wiklander     mbedtls_mpi_montg_init( &mm, N );
170798bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &RR ); mbedtls_mpi_init_mempool( &T );
170898bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &Apos );
1709817466cbSJens Wiklander     memset( W, 0, sizeof( W ) );
1710817466cbSJens Wiklander 
1711817466cbSJens Wiklander     i = mbedtls_mpi_bitlen( E );
1712817466cbSJens Wiklander 
1713817466cbSJens Wiklander     wsize = ( i > 671 ) ? 6 : ( i > 239 ) ? 5 :
1714817466cbSJens Wiklander             ( i >  79 ) ? 4 : ( i >  23 ) ? 3 : 1;
1715817466cbSJens Wiklander 
1716817466cbSJens Wiklander     if( wsize > MBEDTLS_MPI_WINDOW_SIZE )
1717817466cbSJens Wiklander         wsize = MBEDTLS_MPI_WINDOW_SIZE;
1718817466cbSJens Wiklander 
1719817466cbSJens Wiklander     j = N->n + 1;
1720817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, j ) );
1721817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[1],  j ) );
1722817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &T, j * 2 ) );
1723817466cbSJens Wiklander 
1724817466cbSJens Wiklander     /*
1725817466cbSJens Wiklander      * Compensate for negative A (and correct at the end)
1726817466cbSJens Wiklander      */
1727817466cbSJens Wiklander     neg = ( A->s == -1 );
1728817466cbSJens Wiklander     if( neg )
1729817466cbSJens Wiklander     {
1730817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &Apos, A ) );
1731817466cbSJens Wiklander         Apos.s = 1;
1732817466cbSJens Wiklander         A = &Apos;
1733817466cbSJens Wiklander     }
1734817466cbSJens Wiklander 
1735817466cbSJens Wiklander     /*
1736817466cbSJens Wiklander      * If 1st call, pre-compute R^2 mod N
1737817466cbSJens Wiklander      */
1738817466cbSJens Wiklander     if( _RR == NULL || _RR->p == NULL )
1739817466cbSJens Wiklander     {
1740817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &RR, 1 ) );
1741817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &RR, N->n * 2 * biL ) );
1742817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &RR, &RR, N ) );
1743817466cbSJens Wiklander 
1744817466cbSJens Wiklander         if( _RR != NULL )
1745817466cbSJens Wiklander             memcpy( _RR, &RR, sizeof( mbedtls_mpi ) );
1746817466cbSJens Wiklander     }
1747817466cbSJens Wiklander     else
1748817466cbSJens Wiklander         memcpy( &RR, _RR, sizeof( mbedtls_mpi ) );
1749817466cbSJens Wiklander 
1750817466cbSJens Wiklander     /*
1751817466cbSJens Wiklander      * W[1] = A * R^2 * R^-1 mod N = A * R mod N
1752817466cbSJens Wiklander      */
1753817466cbSJens Wiklander     if( mbedtls_mpi_cmp_mpi( A, N ) >= 0 )
1754817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &W[1], A, N ) );
1755817466cbSJens Wiklander     else
1756817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &W[1], A ) );
1757817466cbSJens Wiklander 
175862f21181SJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_montmul( &W[1], &RR, N, mm, &T ) );
1759817466cbSJens Wiklander 
1760817466cbSJens Wiklander     /*
1761817466cbSJens Wiklander      * X = R^2 * R^-1 mod N = R mod N
1762817466cbSJens Wiklander      */
1763817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, &RR ) );
176462f21181SJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_montred( X, N, mm, &T ) );
1765817466cbSJens Wiklander 
1766817466cbSJens Wiklander     if( wsize > 1 )
1767817466cbSJens Wiklander     {
1768817466cbSJens Wiklander         /*
1769817466cbSJens Wiklander          * W[1 << (wsize - 1)] = W[1] ^ (wsize - 1)
1770817466cbSJens Wiklander          */
1771817466cbSJens Wiklander         j =  one << ( wsize - 1 );
1772817466cbSJens Wiklander 
1773817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[j], N->n + 1 ) );
1774817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &W[j], &W[1]    ) );
1775817466cbSJens Wiklander 
1776817466cbSJens Wiklander         for( i = 0; i < wsize - 1; i++ )
177762f21181SJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_montmul( &W[j], &W[j], N, mm, &T ) );
1778817466cbSJens Wiklander 
1779817466cbSJens Wiklander         /*
1780817466cbSJens Wiklander          * W[i] = W[i - 1] * W[1]
1781817466cbSJens Wiklander          */
1782817466cbSJens Wiklander         for( i = j + 1; i < ( one << wsize ); i++ )
1783817466cbSJens Wiklander         {
1784817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[i], N->n + 1 ) );
1785817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &W[i], &W[i - 1] ) );
1786817466cbSJens Wiklander 
178762f21181SJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_montmul( &W[i], &W[1], N, mm, &T ) );
1788817466cbSJens Wiklander         }
1789817466cbSJens Wiklander     }
1790817466cbSJens Wiklander 
1791817466cbSJens Wiklander     nblimbs = E->n;
1792817466cbSJens Wiklander     bufsize = 0;
1793817466cbSJens Wiklander     nbits   = 0;
1794817466cbSJens Wiklander     wbits   = 0;
1795817466cbSJens Wiklander     state   = 0;
1796817466cbSJens Wiklander 
1797817466cbSJens Wiklander     while( 1 )
1798817466cbSJens Wiklander     {
1799817466cbSJens Wiklander         if( bufsize == 0 )
1800817466cbSJens Wiklander         {
1801817466cbSJens Wiklander             if( nblimbs == 0 )
1802817466cbSJens Wiklander                 break;
1803817466cbSJens Wiklander 
1804817466cbSJens Wiklander             nblimbs--;
1805817466cbSJens Wiklander 
1806817466cbSJens Wiklander             bufsize = sizeof( mbedtls_mpi_uint ) << 3;
1807817466cbSJens Wiklander         }
1808817466cbSJens Wiklander 
1809817466cbSJens Wiklander         bufsize--;
1810817466cbSJens Wiklander 
1811817466cbSJens Wiklander         ei = (E->p[nblimbs] >> bufsize) & 1;
1812817466cbSJens Wiklander 
1813817466cbSJens Wiklander         /*
1814817466cbSJens Wiklander          * skip leading 0s
1815817466cbSJens Wiklander          */
1816817466cbSJens Wiklander         if( ei == 0 && state == 0 )
1817817466cbSJens Wiklander             continue;
1818817466cbSJens Wiklander 
1819817466cbSJens Wiklander         if( ei == 0 && state == 1 )
1820817466cbSJens Wiklander         {
1821817466cbSJens Wiklander             /*
1822817466cbSJens Wiklander              * out of window, square X
1823817466cbSJens Wiklander              */
182462f21181SJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_montmul( X, X, N, mm, &T ) );
1825817466cbSJens Wiklander             continue;
1826817466cbSJens Wiklander         }
1827817466cbSJens Wiklander 
1828817466cbSJens Wiklander         /*
1829817466cbSJens Wiklander          * add ei to current window
1830817466cbSJens Wiklander          */
1831817466cbSJens Wiklander         state = 2;
1832817466cbSJens Wiklander 
1833817466cbSJens Wiklander         nbits++;
1834817466cbSJens Wiklander         wbits |= ( ei << ( wsize - nbits ) );
1835817466cbSJens Wiklander 
1836817466cbSJens Wiklander         if( nbits == wsize )
1837817466cbSJens Wiklander         {
1838817466cbSJens Wiklander             /*
1839817466cbSJens Wiklander              * X = X^wsize R^-1 mod N
1840817466cbSJens Wiklander              */
1841817466cbSJens Wiklander             for( i = 0; i < wsize; i++ )
184262f21181SJens Wiklander                 MBEDTLS_MPI_CHK( mbedtls_mpi_montmul( X, X, N, mm, &T ) );
1843817466cbSJens Wiklander 
1844817466cbSJens Wiklander             /*
1845817466cbSJens Wiklander              * X = X * W[wbits] R^-1 mod N
1846817466cbSJens Wiklander              */
184762f21181SJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_montmul( X, &W[wbits], N, mm, &T ) );
1848817466cbSJens Wiklander 
1849817466cbSJens Wiklander             state--;
1850817466cbSJens Wiklander             nbits = 0;
1851817466cbSJens Wiklander             wbits = 0;
1852817466cbSJens Wiklander         }
1853817466cbSJens Wiklander     }
1854817466cbSJens Wiklander 
1855817466cbSJens Wiklander     /*
1856817466cbSJens Wiklander      * process the remaining bits
1857817466cbSJens Wiklander      */
1858817466cbSJens Wiklander     for( i = 0; i < nbits; i++ )
1859817466cbSJens Wiklander     {
186062f21181SJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_montmul( X, X, N, mm, &T ) );
1861817466cbSJens Wiklander 
1862817466cbSJens Wiklander         wbits <<= 1;
1863817466cbSJens Wiklander 
1864817466cbSJens Wiklander         if( ( wbits & ( one << wsize ) ) != 0 )
186562f21181SJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_montmul( X, &W[1], N, mm, &T ) );
1866817466cbSJens Wiklander     }
1867817466cbSJens Wiklander 
1868817466cbSJens Wiklander     /*
1869817466cbSJens Wiklander      * X = A^E * R * R^-1 mod N = A^E mod N
1870817466cbSJens Wiklander      */
187162f21181SJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_montred( X, N, mm, &T ) );
1872817466cbSJens Wiklander 
1873817466cbSJens Wiklander     if( neg && E->n != 0 && ( E->p[0] & 1 ) != 0 )
1874817466cbSJens Wiklander     {
1875817466cbSJens Wiklander         X->s = -1;
1876817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( X, N, X ) );
1877817466cbSJens Wiklander     }
1878817466cbSJens Wiklander 
1879817466cbSJens Wiklander cleanup:
1880817466cbSJens Wiklander 
1881817466cbSJens Wiklander     for( i = ( one << ( wsize - 1 ) ); i < ( one << wsize ); i++ )
1882817466cbSJens Wiklander         mbedtls_mpi_free( &W[i] );
1883817466cbSJens Wiklander 
1884817466cbSJens Wiklander     mbedtls_mpi_free( &W[1] ); mbedtls_mpi_free( &T ); mbedtls_mpi_free( &Apos );
1885817466cbSJens Wiklander 
1886817466cbSJens Wiklander     if( _RR == NULL || _RR->p == NULL )
1887817466cbSJens Wiklander         mbedtls_mpi_free( &RR );
1888817466cbSJens Wiklander 
1889817466cbSJens Wiklander     return( ret );
1890817466cbSJens Wiklander }
1891817466cbSJens Wiklander 
1892817466cbSJens Wiklander /*
1893817466cbSJens Wiklander  * Greatest common divisor: G = gcd(A, B)  (HAC 14.54)
1894817466cbSJens Wiklander  */
1895817466cbSJens Wiklander int mbedtls_mpi_gcd( mbedtls_mpi *G, const mbedtls_mpi *A, const mbedtls_mpi *B )
1896817466cbSJens Wiklander {
1897817466cbSJens Wiklander     int ret;
1898817466cbSJens Wiklander     size_t lz, lzt;
1899817466cbSJens Wiklander     mbedtls_mpi TG, TA, TB;
1900817466cbSJens Wiklander 
190198bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &TG ); mbedtls_mpi_init_mempool( &TA );
190298bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &TB );
1903817466cbSJens Wiklander 
1904817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TA, A ) );
1905817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, B ) );
1906817466cbSJens Wiklander 
1907817466cbSJens Wiklander     lz = mbedtls_mpi_lsb( &TA );
1908817466cbSJens Wiklander     lzt = mbedtls_mpi_lsb( &TB );
1909817466cbSJens Wiklander 
1910817466cbSJens Wiklander     if( lzt < lz )
1911817466cbSJens Wiklander         lz = lzt;
1912817466cbSJens Wiklander 
1913817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TA, lz ) );
1914817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TB, lz ) );
1915817466cbSJens Wiklander 
1916817466cbSJens Wiklander     TA.s = TB.s = 1;
1917817466cbSJens Wiklander 
1918817466cbSJens Wiklander     while( mbedtls_mpi_cmp_int( &TA, 0 ) != 0 )
1919817466cbSJens Wiklander     {
1920817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TA, mbedtls_mpi_lsb( &TA ) ) );
1921817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TB, mbedtls_mpi_lsb( &TB ) ) );
1922817466cbSJens Wiklander 
1923817466cbSJens Wiklander         if( mbedtls_mpi_cmp_mpi( &TA, &TB ) >= 0 )
1924817466cbSJens Wiklander         {
1925817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( &TA, &TA, &TB ) );
1926817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TA, 1 ) );
1927817466cbSJens Wiklander         }
1928817466cbSJens Wiklander         else
1929817466cbSJens Wiklander         {
1930817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( &TB, &TB, &TA ) );
1931817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TB, 1 ) );
1932817466cbSJens Wiklander         }
1933817466cbSJens Wiklander     }
1934817466cbSJens Wiklander 
1935817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &TB, lz ) );
1936817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( G, &TB ) );
1937817466cbSJens Wiklander 
1938817466cbSJens Wiklander cleanup:
1939817466cbSJens Wiklander 
1940817466cbSJens Wiklander     mbedtls_mpi_free( &TG ); mbedtls_mpi_free( &TA ); mbedtls_mpi_free( &TB );
1941817466cbSJens Wiklander 
1942817466cbSJens Wiklander     return( ret );
1943817466cbSJens Wiklander }
1944817466cbSJens Wiklander 
1945817466cbSJens Wiklander /*
1946817466cbSJens Wiklander  * Fill X with size bytes of random.
1947817466cbSJens Wiklander  *
1948817466cbSJens Wiklander  * Use a temporary bytes representation to make sure the result is the same
1949817466cbSJens Wiklander  * regardless of the platform endianness (useful when f_rng is actually
1950817466cbSJens Wiklander  * deterministic, eg for tests).
1951817466cbSJens Wiklander  */
1952817466cbSJens Wiklander int mbedtls_mpi_fill_random( mbedtls_mpi *X, size_t size,
1953817466cbSJens Wiklander                      int (*f_rng)(void *, unsigned char *, size_t),
1954817466cbSJens Wiklander                      void *p_rng )
1955817466cbSJens Wiklander {
1956817466cbSJens Wiklander     int ret;
1957817466cbSJens Wiklander     unsigned char buf[MBEDTLS_MPI_MAX_SIZE];
1958817466cbSJens Wiklander 
1959817466cbSJens Wiklander     if( size > MBEDTLS_MPI_MAX_SIZE )
1960817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
1961817466cbSJens Wiklander 
1962817466cbSJens Wiklander     MBEDTLS_MPI_CHK( f_rng( p_rng, buf, size ) );
1963817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( X, buf, size ) );
1964817466cbSJens Wiklander 
1965817466cbSJens Wiklander cleanup:
1966817466cbSJens Wiklander     return( ret );
1967817466cbSJens Wiklander }
1968817466cbSJens Wiklander 
1969817466cbSJens Wiklander /*
1970817466cbSJens Wiklander  * Modular inverse: X = A^-1 mod N  (HAC 14.61 / 14.64)
1971817466cbSJens Wiklander  */
1972817466cbSJens Wiklander int mbedtls_mpi_inv_mod( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *N )
1973817466cbSJens Wiklander {
1974817466cbSJens Wiklander     int ret;
1975817466cbSJens Wiklander     mbedtls_mpi G, TA, TU, U1, U2, TB, TV, V1, V2;
1976817466cbSJens Wiklander 
1977817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( N, 1 ) <= 0 )
1978817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
1979817466cbSJens Wiklander 
198098bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &TA ); mbedtls_mpi_init_mempool( &TU );
198198bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &U1 ); mbedtls_mpi_init_mempool( &U2 );
198298bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &G ); mbedtls_mpi_init_mempool( &TB );
198398bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &TV ); mbedtls_mpi_init_mempool( &V1 );
198498bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &V2 );
1985817466cbSJens Wiklander 
1986817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &G, A, N ) );
1987817466cbSJens Wiklander 
1988817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( &G, 1 ) != 0 )
1989817466cbSJens Wiklander     {
1990817466cbSJens Wiklander         ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
1991817466cbSJens Wiklander         goto cleanup;
1992817466cbSJens Wiklander     }
1993817466cbSJens Wiklander 
1994817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &TA, A, N ) );
1995817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TU, &TA ) );
1996817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, N ) );
1997817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TV, N ) );
1998817466cbSJens Wiklander 
1999817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &U1, 1 ) );
2000817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &U2, 0 ) );
2001817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &V1, 0 ) );
2002817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &V2, 1 ) );
2003817466cbSJens Wiklander 
2004817466cbSJens Wiklander     do
2005817466cbSJens Wiklander     {
2006817466cbSJens Wiklander         while( ( TU.p[0] & 1 ) == 0 )
2007817466cbSJens Wiklander         {
2008817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TU, 1 ) );
2009817466cbSJens Wiklander 
2010817466cbSJens Wiklander             if( ( U1.p[0] & 1 ) != 0 || ( U2.p[0] & 1 ) != 0 )
2011817466cbSJens Wiklander             {
2012817466cbSJens Wiklander                 MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &U1, &U1, &TB ) );
2013817466cbSJens Wiklander                 MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &U2, &U2, &TA ) );
2014817466cbSJens Wiklander             }
2015817466cbSJens Wiklander 
2016817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &U1, 1 ) );
2017817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &U2, 1 ) );
2018817466cbSJens Wiklander         }
2019817466cbSJens Wiklander 
2020817466cbSJens Wiklander         while( ( TV.p[0] & 1 ) == 0 )
2021817466cbSJens Wiklander         {
2022817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TV, 1 ) );
2023817466cbSJens Wiklander 
2024817466cbSJens Wiklander             if( ( V1.p[0] & 1 ) != 0 || ( V2.p[0] & 1 ) != 0 )
2025817466cbSJens Wiklander             {
2026817466cbSJens Wiklander                 MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &V1, &V1, &TB ) );
2027817466cbSJens Wiklander                 MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &V2, &V2, &TA ) );
2028817466cbSJens Wiklander             }
2029817466cbSJens Wiklander 
2030817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &V1, 1 ) );
2031817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &V2, 1 ) );
2032817466cbSJens Wiklander         }
2033817466cbSJens Wiklander 
2034817466cbSJens Wiklander         if( mbedtls_mpi_cmp_mpi( &TU, &TV ) >= 0 )
2035817466cbSJens Wiklander         {
2036817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &TU, &TU, &TV ) );
2037817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &U1, &U1, &V1 ) );
2038817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &U2, &U2, &V2 ) );
2039817466cbSJens Wiklander         }
2040817466cbSJens Wiklander         else
2041817466cbSJens Wiklander         {
2042817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &TV, &TV, &TU ) );
2043817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &V1, &V1, &U1 ) );
2044817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &V2, &V2, &U2 ) );
2045817466cbSJens Wiklander         }
2046817466cbSJens Wiklander     }
2047817466cbSJens Wiklander     while( mbedtls_mpi_cmp_int( &TU, 0 ) != 0 );
2048817466cbSJens Wiklander 
2049817466cbSJens Wiklander     while( mbedtls_mpi_cmp_int( &V1, 0 ) < 0 )
2050817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &V1, &V1, N ) );
2051817466cbSJens Wiklander 
2052817466cbSJens Wiklander     while( mbedtls_mpi_cmp_mpi( &V1, N ) >= 0 )
2053817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &V1, &V1, N ) );
2054817466cbSJens Wiklander 
2055817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, &V1 ) );
2056817466cbSJens Wiklander 
2057817466cbSJens Wiklander cleanup:
2058817466cbSJens Wiklander 
2059817466cbSJens Wiklander     mbedtls_mpi_free( &TA ); mbedtls_mpi_free( &TU ); mbedtls_mpi_free( &U1 ); mbedtls_mpi_free( &U2 );
2060817466cbSJens Wiklander     mbedtls_mpi_free( &G ); mbedtls_mpi_free( &TB ); mbedtls_mpi_free( &TV );
2061817466cbSJens Wiklander     mbedtls_mpi_free( &V1 ); mbedtls_mpi_free( &V2 );
2062817466cbSJens Wiklander 
2063817466cbSJens Wiklander     return( ret );
2064817466cbSJens Wiklander }
2065817466cbSJens Wiklander 
2066817466cbSJens Wiklander #if defined(MBEDTLS_GENPRIME)
2067817466cbSJens Wiklander 
2068817466cbSJens Wiklander static const int small_prime[] =
2069817466cbSJens Wiklander {
2070817466cbSJens Wiklander         3,    5,    7,   11,   13,   17,   19,   23,
2071817466cbSJens Wiklander        29,   31,   37,   41,   43,   47,   53,   59,
2072817466cbSJens Wiklander        61,   67,   71,   73,   79,   83,   89,   97,
2073817466cbSJens Wiklander       101,  103,  107,  109,  113,  127,  131,  137,
2074817466cbSJens Wiklander       139,  149,  151,  157,  163,  167,  173,  179,
2075817466cbSJens Wiklander       181,  191,  193,  197,  199,  211,  223,  227,
2076817466cbSJens Wiklander       229,  233,  239,  241,  251,  257,  263,  269,
2077817466cbSJens Wiklander       271,  277,  281,  283,  293,  307,  311,  313,
2078817466cbSJens Wiklander       317,  331,  337,  347,  349,  353,  359,  367,
2079817466cbSJens Wiklander       373,  379,  383,  389,  397,  401,  409,  419,
2080817466cbSJens Wiklander       421,  431,  433,  439,  443,  449,  457,  461,
2081817466cbSJens Wiklander       463,  467,  479,  487,  491,  499,  503,  509,
2082817466cbSJens Wiklander       521,  523,  541,  547,  557,  563,  569,  571,
2083817466cbSJens Wiklander       577,  587,  593,  599,  601,  607,  613,  617,
2084817466cbSJens Wiklander       619,  631,  641,  643,  647,  653,  659,  661,
2085817466cbSJens Wiklander       673,  677,  683,  691,  701,  709,  719,  727,
2086817466cbSJens Wiklander       733,  739,  743,  751,  757,  761,  769,  773,
2087817466cbSJens Wiklander       787,  797,  809,  811,  821,  823,  827,  829,
2088817466cbSJens Wiklander       839,  853,  857,  859,  863,  877,  881,  883,
2089817466cbSJens Wiklander       887,  907,  911,  919,  929,  937,  941,  947,
2090817466cbSJens Wiklander       953,  967,  971,  977,  983,  991,  997, -103
2091817466cbSJens Wiklander };
2092817466cbSJens Wiklander 
2093817466cbSJens Wiklander /*
2094817466cbSJens Wiklander  * Small divisors test (X must be positive)
2095817466cbSJens Wiklander  *
2096817466cbSJens Wiklander  * Return values:
2097817466cbSJens Wiklander  * 0: no small factor (possible prime, more tests needed)
2098817466cbSJens Wiklander  * 1: certain prime
2099817466cbSJens Wiklander  * MBEDTLS_ERR_MPI_NOT_ACCEPTABLE: certain non-prime
2100817466cbSJens Wiklander  * other negative: error
2101817466cbSJens Wiklander  */
2102817466cbSJens Wiklander static int mpi_check_small_factors( const mbedtls_mpi *X )
2103817466cbSJens Wiklander {
2104817466cbSJens Wiklander     int ret = 0;
2105817466cbSJens Wiklander     size_t i;
2106817466cbSJens Wiklander     mbedtls_mpi_uint r;
2107817466cbSJens Wiklander 
2108817466cbSJens Wiklander     if( ( X->p[0] & 1 ) == 0 )
2109817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE );
2110817466cbSJens Wiklander 
2111817466cbSJens Wiklander     for( i = 0; small_prime[i] > 0; i++ )
2112817466cbSJens Wiklander     {
2113817466cbSJens Wiklander         if( mbedtls_mpi_cmp_int( X, small_prime[i] ) <= 0 )
2114817466cbSJens Wiklander             return( 1 );
2115817466cbSJens Wiklander 
2116817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mod_int( &r, X, small_prime[i] ) );
2117817466cbSJens Wiklander 
2118817466cbSJens Wiklander         if( r == 0 )
2119817466cbSJens Wiklander             return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE );
2120817466cbSJens Wiklander     }
2121817466cbSJens Wiklander 
2122817466cbSJens Wiklander cleanup:
2123817466cbSJens Wiklander     return( ret );
2124817466cbSJens Wiklander }
2125817466cbSJens Wiklander 
2126817466cbSJens Wiklander /*
2127817466cbSJens Wiklander  * Miller-Rabin pseudo-primality test  (HAC 4.24)
2128817466cbSJens Wiklander  */
2129817466cbSJens Wiklander static int mpi_miller_rabin( const mbedtls_mpi *X,
2130817466cbSJens Wiklander                              int (*f_rng)(void *, unsigned char *, size_t),
2131817466cbSJens Wiklander                              void *p_rng )
2132817466cbSJens Wiklander {
2133817466cbSJens Wiklander     int ret, count;
2134817466cbSJens Wiklander     size_t i, j, k, n, s;
2135817466cbSJens Wiklander     mbedtls_mpi W, R, T, A, RR;
2136817466cbSJens Wiklander 
213798bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &W ); mbedtls_mpi_init_mempool( &R );
213898bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &T ); mbedtls_mpi_init_mempool( &A );
213998bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &RR );
2140817466cbSJens Wiklander 
2141817466cbSJens Wiklander     /*
2142817466cbSJens Wiklander      * W = |X| - 1
2143817466cbSJens Wiklander      * R = W >> lsb( W )
2144817466cbSJens Wiklander      */
2145817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &W, X, 1 ) );
2146817466cbSJens Wiklander     s = mbedtls_mpi_lsb( &W );
2147817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &R, &W ) );
2148817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &R, s ) );
2149817466cbSJens Wiklander 
2150817466cbSJens Wiklander     i = mbedtls_mpi_bitlen( X );
2151817466cbSJens Wiklander     /*
2152817466cbSJens Wiklander      * HAC, table 4.4
2153817466cbSJens Wiklander      */
2154817466cbSJens Wiklander     n = ( ( i >= 1300 ) ?  2 : ( i >=  850 ) ?  3 :
2155817466cbSJens Wiklander           ( i >=  650 ) ?  4 : ( i >=  350 ) ?  8 :
2156817466cbSJens Wiklander           ( i >=  250 ) ? 12 : ( i >=  150 ) ? 18 : 27 );
2157817466cbSJens Wiklander 
2158817466cbSJens Wiklander     for( i = 0; i < n; i++ )
2159817466cbSJens Wiklander     {
2160817466cbSJens Wiklander         /*
2161817466cbSJens Wiklander          * pick a random A, 1 < A < |X| - 1
2162817466cbSJens Wiklander          */
2163817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &A, X->n * ciL, f_rng, p_rng ) );
2164817466cbSJens Wiklander 
2165817466cbSJens Wiklander         if( mbedtls_mpi_cmp_mpi( &A, &W ) >= 0 )
2166817466cbSJens Wiklander         {
2167817466cbSJens Wiklander             j = mbedtls_mpi_bitlen( &A ) - mbedtls_mpi_bitlen( &W );
2168817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &A, j + 1 ) );
2169817466cbSJens Wiklander         }
2170817466cbSJens Wiklander         A.p[0] |= 3;
2171817466cbSJens Wiklander 
2172817466cbSJens Wiklander         count = 0;
2173817466cbSJens Wiklander         do {
2174817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &A, X->n * ciL, f_rng, p_rng ) );
2175817466cbSJens Wiklander 
2176817466cbSJens Wiklander             j = mbedtls_mpi_bitlen( &A );
2177817466cbSJens Wiklander             k = mbedtls_mpi_bitlen( &W );
2178817466cbSJens Wiklander             if (j > k) {
2179817466cbSJens Wiklander                 MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &A, j - k ) );
2180817466cbSJens Wiklander             }
2181817466cbSJens Wiklander 
2182*117cce93SJens Wiklander             if (count++ > 300) {
2183817466cbSJens Wiklander                 return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2184817466cbSJens Wiklander             }
2185817466cbSJens Wiklander 
2186817466cbSJens Wiklander         } while ( mbedtls_mpi_cmp_mpi( &A, &W ) >= 0 ||
2187817466cbSJens Wiklander                   mbedtls_mpi_cmp_int( &A, 1 )  <= 0    );
2188817466cbSJens Wiklander 
2189817466cbSJens Wiklander         /*
2190817466cbSJens Wiklander          * A = A^R mod |X|
2191817466cbSJens Wiklander          */
2192817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &A, &A, &R, X, &RR ) );
2193817466cbSJens Wiklander 
2194817466cbSJens Wiklander         if( mbedtls_mpi_cmp_mpi( &A, &W ) == 0 ||
2195817466cbSJens Wiklander             mbedtls_mpi_cmp_int( &A,  1 ) == 0 )
2196817466cbSJens Wiklander             continue;
2197817466cbSJens Wiklander 
2198817466cbSJens Wiklander         j = 1;
2199817466cbSJens Wiklander         while( j < s && mbedtls_mpi_cmp_mpi( &A, &W ) != 0 )
2200817466cbSJens Wiklander         {
2201817466cbSJens Wiklander             /*
2202817466cbSJens Wiklander              * A = A * A mod |X|
2203817466cbSJens Wiklander              */
2204817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T, &A, &A ) );
2205817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &A, &T, X  ) );
2206817466cbSJens Wiklander 
2207817466cbSJens Wiklander             if( mbedtls_mpi_cmp_int( &A, 1 ) == 0 )
2208817466cbSJens Wiklander                 break;
2209817466cbSJens Wiklander 
2210817466cbSJens Wiklander             j++;
2211817466cbSJens Wiklander         }
2212817466cbSJens Wiklander 
2213817466cbSJens Wiklander         /*
2214817466cbSJens Wiklander          * not prime if A != |X| - 1 or A == 1
2215817466cbSJens Wiklander          */
2216817466cbSJens Wiklander         if( mbedtls_mpi_cmp_mpi( &A, &W ) != 0 ||
2217817466cbSJens Wiklander             mbedtls_mpi_cmp_int( &A,  1 ) == 0 )
2218817466cbSJens Wiklander         {
2219817466cbSJens Wiklander             ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2220817466cbSJens Wiklander             break;
2221817466cbSJens Wiklander         }
2222817466cbSJens Wiklander     }
2223817466cbSJens Wiklander 
2224817466cbSJens Wiklander cleanup:
2225817466cbSJens Wiklander     mbedtls_mpi_free( &W ); mbedtls_mpi_free( &R ); mbedtls_mpi_free( &T ); mbedtls_mpi_free( &A );
2226817466cbSJens Wiklander     mbedtls_mpi_free( &RR );
2227817466cbSJens Wiklander 
2228817466cbSJens Wiklander     return( ret );
2229817466cbSJens Wiklander }
2230817466cbSJens Wiklander 
2231817466cbSJens Wiklander /*
2232817466cbSJens Wiklander  * Pseudo-primality test: small factors, then Miller-Rabin
2233817466cbSJens Wiklander  */
2234817466cbSJens Wiklander int mbedtls_mpi_is_prime( const mbedtls_mpi *X,
2235817466cbSJens Wiklander                   int (*f_rng)(void *, unsigned char *, size_t),
2236817466cbSJens Wiklander                   void *p_rng )
2237817466cbSJens Wiklander {
2238817466cbSJens Wiklander     int ret;
2239817466cbSJens Wiklander     mbedtls_mpi XX;
2240817466cbSJens Wiklander 
2241817466cbSJens Wiklander     XX.s = 1;
2242817466cbSJens Wiklander     XX.n = X->n;
2243817466cbSJens Wiklander     XX.p = X->p;
2244817466cbSJens Wiklander 
2245817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( &XX, 0 ) == 0 ||
2246817466cbSJens Wiklander         mbedtls_mpi_cmp_int( &XX, 1 ) == 0 )
2247817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE );
2248817466cbSJens Wiklander 
2249817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( &XX, 2 ) == 0 )
2250817466cbSJens Wiklander         return( 0 );
2251817466cbSJens Wiklander 
2252817466cbSJens Wiklander     if( ( ret = mpi_check_small_factors( &XX ) ) != 0 )
2253817466cbSJens Wiklander     {
2254817466cbSJens Wiklander         if( ret == 1 )
2255817466cbSJens Wiklander             return( 0 );
2256817466cbSJens Wiklander 
2257817466cbSJens Wiklander         return( ret );
2258817466cbSJens Wiklander     }
2259817466cbSJens Wiklander 
2260817466cbSJens Wiklander     return( mpi_miller_rabin( &XX, f_rng, p_rng ) );
2261817466cbSJens Wiklander }
2262817466cbSJens Wiklander 
2263817466cbSJens Wiklander /*
2264817466cbSJens Wiklander  * Prime number generation
2265817466cbSJens Wiklander  */
2266817466cbSJens Wiklander int mbedtls_mpi_gen_prime( mbedtls_mpi *X, size_t nbits, int dh_flag,
2267817466cbSJens Wiklander                    int (*f_rng)(void *, unsigned char *, size_t),
2268817466cbSJens Wiklander                    void *p_rng )
2269817466cbSJens Wiklander {
2270817466cbSJens Wiklander     int ret;
2271817466cbSJens Wiklander     size_t k, n;
2272817466cbSJens Wiklander     mbedtls_mpi_uint r;
2273817466cbSJens Wiklander     mbedtls_mpi Y;
2274817466cbSJens Wiklander 
2275817466cbSJens Wiklander     if( nbits < 3 || nbits > MBEDTLS_MPI_MAX_BITS )
2276817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
2277817466cbSJens Wiklander 
227898bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &Y );
2279817466cbSJens Wiklander 
2280817466cbSJens Wiklander     n = BITS_TO_LIMBS( nbits );
2281817466cbSJens Wiklander 
2282817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( X, n * ciL, f_rng, p_rng ) );
2283817466cbSJens Wiklander 
2284817466cbSJens Wiklander     k = mbedtls_mpi_bitlen( X );
2285817466cbSJens Wiklander     if( k > nbits ) MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( X, k - nbits + 1 ) );
2286817466cbSJens Wiklander 
2287817466cbSJens Wiklander     mbedtls_mpi_set_bit( X, nbits-1, 1 );
2288817466cbSJens Wiklander 
2289817466cbSJens Wiklander     X->p[0] |= 1;
2290817466cbSJens Wiklander 
2291817466cbSJens Wiklander     if( dh_flag == 0 )
2292817466cbSJens Wiklander     {
2293817466cbSJens Wiklander         while( ( ret = mbedtls_mpi_is_prime( X, f_rng, p_rng ) ) != 0 )
2294817466cbSJens Wiklander         {
2295817466cbSJens Wiklander             if( ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE )
2296817466cbSJens Wiklander                 goto cleanup;
2297817466cbSJens Wiklander 
2298817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, X, 2 ) );
2299817466cbSJens Wiklander         }
2300817466cbSJens Wiklander     }
2301817466cbSJens Wiklander     else
2302817466cbSJens Wiklander     {
2303817466cbSJens Wiklander         /*
2304817466cbSJens Wiklander          * An necessary condition for Y and X = 2Y + 1 to be prime
2305817466cbSJens Wiklander          * is X = 2 mod 3 (which is equivalent to Y = 2 mod 3).
2306817466cbSJens Wiklander          * Make sure it is satisfied, while keeping X = 3 mod 4
2307817466cbSJens Wiklander          */
2308817466cbSJens Wiklander 
2309817466cbSJens Wiklander         X->p[0] |= 2;
2310817466cbSJens Wiklander 
2311817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mod_int( &r, X, 3 ) );
2312817466cbSJens Wiklander         if( r == 0 )
2313817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, X, 8 ) );
2314817466cbSJens Wiklander         else if( r == 1 )
2315817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, X, 4 ) );
2316817466cbSJens Wiklander 
2317817466cbSJens Wiklander         /* Set Y = (X-1) / 2, which is X / 2 because X is odd */
2318817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &Y, X ) );
2319817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &Y, 1 ) );
2320817466cbSJens Wiklander 
2321817466cbSJens Wiklander         while( 1 )
2322817466cbSJens Wiklander         {
2323817466cbSJens Wiklander             /*
2324817466cbSJens Wiklander              * First, check small factors for X and Y
2325817466cbSJens Wiklander              * before doing Miller-Rabin on any of them
2326817466cbSJens Wiklander              */
2327817466cbSJens Wiklander             if( ( ret = mpi_check_small_factors(  X         ) ) == 0 &&
2328817466cbSJens Wiklander                 ( ret = mpi_check_small_factors( &Y         ) ) == 0 &&
2329817466cbSJens Wiklander                 ( ret = mpi_miller_rabin(  X, f_rng, p_rng  ) ) == 0 &&
2330817466cbSJens Wiklander                 ( ret = mpi_miller_rabin( &Y, f_rng, p_rng  ) ) == 0 )
2331817466cbSJens Wiklander             {
2332817466cbSJens Wiklander                 break;
2333817466cbSJens Wiklander             }
2334817466cbSJens Wiklander 
2335817466cbSJens Wiklander             if( ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE )
2336817466cbSJens Wiklander                 goto cleanup;
2337817466cbSJens Wiklander 
2338817466cbSJens Wiklander             /*
2339817466cbSJens Wiklander              * Next candidates. We want to preserve Y = (X-1) / 2 and
2340817466cbSJens Wiklander              * Y = 1 mod 2 and Y = 2 mod 3 (eq X = 3 mod 4 and X = 2 mod 3)
2341817466cbSJens Wiklander              * so up Y by 6 and X by 12.
2342817466cbSJens Wiklander              */
2343817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_add_int(  X,  X, 12 ) );
2344817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( &Y, &Y, 6  ) );
2345817466cbSJens Wiklander         }
2346817466cbSJens Wiklander     }
2347817466cbSJens Wiklander 
2348817466cbSJens Wiklander cleanup:
2349817466cbSJens Wiklander 
2350817466cbSJens Wiklander     mbedtls_mpi_free( &Y );
2351817466cbSJens Wiklander 
2352817466cbSJens Wiklander     return( ret );
2353817466cbSJens Wiklander }
2354817466cbSJens Wiklander 
2355817466cbSJens Wiklander #endif /* MBEDTLS_GENPRIME */
2356817466cbSJens Wiklander 
2357817466cbSJens Wiklander #if defined(MBEDTLS_SELF_TEST)
2358817466cbSJens Wiklander 
2359817466cbSJens Wiklander #define GCD_PAIR_COUNT  3
2360817466cbSJens Wiklander 
2361817466cbSJens Wiklander static const int gcd_pairs[GCD_PAIR_COUNT][3] =
2362817466cbSJens Wiklander {
2363817466cbSJens Wiklander     { 693, 609, 21 },
2364817466cbSJens Wiklander     { 1764, 868, 28 },
2365817466cbSJens Wiklander     { 768454923, 542167814, 1 }
2366817466cbSJens Wiklander };
2367817466cbSJens Wiklander 
2368817466cbSJens Wiklander /*
2369817466cbSJens Wiklander  * Checkup routine
2370817466cbSJens Wiklander  */
2371817466cbSJens Wiklander int mbedtls_mpi_self_test( int verbose )
2372817466cbSJens Wiklander {
2373817466cbSJens Wiklander     int ret, i;
2374817466cbSJens Wiklander     mbedtls_mpi A, E, N, X, Y, U, V;
2375817466cbSJens Wiklander 
237698bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &A ); mbedtls_mpi_init_mempool( &E );
237798bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &N ); mbedtls_mpi_init_mempool( &X );
237898bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &Y ); mbedtls_mpi_init_mempool( &U );
237998bd5fe3SJens Wiklander     mbedtls_mpi_init_mempool( &V );
2380817466cbSJens Wiklander 
2381817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &A, 16,
2382817466cbSJens Wiklander         "EFE021C2645FD1DC586E69184AF4A31E" \
2383817466cbSJens Wiklander         "D5F53E93B5F123FA41680867BA110131" \
2384817466cbSJens Wiklander         "944FE7952E2517337780CB0DB80E61AA" \
2385817466cbSJens Wiklander         "E7C8DDC6C5C6AADEB34EB38A2F40D5E6" ) );
2386817466cbSJens Wiklander 
2387817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &E, 16,
2388817466cbSJens Wiklander         "B2E7EFD37075B9F03FF989C7C5051C20" \
2389817466cbSJens Wiklander         "34D2A323810251127E7BF8625A4F49A5" \
2390817466cbSJens Wiklander         "F3E27F4DA8BD59C47D6DAABA4C8127BD" \
2391817466cbSJens Wiklander         "5B5C25763222FEFCCFC38B832366C29E" ) );
2392817466cbSJens Wiklander 
2393817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &N, 16,
2394817466cbSJens Wiklander         "0066A198186C18C10B2F5ED9B522752A" \
2395817466cbSJens Wiklander         "9830B69916E535C8F047518A889A43A5" \
2396817466cbSJens Wiklander         "94B6BED27A168D31D4A52F88925AA8F5" ) );
2397817466cbSJens Wiklander 
2398817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &X, &A, &N ) );
2399817466cbSJens Wiklander 
2400817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &U, 16,
2401817466cbSJens Wiklander         "602AB7ECA597A3D6B56FF9829A5E8B85" \
2402817466cbSJens Wiklander         "9E857EA95A03512E2BAE7391688D264A" \
2403817466cbSJens Wiklander         "A5663B0341DB9CCFD2C4C5F421FEC814" \
2404817466cbSJens Wiklander         "8001B72E848A38CAE1C65F78E56ABDEF" \
2405817466cbSJens Wiklander         "E12D3C039B8A02D6BE593F0BBBDA56F1" \
2406817466cbSJens Wiklander         "ECF677152EF804370C1A305CAF3B5BF1" \
2407817466cbSJens Wiklander         "30879B56C61DE584A0F53A2447A51E" ) );
2408817466cbSJens Wiklander 
2409817466cbSJens Wiklander     if( verbose != 0 )
2410817466cbSJens Wiklander         mbedtls_printf( "  MPI test #1 (mul_mpi): " );
2411817466cbSJens Wiklander 
2412817466cbSJens Wiklander     if( mbedtls_mpi_cmp_mpi( &X, &U ) != 0 )
2413817466cbSJens Wiklander     {
2414817466cbSJens Wiklander         if( verbose != 0 )
2415817466cbSJens Wiklander             mbedtls_printf( "failed\n" );
2416817466cbSJens Wiklander 
2417817466cbSJens Wiklander         ret = 1;
2418817466cbSJens Wiklander         goto cleanup;
2419817466cbSJens Wiklander     }
2420817466cbSJens Wiklander 
2421817466cbSJens Wiklander     if( verbose != 0 )
2422817466cbSJens Wiklander         mbedtls_printf( "passed\n" );
2423817466cbSJens Wiklander 
2424817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_div_mpi( &X, &Y, &A, &N ) );
2425817466cbSJens Wiklander 
2426817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &U, 16,
2427817466cbSJens Wiklander         "256567336059E52CAE22925474705F39A94" ) );
2428817466cbSJens Wiklander 
2429817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &V, 16,
2430817466cbSJens Wiklander         "6613F26162223DF488E9CD48CC132C7A" \
2431817466cbSJens Wiklander         "0AC93C701B001B092E4E5B9F73BCD27B" \
2432817466cbSJens Wiklander         "9EE50D0657C77F374E903CDFA4C642" ) );
2433817466cbSJens Wiklander 
2434817466cbSJens Wiklander     if( verbose != 0 )
2435817466cbSJens Wiklander         mbedtls_printf( "  MPI test #2 (div_mpi): " );
2436817466cbSJens Wiklander 
2437817466cbSJens Wiklander     if( mbedtls_mpi_cmp_mpi( &X, &U ) != 0 ||
2438817466cbSJens Wiklander         mbedtls_mpi_cmp_mpi( &Y, &V ) != 0 )
2439817466cbSJens Wiklander     {
2440817466cbSJens Wiklander         if( verbose != 0 )
2441817466cbSJens Wiklander             mbedtls_printf( "failed\n" );
2442817466cbSJens Wiklander 
2443817466cbSJens Wiklander         ret = 1;
2444817466cbSJens Wiklander         goto cleanup;
2445817466cbSJens Wiklander     }
2446817466cbSJens Wiklander 
2447817466cbSJens Wiklander     if( verbose != 0 )
2448817466cbSJens Wiklander         mbedtls_printf( "passed\n" );
2449817466cbSJens Wiklander 
2450817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &X, &A, &E, &N, NULL ) );
2451817466cbSJens Wiklander 
2452817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &U, 16,
2453817466cbSJens Wiklander         "36E139AEA55215609D2816998ED020BB" \
2454817466cbSJens Wiklander         "BD96C37890F65171D948E9BC7CBAA4D9" \
2455817466cbSJens Wiklander         "325D24D6A3C12710F10A09FA08AB87" ) );
2456817466cbSJens Wiklander 
2457817466cbSJens Wiklander     if( verbose != 0 )
2458817466cbSJens Wiklander         mbedtls_printf( "  MPI test #3 (exp_mod): " );
2459817466cbSJens Wiklander 
2460817466cbSJens Wiklander     if( mbedtls_mpi_cmp_mpi( &X, &U ) != 0 )
2461817466cbSJens Wiklander     {
2462817466cbSJens Wiklander         if( verbose != 0 )
2463817466cbSJens Wiklander             mbedtls_printf( "failed\n" );
2464817466cbSJens Wiklander 
2465817466cbSJens Wiklander         ret = 1;
2466817466cbSJens Wiklander         goto cleanup;
2467817466cbSJens Wiklander     }
2468817466cbSJens Wiklander 
2469817466cbSJens Wiklander     if( verbose != 0 )
2470817466cbSJens Wiklander         mbedtls_printf( "passed\n" );
2471817466cbSJens Wiklander 
2472817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &X, &A, &N ) );
2473817466cbSJens Wiklander 
2474817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &U, 16,
2475817466cbSJens Wiklander         "003A0AAEDD7E784FC07D8F9EC6E3BFD5" \
2476817466cbSJens Wiklander         "C3DBA76456363A10869622EAC2DD84EC" \
2477817466cbSJens Wiklander         "C5B8A74DAC4D09E03B5E0BE779F2DF61" ) );
2478817466cbSJens Wiklander 
2479817466cbSJens Wiklander     if( verbose != 0 )
2480817466cbSJens Wiklander         mbedtls_printf( "  MPI test #4 (inv_mod): " );
2481817466cbSJens Wiklander 
2482817466cbSJens Wiklander     if( mbedtls_mpi_cmp_mpi( &X, &U ) != 0 )
2483817466cbSJens Wiklander     {
2484817466cbSJens Wiklander         if( verbose != 0 )
2485817466cbSJens Wiklander             mbedtls_printf( "failed\n" );
2486817466cbSJens Wiklander 
2487817466cbSJens Wiklander         ret = 1;
2488817466cbSJens Wiklander         goto cleanup;
2489817466cbSJens Wiklander     }
2490817466cbSJens Wiklander 
2491817466cbSJens Wiklander     if( verbose != 0 )
2492817466cbSJens Wiklander         mbedtls_printf( "passed\n" );
2493817466cbSJens Wiklander 
2494817466cbSJens Wiklander     if( verbose != 0 )
2495817466cbSJens Wiklander         mbedtls_printf( "  MPI test #5 (simple gcd): " );
2496817466cbSJens Wiklander 
2497817466cbSJens Wiklander     for( i = 0; i < GCD_PAIR_COUNT; i++ )
2498817466cbSJens Wiklander     {
2499817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &X, gcd_pairs[i][0] ) );
2500817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &Y, gcd_pairs[i][1] ) );
2501817466cbSJens Wiklander 
2502817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &A, &X, &Y ) );
2503817466cbSJens Wiklander 
2504817466cbSJens Wiklander         if( mbedtls_mpi_cmp_int( &A, gcd_pairs[i][2] ) != 0 )
2505817466cbSJens Wiklander         {
2506817466cbSJens Wiklander             if( verbose != 0 )
2507817466cbSJens Wiklander                 mbedtls_printf( "failed at %d\n", i );
2508817466cbSJens Wiklander 
2509817466cbSJens Wiklander             ret = 1;
2510817466cbSJens Wiklander             goto cleanup;
2511817466cbSJens Wiklander         }
2512817466cbSJens Wiklander     }
2513817466cbSJens Wiklander 
2514817466cbSJens Wiklander     if( verbose != 0 )
2515817466cbSJens Wiklander         mbedtls_printf( "passed\n" );
2516817466cbSJens Wiklander 
2517817466cbSJens Wiklander cleanup:
2518817466cbSJens Wiklander 
2519817466cbSJens Wiklander     if( ret != 0 && verbose != 0 )
2520817466cbSJens Wiklander         mbedtls_printf( "Unexpected error, return code = %08X\n", ret );
2521817466cbSJens Wiklander 
2522817466cbSJens Wiklander     mbedtls_mpi_free( &A ); mbedtls_mpi_free( &E ); mbedtls_mpi_free( &N ); mbedtls_mpi_free( &X );
2523817466cbSJens Wiklander     mbedtls_mpi_free( &Y ); mbedtls_mpi_free( &U ); mbedtls_mpi_free( &V );
2524817466cbSJens Wiklander 
2525817466cbSJens Wiklander     if( verbose != 0 )
2526817466cbSJens Wiklander         mbedtls_printf( "\n" );
2527817466cbSJens Wiklander 
2528817466cbSJens Wiklander     return( ret );
2529817466cbSJens Wiklander }
2530817466cbSJens Wiklander 
2531817466cbSJens Wiklander #endif /* MBEDTLS_SELF_TEST */
2532817466cbSJens Wiklander 
2533817466cbSJens Wiklander #endif /* MBEDTLS_BIGNUM_C */
2534