xref: /optee_os/lib/libmbedtls/mbedtls/library/bignum.c (revision 817466cb476de705a8e3dabe1ef165fe27a18c2f)
1*817466cbSJens Wiklander /*
2*817466cbSJens Wiklander  *  Multi-precision integer library
3*817466cbSJens Wiklander  *
4*817466cbSJens Wiklander  *  Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
5*817466cbSJens Wiklander  *  SPDX-License-Identifier: Apache-2.0
6*817466cbSJens Wiklander  *
7*817466cbSJens Wiklander  *  Licensed under the Apache License, Version 2.0 (the "License"); you may
8*817466cbSJens Wiklander  *  not use this file except in compliance with the License.
9*817466cbSJens Wiklander  *  You may obtain a copy of the License at
10*817466cbSJens Wiklander  *
11*817466cbSJens Wiklander  *  http://www.apache.org/licenses/LICENSE-2.0
12*817466cbSJens Wiklander  *
13*817466cbSJens Wiklander  *  Unless required by applicable law or agreed to in writing, software
14*817466cbSJens Wiklander  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15*817466cbSJens Wiklander  *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16*817466cbSJens Wiklander  *  See the License for the specific language governing permissions and
17*817466cbSJens Wiklander  *  limitations under the License.
18*817466cbSJens Wiklander  *
19*817466cbSJens Wiklander  *  This file is part of mbed TLS (https://tls.mbed.org)
20*817466cbSJens Wiklander  */
21*817466cbSJens Wiklander 
22*817466cbSJens Wiklander /*
23*817466cbSJens Wiklander  *  The following sources were referenced in the design of this Multi-precision
24*817466cbSJens Wiklander  *  Integer library:
25*817466cbSJens Wiklander  *
26*817466cbSJens Wiklander  *  [1] Handbook of Applied Cryptography - 1997
27*817466cbSJens Wiklander  *      Menezes, van Oorschot and Vanstone
28*817466cbSJens Wiklander  *
29*817466cbSJens Wiklander  *  [2] Multi-Precision Math
30*817466cbSJens Wiklander  *      Tom St Denis
31*817466cbSJens Wiklander  *      https://github.com/libtom/libtommath/blob/develop/tommath.pdf
32*817466cbSJens Wiklander  *
33*817466cbSJens Wiklander  *  [3] GNU Multi-Precision Arithmetic Library
34*817466cbSJens Wiklander  *      https://gmplib.org/manual/index.html
35*817466cbSJens Wiklander  *
36*817466cbSJens Wiklander  */
37*817466cbSJens Wiklander 
38*817466cbSJens Wiklander #if !defined(MBEDTLS_CONFIG_FILE)
39*817466cbSJens Wiklander #include "mbedtls/config.h"
40*817466cbSJens Wiklander #else
41*817466cbSJens Wiklander #include MBEDTLS_CONFIG_FILE
42*817466cbSJens Wiklander #endif
43*817466cbSJens Wiklander 
44*817466cbSJens Wiklander #if defined(MBEDTLS_BIGNUM_C)
45*817466cbSJens Wiklander 
46*817466cbSJens Wiklander #include "mbedtls/bignum.h"
47*817466cbSJens Wiklander #include "mbedtls/bn_mul.h"
48*817466cbSJens Wiklander 
49*817466cbSJens Wiklander #include <string.h>
50*817466cbSJens Wiklander 
51*817466cbSJens Wiklander #if defined(MBEDTLS_PLATFORM_C)
52*817466cbSJens Wiklander #include "mbedtls/platform.h"
53*817466cbSJens Wiklander #else
54*817466cbSJens Wiklander #include <stdio.h>
55*817466cbSJens Wiklander #include <stdlib.h>
56*817466cbSJens Wiklander #define mbedtls_printf     printf
57*817466cbSJens Wiklander #define mbedtls_calloc    calloc
58*817466cbSJens Wiklander #define mbedtls_free       free
59*817466cbSJens Wiklander #endif
60*817466cbSJens Wiklander 
61*817466cbSJens Wiklander /* Implementation that should never be optimized out by the compiler */
62*817466cbSJens Wiklander static void mbedtls_mpi_zeroize( mbedtls_mpi_uint *v, size_t n ) {
63*817466cbSJens Wiklander     volatile mbedtls_mpi_uint *p = v; while( n-- ) *p++ = 0;
64*817466cbSJens Wiklander }
65*817466cbSJens Wiklander 
66*817466cbSJens Wiklander #define ciL    (sizeof(mbedtls_mpi_uint))         /* chars in limb  */
67*817466cbSJens Wiklander #define biL    (ciL << 3)               /* bits  in limb  */
68*817466cbSJens Wiklander #define biH    (ciL << 2)               /* half limb size */
69*817466cbSJens Wiklander 
70*817466cbSJens Wiklander #define MPI_SIZE_T_MAX  ( (size_t) -1 ) /* SIZE_T_MAX is not standard */
71*817466cbSJens Wiklander 
72*817466cbSJens Wiklander /*
73*817466cbSJens Wiklander  * Convert between bits/chars and number of limbs
74*817466cbSJens Wiklander  * Divide first in order to avoid potential overflows
75*817466cbSJens Wiklander  */
76*817466cbSJens Wiklander #define BITS_TO_LIMBS(i)  ( (i) / biL + ( (i) % biL != 0 ) )
77*817466cbSJens Wiklander #define CHARS_TO_LIMBS(i) ( (i) / ciL + ( (i) % ciL != 0 ) )
78*817466cbSJens Wiklander 
79*817466cbSJens Wiklander /*
80*817466cbSJens Wiklander  * Initialize one MPI
81*817466cbSJens Wiklander  */
82*817466cbSJens Wiklander void mbedtls_mpi_init( mbedtls_mpi *X )
83*817466cbSJens Wiklander {
84*817466cbSJens Wiklander     if( X == NULL )
85*817466cbSJens Wiklander         return;
86*817466cbSJens Wiklander 
87*817466cbSJens Wiklander     X->s = 1;
88*817466cbSJens Wiklander     X->n = 0;
89*817466cbSJens Wiklander     X->p = NULL;
90*817466cbSJens Wiklander }
91*817466cbSJens Wiklander 
92*817466cbSJens Wiklander /*
93*817466cbSJens Wiklander  * Unallocate one MPI
94*817466cbSJens Wiklander  */
95*817466cbSJens Wiklander void mbedtls_mpi_free( mbedtls_mpi *X )
96*817466cbSJens Wiklander {
97*817466cbSJens Wiklander     if( X == NULL )
98*817466cbSJens Wiklander         return;
99*817466cbSJens Wiklander 
100*817466cbSJens Wiklander     if( X->p != NULL )
101*817466cbSJens Wiklander     {
102*817466cbSJens Wiklander         mbedtls_mpi_zeroize( X->p, X->n );
103*817466cbSJens Wiklander         mbedtls_free( X->p );
104*817466cbSJens Wiklander     }
105*817466cbSJens Wiklander 
106*817466cbSJens Wiklander     X->s = 1;
107*817466cbSJens Wiklander     X->n = 0;
108*817466cbSJens Wiklander     X->p = NULL;
109*817466cbSJens Wiklander }
110*817466cbSJens Wiklander 
111*817466cbSJens Wiklander /*
112*817466cbSJens Wiklander  * Enlarge to the specified number of limbs
113*817466cbSJens Wiklander  */
114*817466cbSJens Wiklander int mbedtls_mpi_grow( mbedtls_mpi *X, size_t nblimbs )
115*817466cbSJens Wiklander {
116*817466cbSJens Wiklander     mbedtls_mpi_uint *p;
117*817466cbSJens Wiklander 
118*817466cbSJens Wiklander     if( nblimbs > MBEDTLS_MPI_MAX_LIMBS )
119*817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_ALLOC_FAILED );
120*817466cbSJens Wiklander 
121*817466cbSJens Wiklander     if( X->n < nblimbs )
122*817466cbSJens Wiklander     {
123*817466cbSJens Wiklander         if( ( p = (mbedtls_mpi_uint*)mbedtls_calloc( nblimbs, ciL ) ) == NULL )
124*817466cbSJens Wiklander             return( MBEDTLS_ERR_MPI_ALLOC_FAILED );
125*817466cbSJens Wiklander 
126*817466cbSJens Wiklander         if( X->p != NULL )
127*817466cbSJens Wiklander         {
128*817466cbSJens Wiklander             memcpy( p, X->p, X->n * ciL );
129*817466cbSJens Wiklander             mbedtls_mpi_zeroize( X->p, X->n );
130*817466cbSJens Wiklander             mbedtls_free( X->p );
131*817466cbSJens Wiklander         }
132*817466cbSJens Wiklander 
133*817466cbSJens Wiklander         X->n = nblimbs;
134*817466cbSJens Wiklander         X->p = p;
135*817466cbSJens Wiklander     }
136*817466cbSJens Wiklander 
137*817466cbSJens Wiklander     return( 0 );
138*817466cbSJens Wiklander }
139*817466cbSJens Wiklander 
140*817466cbSJens Wiklander /*
141*817466cbSJens Wiklander  * Resize down as much as possible,
142*817466cbSJens Wiklander  * while keeping at least the specified number of limbs
143*817466cbSJens Wiklander  */
144*817466cbSJens Wiklander int mbedtls_mpi_shrink( mbedtls_mpi *X, size_t nblimbs )
145*817466cbSJens Wiklander {
146*817466cbSJens Wiklander     mbedtls_mpi_uint *p;
147*817466cbSJens Wiklander     size_t i;
148*817466cbSJens Wiklander 
149*817466cbSJens Wiklander     /* Actually resize up in this case */
150*817466cbSJens Wiklander     if( X->n <= nblimbs )
151*817466cbSJens Wiklander         return( mbedtls_mpi_grow( X, nblimbs ) );
152*817466cbSJens Wiklander 
153*817466cbSJens Wiklander     for( i = X->n - 1; i > 0; i-- )
154*817466cbSJens Wiklander         if( X->p[i] != 0 )
155*817466cbSJens Wiklander             break;
156*817466cbSJens Wiklander     i++;
157*817466cbSJens Wiklander 
158*817466cbSJens Wiklander     if( i < nblimbs )
159*817466cbSJens Wiklander         i = nblimbs;
160*817466cbSJens Wiklander 
161*817466cbSJens Wiklander     if( ( p = (mbedtls_mpi_uint*)mbedtls_calloc( i, ciL ) ) == NULL )
162*817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_ALLOC_FAILED );
163*817466cbSJens Wiklander 
164*817466cbSJens Wiklander     if( X->p != NULL )
165*817466cbSJens Wiklander     {
166*817466cbSJens Wiklander         memcpy( p, X->p, i * ciL );
167*817466cbSJens Wiklander         mbedtls_mpi_zeroize( X->p, X->n );
168*817466cbSJens Wiklander         mbedtls_free( X->p );
169*817466cbSJens Wiklander     }
170*817466cbSJens Wiklander 
171*817466cbSJens Wiklander     X->n = i;
172*817466cbSJens Wiklander     X->p = p;
173*817466cbSJens Wiklander 
174*817466cbSJens Wiklander     return( 0 );
175*817466cbSJens Wiklander }
176*817466cbSJens Wiklander 
177*817466cbSJens Wiklander /*
178*817466cbSJens Wiklander  * Copy the contents of Y into X
179*817466cbSJens Wiklander  */
180*817466cbSJens Wiklander int mbedtls_mpi_copy( mbedtls_mpi *X, const mbedtls_mpi *Y )
181*817466cbSJens Wiklander {
182*817466cbSJens Wiklander     int ret;
183*817466cbSJens Wiklander     size_t i;
184*817466cbSJens Wiklander 
185*817466cbSJens Wiklander     if( X == Y )
186*817466cbSJens Wiklander         return( 0 );
187*817466cbSJens Wiklander 
188*817466cbSJens Wiklander     if( Y->p == NULL )
189*817466cbSJens Wiklander     {
190*817466cbSJens Wiklander         mbedtls_mpi_free( X );
191*817466cbSJens Wiklander         return( 0 );
192*817466cbSJens Wiklander     }
193*817466cbSJens Wiklander 
194*817466cbSJens Wiklander     for( i = Y->n - 1; i > 0; i-- )
195*817466cbSJens Wiklander         if( Y->p[i] != 0 )
196*817466cbSJens Wiklander             break;
197*817466cbSJens Wiklander     i++;
198*817466cbSJens Wiklander 
199*817466cbSJens Wiklander     X->s = Y->s;
200*817466cbSJens Wiklander 
201*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, i ) );
202*817466cbSJens Wiklander 
203*817466cbSJens Wiklander     memset( X->p, 0, X->n * ciL );
204*817466cbSJens Wiklander     memcpy( X->p, Y->p, i * ciL );
205*817466cbSJens Wiklander 
206*817466cbSJens Wiklander cleanup:
207*817466cbSJens Wiklander 
208*817466cbSJens Wiklander     return( ret );
209*817466cbSJens Wiklander }
210*817466cbSJens Wiklander 
211*817466cbSJens Wiklander /*
212*817466cbSJens Wiklander  * Swap the contents of X and Y
213*817466cbSJens Wiklander  */
214*817466cbSJens Wiklander void mbedtls_mpi_swap( mbedtls_mpi *X, mbedtls_mpi *Y )
215*817466cbSJens Wiklander {
216*817466cbSJens Wiklander     mbedtls_mpi T;
217*817466cbSJens Wiklander 
218*817466cbSJens Wiklander     memcpy( &T,  X, sizeof( mbedtls_mpi ) );
219*817466cbSJens Wiklander     memcpy(  X,  Y, sizeof( mbedtls_mpi ) );
220*817466cbSJens Wiklander     memcpy(  Y, &T, sizeof( mbedtls_mpi ) );
221*817466cbSJens Wiklander }
222*817466cbSJens Wiklander 
223*817466cbSJens Wiklander /*
224*817466cbSJens Wiklander  * Conditionally assign X = Y, without leaking information
225*817466cbSJens Wiklander  * about whether the assignment was made or not.
226*817466cbSJens Wiklander  * (Leaking information about the respective sizes of X and Y is ok however.)
227*817466cbSJens Wiklander  */
228*817466cbSJens Wiklander int mbedtls_mpi_safe_cond_assign( mbedtls_mpi *X, const mbedtls_mpi *Y, unsigned char assign )
229*817466cbSJens Wiklander {
230*817466cbSJens Wiklander     int ret = 0;
231*817466cbSJens Wiklander     size_t i;
232*817466cbSJens Wiklander 
233*817466cbSJens Wiklander     /* make sure assign is 0 or 1 in a time-constant manner */
234*817466cbSJens Wiklander     assign = (assign | (unsigned char)-assign) >> 7;
235*817466cbSJens Wiklander 
236*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, Y->n ) );
237*817466cbSJens Wiklander 
238*817466cbSJens Wiklander     X->s = X->s * ( 1 - assign ) + Y->s * assign;
239*817466cbSJens Wiklander 
240*817466cbSJens Wiklander     for( i = 0; i < Y->n; i++ )
241*817466cbSJens Wiklander         X->p[i] = X->p[i] * ( 1 - assign ) + Y->p[i] * assign;
242*817466cbSJens Wiklander 
243*817466cbSJens Wiklander     for( ; i < X->n; i++ )
244*817466cbSJens Wiklander         X->p[i] *= ( 1 - assign );
245*817466cbSJens Wiklander 
246*817466cbSJens Wiklander cleanup:
247*817466cbSJens Wiklander     return( ret );
248*817466cbSJens Wiklander }
249*817466cbSJens Wiklander 
250*817466cbSJens Wiklander /*
251*817466cbSJens Wiklander  * Conditionally swap X and Y, without leaking information
252*817466cbSJens Wiklander  * about whether the swap was made or not.
253*817466cbSJens Wiklander  * Here it is not ok to simply swap the pointers, which whould lead to
254*817466cbSJens Wiklander  * different memory access patterns when X and Y are used afterwards.
255*817466cbSJens Wiklander  */
256*817466cbSJens Wiklander int mbedtls_mpi_safe_cond_swap( mbedtls_mpi *X, mbedtls_mpi *Y, unsigned char swap )
257*817466cbSJens Wiklander {
258*817466cbSJens Wiklander     int ret, s;
259*817466cbSJens Wiklander     size_t i;
260*817466cbSJens Wiklander     mbedtls_mpi_uint tmp;
261*817466cbSJens Wiklander 
262*817466cbSJens Wiklander     if( X == Y )
263*817466cbSJens Wiklander         return( 0 );
264*817466cbSJens Wiklander 
265*817466cbSJens Wiklander     /* make sure swap is 0 or 1 in a time-constant manner */
266*817466cbSJens Wiklander     swap = (swap | (unsigned char)-swap) >> 7;
267*817466cbSJens Wiklander 
268*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, Y->n ) );
269*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( Y, X->n ) );
270*817466cbSJens Wiklander 
271*817466cbSJens Wiklander     s = X->s;
272*817466cbSJens Wiklander     X->s = X->s * ( 1 - swap ) + Y->s * swap;
273*817466cbSJens Wiklander     Y->s = Y->s * ( 1 - swap ) +    s * swap;
274*817466cbSJens Wiklander 
275*817466cbSJens Wiklander 
276*817466cbSJens Wiklander     for( i = 0; i < X->n; i++ )
277*817466cbSJens Wiklander     {
278*817466cbSJens Wiklander         tmp = X->p[i];
279*817466cbSJens Wiklander         X->p[i] = X->p[i] * ( 1 - swap ) + Y->p[i] * swap;
280*817466cbSJens Wiklander         Y->p[i] = Y->p[i] * ( 1 - swap ) +     tmp * swap;
281*817466cbSJens Wiklander     }
282*817466cbSJens Wiklander 
283*817466cbSJens Wiklander cleanup:
284*817466cbSJens Wiklander     return( ret );
285*817466cbSJens Wiklander }
286*817466cbSJens Wiklander 
287*817466cbSJens Wiklander /*
288*817466cbSJens Wiklander  * Set value from integer
289*817466cbSJens Wiklander  */
290*817466cbSJens Wiklander int mbedtls_mpi_lset( mbedtls_mpi *X, mbedtls_mpi_sint z )
291*817466cbSJens Wiklander {
292*817466cbSJens Wiklander     int ret;
293*817466cbSJens Wiklander 
294*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, 1 ) );
295*817466cbSJens Wiklander     memset( X->p, 0, X->n * ciL );
296*817466cbSJens Wiklander 
297*817466cbSJens Wiklander     X->p[0] = ( z < 0 ) ? -z : z;
298*817466cbSJens Wiklander     X->s    = ( z < 0 ) ? -1 : 1;
299*817466cbSJens Wiklander 
300*817466cbSJens Wiklander cleanup:
301*817466cbSJens Wiklander 
302*817466cbSJens Wiklander     return( ret );
303*817466cbSJens Wiklander }
304*817466cbSJens Wiklander 
305*817466cbSJens Wiklander /*
306*817466cbSJens Wiklander  * Get a specific bit
307*817466cbSJens Wiklander  */
308*817466cbSJens Wiklander int mbedtls_mpi_get_bit( const mbedtls_mpi *X, size_t pos )
309*817466cbSJens Wiklander {
310*817466cbSJens Wiklander     if( X->n * biL <= pos )
311*817466cbSJens Wiklander         return( 0 );
312*817466cbSJens Wiklander 
313*817466cbSJens Wiklander     return( ( X->p[pos / biL] >> ( pos % biL ) ) & 0x01 );
314*817466cbSJens Wiklander }
315*817466cbSJens Wiklander 
316*817466cbSJens Wiklander /*
317*817466cbSJens Wiklander  * Set a bit to a specific value of 0 or 1
318*817466cbSJens Wiklander  */
319*817466cbSJens Wiklander int mbedtls_mpi_set_bit( mbedtls_mpi *X, size_t pos, unsigned char val )
320*817466cbSJens Wiklander {
321*817466cbSJens Wiklander     int ret = 0;
322*817466cbSJens Wiklander     size_t off = pos / biL;
323*817466cbSJens Wiklander     size_t idx = pos % biL;
324*817466cbSJens Wiklander 
325*817466cbSJens Wiklander     if( val != 0 && val != 1 )
326*817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
327*817466cbSJens Wiklander 
328*817466cbSJens Wiklander     if( X->n * biL <= pos )
329*817466cbSJens Wiklander     {
330*817466cbSJens Wiklander         if( val == 0 )
331*817466cbSJens Wiklander             return( 0 );
332*817466cbSJens Wiklander 
333*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, off + 1 ) );
334*817466cbSJens Wiklander     }
335*817466cbSJens Wiklander 
336*817466cbSJens Wiklander     X->p[off] &= ~( (mbedtls_mpi_uint) 0x01 << idx );
337*817466cbSJens Wiklander     X->p[off] |= (mbedtls_mpi_uint) val << idx;
338*817466cbSJens Wiklander 
339*817466cbSJens Wiklander cleanup:
340*817466cbSJens Wiklander 
341*817466cbSJens Wiklander     return( ret );
342*817466cbSJens Wiklander }
343*817466cbSJens Wiklander 
344*817466cbSJens Wiklander /*
345*817466cbSJens Wiklander  * Return the number of less significant zero-bits
346*817466cbSJens Wiklander  */
347*817466cbSJens Wiklander size_t mbedtls_mpi_lsb( const mbedtls_mpi *X )
348*817466cbSJens Wiklander {
349*817466cbSJens Wiklander     size_t i, j, count = 0;
350*817466cbSJens Wiklander 
351*817466cbSJens Wiklander     for( i = 0; i < X->n; i++ )
352*817466cbSJens Wiklander         for( j = 0; j < biL; j++, count++ )
353*817466cbSJens Wiklander             if( ( ( X->p[i] >> j ) & 1 ) != 0 )
354*817466cbSJens Wiklander                 return( count );
355*817466cbSJens Wiklander 
356*817466cbSJens Wiklander     return( 0 );
357*817466cbSJens Wiklander }
358*817466cbSJens Wiklander 
359*817466cbSJens Wiklander /*
360*817466cbSJens Wiklander  * Count leading zero bits in a given integer
361*817466cbSJens Wiklander  */
362*817466cbSJens Wiklander static size_t mbedtls_clz( const mbedtls_mpi_uint x )
363*817466cbSJens Wiklander {
364*817466cbSJens Wiklander     size_t j;
365*817466cbSJens Wiklander     mbedtls_mpi_uint mask = (mbedtls_mpi_uint) 1 << (biL - 1);
366*817466cbSJens Wiklander 
367*817466cbSJens Wiklander     for( j = 0; j < biL; j++ )
368*817466cbSJens Wiklander     {
369*817466cbSJens Wiklander         if( x & mask ) break;
370*817466cbSJens Wiklander 
371*817466cbSJens Wiklander         mask >>= 1;
372*817466cbSJens Wiklander     }
373*817466cbSJens Wiklander 
374*817466cbSJens Wiklander     return j;
375*817466cbSJens Wiklander }
376*817466cbSJens Wiklander 
377*817466cbSJens Wiklander /*
378*817466cbSJens Wiklander  * Return the number of bits
379*817466cbSJens Wiklander  */
380*817466cbSJens Wiklander size_t mbedtls_mpi_bitlen( const mbedtls_mpi *X )
381*817466cbSJens Wiklander {
382*817466cbSJens Wiklander     size_t i, j;
383*817466cbSJens Wiklander 
384*817466cbSJens Wiklander     if( X->n == 0 )
385*817466cbSJens Wiklander         return( 0 );
386*817466cbSJens Wiklander 
387*817466cbSJens Wiklander     for( i = X->n - 1; i > 0; i-- )
388*817466cbSJens Wiklander         if( X->p[i] != 0 )
389*817466cbSJens Wiklander             break;
390*817466cbSJens Wiklander 
391*817466cbSJens Wiklander     j = biL - mbedtls_clz( X->p[i] );
392*817466cbSJens Wiklander 
393*817466cbSJens Wiklander     return( ( i * biL ) + j );
394*817466cbSJens Wiklander }
395*817466cbSJens Wiklander 
396*817466cbSJens Wiklander /*
397*817466cbSJens Wiklander  * Return the total size in bytes
398*817466cbSJens Wiklander  */
399*817466cbSJens Wiklander size_t mbedtls_mpi_size( const mbedtls_mpi *X )
400*817466cbSJens Wiklander {
401*817466cbSJens Wiklander     return( ( mbedtls_mpi_bitlen( X ) + 7 ) >> 3 );
402*817466cbSJens Wiklander }
403*817466cbSJens Wiklander 
404*817466cbSJens Wiklander /*
405*817466cbSJens Wiklander  * Convert an ASCII character to digit value
406*817466cbSJens Wiklander  */
407*817466cbSJens Wiklander static int mpi_get_digit( mbedtls_mpi_uint *d, int radix, char c )
408*817466cbSJens Wiklander {
409*817466cbSJens Wiklander     *d = 255;
410*817466cbSJens Wiklander 
411*817466cbSJens Wiklander     if( c >= 0x30 && c <= 0x39 ) *d = c - 0x30;
412*817466cbSJens Wiklander     if( c >= 0x41 && c <= 0x46 ) *d = c - 0x37;
413*817466cbSJens Wiklander     if( c >= 0x61 && c <= 0x66 ) *d = c - 0x57;
414*817466cbSJens Wiklander 
415*817466cbSJens Wiklander     if( *d >= (mbedtls_mpi_uint) radix )
416*817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_INVALID_CHARACTER );
417*817466cbSJens Wiklander 
418*817466cbSJens Wiklander     return( 0 );
419*817466cbSJens Wiklander }
420*817466cbSJens Wiklander 
421*817466cbSJens Wiklander /*
422*817466cbSJens Wiklander  * Import from an ASCII string
423*817466cbSJens Wiklander  */
424*817466cbSJens Wiklander int mbedtls_mpi_read_string( mbedtls_mpi *X, int radix, const char *s )
425*817466cbSJens Wiklander {
426*817466cbSJens Wiklander     int ret;
427*817466cbSJens Wiklander     size_t i, j, slen, n;
428*817466cbSJens Wiklander     mbedtls_mpi_uint d;
429*817466cbSJens Wiklander     mbedtls_mpi T;
430*817466cbSJens Wiklander 
431*817466cbSJens Wiklander     if( radix < 2 || radix > 16 )
432*817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
433*817466cbSJens Wiklander 
434*817466cbSJens Wiklander     mbedtls_mpi_init( &T );
435*817466cbSJens Wiklander 
436*817466cbSJens Wiklander     slen = strlen( s );
437*817466cbSJens Wiklander 
438*817466cbSJens Wiklander     if( radix == 16 )
439*817466cbSJens Wiklander     {
440*817466cbSJens Wiklander         if( slen > MPI_SIZE_T_MAX >> 2 )
441*817466cbSJens Wiklander             return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
442*817466cbSJens Wiklander 
443*817466cbSJens Wiklander         n = BITS_TO_LIMBS( slen << 2 );
444*817466cbSJens Wiklander 
445*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, n ) );
446*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) );
447*817466cbSJens Wiklander 
448*817466cbSJens Wiklander         for( i = slen, j = 0; i > 0; i--, j++ )
449*817466cbSJens Wiklander         {
450*817466cbSJens Wiklander             if( i == 1 && s[i - 1] == '-' )
451*817466cbSJens Wiklander             {
452*817466cbSJens Wiklander                 X->s = -1;
453*817466cbSJens Wiklander                 break;
454*817466cbSJens Wiklander             }
455*817466cbSJens Wiklander 
456*817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mpi_get_digit( &d, radix, s[i - 1] ) );
457*817466cbSJens Wiklander             X->p[j / ( 2 * ciL )] |= d << ( ( j % ( 2 * ciL ) ) << 2 );
458*817466cbSJens Wiklander         }
459*817466cbSJens Wiklander     }
460*817466cbSJens Wiklander     else
461*817466cbSJens Wiklander     {
462*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) );
463*817466cbSJens Wiklander 
464*817466cbSJens Wiklander         for( i = 0; i < slen; i++ )
465*817466cbSJens Wiklander         {
466*817466cbSJens Wiklander             if( i == 0 && s[i] == '-' )
467*817466cbSJens Wiklander             {
468*817466cbSJens Wiklander                 X->s = -1;
469*817466cbSJens Wiklander                 continue;
470*817466cbSJens Wiklander             }
471*817466cbSJens Wiklander 
472*817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mpi_get_digit( &d, radix, s[i] ) );
473*817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &T, X, radix ) );
474*817466cbSJens Wiklander 
475*817466cbSJens Wiklander             if( X->s == 1 )
476*817466cbSJens Wiklander             {
477*817466cbSJens Wiklander                 MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, &T, d ) );
478*817466cbSJens Wiklander             }
479*817466cbSJens Wiklander             else
480*817466cbSJens Wiklander             {
481*817466cbSJens Wiklander                 MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( X, &T, d ) );
482*817466cbSJens Wiklander             }
483*817466cbSJens Wiklander         }
484*817466cbSJens Wiklander     }
485*817466cbSJens Wiklander 
486*817466cbSJens Wiklander cleanup:
487*817466cbSJens Wiklander 
488*817466cbSJens Wiklander     mbedtls_mpi_free( &T );
489*817466cbSJens Wiklander 
490*817466cbSJens Wiklander     return( ret );
491*817466cbSJens Wiklander }
492*817466cbSJens Wiklander 
493*817466cbSJens Wiklander /*
494*817466cbSJens Wiklander  * Helper to write the digits high-order first
495*817466cbSJens Wiklander  */
496*817466cbSJens Wiklander static int mpi_write_hlp( mbedtls_mpi *X, int radix, char **p )
497*817466cbSJens Wiklander {
498*817466cbSJens Wiklander     int ret;
499*817466cbSJens Wiklander     mbedtls_mpi_uint r;
500*817466cbSJens Wiklander 
501*817466cbSJens Wiklander     if( radix < 2 || radix > 16 )
502*817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
503*817466cbSJens Wiklander 
504*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mod_int( &r, X, radix ) );
505*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_div_int( X, NULL, X, radix ) );
506*817466cbSJens Wiklander 
507*817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( X, 0 ) != 0 )
508*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mpi_write_hlp( X, radix, p ) );
509*817466cbSJens Wiklander 
510*817466cbSJens Wiklander     if( r < 10 )
511*817466cbSJens Wiklander         *(*p)++ = (char)( r + 0x30 );
512*817466cbSJens Wiklander     else
513*817466cbSJens Wiklander         *(*p)++ = (char)( r + 0x37 );
514*817466cbSJens Wiklander 
515*817466cbSJens Wiklander cleanup:
516*817466cbSJens Wiklander 
517*817466cbSJens Wiklander     return( ret );
518*817466cbSJens Wiklander }
519*817466cbSJens Wiklander 
520*817466cbSJens Wiklander /*
521*817466cbSJens Wiklander  * Export into an ASCII string
522*817466cbSJens Wiklander  */
523*817466cbSJens Wiklander int mbedtls_mpi_write_string( const mbedtls_mpi *X, int radix,
524*817466cbSJens Wiklander                               char *buf, size_t buflen, size_t *olen )
525*817466cbSJens Wiklander {
526*817466cbSJens Wiklander     int ret = 0;
527*817466cbSJens Wiklander     size_t n;
528*817466cbSJens Wiklander     char *p;
529*817466cbSJens Wiklander     mbedtls_mpi T;
530*817466cbSJens Wiklander 
531*817466cbSJens Wiklander     if( radix < 2 || radix > 16 )
532*817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
533*817466cbSJens Wiklander 
534*817466cbSJens Wiklander     n = mbedtls_mpi_bitlen( X );
535*817466cbSJens Wiklander     if( radix >=  4 ) n >>= 1;
536*817466cbSJens Wiklander     if( radix >= 16 ) n >>= 1;
537*817466cbSJens Wiklander     /*
538*817466cbSJens Wiklander      * Round up the buffer length to an even value to ensure that there is
539*817466cbSJens Wiklander      * enough room for hexadecimal values that can be represented in an odd
540*817466cbSJens Wiklander      * number of digits.
541*817466cbSJens Wiklander      */
542*817466cbSJens Wiklander     n += 3 + ( ( n + 1 ) & 1 );
543*817466cbSJens Wiklander 
544*817466cbSJens Wiklander     if( buflen < n )
545*817466cbSJens Wiklander     {
546*817466cbSJens Wiklander         *olen = n;
547*817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL );
548*817466cbSJens Wiklander     }
549*817466cbSJens Wiklander 
550*817466cbSJens Wiklander     p = buf;
551*817466cbSJens Wiklander     mbedtls_mpi_init( &T );
552*817466cbSJens Wiklander 
553*817466cbSJens Wiklander     if( X->s == -1 )
554*817466cbSJens Wiklander         *p++ = '-';
555*817466cbSJens Wiklander 
556*817466cbSJens Wiklander     if( radix == 16 )
557*817466cbSJens Wiklander     {
558*817466cbSJens Wiklander         int c;
559*817466cbSJens Wiklander         size_t i, j, k;
560*817466cbSJens Wiklander 
561*817466cbSJens Wiklander         for( i = X->n, k = 0; i > 0; i-- )
562*817466cbSJens Wiklander         {
563*817466cbSJens Wiklander             for( j = ciL; j > 0; j-- )
564*817466cbSJens Wiklander             {
565*817466cbSJens Wiklander                 c = ( X->p[i - 1] >> ( ( j - 1 ) << 3) ) & 0xFF;
566*817466cbSJens Wiklander 
567*817466cbSJens Wiklander                 if( c == 0 && k == 0 && ( i + j ) != 2 )
568*817466cbSJens Wiklander                     continue;
569*817466cbSJens Wiklander 
570*817466cbSJens Wiklander                 *(p++) = "0123456789ABCDEF" [c / 16];
571*817466cbSJens Wiklander                 *(p++) = "0123456789ABCDEF" [c % 16];
572*817466cbSJens Wiklander                 k = 1;
573*817466cbSJens Wiklander             }
574*817466cbSJens Wiklander         }
575*817466cbSJens Wiklander     }
576*817466cbSJens Wiklander     else
577*817466cbSJens Wiklander     {
578*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &T, X ) );
579*817466cbSJens Wiklander 
580*817466cbSJens Wiklander         if( T.s == -1 )
581*817466cbSJens Wiklander             T.s = 1;
582*817466cbSJens Wiklander 
583*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mpi_write_hlp( &T, radix, &p ) );
584*817466cbSJens Wiklander     }
585*817466cbSJens Wiklander 
586*817466cbSJens Wiklander     *p++ = '\0';
587*817466cbSJens Wiklander     *olen = p - buf;
588*817466cbSJens Wiklander 
589*817466cbSJens Wiklander cleanup:
590*817466cbSJens Wiklander 
591*817466cbSJens Wiklander     mbedtls_mpi_free( &T );
592*817466cbSJens Wiklander 
593*817466cbSJens Wiklander     return( ret );
594*817466cbSJens Wiklander }
595*817466cbSJens Wiklander 
596*817466cbSJens Wiklander #if defined(MBEDTLS_FS_IO)
597*817466cbSJens Wiklander /*
598*817466cbSJens Wiklander  * Read X from an opened file
599*817466cbSJens Wiklander  */
600*817466cbSJens Wiklander int mbedtls_mpi_read_file( mbedtls_mpi *X, int radix, FILE *fin )
601*817466cbSJens Wiklander {
602*817466cbSJens Wiklander     mbedtls_mpi_uint d;
603*817466cbSJens Wiklander     size_t slen;
604*817466cbSJens Wiklander     char *p;
605*817466cbSJens Wiklander     /*
606*817466cbSJens Wiklander      * Buffer should have space for (short) label and decimal formatted MPI,
607*817466cbSJens Wiklander      * newline characters and '\0'
608*817466cbSJens Wiklander      */
609*817466cbSJens Wiklander     char s[ MBEDTLS_MPI_RW_BUFFER_SIZE ];
610*817466cbSJens Wiklander 
611*817466cbSJens Wiklander     memset( s, 0, sizeof( s ) );
612*817466cbSJens Wiklander     if( fgets( s, sizeof( s ) - 1, fin ) == NULL )
613*817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_FILE_IO_ERROR );
614*817466cbSJens Wiklander 
615*817466cbSJens Wiklander     slen = strlen( s );
616*817466cbSJens Wiklander     if( slen == sizeof( s ) - 2 )
617*817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL );
618*817466cbSJens Wiklander 
619*817466cbSJens Wiklander     if( slen > 0 && s[slen - 1] == '\n' ) { slen--; s[slen] = '\0'; }
620*817466cbSJens Wiklander     if( slen > 0 && s[slen - 1] == '\r' ) { slen--; s[slen] = '\0'; }
621*817466cbSJens Wiklander 
622*817466cbSJens Wiklander     p = s + slen;
623*817466cbSJens Wiklander     while( p-- > s )
624*817466cbSJens Wiklander         if( mpi_get_digit( &d, radix, *p ) != 0 )
625*817466cbSJens Wiklander             break;
626*817466cbSJens Wiklander 
627*817466cbSJens Wiklander     return( mbedtls_mpi_read_string( X, radix, p + 1 ) );
628*817466cbSJens Wiklander }
629*817466cbSJens Wiklander 
630*817466cbSJens Wiklander /*
631*817466cbSJens Wiklander  * Write X into an opened file (or stdout if fout == NULL)
632*817466cbSJens Wiklander  */
633*817466cbSJens Wiklander int mbedtls_mpi_write_file( const char *p, const mbedtls_mpi *X, int radix, FILE *fout )
634*817466cbSJens Wiklander {
635*817466cbSJens Wiklander     int ret;
636*817466cbSJens Wiklander     size_t n, slen, plen;
637*817466cbSJens Wiklander     /*
638*817466cbSJens Wiklander      * Buffer should have space for (short) label and decimal formatted MPI,
639*817466cbSJens Wiklander      * newline characters and '\0'
640*817466cbSJens Wiklander      */
641*817466cbSJens Wiklander     char s[ MBEDTLS_MPI_RW_BUFFER_SIZE ];
642*817466cbSJens Wiklander 
643*817466cbSJens Wiklander     memset( s, 0, sizeof( s ) );
644*817466cbSJens Wiklander 
645*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_write_string( X, radix, s, sizeof( s ) - 2, &n ) );
646*817466cbSJens Wiklander 
647*817466cbSJens Wiklander     if( p == NULL ) p = "";
648*817466cbSJens Wiklander 
649*817466cbSJens Wiklander     plen = strlen( p );
650*817466cbSJens Wiklander     slen = strlen( s );
651*817466cbSJens Wiklander     s[slen++] = '\r';
652*817466cbSJens Wiklander     s[slen++] = '\n';
653*817466cbSJens Wiklander 
654*817466cbSJens Wiklander     if( fout != NULL )
655*817466cbSJens Wiklander     {
656*817466cbSJens Wiklander         if( fwrite( p, 1, plen, fout ) != plen ||
657*817466cbSJens Wiklander             fwrite( s, 1, slen, fout ) != slen )
658*817466cbSJens Wiklander             return( MBEDTLS_ERR_MPI_FILE_IO_ERROR );
659*817466cbSJens Wiklander     }
660*817466cbSJens Wiklander     else
661*817466cbSJens Wiklander         mbedtls_printf( "%s%s", p, s );
662*817466cbSJens Wiklander 
663*817466cbSJens Wiklander cleanup:
664*817466cbSJens Wiklander 
665*817466cbSJens Wiklander     return( ret );
666*817466cbSJens Wiklander }
667*817466cbSJens Wiklander #endif /* MBEDTLS_FS_IO */
668*817466cbSJens Wiklander 
669*817466cbSJens Wiklander /*
670*817466cbSJens Wiklander  * Import X from unsigned binary data, big endian
671*817466cbSJens Wiklander  */
672*817466cbSJens Wiklander int mbedtls_mpi_read_binary( mbedtls_mpi *X, const unsigned char *buf, size_t buflen )
673*817466cbSJens Wiklander {
674*817466cbSJens Wiklander     int ret;
675*817466cbSJens Wiklander     size_t i, j, n;
676*817466cbSJens Wiklander 
677*817466cbSJens Wiklander     for( n = 0; n < buflen; n++ )
678*817466cbSJens Wiklander         if( buf[n] != 0 )
679*817466cbSJens Wiklander             break;
680*817466cbSJens Wiklander 
681*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, CHARS_TO_LIMBS( buflen - n ) ) );
682*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) );
683*817466cbSJens Wiklander 
684*817466cbSJens Wiklander     for( i = buflen, j = 0; i > n; i--, j++ )
685*817466cbSJens Wiklander         X->p[j / ciL] |= ((mbedtls_mpi_uint) buf[i - 1]) << ((j % ciL) << 3);
686*817466cbSJens Wiklander 
687*817466cbSJens Wiklander cleanup:
688*817466cbSJens Wiklander 
689*817466cbSJens Wiklander     return( ret );
690*817466cbSJens Wiklander }
691*817466cbSJens Wiklander 
692*817466cbSJens Wiklander /*
693*817466cbSJens Wiklander  * Export X into unsigned binary data, big endian
694*817466cbSJens Wiklander  */
695*817466cbSJens Wiklander int mbedtls_mpi_write_binary( const mbedtls_mpi *X, unsigned char *buf, size_t buflen )
696*817466cbSJens Wiklander {
697*817466cbSJens Wiklander     size_t i, j, n;
698*817466cbSJens Wiklander 
699*817466cbSJens Wiklander     n = mbedtls_mpi_size( X );
700*817466cbSJens Wiklander 
701*817466cbSJens Wiklander     if( buflen < n )
702*817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL );
703*817466cbSJens Wiklander 
704*817466cbSJens Wiklander     memset( buf, 0, buflen );
705*817466cbSJens Wiklander 
706*817466cbSJens Wiklander     for( i = buflen - 1, j = 0; n > 0; i--, j++, n-- )
707*817466cbSJens Wiklander         buf[i] = (unsigned char)( X->p[j / ciL] >> ((j % ciL) << 3) );
708*817466cbSJens Wiklander 
709*817466cbSJens Wiklander     return( 0 );
710*817466cbSJens Wiklander }
711*817466cbSJens Wiklander 
712*817466cbSJens Wiklander /*
713*817466cbSJens Wiklander  * Left-shift: X <<= count
714*817466cbSJens Wiklander  */
715*817466cbSJens Wiklander int mbedtls_mpi_shift_l( mbedtls_mpi *X, size_t count )
716*817466cbSJens Wiklander {
717*817466cbSJens Wiklander     int ret;
718*817466cbSJens Wiklander     size_t i, v0, t1;
719*817466cbSJens Wiklander     mbedtls_mpi_uint r0 = 0, r1;
720*817466cbSJens Wiklander 
721*817466cbSJens Wiklander     v0 = count / (biL    );
722*817466cbSJens Wiklander     t1 = count & (biL - 1);
723*817466cbSJens Wiklander 
724*817466cbSJens Wiklander     i = mbedtls_mpi_bitlen( X ) + count;
725*817466cbSJens Wiklander 
726*817466cbSJens Wiklander     if( X->n * biL < i )
727*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, BITS_TO_LIMBS( i ) ) );
728*817466cbSJens Wiklander 
729*817466cbSJens Wiklander     ret = 0;
730*817466cbSJens Wiklander 
731*817466cbSJens Wiklander     /*
732*817466cbSJens Wiklander      * shift by count / limb_size
733*817466cbSJens Wiklander      */
734*817466cbSJens Wiklander     if( v0 > 0 )
735*817466cbSJens Wiklander     {
736*817466cbSJens Wiklander         for( i = X->n; i > v0; i-- )
737*817466cbSJens Wiklander             X->p[i - 1] = X->p[i - v0 - 1];
738*817466cbSJens Wiklander 
739*817466cbSJens Wiklander         for( ; i > 0; i-- )
740*817466cbSJens Wiklander             X->p[i - 1] = 0;
741*817466cbSJens Wiklander     }
742*817466cbSJens Wiklander 
743*817466cbSJens Wiklander     /*
744*817466cbSJens Wiklander      * shift by count % limb_size
745*817466cbSJens Wiklander      */
746*817466cbSJens Wiklander     if( t1 > 0 )
747*817466cbSJens Wiklander     {
748*817466cbSJens Wiklander         for( i = v0; i < X->n; i++ )
749*817466cbSJens Wiklander         {
750*817466cbSJens Wiklander             r1 = X->p[i] >> (biL - t1);
751*817466cbSJens Wiklander             X->p[i] <<= t1;
752*817466cbSJens Wiklander             X->p[i] |= r0;
753*817466cbSJens Wiklander             r0 = r1;
754*817466cbSJens Wiklander         }
755*817466cbSJens Wiklander     }
756*817466cbSJens Wiklander 
757*817466cbSJens Wiklander cleanup:
758*817466cbSJens Wiklander 
759*817466cbSJens Wiklander     return( ret );
760*817466cbSJens Wiklander }
761*817466cbSJens Wiklander 
762*817466cbSJens Wiklander /*
763*817466cbSJens Wiklander  * Right-shift: X >>= count
764*817466cbSJens Wiklander  */
765*817466cbSJens Wiklander int mbedtls_mpi_shift_r( mbedtls_mpi *X, size_t count )
766*817466cbSJens Wiklander {
767*817466cbSJens Wiklander     size_t i, v0, v1;
768*817466cbSJens Wiklander     mbedtls_mpi_uint r0 = 0, r1;
769*817466cbSJens Wiklander 
770*817466cbSJens Wiklander     v0 = count /  biL;
771*817466cbSJens Wiklander     v1 = count & (biL - 1);
772*817466cbSJens Wiklander 
773*817466cbSJens Wiklander     if( v0 > X->n || ( v0 == X->n && v1 > 0 ) )
774*817466cbSJens Wiklander         return mbedtls_mpi_lset( X, 0 );
775*817466cbSJens Wiklander 
776*817466cbSJens Wiklander     /*
777*817466cbSJens Wiklander      * shift by count / limb_size
778*817466cbSJens Wiklander      */
779*817466cbSJens Wiklander     if( v0 > 0 )
780*817466cbSJens Wiklander     {
781*817466cbSJens Wiklander         for( i = 0; i < X->n - v0; i++ )
782*817466cbSJens Wiklander             X->p[i] = X->p[i + v0];
783*817466cbSJens Wiklander 
784*817466cbSJens Wiklander         for( ; i < X->n; i++ )
785*817466cbSJens Wiklander             X->p[i] = 0;
786*817466cbSJens Wiklander     }
787*817466cbSJens Wiklander 
788*817466cbSJens Wiklander     /*
789*817466cbSJens Wiklander      * shift by count % limb_size
790*817466cbSJens Wiklander      */
791*817466cbSJens Wiklander     if( v1 > 0 )
792*817466cbSJens Wiklander     {
793*817466cbSJens Wiklander         for( i = X->n; i > 0; i-- )
794*817466cbSJens Wiklander         {
795*817466cbSJens Wiklander             r1 = X->p[i - 1] << (biL - v1);
796*817466cbSJens Wiklander             X->p[i - 1] >>= v1;
797*817466cbSJens Wiklander             X->p[i - 1] |= r0;
798*817466cbSJens Wiklander             r0 = r1;
799*817466cbSJens Wiklander         }
800*817466cbSJens Wiklander     }
801*817466cbSJens Wiklander 
802*817466cbSJens Wiklander     return( 0 );
803*817466cbSJens Wiklander }
804*817466cbSJens Wiklander 
805*817466cbSJens Wiklander /*
806*817466cbSJens Wiklander  * Compare unsigned values
807*817466cbSJens Wiklander  */
808*817466cbSJens Wiklander int mbedtls_mpi_cmp_abs( const mbedtls_mpi *X, const mbedtls_mpi *Y )
809*817466cbSJens Wiklander {
810*817466cbSJens Wiklander     size_t i, j;
811*817466cbSJens Wiklander 
812*817466cbSJens Wiklander     for( i = X->n; i > 0; i-- )
813*817466cbSJens Wiklander         if( X->p[i - 1] != 0 )
814*817466cbSJens Wiklander             break;
815*817466cbSJens Wiklander 
816*817466cbSJens Wiklander     for( j = Y->n; j > 0; j-- )
817*817466cbSJens Wiklander         if( Y->p[j - 1] != 0 )
818*817466cbSJens Wiklander             break;
819*817466cbSJens Wiklander 
820*817466cbSJens Wiklander     if( i == 0 && j == 0 )
821*817466cbSJens Wiklander         return( 0 );
822*817466cbSJens Wiklander 
823*817466cbSJens Wiklander     if( i > j ) return(  1 );
824*817466cbSJens Wiklander     if( j > i ) return( -1 );
825*817466cbSJens Wiklander 
826*817466cbSJens Wiklander     for( ; i > 0; i-- )
827*817466cbSJens Wiklander     {
828*817466cbSJens Wiklander         if( X->p[i - 1] > Y->p[i - 1] ) return(  1 );
829*817466cbSJens Wiklander         if( X->p[i - 1] < Y->p[i - 1] ) return( -1 );
830*817466cbSJens Wiklander     }
831*817466cbSJens Wiklander 
832*817466cbSJens Wiklander     return( 0 );
833*817466cbSJens Wiklander }
834*817466cbSJens Wiklander 
835*817466cbSJens Wiklander /*
836*817466cbSJens Wiklander  * Compare signed values
837*817466cbSJens Wiklander  */
838*817466cbSJens Wiklander int mbedtls_mpi_cmp_mpi( const mbedtls_mpi *X, const mbedtls_mpi *Y )
839*817466cbSJens Wiklander {
840*817466cbSJens Wiklander     size_t i, j;
841*817466cbSJens Wiklander 
842*817466cbSJens Wiklander     for( i = X->n; i > 0; i-- )
843*817466cbSJens Wiklander         if( X->p[i - 1] != 0 )
844*817466cbSJens Wiklander             break;
845*817466cbSJens Wiklander 
846*817466cbSJens Wiklander     for( j = Y->n; j > 0; j-- )
847*817466cbSJens Wiklander         if( Y->p[j - 1] != 0 )
848*817466cbSJens Wiklander             break;
849*817466cbSJens Wiklander 
850*817466cbSJens Wiklander     if( i == 0 && j == 0 )
851*817466cbSJens Wiklander         return( 0 );
852*817466cbSJens Wiklander 
853*817466cbSJens Wiklander     if( i > j ) return(  X->s );
854*817466cbSJens Wiklander     if( j > i ) return( -Y->s );
855*817466cbSJens Wiklander 
856*817466cbSJens Wiklander     if( X->s > 0 && Y->s < 0 ) return(  1 );
857*817466cbSJens Wiklander     if( Y->s > 0 && X->s < 0 ) return( -1 );
858*817466cbSJens Wiklander 
859*817466cbSJens Wiklander     for( ; i > 0; i-- )
860*817466cbSJens Wiklander     {
861*817466cbSJens Wiklander         if( X->p[i - 1] > Y->p[i - 1] ) return(  X->s );
862*817466cbSJens Wiklander         if( X->p[i - 1] < Y->p[i - 1] ) return( -X->s );
863*817466cbSJens Wiklander     }
864*817466cbSJens Wiklander 
865*817466cbSJens Wiklander     return( 0 );
866*817466cbSJens Wiklander }
867*817466cbSJens Wiklander 
868*817466cbSJens Wiklander /*
869*817466cbSJens Wiklander  * Compare signed values
870*817466cbSJens Wiklander  */
871*817466cbSJens Wiklander int mbedtls_mpi_cmp_int( const mbedtls_mpi *X, mbedtls_mpi_sint z )
872*817466cbSJens Wiklander {
873*817466cbSJens Wiklander     mbedtls_mpi Y;
874*817466cbSJens Wiklander     mbedtls_mpi_uint p[1];
875*817466cbSJens Wiklander 
876*817466cbSJens Wiklander     *p  = ( z < 0 ) ? -z : z;
877*817466cbSJens Wiklander     Y.s = ( z < 0 ) ? -1 : 1;
878*817466cbSJens Wiklander     Y.n = 1;
879*817466cbSJens Wiklander     Y.p = p;
880*817466cbSJens Wiklander 
881*817466cbSJens Wiklander     return( mbedtls_mpi_cmp_mpi( X, &Y ) );
882*817466cbSJens Wiklander }
883*817466cbSJens Wiklander 
884*817466cbSJens Wiklander /*
885*817466cbSJens Wiklander  * Unsigned addition: X = |A| + |B|  (HAC 14.7)
886*817466cbSJens Wiklander  */
887*817466cbSJens Wiklander int mbedtls_mpi_add_abs( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B )
888*817466cbSJens Wiklander {
889*817466cbSJens Wiklander     int ret;
890*817466cbSJens Wiklander     size_t i, j;
891*817466cbSJens Wiklander     mbedtls_mpi_uint *o, *p, c, tmp;
892*817466cbSJens Wiklander 
893*817466cbSJens Wiklander     if( X == B )
894*817466cbSJens Wiklander     {
895*817466cbSJens Wiklander         const mbedtls_mpi *T = A; A = X; B = T;
896*817466cbSJens Wiklander     }
897*817466cbSJens Wiklander 
898*817466cbSJens Wiklander     if( X != A )
899*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, A ) );
900*817466cbSJens Wiklander 
901*817466cbSJens Wiklander     /*
902*817466cbSJens Wiklander      * X should always be positive as a result of unsigned additions.
903*817466cbSJens Wiklander      */
904*817466cbSJens Wiklander     X->s = 1;
905*817466cbSJens Wiklander 
906*817466cbSJens Wiklander     for( j = B->n; j > 0; j-- )
907*817466cbSJens Wiklander         if( B->p[j - 1] != 0 )
908*817466cbSJens Wiklander             break;
909*817466cbSJens Wiklander 
910*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, j ) );
911*817466cbSJens Wiklander 
912*817466cbSJens Wiklander     o = B->p; p = X->p; c = 0;
913*817466cbSJens Wiklander 
914*817466cbSJens Wiklander     /*
915*817466cbSJens Wiklander      * tmp is used because it might happen that p == o
916*817466cbSJens Wiklander      */
917*817466cbSJens Wiklander     for( i = 0; i < j; i++, o++, p++ )
918*817466cbSJens Wiklander     {
919*817466cbSJens Wiklander         tmp= *o;
920*817466cbSJens Wiklander         *p +=  c; c  = ( *p <  c );
921*817466cbSJens Wiklander         *p += tmp; c += ( *p < tmp );
922*817466cbSJens Wiklander     }
923*817466cbSJens Wiklander 
924*817466cbSJens Wiklander     while( c != 0 )
925*817466cbSJens Wiklander     {
926*817466cbSJens Wiklander         if( i >= X->n )
927*817466cbSJens Wiklander         {
928*817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, i + 1 ) );
929*817466cbSJens Wiklander             p = X->p + i;
930*817466cbSJens Wiklander         }
931*817466cbSJens Wiklander 
932*817466cbSJens Wiklander         *p += c; c = ( *p < c ); i++; p++;
933*817466cbSJens Wiklander     }
934*817466cbSJens Wiklander 
935*817466cbSJens Wiklander cleanup:
936*817466cbSJens Wiklander 
937*817466cbSJens Wiklander     return( ret );
938*817466cbSJens Wiklander }
939*817466cbSJens Wiklander 
940*817466cbSJens Wiklander /*
941*817466cbSJens Wiklander  * Helper for mbedtls_mpi subtraction
942*817466cbSJens Wiklander  */
943*817466cbSJens Wiklander static void mpi_sub_hlp( size_t n, mbedtls_mpi_uint *s, mbedtls_mpi_uint *d )
944*817466cbSJens Wiklander {
945*817466cbSJens Wiklander     size_t i;
946*817466cbSJens Wiklander     mbedtls_mpi_uint c, z;
947*817466cbSJens Wiklander 
948*817466cbSJens Wiklander     for( i = c = 0; i < n; i++, s++, d++ )
949*817466cbSJens Wiklander     {
950*817466cbSJens Wiklander         z = ( *d <  c );     *d -=  c;
951*817466cbSJens Wiklander         c = ( *d < *s ) + z; *d -= *s;
952*817466cbSJens Wiklander     }
953*817466cbSJens Wiklander 
954*817466cbSJens Wiklander     while( c != 0 )
955*817466cbSJens Wiklander     {
956*817466cbSJens Wiklander         z = ( *d < c ); *d -= c;
957*817466cbSJens Wiklander         c = z; i++; d++;
958*817466cbSJens Wiklander     }
959*817466cbSJens Wiklander }
960*817466cbSJens Wiklander 
961*817466cbSJens Wiklander /*
962*817466cbSJens Wiklander  * Unsigned subtraction: X = |A| - |B|  (HAC 14.9)
963*817466cbSJens Wiklander  */
964*817466cbSJens Wiklander int mbedtls_mpi_sub_abs( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B )
965*817466cbSJens Wiklander {
966*817466cbSJens Wiklander     mbedtls_mpi TB;
967*817466cbSJens Wiklander     int ret;
968*817466cbSJens Wiklander     size_t n;
969*817466cbSJens Wiklander 
970*817466cbSJens Wiklander     if( mbedtls_mpi_cmp_abs( A, B ) < 0 )
971*817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_NEGATIVE_VALUE );
972*817466cbSJens Wiklander 
973*817466cbSJens Wiklander     mbedtls_mpi_init( &TB );
974*817466cbSJens Wiklander 
975*817466cbSJens Wiklander     if( X == B )
976*817466cbSJens Wiklander     {
977*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, B ) );
978*817466cbSJens Wiklander         B = &TB;
979*817466cbSJens Wiklander     }
980*817466cbSJens Wiklander 
981*817466cbSJens Wiklander     if( X != A )
982*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, A ) );
983*817466cbSJens Wiklander 
984*817466cbSJens Wiklander     /*
985*817466cbSJens Wiklander      * X should always be positive as a result of unsigned subtractions.
986*817466cbSJens Wiklander      */
987*817466cbSJens Wiklander     X->s = 1;
988*817466cbSJens Wiklander 
989*817466cbSJens Wiklander     ret = 0;
990*817466cbSJens Wiklander 
991*817466cbSJens Wiklander     for( n = B->n; n > 0; n-- )
992*817466cbSJens Wiklander         if( B->p[n - 1] != 0 )
993*817466cbSJens Wiklander             break;
994*817466cbSJens Wiklander 
995*817466cbSJens Wiklander     mpi_sub_hlp( n, B->p, X->p );
996*817466cbSJens Wiklander 
997*817466cbSJens Wiklander cleanup:
998*817466cbSJens Wiklander 
999*817466cbSJens Wiklander     mbedtls_mpi_free( &TB );
1000*817466cbSJens Wiklander 
1001*817466cbSJens Wiklander     return( ret );
1002*817466cbSJens Wiklander }
1003*817466cbSJens Wiklander 
1004*817466cbSJens Wiklander /*
1005*817466cbSJens Wiklander  * Signed addition: X = A + B
1006*817466cbSJens Wiklander  */
1007*817466cbSJens Wiklander int mbedtls_mpi_add_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B )
1008*817466cbSJens Wiklander {
1009*817466cbSJens Wiklander     int ret, s = A->s;
1010*817466cbSJens Wiklander 
1011*817466cbSJens Wiklander     if( A->s * B->s < 0 )
1012*817466cbSJens Wiklander     {
1013*817466cbSJens Wiklander         if( mbedtls_mpi_cmp_abs( A, B ) >= 0 )
1014*817466cbSJens Wiklander         {
1015*817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, A, B ) );
1016*817466cbSJens Wiklander             X->s =  s;
1017*817466cbSJens Wiklander         }
1018*817466cbSJens Wiklander         else
1019*817466cbSJens Wiklander         {
1020*817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, B, A ) );
1021*817466cbSJens Wiklander             X->s = -s;
1022*817466cbSJens Wiklander         }
1023*817466cbSJens Wiklander     }
1024*817466cbSJens Wiklander     else
1025*817466cbSJens Wiklander     {
1026*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_add_abs( X, A, B ) );
1027*817466cbSJens Wiklander         X->s = s;
1028*817466cbSJens Wiklander     }
1029*817466cbSJens Wiklander 
1030*817466cbSJens Wiklander cleanup:
1031*817466cbSJens Wiklander 
1032*817466cbSJens Wiklander     return( ret );
1033*817466cbSJens Wiklander }
1034*817466cbSJens Wiklander 
1035*817466cbSJens Wiklander /*
1036*817466cbSJens Wiklander  * Signed subtraction: X = A - B
1037*817466cbSJens Wiklander  */
1038*817466cbSJens Wiklander int mbedtls_mpi_sub_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B )
1039*817466cbSJens Wiklander {
1040*817466cbSJens Wiklander     int ret, s = A->s;
1041*817466cbSJens Wiklander 
1042*817466cbSJens Wiklander     if( A->s * B->s > 0 )
1043*817466cbSJens Wiklander     {
1044*817466cbSJens Wiklander         if( mbedtls_mpi_cmp_abs( A, B ) >= 0 )
1045*817466cbSJens Wiklander         {
1046*817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, A, B ) );
1047*817466cbSJens Wiklander             X->s =  s;
1048*817466cbSJens Wiklander         }
1049*817466cbSJens Wiklander         else
1050*817466cbSJens Wiklander         {
1051*817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, B, A ) );
1052*817466cbSJens Wiklander             X->s = -s;
1053*817466cbSJens Wiklander         }
1054*817466cbSJens Wiklander     }
1055*817466cbSJens Wiklander     else
1056*817466cbSJens Wiklander     {
1057*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_add_abs( X, A, B ) );
1058*817466cbSJens Wiklander         X->s = s;
1059*817466cbSJens Wiklander     }
1060*817466cbSJens Wiklander 
1061*817466cbSJens Wiklander cleanup:
1062*817466cbSJens Wiklander 
1063*817466cbSJens Wiklander     return( ret );
1064*817466cbSJens Wiklander }
1065*817466cbSJens Wiklander 
1066*817466cbSJens Wiklander /*
1067*817466cbSJens Wiklander  * Signed addition: X = A + b
1068*817466cbSJens Wiklander  */
1069*817466cbSJens Wiklander int mbedtls_mpi_add_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b )
1070*817466cbSJens Wiklander {
1071*817466cbSJens Wiklander     mbedtls_mpi _B;
1072*817466cbSJens Wiklander     mbedtls_mpi_uint p[1];
1073*817466cbSJens Wiklander 
1074*817466cbSJens Wiklander     p[0] = ( b < 0 ) ? -b : b;
1075*817466cbSJens Wiklander     _B.s = ( b < 0 ) ? -1 : 1;
1076*817466cbSJens Wiklander     _B.n = 1;
1077*817466cbSJens Wiklander     _B.p = p;
1078*817466cbSJens Wiklander 
1079*817466cbSJens Wiklander     return( mbedtls_mpi_add_mpi( X, A, &_B ) );
1080*817466cbSJens Wiklander }
1081*817466cbSJens Wiklander 
1082*817466cbSJens Wiklander /*
1083*817466cbSJens Wiklander  * Signed subtraction: X = A - b
1084*817466cbSJens Wiklander  */
1085*817466cbSJens Wiklander int mbedtls_mpi_sub_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b )
1086*817466cbSJens Wiklander {
1087*817466cbSJens Wiklander     mbedtls_mpi _B;
1088*817466cbSJens Wiklander     mbedtls_mpi_uint p[1];
1089*817466cbSJens Wiklander 
1090*817466cbSJens Wiklander     p[0] = ( b < 0 ) ? -b : b;
1091*817466cbSJens Wiklander     _B.s = ( b < 0 ) ? -1 : 1;
1092*817466cbSJens Wiklander     _B.n = 1;
1093*817466cbSJens Wiklander     _B.p = p;
1094*817466cbSJens Wiklander 
1095*817466cbSJens Wiklander     return( mbedtls_mpi_sub_mpi( X, A, &_B ) );
1096*817466cbSJens Wiklander }
1097*817466cbSJens Wiklander 
1098*817466cbSJens Wiklander /*
1099*817466cbSJens Wiklander  * Helper for mbedtls_mpi multiplication
1100*817466cbSJens Wiklander  */
1101*817466cbSJens Wiklander static
1102*817466cbSJens Wiklander #if defined(__APPLE__) && defined(__arm__)
1103*817466cbSJens Wiklander /*
1104*817466cbSJens Wiklander  * Apple LLVM version 4.2 (clang-425.0.24) (based on LLVM 3.2svn)
1105*817466cbSJens Wiklander  * appears to need this to prevent bad ARM code generation at -O3.
1106*817466cbSJens Wiklander  */
1107*817466cbSJens Wiklander __attribute__ ((noinline))
1108*817466cbSJens Wiklander #endif
1109*817466cbSJens Wiklander void mpi_mul_hlp( size_t i, mbedtls_mpi_uint *s, mbedtls_mpi_uint *d, mbedtls_mpi_uint b )
1110*817466cbSJens Wiklander {
1111*817466cbSJens Wiklander     mbedtls_mpi_uint c = 0, t = 0;
1112*817466cbSJens Wiklander 
1113*817466cbSJens Wiklander #if defined(MULADDC_HUIT)
1114*817466cbSJens Wiklander     for( ; i >= 8; i -= 8 )
1115*817466cbSJens Wiklander     {
1116*817466cbSJens Wiklander         MULADDC_INIT
1117*817466cbSJens Wiklander         MULADDC_HUIT
1118*817466cbSJens Wiklander         MULADDC_STOP
1119*817466cbSJens Wiklander     }
1120*817466cbSJens Wiklander 
1121*817466cbSJens Wiklander     for( ; i > 0; i-- )
1122*817466cbSJens Wiklander     {
1123*817466cbSJens Wiklander         MULADDC_INIT
1124*817466cbSJens Wiklander         MULADDC_CORE
1125*817466cbSJens Wiklander         MULADDC_STOP
1126*817466cbSJens Wiklander     }
1127*817466cbSJens Wiklander #else /* MULADDC_HUIT */
1128*817466cbSJens Wiklander     for( ; i >= 16; i -= 16 )
1129*817466cbSJens Wiklander     {
1130*817466cbSJens Wiklander         MULADDC_INIT
1131*817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1132*817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1133*817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1134*817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1135*817466cbSJens Wiklander 
1136*817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1137*817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1138*817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1139*817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1140*817466cbSJens Wiklander         MULADDC_STOP
1141*817466cbSJens Wiklander     }
1142*817466cbSJens Wiklander 
1143*817466cbSJens Wiklander     for( ; i >= 8; i -= 8 )
1144*817466cbSJens Wiklander     {
1145*817466cbSJens Wiklander         MULADDC_INIT
1146*817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1147*817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1148*817466cbSJens Wiklander 
1149*817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1150*817466cbSJens Wiklander         MULADDC_CORE   MULADDC_CORE
1151*817466cbSJens Wiklander         MULADDC_STOP
1152*817466cbSJens Wiklander     }
1153*817466cbSJens Wiklander 
1154*817466cbSJens Wiklander     for( ; i > 0; i-- )
1155*817466cbSJens Wiklander     {
1156*817466cbSJens Wiklander         MULADDC_INIT
1157*817466cbSJens Wiklander         MULADDC_CORE
1158*817466cbSJens Wiklander         MULADDC_STOP
1159*817466cbSJens Wiklander     }
1160*817466cbSJens Wiklander #endif /* MULADDC_HUIT */
1161*817466cbSJens Wiklander 
1162*817466cbSJens Wiklander     t++;
1163*817466cbSJens Wiklander 
1164*817466cbSJens Wiklander     do {
1165*817466cbSJens Wiklander         *d += c; c = ( *d < c ); d++;
1166*817466cbSJens Wiklander     }
1167*817466cbSJens Wiklander     while( c != 0 );
1168*817466cbSJens Wiklander }
1169*817466cbSJens Wiklander 
1170*817466cbSJens Wiklander /*
1171*817466cbSJens Wiklander  * Baseline multiplication: X = A * B  (HAC 14.12)
1172*817466cbSJens Wiklander  */
1173*817466cbSJens Wiklander int mbedtls_mpi_mul_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B )
1174*817466cbSJens Wiklander {
1175*817466cbSJens Wiklander     int ret;
1176*817466cbSJens Wiklander     size_t i, j;
1177*817466cbSJens Wiklander     mbedtls_mpi TA, TB;
1178*817466cbSJens Wiklander 
1179*817466cbSJens Wiklander     mbedtls_mpi_init( &TA ); mbedtls_mpi_init( &TB );
1180*817466cbSJens Wiklander 
1181*817466cbSJens Wiklander     if( X == A ) { MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TA, A ) ); A = &TA; }
1182*817466cbSJens Wiklander     if( X == B ) { MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, B ) ); B = &TB; }
1183*817466cbSJens Wiklander 
1184*817466cbSJens Wiklander     for( i = A->n; i > 0; i-- )
1185*817466cbSJens Wiklander         if( A->p[i - 1] != 0 )
1186*817466cbSJens Wiklander             break;
1187*817466cbSJens Wiklander 
1188*817466cbSJens Wiklander     for( j = B->n; j > 0; j-- )
1189*817466cbSJens Wiklander         if( B->p[j - 1] != 0 )
1190*817466cbSJens Wiklander             break;
1191*817466cbSJens Wiklander 
1192*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, i + j ) );
1193*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) );
1194*817466cbSJens Wiklander 
1195*817466cbSJens Wiklander     for( i++; j > 0; j-- )
1196*817466cbSJens Wiklander         mpi_mul_hlp( i - 1, A->p, X->p + j - 1, B->p[j - 1] );
1197*817466cbSJens Wiklander 
1198*817466cbSJens Wiklander     X->s = A->s * B->s;
1199*817466cbSJens Wiklander 
1200*817466cbSJens Wiklander cleanup:
1201*817466cbSJens Wiklander 
1202*817466cbSJens Wiklander     mbedtls_mpi_free( &TB ); mbedtls_mpi_free( &TA );
1203*817466cbSJens Wiklander 
1204*817466cbSJens Wiklander     return( ret );
1205*817466cbSJens Wiklander }
1206*817466cbSJens Wiklander 
1207*817466cbSJens Wiklander /*
1208*817466cbSJens Wiklander  * Baseline multiplication: X = A * b
1209*817466cbSJens Wiklander  */
1210*817466cbSJens Wiklander int mbedtls_mpi_mul_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_uint b )
1211*817466cbSJens Wiklander {
1212*817466cbSJens Wiklander     mbedtls_mpi _B;
1213*817466cbSJens Wiklander     mbedtls_mpi_uint p[1];
1214*817466cbSJens Wiklander 
1215*817466cbSJens Wiklander     _B.s = 1;
1216*817466cbSJens Wiklander     _B.n = 1;
1217*817466cbSJens Wiklander     _B.p = p;
1218*817466cbSJens Wiklander     p[0] = b;
1219*817466cbSJens Wiklander 
1220*817466cbSJens Wiklander     return( mbedtls_mpi_mul_mpi( X, A, &_B ) );
1221*817466cbSJens Wiklander }
1222*817466cbSJens Wiklander 
1223*817466cbSJens Wiklander /*
1224*817466cbSJens Wiklander  * Unsigned integer divide - double mbedtls_mpi_uint dividend, u1/u0, and
1225*817466cbSJens Wiklander  * mbedtls_mpi_uint divisor, d
1226*817466cbSJens Wiklander  */
1227*817466cbSJens Wiklander static mbedtls_mpi_uint mbedtls_int_div_int( mbedtls_mpi_uint u1,
1228*817466cbSJens Wiklander             mbedtls_mpi_uint u0, mbedtls_mpi_uint d, mbedtls_mpi_uint *r )
1229*817466cbSJens Wiklander {
1230*817466cbSJens Wiklander #if defined(MBEDTLS_HAVE_UDBL)
1231*817466cbSJens Wiklander     mbedtls_t_udbl dividend, quotient;
1232*817466cbSJens Wiklander #else
1233*817466cbSJens Wiklander     const mbedtls_mpi_uint radix = (mbedtls_mpi_uint) 1 << biH;
1234*817466cbSJens Wiklander     const mbedtls_mpi_uint uint_halfword_mask = ( (mbedtls_mpi_uint) 1 << biH ) - 1;
1235*817466cbSJens Wiklander     mbedtls_mpi_uint d0, d1, q0, q1, rAX, r0, quotient;
1236*817466cbSJens Wiklander     mbedtls_mpi_uint u0_msw, u0_lsw;
1237*817466cbSJens Wiklander     size_t s;
1238*817466cbSJens Wiklander #endif
1239*817466cbSJens Wiklander 
1240*817466cbSJens Wiklander     /*
1241*817466cbSJens Wiklander      * Check for overflow
1242*817466cbSJens Wiklander      */
1243*817466cbSJens Wiklander     if( 0 == d || u1 >= d )
1244*817466cbSJens Wiklander     {
1245*817466cbSJens Wiklander         if (r != NULL) *r = ~0;
1246*817466cbSJens Wiklander 
1247*817466cbSJens Wiklander         return ( ~0 );
1248*817466cbSJens Wiklander     }
1249*817466cbSJens Wiklander 
1250*817466cbSJens Wiklander #if defined(MBEDTLS_HAVE_UDBL)
1251*817466cbSJens Wiklander     dividend  = (mbedtls_t_udbl) u1 << biL;
1252*817466cbSJens Wiklander     dividend |= (mbedtls_t_udbl) u0;
1253*817466cbSJens Wiklander     quotient = dividend / d;
1254*817466cbSJens Wiklander     if( quotient > ( (mbedtls_t_udbl) 1 << biL ) - 1 )
1255*817466cbSJens Wiklander         quotient = ( (mbedtls_t_udbl) 1 << biL ) - 1;
1256*817466cbSJens Wiklander 
1257*817466cbSJens Wiklander     if( r != NULL )
1258*817466cbSJens Wiklander         *r = (mbedtls_mpi_uint)( dividend - (quotient * d ) );
1259*817466cbSJens Wiklander 
1260*817466cbSJens Wiklander     return (mbedtls_mpi_uint) quotient;
1261*817466cbSJens Wiklander #else
1262*817466cbSJens Wiklander 
1263*817466cbSJens Wiklander     /*
1264*817466cbSJens Wiklander      * Algorithm D, Section 4.3.1 - The Art of Computer Programming
1265*817466cbSJens Wiklander      *   Vol. 2 - Seminumerical Algorithms, Knuth
1266*817466cbSJens Wiklander      */
1267*817466cbSJens Wiklander 
1268*817466cbSJens Wiklander     /*
1269*817466cbSJens Wiklander      * Normalize the divisor, d, and dividend, u0, u1
1270*817466cbSJens Wiklander      */
1271*817466cbSJens Wiklander     s = mbedtls_clz( d );
1272*817466cbSJens Wiklander     d = d << s;
1273*817466cbSJens Wiklander 
1274*817466cbSJens Wiklander     u1 = u1 << s;
1275*817466cbSJens Wiklander     u1 |= ( u0 >> ( biL - s ) ) & ( -(mbedtls_mpi_sint)s >> ( biL - 1 ) );
1276*817466cbSJens Wiklander     u0 =  u0 << s;
1277*817466cbSJens Wiklander 
1278*817466cbSJens Wiklander     d1 = d >> biH;
1279*817466cbSJens Wiklander     d0 = d & uint_halfword_mask;
1280*817466cbSJens Wiklander 
1281*817466cbSJens Wiklander     u0_msw = u0 >> biH;
1282*817466cbSJens Wiklander     u0_lsw = u0 & uint_halfword_mask;
1283*817466cbSJens Wiklander 
1284*817466cbSJens Wiklander     /*
1285*817466cbSJens Wiklander      * Find the first quotient and remainder
1286*817466cbSJens Wiklander      */
1287*817466cbSJens Wiklander     q1 = u1 / d1;
1288*817466cbSJens Wiklander     r0 = u1 - d1 * q1;
1289*817466cbSJens Wiklander 
1290*817466cbSJens Wiklander     while( q1 >= radix || ( q1 * d0 > radix * r0 + u0_msw ) )
1291*817466cbSJens Wiklander     {
1292*817466cbSJens Wiklander         q1 -= 1;
1293*817466cbSJens Wiklander         r0 += d1;
1294*817466cbSJens Wiklander 
1295*817466cbSJens Wiklander         if ( r0 >= radix ) break;
1296*817466cbSJens Wiklander     }
1297*817466cbSJens Wiklander 
1298*817466cbSJens Wiklander     rAX = ( u1 * radix ) + ( u0_msw - q1 * d );
1299*817466cbSJens Wiklander     q0 = rAX / d1;
1300*817466cbSJens Wiklander     r0 = rAX - q0 * d1;
1301*817466cbSJens Wiklander 
1302*817466cbSJens Wiklander     while( q0 >= radix || ( q0 * d0 > radix * r0 + u0_lsw ) )
1303*817466cbSJens Wiklander     {
1304*817466cbSJens Wiklander         q0 -= 1;
1305*817466cbSJens Wiklander         r0 += d1;
1306*817466cbSJens Wiklander 
1307*817466cbSJens Wiklander         if ( r0 >= radix ) break;
1308*817466cbSJens Wiklander     }
1309*817466cbSJens Wiklander 
1310*817466cbSJens Wiklander     if (r != NULL)
1311*817466cbSJens Wiklander         *r = ( rAX * radix + u0_lsw - q0 * d ) >> s;
1312*817466cbSJens Wiklander 
1313*817466cbSJens Wiklander     quotient = q1 * radix + q0;
1314*817466cbSJens Wiklander 
1315*817466cbSJens Wiklander     return quotient;
1316*817466cbSJens Wiklander #endif
1317*817466cbSJens Wiklander }
1318*817466cbSJens Wiklander 
1319*817466cbSJens Wiklander /*
1320*817466cbSJens Wiklander  * Division by mbedtls_mpi: A = Q * B + R  (HAC 14.20)
1321*817466cbSJens Wiklander  */
1322*817466cbSJens Wiklander int mbedtls_mpi_div_mpi( mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B )
1323*817466cbSJens Wiklander {
1324*817466cbSJens Wiklander     int ret;
1325*817466cbSJens Wiklander     size_t i, n, t, k;
1326*817466cbSJens Wiklander     mbedtls_mpi X, Y, Z, T1, T2;
1327*817466cbSJens Wiklander 
1328*817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( B, 0 ) == 0 )
1329*817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_DIVISION_BY_ZERO );
1330*817466cbSJens Wiklander 
1331*817466cbSJens Wiklander     mbedtls_mpi_init( &X ); mbedtls_mpi_init( &Y ); mbedtls_mpi_init( &Z );
1332*817466cbSJens Wiklander     mbedtls_mpi_init( &T1 ); mbedtls_mpi_init( &T2 );
1333*817466cbSJens Wiklander 
1334*817466cbSJens Wiklander     if( mbedtls_mpi_cmp_abs( A, B ) < 0 )
1335*817466cbSJens Wiklander     {
1336*817466cbSJens Wiklander         if( Q != NULL ) MBEDTLS_MPI_CHK( mbedtls_mpi_lset( Q, 0 ) );
1337*817466cbSJens Wiklander         if( R != NULL ) MBEDTLS_MPI_CHK( mbedtls_mpi_copy( R, A ) );
1338*817466cbSJens Wiklander         return( 0 );
1339*817466cbSJens Wiklander     }
1340*817466cbSJens Wiklander 
1341*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &X, A ) );
1342*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &Y, B ) );
1343*817466cbSJens Wiklander     X.s = Y.s = 1;
1344*817466cbSJens Wiklander 
1345*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &Z, A->n + 2 ) );
1346*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &Z,  0 ) );
1347*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &T1, 2 ) );
1348*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &T2, 3 ) );
1349*817466cbSJens Wiklander 
1350*817466cbSJens Wiklander     k = mbedtls_mpi_bitlen( &Y ) % biL;
1351*817466cbSJens Wiklander     if( k < biL - 1 )
1352*817466cbSJens Wiklander     {
1353*817466cbSJens Wiklander         k = biL - 1 - k;
1354*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &X, k ) );
1355*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &Y, k ) );
1356*817466cbSJens Wiklander     }
1357*817466cbSJens Wiklander     else k = 0;
1358*817466cbSJens Wiklander 
1359*817466cbSJens Wiklander     n = X.n - 1;
1360*817466cbSJens Wiklander     t = Y.n - 1;
1361*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &Y, biL * ( n - t ) ) );
1362*817466cbSJens Wiklander 
1363*817466cbSJens Wiklander     while( mbedtls_mpi_cmp_mpi( &X, &Y ) >= 0 )
1364*817466cbSJens Wiklander     {
1365*817466cbSJens Wiklander         Z.p[n - t]++;
1366*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &X, &X, &Y ) );
1367*817466cbSJens Wiklander     }
1368*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &Y, biL * ( n - t ) ) );
1369*817466cbSJens Wiklander 
1370*817466cbSJens Wiklander     for( i = n; i > t ; i-- )
1371*817466cbSJens Wiklander     {
1372*817466cbSJens Wiklander         if( X.p[i] >= Y.p[t] )
1373*817466cbSJens Wiklander             Z.p[i - t - 1] = ~0;
1374*817466cbSJens Wiklander         else
1375*817466cbSJens Wiklander         {
1376*817466cbSJens Wiklander             Z.p[i - t - 1] = mbedtls_int_div_int( X.p[i], X.p[i - 1],
1377*817466cbSJens Wiklander                                                             Y.p[t], NULL);
1378*817466cbSJens Wiklander         }
1379*817466cbSJens Wiklander 
1380*817466cbSJens Wiklander         Z.p[i - t - 1]++;
1381*817466cbSJens Wiklander         do
1382*817466cbSJens Wiklander         {
1383*817466cbSJens Wiklander             Z.p[i - t - 1]--;
1384*817466cbSJens Wiklander 
1385*817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &T1, 0 ) );
1386*817466cbSJens Wiklander             T1.p[0] = ( t < 1 ) ? 0 : Y.p[t - 1];
1387*817466cbSJens Wiklander             T1.p[1] = Y.p[t];
1388*817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &T1, &T1, Z.p[i - t - 1] ) );
1389*817466cbSJens Wiklander 
1390*817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &T2, 0 ) );
1391*817466cbSJens Wiklander             T2.p[0] = ( i < 2 ) ? 0 : X.p[i - 2];
1392*817466cbSJens Wiklander             T2.p[1] = ( i < 1 ) ? 0 : X.p[i - 1];
1393*817466cbSJens Wiklander             T2.p[2] = X.p[i];
1394*817466cbSJens Wiklander         }
1395*817466cbSJens Wiklander         while( mbedtls_mpi_cmp_mpi( &T1, &T2 ) > 0 );
1396*817466cbSJens Wiklander 
1397*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &T1, &Y, Z.p[i - t - 1] ) );
1398*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &T1,  biL * ( i - t - 1 ) ) );
1399*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &X, &X, &T1 ) );
1400*817466cbSJens Wiklander 
1401*817466cbSJens Wiklander         if( mbedtls_mpi_cmp_int( &X, 0 ) < 0 )
1402*817466cbSJens Wiklander         {
1403*817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &T1, &Y ) );
1404*817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &T1, biL * ( i - t - 1 ) ) );
1405*817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &X, &X, &T1 ) );
1406*817466cbSJens Wiklander             Z.p[i - t - 1]--;
1407*817466cbSJens Wiklander         }
1408*817466cbSJens Wiklander     }
1409*817466cbSJens Wiklander 
1410*817466cbSJens Wiklander     if( Q != NULL )
1411*817466cbSJens Wiklander     {
1412*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( Q, &Z ) );
1413*817466cbSJens Wiklander         Q->s = A->s * B->s;
1414*817466cbSJens Wiklander     }
1415*817466cbSJens Wiklander 
1416*817466cbSJens Wiklander     if( R != NULL )
1417*817466cbSJens Wiklander     {
1418*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &X, k ) );
1419*817466cbSJens Wiklander         X.s = A->s;
1420*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( R, &X ) );
1421*817466cbSJens Wiklander 
1422*817466cbSJens Wiklander         if( mbedtls_mpi_cmp_int( R, 0 ) == 0 )
1423*817466cbSJens Wiklander             R->s = 1;
1424*817466cbSJens Wiklander     }
1425*817466cbSJens Wiklander 
1426*817466cbSJens Wiklander cleanup:
1427*817466cbSJens Wiklander 
1428*817466cbSJens Wiklander     mbedtls_mpi_free( &X ); mbedtls_mpi_free( &Y ); mbedtls_mpi_free( &Z );
1429*817466cbSJens Wiklander     mbedtls_mpi_free( &T1 ); mbedtls_mpi_free( &T2 );
1430*817466cbSJens Wiklander 
1431*817466cbSJens Wiklander     return( ret );
1432*817466cbSJens Wiklander }
1433*817466cbSJens Wiklander 
1434*817466cbSJens Wiklander /*
1435*817466cbSJens Wiklander  * Division by int: A = Q * b + R
1436*817466cbSJens Wiklander  */
1437*817466cbSJens Wiklander int mbedtls_mpi_div_int( mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A, mbedtls_mpi_sint b )
1438*817466cbSJens Wiklander {
1439*817466cbSJens Wiklander     mbedtls_mpi _B;
1440*817466cbSJens Wiklander     mbedtls_mpi_uint p[1];
1441*817466cbSJens Wiklander 
1442*817466cbSJens Wiklander     p[0] = ( b < 0 ) ? -b : b;
1443*817466cbSJens Wiklander     _B.s = ( b < 0 ) ? -1 : 1;
1444*817466cbSJens Wiklander     _B.n = 1;
1445*817466cbSJens Wiklander     _B.p = p;
1446*817466cbSJens Wiklander 
1447*817466cbSJens Wiklander     return( mbedtls_mpi_div_mpi( Q, R, A, &_B ) );
1448*817466cbSJens Wiklander }
1449*817466cbSJens Wiklander 
1450*817466cbSJens Wiklander /*
1451*817466cbSJens Wiklander  * Modulo: R = A mod B
1452*817466cbSJens Wiklander  */
1453*817466cbSJens Wiklander int mbedtls_mpi_mod_mpi( mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B )
1454*817466cbSJens Wiklander {
1455*817466cbSJens Wiklander     int ret;
1456*817466cbSJens Wiklander 
1457*817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( B, 0 ) < 0 )
1458*817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_NEGATIVE_VALUE );
1459*817466cbSJens Wiklander 
1460*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_div_mpi( NULL, R, A, B ) );
1461*817466cbSJens Wiklander 
1462*817466cbSJens Wiklander     while( mbedtls_mpi_cmp_int( R, 0 ) < 0 )
1463*817466cbSJens Wiklander       MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( R, R, B ) );
1464*817466cbSJens Wiklander 
1465*817466cbSJens Wiklander     while( mbedtls_mpi_cmp_mpi( R, B ) >= 0 )
1466*817466cbSJens Wiklander       MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( R, R, B ) );
1467*817466cbSJens Wiklander 
1468*817466cbSJens Wiklander cleanup:
1469*817466cbSJens Wiklander 
1470*817466cbSJens Wiklander     return( ret );
1471*817466cbSJens Wiklander }
1472*817466cbSJens Wiklander 
1473*817466cbSJens Wiklander /*
1474*817466cbSJens Wiklander  * Modulo: r = A mod b
1475*817466cbSJens Wiklander  */
1476*817466cbSJens Wiklander int mbedtls_mpi_mod_int( mbedtls_mpi_uint *r, const mbedtls_mpi *A, mbedtls_mpi_sint b )
1477*817466cbSJens Wiklander {
1478*817466cbSJens Wiklander     size_t i;
1479*817466cbSJens Wiklander     mbedtls_mpi_uint x, y, z;
1480*817466cbSJens Wiklander 
1481*817466cbSJens Wiklander     if( b == 0 )
1482*817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_DIVISION_BY_ZERO );
1483*817466cbSJens Wiklander 
1484*817466cbSJens Wiklander     if( b < 0 )
1485*817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_NEGATIVE_VALUE );
1486*817466cbSJens Wiklander 
1487*817466cbSJens Wiklander     /*
1488*817466cbSJens Wiklander      * handle trivial cases
1489*817466cbSJens Wiklander      */
1490*817466cbSJens Wiklander     if( b == 1 )
1491*817466cbSJens Wiklander     {
1492*817466cbSJens Wiklander         *r = 0;
1493*817466cbSJens Wiklander         return( 0 );
1494*817466cbSJens Wiklander     }
1495*817466cbSJens Wiklander 
1496*817466cbSJens Wiklander     if( b == 2 )
1497*817466cbSJens Wiklander     {
1498*817466cbSJens Wiklander         *r = A->p[0] & 1;
1499*817466cbSJens Wiklander         return( 0 );
1500*817466cbSJens Wiklander     }
1501*817466cbSJens Wiklander 
1502*817466cbSJens Wiklander     /*
1503*817466cbSJens Wiklander      * general case
1504*817466cbSJens Wiklander      */
1505*817466cbSJens Wiklander     for( i = A->n, y = 0; i > 0; i-- )
1506*817466cbSJens Wiklander     {
1507*817466cbSJens Wiklander         x  = A->p[i - 1];
1508*817466cbSJens Wiklander         y  = ( y << biH ) | ( x >> biH );
1509*817466cbSJens Wiklander         z  = y / b;
1510*817466cbSJens Wiklander         y -= z * b;
1511*817466cbSJens Wiklander 
1512*817466cbSJens Wiklander         x <<= biH;
1513*817466cbSJens Wiklander         y  = ( y << biH ) | ( x >> biH );
1514*817466cbSJens Wiklander         z  = y / b;
1515*817466cbSJens Wiklander         y -= z * b;
1516*817466cbSJens Wiklander     }
1517*817466cbSJens Wiklander 
1518*817466cbSJens Wiklander     /*
1519*817466cbSJens Wiklander      * If A is negative, then the current y represents a negative value.
1520*817466cbSJens Wiklander      * Flipping it to the positive side.
1521*817466cbSJens Wiklander      */
1522*817466cbSJens Wiklander     if( A->s < 0 && y != 0 )
1523*817466cbSJens Wiklander         y = b - y;
1524*817466cbSJens Wiklander 
1525*817466cbSJens Wiklander     *r = y;
1526*817466cbSJens Wiklander 
1527*817466cbSJens Wiklander     return( 0 );
1528*817466cbSJens Wiklander }
1529*817466cbSJens Wiklander 
1530*817466cbSJens Wiklander /*
1531*817466cbSJens Wiklander  * Fast Montgomery initialization (thanks to Tom St Denis)
1532*817466cbSJens Wiklander  */
1533*817466cbSJens Wiklander static void mpi_montg_init( mbedtls_mpi_uint *mm, const mbedtls_mpi *N )
1534*817466cbSJens Wiklander {
1535*817466cbSJens Wiklander     mbedtls_mpi_uint x, m0 = N->p[0];
1536*817466cbSJens Wiklander     unsigned int i;
1537*817466cbSJens Wiklander 
1538*817466cbSJens Wiklander     x  = m0;
1539*817466cbSJens Wiklander     x += ( ( m0 + 2 ) & 4 ) << 1;
1540*817466cbSJens Wiklander 
1541*817466cbSJens Wiklander     for( i = biL; i >= 8; i /= 2 )
1542*817466cbSJens Wiklander         x *= ( 2 - ( m0 * x ) );
1543*817466cbSJens Wiklander 
1544*817466cbSJens Wiklander     *mm = ~x + 1;
1545*817466cbSJens Wiklander }
1546*817466cbSJens Wiklander 
1547*817466cbSJens Wiklander /*
1548*817466cbSJens Wiklander  * Montgomery multiplication: A = A * B * R^-1 mod N  (HAC 14.36)
1549*817466cbSJens Wiklander  */
1550*817466cbSJens Wiklander static int mpi_montmul( mbedtls_mpi *A, const mbedtls_mpi *B, const mbedtls_mpi *N, mbedtls_mpi_uint mm,
1551*817466cbSJens Wiklander                          const mbedtls_mpi *T )
1552*817466cbSJens Wiklander {
1553*817466cbSJens Wiklander     size_t i, n, m;
1554*817466cbSJens Wiklander     mbedtls_mpi_uint u0, u1, *d;
1555*817466cbSJens Wiklander 
1556*817466cbSJens Wiklander     if( T->n < N->n + 1 || T->p == NULL )
1557*817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
1558*817466cbSJens Wiklander 
1559*817466cbSJens Wiklander     memset( T->p, 0, T->n * ciL );
1560*817466cbSJens Wiklander 
1561*817466cbSJens Wiklander     d = T->p;
1562*817466cbSJens Wiklander     n = N->n;
1563*817466cbSJens Wiklander     m = ( B->n < n ) ? B->n : n;
1564*817466cbSJens Wiklander 
1565*817466cbSJens Wiklander     for( i = 0; i < n; i++ )
1566*817466cbSJens Wiklander     {
1567*817466cbSJens Wiklander         /*
1568*817466cbSJens Wiklander          * T = (T + u0*B + u1*N) / 2^biL
1569*817466cbSJens Wiklander          */
1570*817466cbSJens Wiklander         u0 = A->p[i];
1571*817466cbSJens Wiklander         u1 = ( d[0] + u0 * B->p[0] ) * mm;
1572*817466cbSJens Wiklander 
1573*817466cbSJens Wiklander         mpi_mul_hlp( m, B->p, d, u0 );
1574*817466cbSJens Wiklander         mpi_mul_hlp( n, N->p, d, u1 );
1575*817466cbSJens Wiklander 
1576*817466cbSJens Wiklander         *d++ = u0; d[n + 1] = 0;
1577*817466cbSJens Wiklander     }
1578*817466cbSJens Wiklander 
1579*817466cbSJens Wiklander     memcpy( A->p, d, ( n + 1 ) * ciL );
1580*817466cbSJens Wiklander 
1581*817466cbSJens Wiklander     if( mbedtls_mpi_cmp_abs( A, N ) >= 0 )
1582*817466cbSJens Wiklander         mpi_sub_hlp( n, N->p, A->p );
1583*817466cbSJens Wiklander     else
1584*817466cbSJens Wiklander         /* prevent timing attacks */
1585*817466cbSJens Wiklander         mpi_sub_hlp( n, A->p, T->p );
1586*817466cbSJens Wiklander 
1587*817466cbSJens Wiklander     return( 0 );
1588*817466cbSJens Wiklander }
1589*817466cbSJens Wiklander 
1590*817466cbSJens Wiklander /*
1591*817466cbSJens Wiklander  * Montgomery reduction: A = A * R^-1 mod N
1592*817466cbSJens Wiklander  */
1593*817466cbSJens Wiklander static int mpi_montred( mbedtls_mpi *A, const mbedtls_mpi *N, mbedtls_mpi_uint mm, const mbedtls_mpi *T )
1594*817466cbSJens Wiklander {
1595*817466cbSJens Wiklander     mbedtls_mpi_uint z = 1;
1596*817466cbSJens Wiklander     mbedtls_mpi U;
1597*817466cbSJens Wiklander 
1598*817466cbSJens Wiklander     U.n = U.s = (int) z;
1599*817466cbSJens Wiklander     U.p = &z;
1600*817466cbSJens Wiklander 
1601*817466cbSJens Wiklander     return( mpi_montmul( A, &U, N, mm, T ) );
1602*817466cbSJens Wiklander }
1603*817466cbSJens Wiklander 
1604*817466cbSJens Wiklander /*
1605*817466cbSJens Wiklander  * Sliding-window exponentiation: X = A^E mod N  (HAC 14.85)
1606*817466cbSJens Wiklander  */
1607*817466cbSJens Wiklander int mbedtls_mpi_exp_mod( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *E, const mbedtls_mpi *N, mbedtls_mpi *_RR )
1608*817466cbSJens Wiklander {
1609*817466cbSJens Wiklander     int ret;
1610*817466cbSJens Wiklander     size_t wbits, wsize, one = 1;
1611*817466cbSJens Wiklander     size_t i, j, nblimbs;
1612*817466cbSJens Wiklander     size_t bufsize, nbits;
1613*817466cbSJens Wiklander     mbedtls_mpi_uint ei, mm, state;
1614*817466cbSJens Wiklander     mbedtls_mpi RR, T, W[ 2 << MBEDTLS_MPI_WINDOW_SIZE ], Apos;
1615*817466cbSJens Wiklander     int neg;
1616*817466cbSJens Wiklander 
1617*817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( N, 0 ) < 0 || ( N->p[0] & 1 ) == 0 )
1618*817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
1619*817466cbSJens Wiklander 
1620*817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( E, 0 ) < 0 )
1621*817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
1622*817466cbSJens Wiklander 
1623*817466cbSJens Wiklander     /*
1624*817466cbSJens Wiklander      * Init temps and window size
1625*817466cbSJens Wiklander      */
1626*817466cbSJens Wiklander     mpi_montg_init( &mm, N );
1627*817466cbSJens Wiklander     mbedtls_mpi_init( &RR ); mbedtls_mpi_init( &T );
1628*817466cbSJens Wiklander     mbedtls_mpi_init( &Apos );
1629*817466cbSJens Wiklander     memset( W, 0, sizeof( W ) );
1630*817466cbSJens Wiklander 
1631*817466cbSJens Wiklander     i = mbedtls_mpi_bitlen( E );
1632*817466cbSJens Wiklander 
1633*817466cbSJens Wiklander     wsize = ( i > 671 ) ? 6 : ( i > 239 ) ? 5 :
1634*817466cbSJens Wiklander             ( i >  79 ) ? 4 : ( i >  23 ) ? 3 : 1;
1635*817466cbSJens Wiklander 
1636*817466cbSJens Wiklander     if( wsize > MBEDTLS_MPI_WINDOW_SIZE )
1637*817466cbSJens Wiklander         wsize = MBEDTLS_MPI_WINDOW_SIZE;
1638*817466cbSJens Wiklander 
1639*817466cbSJens Wiklander     j = N->n + 1;
1640*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, j ) );
1641*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[1],  j ) );
1642*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &T, j * 2 ) );
1643*817466cbSJens Wiklander 
1644*817466cbSJens Wiklander     /*
1645*817466cbSJens Wiklander      * Compensate for negative A (and correct at the end)
1646*817466cbSJens Wiklander      */
1647*817466cbSJens Wiklander     neg = ( A->s == -1 );
1648*817466cbSJens Wiklander     if( neg )
1649*817466cbSJens Wiklander     {
1650*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &Apos, A ) );
1651*817466cbSJens Wiklander         Apos.s = 1;
1652*817466cbSJens Wiklander         A = &Apos;
1653*817466cbSJens Wiklander     }
1654*817466cbSJens Wiklander 
1655*817466cbSJens Wiklander     /*
1656*817466cbSJens Wiklander      * If 1st call, pre-compute R^2 mod N
1657*817466cbSJens Wiklander      */
1658*817466cbSJens Wiklander     if( _RR == NULL || _RR->p == NULL )
1659*817466cbSJens Wiklander     {
1660*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &RR, 1 ) );
1661*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &RR, N->n * 2 * biL ) );
1662*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &RR, &RR, N ) );
1663*817466cbSJens Wiklander 
1664*817466cbSJens Wiklander         if( _RR != NULL )
1665*817466cbSJens Wiklander             memcpy( _RR, &RR, sizeof( mbedtls_mpi ) );
1666*817466cbSJens Wiklander     }
1667*817466cbSJens Wiklander     else
1668*817466cbSJens Wiklander         memcpy( &RR, _RR, sizeof( mbedtls_mpi ) );
1669*817466cbSJens Wiklander 
1670*817466cbSJens Wiklander     /*
1671*817466cbSJens Wiklander      * W[1] = A * R^2 * R^-1 mod N = A * R mod N
1672*817466cbSJens Wiklander      */
1673*817466cbSJens Wiklander     if( mbedtls_mpi_cmp_mpi( A, N ) >= 0 )
1674*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &W[1], A, N ) );
1675*817466cbSJens Wiklander     else
1676*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &W[1], A ) );
1677*817466cbSJens Wiklander 
1678*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mpi_montmul( &W[1], &RR, N, mm, &T ) );
1679*817466cbSJens Wiklander 
1680*817466cbSJens Wiklander     /*
1681*817466cbSJens Wiklander      * X = R^2 * R^-1 mod N = R mod N
1682*817466cbSJens Wiklander      */
1683*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, &RR ) );
1684*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mpi_montred( X, N, mm, &T ) );
1685*817466cbSJens Wiklander 
1686*817466cbSJens Wiklander     if( wsize > 1 )
1687*817466cbSJens Wiklander     {
1688*817466cbSJens Wiklander         /*
1689*817466cbSJens Wiklander          * W[1 << (wsize - 1)] = W[1] ^ (wsize - 1)
1690*817466cbSJens Wiklander          */
1691*817466cbSJens Wiklander         j =  one << ( wsize - 1 );
1692*817466cbSJens Wiklander 
1693*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[j], N->n + 1 ) );
1694*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &W[j], &W[1]    ) );
1695*817466cbSJens Wiklander 
1696*817466cbSJens Wiklander         for( i = 0; i < wsize - 1; i++ )
1697*817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mpi_montmul( &W[j], &W[j], N, mm, &T ) );
1698*817466cbSJens Wiklander 
1699*817466cbSJens Wiklander         /*
1700*817466cbSJens Wiklander          * W[i] = W[i - 1] * W[1]
1701*817466cbSJens Wiklander          */
1702*817466cbSJens Wiklander         for( i = j + 1; i < ( one << wsize ); i++ )
1703*817466cbSJens Wiklander         {
1704*817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[i], N->n + 1 ) );
1705*817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &W[i], &W[i - 1] ) );
1706*817466cbSJens Wiklander 
1707*817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mpi_montmul( &W[i], &W[1], N, mm, &T ) );
1708*817466cbSJens Wiklander         }
1709*817466cbSJens Wiklander     }
1710*817466cbSJens Wiklander 
1711*817466cbSJens Wiklander     nblimbs = E->n;
1712*817466cbSJens Wiklander     bufsize = 0;
1713*817466cbSJens Wiklander     nbits   = 0;
1714*817466cbSJens Wiklander     wbits   = 0;
1715*817466cbSJens Wiklander     state   = 0;
1716*817466cbSJens Wiklander 
1717*817466cbSJens Wiklander     while( 1 )
1718*817466cbSJens Wiklander     {
1719*817466cbSJens Wiklander         if( bufsize == 0 )
1720*817466cbSJens Wiklander         {
1721*817466cbSJens Wiklander             if( nblimbs == 0 )
1722*817466cbSJens Wiklander                 break;
1723*817466cbSJens Wiklander 
1724*817466cbSJens Wiklander             nblimbs--;
1725*817466cbSJens Wiklander 
1726*817466cbSJens Wiklander             bufsize = sizeof( mbedtls_mpi_uint ) << 3;
1727*817466cbSJens Wiklander         }
1728*817466cbSJens Wiklander 
1729*817466cbSJens Wiklander         bufsize--;
1730*817466cbSJens Wiklander 
1731*817466cbSJens Wiklander         ei = (E->p[nblimbs] >> bufsize) & 1;
1732*817466cbSJens Wiklander 
1733*817466cbSJens Wiklander         /*
1734*817466cbSJens Wiklander          * skip leading 0s
1735*817466cbSJens Wiklander          */
1736*817466cbSJens Wiklander         if( ei == 0 && state == 0 )
1737*817466cbSJens Wiklander             continue;
1738*817466cbSJens Wiklander 
1739*817466cbSJens Wiklander         if( ei == 0 && state == 1 )
1740*817466cbSJens Wiklander         {
1741*817466cbSJens Wiklander             /*
1742*817466cbSJens Wiklander              * out of window, square X
1743*817466cbSJens Wiklander              */
1744*817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mpi_montmul( X, X, N, mm, &T ) );
1745*817466cbSJens Wiklander             continue;
1746*817466cbSJens Wiklander         }
1747*817466cbSJens Wiklander 
1748*817466cbSJens Wiklander         /*
1749*817466cbSJens Wiklander          * add ei to current window
1750*817466cbSJens Wiklander          */
1751*817466cbSJens Wiklander         state = 2;
1752*817466cbSJens Wiklander 
1753*817466cbSJens Wiklander         nbits++;
1754*817466cbSJens Wiklander         wbits |= ( ei << ( wsize - nbits ) );
1755*817466cbSJens Wiklander 
1756*817466cbSJens Wiklander         if( nbits == wsize )
1757*817466cbSJens Wiklander         {
1758*817466cbSJens Wiklander             /*
1759*817466cbSJens Wiklander              * X = X^wsize R^-1 mod N
1760*817466cbSJens Wiklander              */
1761*817466cbSJens Wiklander             for( i = 0; i < wsize; i++ )
1762*817466cbSJens Wiklander                 MBEDTLS_MPI_CHK( mpi_montmul( X, X, N, mm, &T ) );
1763*817466cbSJens Wiklander 
1764*817466cbSJens Wiklander             /*
1765*817466cbSJens Wiklander              * X = X * W[wbits] R^-1 mod N
1766*817466cbSJens Wiklander              */
1767*817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mpi_montmul( X, &W[wbits], N, mm, &T ) );
1768*817466cbSJens Wiklander 
1769*817466cbSJens Wiklander             state--;
1770*817466cbSJens Wiklander             nbits = 0;
1771*817466cbSJens Wiklander             wbits = 0;
1772*817466cbSJens Wiklander         }
1773*817466cbSJens Wiklander     }
1774*817466cbSJens Wiklander 
1775*817466cbSJens Wiklander     /*
1776*817466cbSJens Wiklander      * process the remaining bits
1777*817466cbSJens Wiklander      */
1778*817466cbSJens Wiklander     for( i = 0; i < nbits; i++ )
1779*817466cbSJens Wiklander     {
1780*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mpi_montmul( X, X, N, mm, &T ) );
1781*817466cbSJens Wiklander 
1782*817466cbSJens Wiklander         wbits <<= 1;
1783*817466cbSJens Wiklander 
1784*817466cbSJens Wiklander         if( ( wbits & ( one << wsize ) ) != 0 )
1785*817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mpi_montmul( X, &W[1], N, mm, &T ) );
1786*817466cbSJens Wiklander     }
1787*817466cbSJens Wiklander 
1788*817466cbSJens Wiklander     /*
1789*817466cbSJens Wiklander      * X = A^E * R * R^-1 mod N = A^E mod N
1790*817466cbSJens Wiklander      */
1791*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mpi_montred( X, N, mm, &T ) );
1792*817466cbSJens Wiklander 
1793*817466cbSJens Wiklander     if( neg && E->n != 0 && ( E->p[0] & 1 ) != 0 )
1794*817466cbSJens Wiklander     {
1795*817466cbSJens Wiklander         X->s = -1;
1796*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( X, N, X ) );
1797*817466cbSJens Wiklander     }
1798*817466cbSJens Wiklander 
1799*817466cbSJens Wiklander cleanup:
1800*817466cbSJens Wiklander 
1801*817466cbSJens Wiklander     for( i = ( one << ( wsize - 1 ) ); i < ( one << wsize ); i++ )
1802*817466cbSJens Wiklander         mbedtls_mpi_free( &W[i] );
1803*817466cbSJens Wiklander 
1804*817466cbSJens Wiklander     mbedtls_mpi_free( &W[1] ); mbedtls_mpi_free( &T ); mbedtls_mpi_free( &Apos );
1805*817466cbSJens Wiklander 
1806*817466cbSJens Wiklander     if( _RR == NULL || _RR->p == NULL )
1807*817466cbSJens Wiklander         mbedtls_mpi_free( &RR );
1808*817466cbSJens Wiklander 
1809*817466cbSJens Wiklander     return( ret );
1810*817466cbSJens Wiklander }
1811*817466cbSJens Wiklander 
1812*817466cbSJens Wiklander /*
1813*817466cbSJens Wiklander  * Greatest common divisor: G = gcd(A, B)  (HAC 14.54)
1814*817466cbSJens Wiklander  */
1815*817466cbSJens Wiklander int mbedtls_mpi_gcd( mbedtls_mpi *G, const mbedtls_mpi *A, const mbedtls_mpi *B )
1816*817466cbSJens Wiklander {
1817*817466cbSJens Wiklander     int ret;
1818*817466cbSJens Wiklander     size_t lz, lzt;
1819*817466cbSJens Wiklander     mbedtls_mpi TG, TA, TB;
1820*817466cbSJens Wiklander 
1821*817466cbSJens Wiklander     mbedtls_mpi_init( &TG ); mbedtls_mpi_init( &TA ); mbedtls_mpi_init( &TB );
1822*817466cbSJens Wiklander 
1823*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TA, A ) );
1824*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, B ) );
1825*817466cbSJens Wiklander 
1826*817466cbSJens Wiklander     lz = mbedtls_mpi_lsb( &TA );
1827*817466cbSJens Wiklander     lzt = mbedtls_mpi_lsb( &TB );
1828*817466cbSJens Wiklander 
1829*817466cbSJens Wiklander     if( lzt < lz )
1830*817466cbSJens Wiklander         lz = lzt;
1831*817466cbSJens Wiklander 
1832*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TA, lz ) );
1833*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TB, lz ) );
1834*817466cbSJens Wiklander 
1835*817466cbSJens Wiklander     TA.s = TB.s = 1;
1836*817466cbSJens Wiklander 
1837*817466cbSJens Wiklander     while( mbedtls_mpi_cmp_int( &TA, 0 ) != 0 )
1838*817466cbSJens Wiklander     {
1839*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TA, mbedtls_mpi_lsb( &TA ) ) );
1840*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TB, mbedtls_mpi_lsb( &TB ) ) );
1841*817466cbSJens Wiklander 
1842*817466cbSJens Wiklander         if( mbedtls_mpi_cmp_mpi( &TA, &TB ) >= 0 )
1843*817466cbSJens Wiklander         {
1844*817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( &TA, &TA, &TB ) );
1845*817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TA, 1 ) );
1846*817466cbSJens Wiklander         }
1847*817466cbSJens Wiklander         else
1848*817466cbSJens Wiklander         {
1849*817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( &TB, &TB, &TA ) );
1850*817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TB, 1 ) );
1851*817466cbSJens Wiklander         }
1852*817466cbSJens Wiklander     }
1853*817466cbSJens Wiklander 
1854*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &TB, lz ) );
1855*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( G, &TB ) );
1856*817466cbSJens Wiklander 
1857*817466cbSJens Wiklander cleanup:
1858*817466cbSJens Wiklander 
1859*817466cbSJens Wiklander     mbedtls_mpi_free( &TG ); mbedtls_mpi_free( &TA ); mbedtls_mpi_free( &TB );
1860*817466cbSJens Wiklander 
1861*817466cbSJens Wiklander     return( ret );
1862*817466cbSJens Wiklander }
1863*817466cbSJens Wiklander 
1864*817466cbSJens Wiklander /*
1865*817466cbSJens Wiklander  * Fill X with size bytes of random.
1866*817466cbSJens Wiklander  *
1867*817466cbSJens Wiklander  * Use a temporary bytes representation to make sure the result is the same
1868*817466cbSJens Wiklander  * regardless of the platform endianness (useful when f_rng is actually
1869*817466cbSJens Wiklander  * deterministic, eg for tests).
1870*817466cbSJens Wiklander  */
1871*817466cbSJens Wiklander int mbedtls_mpi_fill_random( mbedtls_mpi *X, size_t size,
1872*817466cbSJens Wiklander                      int (*f_rng)(void *, unsigned char *, size_t),
1873*817466cbSJens Wiklander                      void *p_rng )
1874*817466cbSJens Wiklander {
1875*817466cbSJens Wiklander     int ret;
1876*817466cbSJens Wiklander     unsigned char buf[MBEDTLS_MPI_MAX_SIZE];
1877*817466cbSJens Wiklander 
1878*817466cbSJens Wiklander     if( size > MBEDTLS_MPI_MAX_SIZE )
1879*817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
1880*817466cbSJens Wiklander 
1881*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( f_rng( p_rng, buf, size ) );
1882*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( X, buf, size ) );
1883*817466cbSJens Wiklander 
1884*817466cbSJens Wiklander cleanup:
1885*817466cbSJens Wiklander     return( ret );
1886*817466cbSJens Wiklander }
1887*817466cbSJens Wiklander 
1888*817466cbSJens Wiklander /*
1889*817466cbSJens Wiklander  * Modular inverse: X = A^-1 mod N  (HAC 14.61 / 14.64)
1890*817466cbSJens Wiklander  */
1891*817466cbSJens Wiklander int mbedtls_mpi_inv_mod( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *N )
1892*817466cbSJens Wiklander {
1893*817466cbSJens Wiklander     int ret;
1894*817466cbSJens Wiklander     mbedtls_mpi G, TA, TU, U1, U2, TB, TV, V1, V2;
1895*817466cbSJens Wiklander 
1896*817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( N, 1 ) <= 0 )
1897*817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
1898*817466cbSJens Wiklander 
1899*817466cbSJens Wiklander     mbedtls_mpi_init( &TA ); mbedtls_mpi_init( &TU ); mbedtls_mpi_init( &U1 ); mbedtls_mpi_init( &U2 );
1900*817466cbSJens Wiklander     mbedtls_mpi_init( &G ); mbedtls_mpi_init( &TB ); mbedtls_mpi_init( &TV );
1901*817466cbSJens Wiklander     mbedtls_mpi_init( &V1 ); mbedtls_mpi_init( &V2 );
1902*817466cbSJens Wiklander 
1903*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &G, A, N ) );
1904*817466cbSJens Wiklander 
1905*817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( &G, 1 ) != 0 )
1906*817466cbSJens Wiklander     {
1907*817466cbSJens Wiklander         ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
1908*817466cbSJens Wiklander         goto cleanup;
1909*817466cbSJens Wiklander     }
1910*817466cbSJens Wiklander 
1911*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &TA, A, N ) );
1912*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TU, &TA ) );
1913*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, N ) );
1914*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TV, N ) );
1915*817466cbSJens Wiklander 
1916*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &U1, 1 ) );
1917*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &U2, 0 ) );
1918*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &V1, 0 ) );
1919*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &V2, 1 ) );
1920*817466cbSJens Wiklander 
1921*817466cbSJens Wiklander     do
1922*817466cbSJens Wiklander     {
1923*817466cbSJens Wiklander         while( ( TU.p[0] & 1 ) == 0 )
1924*817466cbSJens Wiklander         {
1925*817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TU, 1 ) );
1926*817466cbSJens Wiklander 
1927*817466cbSJens Wiklander             if( ( U1.p[0] & 1 ) != 0 || ( U2.p[0] & 1 ) != 0 )
1928*817466cbSJens Wiklander             {
1929*817466cbSJens Wiklander                 MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &U1, &U1, &TB ) );
1930*817466cbSJens Wiklander                 MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &U2, &U2, &TA ) );
1931*817466cbSJens Wiklander             }
1932*817466cbSJens Wiklander 
1933*817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &U1, 1 ) );
1934*817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &U2, 1 ) );
1935*817466cbSJens Wiklander         }
1936*817466cbSJens Wiklander 
1937*817466cbSJens Wiklander         while( ( TV.p[0] & 1 ) == 0 )
1938*817466cbSJens Wiklander         {
1939*817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TV, 1 ) );
1940*817466cbSJens Wiklander 
1941*817466cbSJens Wiklander             if( ( V1.p[0] & 1 ) != 0 || ( V2.p[0] & 1 ) != 0 )
1942*817466cbSJens Wiklander             {
1943*817466cbSJens Wiklander                 MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &V1, &V1, &TB ) );
1944*817466cbSJens Wiklander                 MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &V2, &V2, &TA ) );
1945*817466cbSJens Wiklander             }
1946*817466cbSJens Wiklander 
1947*817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &V1, 1 ) );
1948*817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &V2, 1 ) );
1949*817466cbSJens Wiklander         }
1950*817466cbSJens Wiklander 
1951*817466cbSJens Wiklander         if( mbedtls_mpi_cmp_mpi( &TU, &TV ) >= 0 )
1952*817466cbSJens Wiklander         {
1953*817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &TU, &TU, &TV ) );
1954*817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &U1, &U1, &V1 ) );
1955*817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &U2, &U2, &V2 ) );
1956*817466cbSJens Wiklander         }
1957*817466cbSJens Wiklander         else
1958*817466cbSJens Wiklander         {
1959*817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &TV, &TV, &TU ) );
1960*817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &V1, &V1, &U1 ) );
1961*817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &V2, &V2, &U2 ) );
1962*817466cbSJens Wiklander         }
1963*817466cbSJens Wiklander     }
1964*817466cbSJens Wiklander     while( mbedtls_mpi_cmp_int( &TU, 0 ) != 0 );
1965*817466cbSJens Wiklander 
1966*817466cbSJens Wiklander     while( mbedtls_mpi_cmp_int( &V1, 0 ) < 0 )
1967*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &V1, &V1, N ) );
1968*817466cbSJens Wiklander 
1969*817466cbSJens Wiklander     while( mbedtls_mpi_cmp_mpi( &V1, N ) >= 0 )
1970*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &V1, &V1, N ) );
1971*817466cbSJens Wiklander 
1972*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, &V1 ) );
1973*817466cbSJens Wiklander 
1974*817466cbSJens Wiklander cleanup:
1975*817466cbSJens Wiklander 
1976*817466cbSJens Wiklander     mbedtls_mpi_free( &TA ); mbedtls_mpi_free( &TU ); mbedtls_mpi_free( &U1 ); mbedtls_mpi_free( &U2 );
1977*817466cbSJens Wiklander     mbedtls_mpi_free( &G ); mbedtls_mpi_free( &TB ); mbedtls_mpi_free( &TV );
1978*817466cbSJens Wiklander     mbedtls_mpi_free( &V1 ); mbedtls_mpi_free( &V2 );
1979*817466cbSJens Wiklander 
1980*817466cbSJens Wiklander     return( ret );
1981*817466cbSJens Wiklander }
1982*817466cbSJens Wiklander 
1983*817466cbSJens Wiklander #if defined(MBEDTLS_GENPRIME)
1984*817466cbSJens Wiklander 
1985*817466cbSJens Wiklander static const int small_prime[] =
1986*817466cbSJens Wiklander {
1987*817466cbSJens Wiklander         3,    5,    7,   11,   13,   17,   19,   23,
1988*817466cbSJens Wiklander        29,   31,   37,   41,   43,   47,   53,   59,
1989*817466cbSJens Wiklander        61,   67,   71,   73,   79,   83,   89,   97,
1990*817466cbSJens Wiklander       101,  103,  107,  109,  113,  127,  131,  137,
1991*817466cbSJens Wiklander       139,  149,  151,  157,  163,  167,  173,  179,
1992*817466cbSJens Wiklander       181,  191,  193,  197,  199,  211,  223,  227,
1993*817466cbSJens Wiklander       229,  233,  239,  241,  251,  257,  263,  269,
1994*817466cbSJens Wiklander       271,  277,  281,  283,  293,  307,  311,  313,
1995*817466cbSJens Wiklander       317,  331,  337,  347,  349,  353,  359,  367,
1996*817466cbSJens Wiklander       373,  379,  383,  389,  397,  401,  409,  419,
1997*817466cbSJens Wiklander       421,  431,  433,  439,  443,  449,  457,  461,
1998*817466cbSJens Wiklander       463,  467,  479,  487,  491,  499,  503,  509,
1999*817466cbSJens Wiklander       521,  523,  541,  547,  557,  563,  569,  571,
2000*817466cbSJens Wiklander       577,  587,  593,  599,  601,  607,  613,  617,
2001*817466cbSJens Wiklander       619,  631,  641,  643,  647,  653,  659,  661,
2002*817466cbSJens Wiklander       673,  677,  683,  691,  701,  709,  719,  727,
2003*817466cbSJens Wiklander       733,  739,  743,  751,  757,  761,  769,  773,
2004*817466cbSJens Wiklander       787,  797,  809,  811,  821,  823,  827,  829,
2005*817466cbSJens Wiklander       839,  853,  857,  859,  863,  877,  881,  883,
2006*817466cbSJens Wiklander       887,  907,  911,  919,  929,  937,  941,  947,
2007*817466cbSJens Wiklander       953,  967,  971,  977,  983,  991,  997, -103
2008*817466cbSJens Wiklander };
2009*817466cbSJens Wiklander 
2010*817466cbSJens Wiklander /*
2011*817466cbSJens Wiklander  * Small divisors test (X must be positive)
2012*817466cbSJens Wiklander  *
2013*817466cbSJens Wiklander  * Return values:
2014*817466cbSJens Wiklander  * 0: no small factor (possible prime, more tests needed)
2015*817466cbSJens Wiklander  * 1: certain prime
2016*817466cbSJens Wiklander  * MBEDTLS_ERR_MPI_NOT_ACCEPTABLE: certain non-prime
2017*817466cbSJens Wiklander  * other negative: error
2018*817466cbSJens Wiklander  */
2019*817466cbSJens Wiklander static int mpi_check_small_factors( const mbedtls_mpi *X )
2020*817466cbSJens Wiklander {
2021*817466cbSJens Wiklander     int ret = 0;
2022*817466cbSJens Wiklander     size_t i;
2023*817466cbSJens Wiklander     mbedtls_mpi_uint r;
2024*817466cbSJens Wiklander 
2025*817466cbSJens Wiklander     if( ( X->p[0] & 1 ) == 0 )
2026*817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE );
2027*817466cbSJens Wiklander 
2028*817466cbSJens Wiklander     for( i = 0; small_prime[i] > 0; i++ )
2029*817466cbSJens Wiklander     {
2030*817466cbSJens Wiklander         if( mbedtls_mpi_cmp_int( X, small_prime[i] ) <= 0 )
2031*817466cbSJens Wiklander             return( 1 );
2032*817466cbSJens Wiklander 
2033*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mod_int( &r, X, small_prime[i] ) );
2034*817466cbSJens Wiklander 
2035*817466cbSJens Wiklander         if( r == 0 )
2036*817466cbSJens Wiklander             return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE );
2037*817466cbSJens Wiklander     }
2038*817466cbSJens Wiklander 
2039*817466cbSJens Wiklander cleanup:
2040*817466cbSJens Wiklander     return( ret );
2041*817466cbSJens Wiklander }
2042*817466cbSJens Wiklander 
2043*817466cbSJens Wiklander /*
2044*817466cbSJens Wiklander  * Miller-Rabin pseudo-primality test  (HAC 4.24)
2045*817466cbSJens Wiklander  */
2046*817466cbSJens Wiklander static int mpi_miller_rabin( const mbedtls_mpi *X,
2047*817466cbSJens Wiklander                              int (*f_rng)(void *, unsigned char *, size_t),
2048*817466cbSJens Wiklander                              void *p_rng )
2049*817466cbSJens Wiklander {
2050*817466cbSJens Wiklander     int ret, count;
2051*817466cbSJens Wiklander     size_t i, j, k, n, s;
2052*817466cbSJens Wiklander     mbedtls_mpi W, R, T, A, RR;
2053*817466cbSJens Wiklander 
2054*817466cbSJens Wiklander     mbedtls_mpi_init( &W ); mbedtls_mpi_init( &R ); mbedtls_mpi_init( &T ); mbedtls_mpi_init( &A );
2055*817466cbSJens Wiklander     mbedtls_mpi_init( &RR );
2056*817466cbSJens Wiklander 
2057*817466cbSJens Wiklander     /*
2058*817466cbSJens Wiklander      * W = |X| - 1
2059*817466cbSJens Wiklander      * R = W >> lsb( W )
2060*817466cbSJens Wiklander      */
2061*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &W, X, 1 ) );
2062*817466cbSJens Wiklander     s = mbedtls_mpi_lsb( &W );
2063*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &R, &W ) );
2064*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &R, s ) );
2065*817466cbSJens Wiklander 
2066*817466cbSJens Wiklander     i = mbedtls_mpi_bitlen( X );
2067*817466cbSJens Wiklander     /*
2068*817466cbSJens Wiklander      * HAC, table 4.4
2069*817466cbSJens Wiklander      */
2070*817466cbSJens Wiklander     n = ( ( i >= 1300 ) ?  2 : ( i >=  850 ) ?  3 :
2071*817466cbSJens Wiklander           ( i >=  650 ) ?  4 : ( i >=  350 ) ?  8 :
2072*817466cbSJens Wiklander           ( i >=  250 ) ? 12 : ( i >=  150 ) ? 18 : 27 );
2073*817466cbSJens Wiklander 
2074*817466cbSJens Wiklander     for( i = 0; i < n; i++ )
2075*817466cbSJens Wiklander     {
2076*817466cbSJens Wiklander         /*
2077*817466cbSJens Wiklander          * pick a random A, 1 < A < |X| - 1
2078*817466cbSJens Wiklander          */
2079*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &A, X->n * ciL, f_rng, p_rng ) );
2080*817466cbSJens Wiklander 
2081*817466cbSJens Wiklander         if( mbedtls_mpi_cmp_mpi( &A, &W ) >= 0 )
2082*817466cbSJens Wiklander         {
2083*817466cbSJens Wiklander             j = mbedtls_mpi_bitlen( &A ) - mbedtls_mpi_bitlen( &W );
2084*817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &A, j + 1 ) );
2085*817466cbSJens Wiklander         }
2086*817466cbSJens Wiklander         A.p[0] |= 3;
2087*817466cbSJens Wiklander 
2088*817466cbSJens Wiklander         count = 0;
2089*817466cbSJens Wiklander         do {
2090*817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &A, X->n * ciL, f_rng, p_rng ) );
2091*817466cbSJens Wiklander 
2092*817466cbSJens Wiklander             j = mbedtls_mpi_bitlen( &A );
2093*817466cbSJens Wiklander             k = mbedtls_mpi_bitlen( &W );
2094*817466cbSJens Wiklander             if (j > k) {
2095*817466cbSJens Wiklander                 MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &A, j - k ) );
2096*817466cbSJens Wiklander             }
2097*817466cbSJens Wiklander 
2098*817466cbSJens Wiklander             if (count++ > 30) {
2099*817466cbSJens Wiklander                 return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2100*817466cbSJens Wiklander             }
2101*817466cbSJens Wiklander 
2102*817466cbSJens Wiklander         } while ( mbedtls_mpi_cmp_mpi( &A, &W ) >= 0 ||
2103*817466cbSJens Wiklander                   mbedtls_mpi_cmp_int( &A, 1 )  <= 0    );
2104*817466cbSJens Wiklander 
2105*817466cbSJens Wiklander         /*
2106*817466cbSJens Wiklander          * A = A^R mod |X|
2107*817466cbSJens Wiklander          */
2108*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &A, &A, &R, X, &RR ) );
2109*817466cbSJens Wiklander 
2110*817466cbSJens Wiklander         if( mbedtls_mpi_cmp_mpi( &A, &W ) == 0 ||
2111*817466cbSJens Wiklander             mbedtls_mpi_cmp_int( &A,  1 ) == 0 )
2112*817466cbSJens Wiklander             continue;
2113*817466cbSJens Wiklander 
2114*817466cbSJens Wiklander         j = 1;
2115*817466cbSJens Wiklander         while( j < s && mbedtls_mpi_cmp_mpi( &A, &W ) != 0 )
2116*817466cbSJens Wiklander         {
2117*817466cbSJens Wiklander             /*
2118*817466cbSJens Wiklander              * A = A * A mod |X|
2119*817466cbSJens Wiklander              */
2120*817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T, &A, &A ) );
2121*817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &A, &T, X  ) );
2122*817466cbSJens Wiklander 
2123*817466cbSJens Wiklander             if( mbedtls_mpi_cmp_int( &A, 1 ) == 0 )
2124*817466cbSJens Wiklander                 break;
2125*817466cbSJens Wiklander 
2126*817466cbSJens Wiklander             j++;
2127*817466cbSJens Wiklander         }
2128*817466cbSJens Wiklander 
2129*817466cbSJens Wiklander         /*
2130*817466cbSJens Wiklander          * not prime if A != |X| - 1 or A == 1
2131*817466cbSJens Wiklander          */
2132*817466cbSJens Wiklander         if( mbedtls_mpi_cmp_mpi( &A, &W ) != 0 ||
2133*817466cbSJens Wiklander             mbedtls_mpi_cmp_int( &A,  1 ) == 0 )
2134*817466cbSJens Wiklander         {
2135*817466cbSJens Wiklander             ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2136*817466cbSJens Wiklander             break;
2137*817466cbSJens Wiklander         }
2138*817466cbSJens Wiklander     }
2139*817466cbSJens Wiklander 
2140*817466cbSJens Wiklander cleanup:
2141*817466cbSJens Wiklander     mbedtls_mpi_free( &W ); mbedtls_mpi_free( &R ); mbedtls_mpi_free( &T ); mbedtls_mpi_free( &A );
2142*817466cbSJens Wiklander     mbedtls_mpi_free( &RR );
2143*817466cbSJens Wiklander 
2144*817466cbSJens Wiklander     return( ret );
2145*817466cbSJens Wiklander }
2146*817466cbSJens Wiklander 
2147*817466cbSJens Wiklander /*
2148*817466cbSJens Wiklander  * Pseudo-primality test: small factors, then Miller-Rabin
2149*817466cbSJens Wiklander  */
2150*817466cbSJens Wiklander int mbedtls_mpi_is_prime( const mbedtls_mpi *X,
2151*817466cbSJens Wiklander                   int (*f_rng)(void *, unsigned char *, size_t),
2152*817466cbSJens Wiklander                   void *p_rng )
2153*817466cbSJens Wiklander {
2154*817466cbSJens Wiklander     int ret;
2155*817466cbSJens Wiklander     mbedtls_mpi XX;
2156*817466cbSJens Wiklander 
2157*817466cbSJens Wiklander     XX.s = 1;
2158*817466cbSJens Wiklander     XX.n = X->n;
2159*817466cbSJens Wiklander     XX.p = X->p;
2160*817466cbSJens Wiklander 
2161*817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( &XX, 0 ) == 0 ||
2162*817466cbSJens Wiklander         mbedtls_mpi_cmp_int( &XX, 1 ) == 0 )
2163*817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE );
2164*817466cbSJens Wiklander 
2165*817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( &XX, 2 ) == 0 )
2166*817466cbSJens Wiklander         return( 0 );
2167*817466cbSJens Wiklander 
2168*817466cbSJens Wiklander     if( ( ret = mpi_check_small_factors( &XX ) ) != 0 )
2169*817466cbSJens Wiklander     {
2170*817466cbSJens Wiklander         if( ret == 1 )
2171*817466cbSJens Wiklander             return( 0 );
2172*817466cbSJens Wiklander 
2173*817466cbSJens Wiklander         return( ret );
2174*817466cbSJens Wiklander     }
2175*817466cbSJens Wiklander 
2176*817466cbSJens Wiklander     return( mpi_miller_rabin( &XX, f_rng, p_rng ) );
2177*817466cbSJens Wiklander }
2178*817466cbSJens Wiklander 
2179*817466cbSJens Wiklander /*
2180*817466cbSJens Wiklander  * Prime number generation
2181*817466cbSJens Wiklander  */
2182*817466cbSJens Wiklander int mbedtls_mpi_gen_prime( mbedtls_mpi *X, size_t nbits, int dh_flag,
2183*817466cbSJens Wiklander                    int (*f_rng)(void *, unsigned char *, size_t),
2184*817466cbSJens Wiklander                    void *p_rng )
2185*817466cbSJens Wiklander {
2186*817466cbSJens Wiklander     int ret;
2187*817466cbSJens Wiklander     size_t k, n;
2188*817466cbSJens Wiklander     mbedtls_mpi_uint r;
2189*817466cbSJens Wiklander     mbedtls_mpi Y;
2190*817466cbSJens Wiklander 
2191*817466cbSJens Wiklander     if( nbits < 3 || nbits > MBEDTLS_MPI_MAX_BITS )
2192*817466cbSJens Wiklander         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
2193*817466cbSJens Wiklander 
2194*817466cbSJens Wiklander     mbedtls_mpi_init( &Y );
2195*817466cbSJens Wiklander 
2196*817466cbSJens Wiklander     n = BITS_TO_LIMBS( nbits );
2197*817466cbSJens Wiklander 
2198*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( X, n * ciL, f_rng, p_rng ) );
2199*817466cbSJens Wiklander 
2200*817466cbSJens Wiklander     k = mbedtls_mpi_bitlen( X );
2201*817466cbSJens Wiklander     if( k > nbits ) MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( X, k - nbits + 1 ) );
2202*817466cbSJens Wiklander 
2203*817466cbSJens Wiklander     mbedtls_mpi_set_bit( X, nbits-1, 1 );
2204*817466cbSJens Wiklander 
2205*817466cbSJens Wiklander     X->p[0] |= 1;
2206*817466cbSJens Wiklander 
2207*817466cbSJens Wiklander     if( dh_flag == 0 )
2208*817466cbSJens Wiklander     {
2209*817466cbSJens Wiklander         while( ( ret = mbedtls_mpi_is_prime( X, f_rng, p_rng ) ) != 0 )
2210*817466cbSJens Wiklander         {
2211*817466cbSJens Wiklander             if( ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE )
2212*817466cbSJens Wiklander                 goto cleanup;
2213*817466cbSJens Wiklander 
2214*817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, X, 2 ) );
2215*817466cbSJens Wiklander         }
2216*817466cbSJens Wiklander     }
2217*817466cbSJens Wiklander     else
2218*817466cbSJens Wiklander     {
2219*817466cbSJens Wiklander         /*
2220*817466cbSJens Wiklander          * An necessary condition for Y and X = 2Y + 1 to be prime
2221*817466cbSJens Wiklander          * is X = 2 mod 3 (which is equivalent to Y = 2 mod 3).
2222*817466cbSJens Wiklander          * Make sure it is satisfied, while keeping X = 3 mod 4
2223*817466cbSJens Wiklander          */
2224*817466cbSJens Wiklander 
2225*817466cbSJens Wiklander         X->p[0] |= 2;
2226*817466cbSJens Wiklander 
2227*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mod_int( &r, X, 3 ) );
2228*817466cbSJens Wiklander         if( r == 0 )
2229*817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, X, 8 ) );
2230*817466cbSJens Wiklander         else if( r == 1 )
2231*817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, X, 4 ) );
2232*817466cbSJens Wiklander 
2233*817466cbSJens Wiklander         /* Set Y = (X-1) / 2, which is X / 2 because X is odd */
2234*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &Y, X ) );
2235*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &Y, 1 ) );
2236*817466cbSJens Wiklander 
2237*817466cbSJens Wiklander         while( 1 )
2238*817466cbSJens Wiklander         {
2239*817466cbSJens Wiklander             /*
2240*817466cbSJens Wiklander              * First, check small factors for X and Y
2241*817466cbSJens Wiklander              * before doing Miller-Rabin on any of them
2242*817466cbSJens Wiklander              */
2243*817466cbSJens Wiklander             if( ( ret = mpi_check_small_factors(  X         ) ) == 0 &&
2244*817466cbSJens Wiklander                 ( ret = mpi_check_small_factors( &Y         ) ) == 0 &&
2245*817466cbSJens Wiklander                 ( ret = mpi_miller_rabin(  X, f_rng, p_rng  ) ) == 0 &&
2246*817466cbSJens Wiklander                 ( ret = mpi_miller_rabin( &Y, f_rng, p_rng  ) ) == 0 )
2247*817466cbSJens Wiklander             {
2248*817466cbSJens Wiklander                 break;
2249*817466cbSJens Wiklander             }
2250*817466cbSJens Wiklander 
2251*817466cbSJens Wiklander             if( ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE )
2252*817466cbSJens Wiklander                 goto cleanup;
2253*817466cbSJens Wiklander 
2254*817466cbSJens Wiklander             /*
2255*817466cbSJens Wiklander              * Next candidates. We want to preserve Y = (X-1) / 2 and
2256*817466cbSJens Wiklander              * Y = 1 mod 2 and Y = 2 mod 3 (eq X = 3 mod 4 and X = 2 mod 3)
2257*817466cbSJens Wiklander              * so up Y by 6 and X by 12.
2258*817466cbSJens Wiklander              */
2259*817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_add_int(  X,  X, 12 ) );
2260*817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( &Y, &Y, 6  ) );
2261*817466cbSJens Wiklander         }
2262*817466cbSJens Wiklander     }
2263*817466cbSJens Wiklander 
2264*817466cbSJens Wiklander cleanup:
2265*817466cbSJens Wiklander 
2266*817466cbSJens Wiklander     mbedtls_mpi_free( &Y );
2267*817466cbSJens Wiklander 
2268*817466cbSJens Wiklander     return( ret );
2269*817466cbSJens Wiklander }
2270*817466cbSJens Wiklander 
2271*817466cbSJens Wiklander #endif /* MBEDTLS_GENPRIME */
2272*817466cbSJens Wiklander 
2273*817466cbSJens Wiklander #if defined(MBEDTLS_SELF_TEST)
2274*817466cbSJens Wiklander 
2275*817466cbSJens Wiklander #define GCD_PAIR_COUNT  3
2276*817466cbSJens Wiklander 
2277*817466cbSJens Wiklander static const int gcd_pairs[GCD_PAIR_COUNT][3] =
2278*817466cbSJens Wiklander {
2279*817466cbSJens Wiklander     { 693, 609, 21 },
2280*817466cbSJens Wiklander     { 1764, 868, 28 },
2281*817466cbSJens Wiklander     { 768454923, 542167814, 1 }
2282*817466cbSJens Wiklander };
2283*817466cbSJens Wiklander 
2284*817466cbSJens Wiklander /*
2285*817466cbSJens Wiklander  * Checkup routine
2286*817466cbSJens Wiklander  */
2287*817466cbSJens Wiklander int mbedtls_mpi_self_test( int verbose )
2288*817466cbSJens Wiklander {
2289*817466cbSJens Wiklander     int ret, i;
2290*817466cbSJens Wiklander     mbedtls_mpi A, E, N, X, Y, U, V;
2291*817466cbSJens Wiklander 
2292*817466cbSJens Wiklander     mbedtls_mpi_init( &A ); mbedtls_mpi_init( &E ); mbedtls_mpi_init( &N ); mbedtls_mpi_init( &X );
2293*817466cbSJens Wiklander     mbedtls_mpi_init( &Y ); mbedtls_mpi_init( &U ); mbedtls_mpi_init( &V );
2294*817466cbSJens Wiklander 
2295*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &A, 16,
2296*817466cbSJens Wiklander         "EFE021C2645FD1DC586E69184AF4A31E" \
2297*817466cbSJens Wiklander         "D5F53E93B5F123FA41680867BA110131" \
2298*817466cbSJens Wiklander         "944FE7952E2517337780CB0DB80E61AA" \
2299*817466cbSJens Wiklander         "E7C8DDC6C5C6AADEB34EB38A2F40D5E6" ) );
2300*817466cbSJens Wiklander 
2301*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &E, 16,
2302*817466cbSJens Wiklander         "B2E7EFD37075B9F03FF989C7C5051C20" \
2303*817466cbSJens Wiklander         "34D2A323810251127E7BF8625A4F49A5" \
2304*817466cbSJens Wiklander         "F3E27F4DA8BD59C47D6DAABA4C8127BD" \
2305*817466cbSJens Wiklander         "5B5C25763222FEFCCFC38B832366C29E" ) );
2306*817466cbSJens Wiklander 
2307*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &N, 16,
2308*817466cbSJens Wiklander         "0066A198186C18C10B2F5ED9B522752A" \
2309*817466cbSJens Wiklander         "9830B69916E535C8F047518A889A43A5" \
2310*817466cbSJens Wiklander         "94B6BED27A168D31D4A52F88925AA8F5" ) );
2311*817466cbSJens Wiklander 
2312*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &X, &A, &N ) );
2313*817466cbSJens Wiklander 
2314*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &U, 16,
2315*817466cbSJens Wiklander         "602AB7ECA597A3D6B56FF9829A5E8B85" \
2316*817466cbSJens Wiklander         "9E857EA95A03512E2BAE7391688D264A" \
2317*817466cbSJens Wiklander         "A5663B0341DB9CCFD2C4C5F421FEC814" \
2318*817466cbSJens Wiklander         "8001B72E848A38CAE1C65F78E56ABDEF" \
2319*817466cbSJens Wiklander         "E12D3C039B8A02D6BE593F0BBBDA56F1" \
2320*817466cbSJens Wiklander         "ECF677152EF804370C1A305CAF3B5BF1" \
2321*817466cbSJens Wiklander         "30879B56C61DE584A0F53A2447A51E" ) );
2322*817466cbSJens Wiklander 
2323*817466cbSJens Wiklander     if( verbose != 0 )
2324*817466cbSJens Wiklander         mbedtls_printf( "  MPI test #1 (mul_mpi): " );
2325*817466cbSJens Wiklander 
2326*817466cbSJens Wiklander     if( mbedtls_mpi_cmp_mpi( &X, &U ) != 0 )
2327*817466cbSJens Wiklander     {
2328*817466cbSJens Wiklander         if( verbose != 0 )
2329*817466cbSJens Wiklander             mbedtls_printf( "failed\n" );
2330*817466cbSJens Wiklander 
2331*817466cbSJens Wiklander         ret = 1;
2332*817466cbSJens Wiklander         goto cleanup;
2333*817466cbSJens Wiklander     }
2334*817466cbSJens Wiklander 
2335*817466cbSJens Wiklander     if( verbose != 0 )
2336*817466cbSJens Wiklander         mbedtls_printf( "passed\n" );
2337*817466cbSJens Wiklander 
2338*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_div_mpi( &X, &Y, &A, &N ) );
2339*817466cbSJens Wiklander 
2340*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &U, 16,
2341*817466cbSJens Wiklander         "256567336059E52CAE22925474705F39A94" ) );
2342*817466cbSJens Wiklander 
2343*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &V, 16,
2344*817466cbSJens Wiklander         "6613F26162223DF488E9CD48CC132C7A" \
2345*817466cbSJens Wiklander         "0AC93C701B001B092E4E5B9F73BCD27B" \
2346*817466cbSJens Wiklander         "9EE50D0657C77F374E903CDFA4C642" ) );
2347*817466cbSJens Wiklander 
2348*817466cbSJens Wiklander     if( verbose != 0 )
2349*817466cbSJens Wiklander         mbedtls_printf( "  MPI test #2 (div_mpi): " );
2350*817466cbSJens Wiklander 
2351*817466cbSJens Wiklander     if( mbedtls_mpi_cmp_mpi( &X, &U ) != 0 ||
2352*817466cbSJens Wiklander         mbedtls_mpi_cmp_mpi( &Y, &V ) != 0 )
2353*817466cbSJens Wiklander     {
2354*817466cbSJens Wiklander         if( verbose != 0 )
2355*817466cbSJens Wiklander             mbedtls_printf( "failed\n" );
2356*817466cbSJens Wiklander 
2357*817466cbSJens Wiklander         ret = 1;
2358*817466cbSJens Wiklander         goto cleanup;
2359*817466cbSJens Wiklander     }
2360*817466cbSJens Wiklander 
2361*817466cbSJens Wiklander     if( verbose != 0 )
2362*817466cbSJens Wiklander         mbedtls_printf( "passed\n" );
2363*817466cbSJens Wiklander 
2364*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &X, &A, &E, &N, NULL ) );
2365*817466cbSJens Wiklander 
2366*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &U, 16,
2367*817466cbSJens Wiklander         "36E139AEA55215609D2816998ED020BB" \
2368*817466cbSJens Wiklander         "BD96C37890F65171D948E9BC7CBAA4D9" \
2369*817466cbSJens Wiklander         "325D24D6A3C12710F10A09FA08AB87" ) );
2370*817466cbSJens Wiklander 
2371*817466cbSJens Wiklander     if( verbose != 0 )
2372*817466cbSJens Wiklander         mbedtls_printf( "  MPI test #3 (exp_mod): " );
2373*817466cbSJens Wiklander 
2374*817466cbSJens Wiklander     if( mbedtls_mpi_cmp_mpi( &X, &U ) != 0 )
2375*817466cbSJens Wiklander     {
2376*817466cbSJens Wiklander         if( verbose != 0 )
2377*817466cbSJens Wiklander             mbedtls_printf( "failed\n" );
2378*817466cbSJens Wiklander 
2379*817466cbSJens Wiklander         ret = 1;
2380*817466cbSJens Wiklander         goto cleanup;
2381*817466cbSJens Wiklander     }
2382*817466cbSJens Wiklander 
2383*817466cbSJens Wiklander     if( verbose != 0 )
2384*817466cbSJens Wiklander         mbedtls_printf( "passed\n" );
2385*817466cbSJens Wiklander 
2386*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &X, &A, &N ) );
2387*817466cbSJens Wiklander 
2388*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &U, 16,
2389*817466cbSJens Wiklander         "003A0AAEDD7E784FC07D8F9EC6E3BFD5" \
2390*817466cbSJens Wiklander         "C3DBA76456363A10869622EAC2DD84EC" \
2391*817466cbSJens Wiklander         "C5B8A74DAC4D09E03B5E0BE779F2DF61" ) );
2392*817466cbSJens Wiklander 
2393*817466cbSJens Wiklander     if( verbose != 0 )
2394*817466cbSJens Wiklander         mbedtls_printf( "  MPI test #4 (inv_mod): " );
2395*817466cbSJens Wiklander 
2396*817466cbSJens Wiklander     if( mbedtls_mpi_cmp_mpi( &X, &U ) != 0 )
2397*817466cbSJens Wiklander     {
2398*817466cbSJens Wiklander         if( verbose != 0 )
2399*817466cbSJens Wiklander             mbedtls_printf( "failed\n" );
2400*817466cbSJens Wiklander 
2401*817466cbSJens Wiklander         ret = 1;
2402*817466cbSJens Wiklander         goto cleanup;
2403*817466cbSJens Wiklander     }
2404*817466cbSJens Wiklander 
2405*817466cbSJens Wiklander     if( verbose != 0 )
2406*817466cbSJens Wiklander         mbedtls_printf( "passed\n" );
2407*817466cbSJens Wiklander 
2408*817466cbSJens Wiklander     if( verbose != 0 )
2409*817466cbSJens Wiklander         mbedtls_printf( "  MPI test #5 (simple gcd): " );
2410*817466cbSJens Wiklander 
2411*817466cbSJens Wiklander     for( i = 0; i < GCD_PAIR_COUNT; i++ )
2412*817466cbSJens Wiklander     {
2413*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &X, gcd_pairs[i][0] ) );
2414*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &Y, gcd_pairs[i][1] ) );
2415*817466cbSJens Wiklander 
2416*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &A, &X, &Y ) );
2417*817466cbSJens Wiklander 
2418*817466cbSJens Wiklander         if( mbedtls_mpi_cmp_int( &A, gcd_pairs[i][2] ) != 0 )
2419*817466cbSJens Wiklander         {
2420*817466cbSJens Wiklander             if( verbose != 0 )
2421*817466cbSJens Wiklander                 mbedtls_printf( "failed at %d\n", i );
2422*817466cbSJens Wiklander 
2423*817466cbSJens Wiklander             ret = 1;
2424*817466cbSJens Wiklander             goto cleanup;
2425*817466cbSJens Wiklander         }
2426*817466cbSJens Wiklander     }
2427*817466cbSJens Wiklander 
2428*817466cbSJens Wiklander     if( verbose != 0 )
2429*817466cbSJens Wiklander         mbedtls_printf( "passed\n" );
2430*817466cbSJens Wiklander 
2431*817466cbSJens Wiklander cleanup:
2432*817466cbSJens Wiklander 
2433*817466cbSJens Wiklander     if( ret != 0 && verbose != 0 )
2434*817466cbSJens Wiklander         mbedtls_printf( "Unexpected error, return code = %08X\n", ret );
2435*817466cbSJens Wiklander 
2436*817466cbSJens Wiklander     mbedtls_mpi_free( &A ); mbedtls_mpi_free( &E ); mbedtls_mpi_free( &N ); mbedtls_mpi_free( &X );
2437*817466cbSJens Wiklander     mbedtls_mpi_free( &Y ); mbedtls_mpi_free( &U ); mbedtls_mpi_free( &V );
2438*817466cbSJens Wiklander 
2439*817466cbSJens Wiklander     if( verbose != 0 )
2440*817466cbSJens Wiklander         mbedtls_printf( "\n" );
2441*817466cbSJens Wiklander 
2442*817466cbSJens Wiklander     return( ret );
2443*817466cbSJens Wiklander }
2444*817466cbSJens Wiklander 
2445*817466cbSJens Wiklander #endif /* MBEDTLS_SELF_TEST */
2446*817466cbSJens Wiklander 
2447*817466cbSJens Wiklander #endif /* MBEDTLS_BIGNUM_C */
2448