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