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