blob: 4b291d75abac379a552e80bc139b80edf147cb87 [file] [log] [blame]
Paul Bakker5121ce52009-01-03 21:22:43 +00001/*
2 * Multi-precision integer library
3 *
Manuel Pégourié-Gonnard6fb81872015-07-27 11:11:48 +02004 * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
Manuel Pégourié-Gonnard37ff1402015-09-04 14:21:07 +02005 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License"); you may
8 * not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
Paul Bakkerb96f1542010-07-18 20:36:00 +000018 *
Manuel Pégourié-Gonnardfe446432015-03-06 13:17:10 +000019 * This file is part of mbed TLS (https://tls.mbed.org)
Paul Bakker5121ce52009-01-03 21:22:43 +000020 */
21/*
22 * This MPI implementation is based on:
23 *
24 * http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020025 * http://www.stillhq.com/extracted/gnupg-api/mbedtls_mpi/
Paul Bakker5121ce52009-01-03 21:22:43 +000026 * http://math.libtomcrypt.com/files/tommath.pdf
27 */
28
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020029#if !defined(MBEDTLS_CONFIG_FILE)
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000030#include "mbedtls/config.h"
Manuel Pégourié-Gonnardcef4ad22014-04-29 12:39:06 +020031#else
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020032#include MBEDTLS_CONFIG_FILE
Manuel Pégourié-Gonnardcef4ad22014-04-29 12:39:06 +020033#endif
Paul Bakker5121ce52009-01-03 21:22:43 +000034
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020035#if defined(MBEDTLS_BIGNUM_C)
Paul Bakker5121ce52009-01-03 21:22:43 +000036
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000037#include "mbedtls/bignum.h"
38#include "mbedtls/bn_mul.h"
Paul Bakker5121ce52009-01-03 21:22:43 +000039
Rich Evans00ab4702015-02-06 13:43:58 +000040#include <string.h>
41
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020042#if defined(MBEDTLS_PLATFORM_C)
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000043#include "mbedtls/platform.h"
Paul Bakker6e339b52013-07-03 13:37:05 +020044#else
Rich Evans00ab4702015-02-06 13:43:58 +000045#include <stdio.h>
46#include <stdlib.h>
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020047#define mbedtls_printf printf
Manuel Pégourié-Gonnard7551cb92015-05-26 16:04:06 +020048#define mbedtls_calloc calloc
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020049#define mbedtls_free free
Paul Bakker6e339b52013-07-03 13:37:05 +020050#endif
51
Paul Bakker34617722014-06-13 17:20:13 +020052/* Implementation that should never be optimized out by the compiler */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020053static void mbedtls_zeroize( void *v, size_t n ) {
Paul Bakker34617722014-06-13 17:20:13 +020054 volatile unsigned char *p = v; while( n-- ) *p++ = 0;
55}
56
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020057#define ciL (sizeof(mbedtls_mpi_uint)) /* chars in limb */
Paul Bakker5121ce52009-01-03 21:22:43 +000058#define biL (ciL << 3) /* bits in limb */
59#define biH (ciL << 2) /* half limb size */
60
61/*
62 * Convert between bits/chars and number of limbs
63 */
64#define BITS_TO_LIMBS(i) (((i) + biL - 1) / biL)
65#define CHARS_TO_LIMBS(i) (((i) + ciL - 1) / ciL)
66
67/*
Paul Bakker6c591fa2011-05-05 11:49:20 +000068 * Initialize one MPI
Paul Bakker5121ce52009-01-03 21:22:43 +000069 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020070void mbedtls_mpi_init( mbedtls_mpi *X )
Paul Bakker5121ce52009-01-03 21:22:43 +000071{
Paul Bakker6c591fa2011-05-05 11:49:20 +000072 if( X == NULL )
73 return;
Paul Bakker5121ce52009-01-03 21:22:43 +000074
Paul Bakker6c591fa2011-05-05 11:49:20 +000075 X->s = 1;
76 X->n = 0;
77 X->p = NULL;
Paul Bakker5121ce52009-01-03 21:22:43 +000078}
79
80/*
Paul Bakker6c591fa2011-05-05 11:49:20 +000081 * Unallocate one MPI
Paul Bakker5121ce52009-01-03 21:22:43 +000082 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020083void mbedtls_mpi_free( mbedtls_mpi *X )
Paul Bakker5121ce52009-01-03 21:22:43 +000084{
Paul Bakker6c591fa2011-05-05 11:49:20 +000085 if( X == NULL )
86 return;
Paul Bakker5121ce52009-01-03 21:22:43 +000087
Paul Bakker6c591fa2011-05-05 11:49:20 +000088 if( X->p != NULL )
Paul Bakker5121ce52009-01-03 21:22:43 +000089 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020090 mbedtls_zeroize( X->p, X->n * ciL );
91 mbedtls_free( X->p );
Paul Bakker5121ce52009-01-03 21:22:43 +000092 }
93
Paul Bakker6c591fa2011-05-05 11:49:20 +000094 X->s = 1;
95 X->n = 0;
96 X->p = NULL;
Paul Bakker5121ce52009-01-03 21:22:43 +000097}
98
99/*
100 * Enlarge to the specified number of limbs
101 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200102int mbedtls_mpi_grow( mbedtls_mpi *X, size_t nblimbs )
Paul Bakker5121ce52009-01-03 21:22:43 +0000103{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200104 mbedtls_mpi_uint *p;
Paul Bakker5121ce52009-01-03 21:22:43 +0000105
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200106 if( nblimbs > MBEDTLS_MPI_MAX_LIMBS )
Manuel Pégourié-Gonnard6a8ca332015-05-28 09:33:39 +0200107 return( MBEDTLS_ERR_MPI_ALLOC_FAILED );
Paul Bakkerf9688572011-05-05 10:00:45 +0000108
Paul Bakker5121ce52009-01-03 21:22:43 +0000109 if( X->n < nblimbs )
110 {
Manuel Pégourié-Gonnard7551cb92015-05-26 16:04:06 +0200111 if( ( p = mbedtls_calloc( nblimbs, ciL ) ) == NULL )
Manuel Pégourié-Gonnarda0d3a262014-04-11 15:31:02 +0200112 return( MBEDTLS_ERR_MPI_ALLOC_FAILED ); // LCOV_EXCL_LINE
Paul Bakker5121ce52009-01-03 21:22:43 +0000113
Paul Bakker5121ce52009-01-03 21:22:43 +0000114 if( X->p != NULL )
115 {
116 memcpy( p, X->p, X->n * ciL );
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200117 mbedtls_zeroize( X->p, X->n * ciL );
118 mbedtls_free( X->p );
Paul Bakker5121ce52009-01-03 21:22:43 +0000119 }
120
121 X->n = nblimbs;
122 X->p = p;
123 }
124
125 return( 0 );
126}
127
128/*
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100129 * Resize down as much as possible,
130 * while keeping at least the specified number of limbs
131 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200132int mbedtls_mpi_shrink( mbedtls_mpi *X, size_t nblimbs )
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100133{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200134 mbedtls_mpi_uint *p;
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100135 size_t i;
136
137 /* Actually resize up in this case */
138 if( X->n <= nblimbs )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200139 return( mbedtls_mpi_grow( X, nblimbs ) );
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100140
141 for( i = X->n - 1; i > 0; i-- )
142 if( X->p[i] != 0 )
143 break;
144 i++;
145
146 if( i < nblimbs )
147 i = nblimbs;
148
Manuel Pégourié-Gonnard7551cb92015-05-26 16:04:06 +0200149 if( ( p = mbedtls_calloc( i, ciL ) ) == NULL )
Manuel Pégourié-Gonnarda0d3a262014-04-11 15:31:02 +0200150 return( MBEDTLS_ERR_MPI_ALLOC_FAILED ); // LCOV_EXCL_LINE
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100151
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100152 if( X->p != NULL )
153 {
154 memcpy( p, X->p, i * ciL );
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200155 mbedtls_zeroize( X->p, X->n * ciL );
156 mbedtls_free( X->p );
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100157 }
158
159 X->n = i;
160 X->p = p;
161
162 return( 0 );
163}
164
165/*
Paul Bakker5121ce52009-01-03 21:22:43 +0000166 * Copy the contents of Y into X
167 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200168int mbedtls_mpi_copy( mbedtls_mpi *X, const mbedtls_mpi *Y )
Paul Bakker5121ce52009-01-03 21:22:43 +0000169{
Paul Bakker23986e52011-04-24 08:57:21 +0000170 int ret;
171 size_t i;
Paul Bakker5121ce52009-01-03 21:22:43 +0000172
173 if( X == Y )
174 return( 0 );
175
Manuel Pégourié-Gonnardf4999932013-08-12 17:02:59 +0200176 if( Y->p == NULL )
177 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200178 mbedtls_mpi_free( X );
Manuel Pégourié-Gonnardf4999932013-08-12 17:02:59 +0200179 return( 0 );
180 }
181
Paul Bakker5121ce52009-01-03 21:22:43 +0000182 for( i = Y->n - 1; i > 0; i-- )
183 if( Y->p[i] != 0 )
184 break;
185 i++;
186
187 X->s = Y->s;
188
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200189 MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, i ) );
Paul Bakker5121ce52009-01-03 21:22:43 +0000190
191 memset( X->p, 0, X->n * ciL );
192 memcpy( X->p, Y->p, i * ciL );
193
194cleanup:
195
196 return( ret );
197}
198
199/*
200 * Swap the contents of X and Y
201 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200202void mbedtls_mpi_swap( mbedtls_mpi *X, mbedtls_mpi *Y )
Paul Bakker5121ce52009-01-03 21:22:43 +0000203{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200204 mbedtls_mpi T;
Paul Bakker5121ce52009-01-03 21:22:43 +0000205
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200206 memcpy( &T, X, sizeof( mbedtls_mpi ) );
207 memcpy( X, Y, sizeof( mbedtls_mpi ) );
208 memcpy( Y, &T, sizeof( mbedtls_mpi ) );
Paul Bakker5121ce52009-01-03 21:22:43 +0000209}
210
211/*
Manuel Pégourié-Gonnard71c2c212013-11-21 16:56:39 +0100212 * Conditionally assign X = Y, without leaking information
Manuel Pégourié-Gonnard96c7a922013-11-25 18:28:53 +0100213 * about whether the assignment was made or not.
214 * (Leaking information about the respective sizes of X and Y is ok however.)
Manuel Pégourié-Gonnard71c2c212013-11-21 16:56:39 +0100215 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200216int mbedtls_mpi_safe_cond_assign( mbedtls_mpi *X, const mbedtls_mpi *Y, unsigned char assign )
Manuel Pégourié-Gonnard71c2c212013-11-21 16:56:39 +0100217{
218 int ret = 0;
219 size_t i;
220
Pascal Junodb99183d2015-03-11 16:49:45 +0100221 /* make sure assign is 0 or 1 in a time-constant manner */
222 assign = (assign | (unsigned char)-assign) >> 7;
Manuel Pégourié-Gonnard71c2c212013-11-21 16:56:39 +0100223
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200224 MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, Y->n ) );
Manuel Pégourié-Gonnard71c2c212013-11-21 16:56:39 +0100225
Paul Bakker66d5d072014-06-17 16:39:18 +0200226 X->s = X->s * ( 1 - assign ) + Y->s * assign;
Manuel Pégourié-Gonnarda60fe892013-12-04 21:41:50 +0100227
Manuel Pégourié-Gonnard96c7a922013-11-25 18:28:53 +0100228 for( i = 0; i < Y->n; i++ )
Paul Bakker66d5d072014-06-17 16:39:18 +0200229 X->p[i] = X->p[i] * ( 1 - assign ) + Y->p[i] * assign;
Manuel Pégourié-Gonnarda60fe892013-12-04 21:41:50 +0100230
Manuel Pégourié-Gonnard96c7a922013-11-25 18:28:53 +0100231 for( ; i < X->n; i++ )
Paul Bakker66d5d072014-06-17 16:39:18 +0200232 X->p[i] *= ( 1 - assign );
Manuel Pégourié-Gonnard71c2c212013-11-21 16:56:39 +0100233
234cleanup:
235 return( ret );
236}
237
238/*
Manuel Pégourié-Gonnarda60fe892013-12-04 21:41:50 +0100239 * Conditionally swap X and Y, without leaking information
240 * about whether the swap was made or not.
241 * Here it is not ok to simply swap the pointers, which whould lead to
242 * different memory access patterns when X and Y are used afterwards.
243 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200244int mbedtls_mpi_safe_cond_swap( mbedtls_mpi *X, mbedtls_mpi *Y, unsigned char swap )
Manuel Pégourié-Gonnarda60fe892013-12-04 21:41:50 +0100245{
246 int ret, s;
247 size_t i;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200248 mbedtls_mpi_uint tmp;
Manuel Pégourié-Gonnarda60fe892013-12-04 21:41:50 +0100249
250 if( X == Y )
251 return( 0 );
252
Pascal Junodb99183d2015-03-11 16:49:45 +0100253 /* make sure swap is 0 or 1 in a time-constant manner */
254 swap = (swap | (unsigned char)-swap) >> 7;
Manuel Pégourié-Gonnarda60fe892013-12-04 21:41:50 +0100255
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200256 MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, Y->n ) );
257 MBEDTLS_MPI_CHK( mbedtls_mpi_grow( Y, X->n ) );
Manuel Pégourié-Gonnarda60fe892013-12-04 21:41:50 +0100258
259 s = X->s;
Paul Bakker66d5d072014-06-17 16:39:18 +0200260 X->s = X->s * ( 1 - swap ) + Y->s * swap;
261 Y->s = Y->s * ( 1 - swap ) + s * swap;
Manuel Pégourié-Gonnarda60fe892013-12-04 21:41:50 +0100262
263
264 for( i = 0; i < X->n; i++ )
265 {
266 tmp = X->p[i];
Paul Bakker66d5d072014-06-17 16:39:18 +0200267 X->p[i] = X->p[i] * ( 1 - swap ) + Y->p[i] * swap;
268 Y->p[i] = Y->p[i] * ( 1 - swap ) + tmp * swap;
Manuel Pégourié-Gonnarda60fe892013-12-04 21:41:50 +0100269 }
270
271cleanup:
272 return( ret );
273}
274
275/*
Paul Bakker5121ce52009-01-03 21:22:43 +0000276 * Set value from integer
277 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200278int mbedtls_mpi_lset( mbedtls_mpi *X, mbedtls_mpi_sint z )
Paul Bakker5121ce52009-01-03 21:22:43 +0000279{
280 int ret;
281
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200282 MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, 1 ) );
Paul Bakker5121ce52009-01-03 21:22:43 +0000283 memset( X->p, 0, X->n * ciL );
284
285 X->p[0] = ( z < 0 ) ? -z : z;
286 X->s = ( z < 0 ) ? -1 : 1;
287
288cleanup:
289
290 return( ret );
291}
292
293/*
Paul Bakker2f5947e2011-05-18 15:47:11 +0000294 * Get a specific bit
295 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200296int mbedtls_mpi_get_bit( const mbedtls_mpi *X, size_t pos )
Paul Bakker2f5947e2011-05-18 15:47:11 +0000297{
298 if( X->n * biL <= pos )
299 return( 0 );
300
Paul Bakkerd8bb8262014-06-17 14:06:49 +0200301 return( ( X->p[pos / biL] >> ( pos % biL ) ) & 0x01 );
Paul Bakker2f5947e2011-05-18 15:47:11 +0000302}
303
304/*
305 * Set a bit to a specific value of 0 or 1
306 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200307int mbedtls_mpi_set_bit( mbedtls_mpi *X, size_t pos, unsigned char val )
Paul Bakker2f5947e2011-05-18 15:47:11 +0000308{
309 int ret = 0;
310 size_t off = pos / biL;
311 size_t idx = pos % biL;
312
313 if( val != 0 && val != 1 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200314 return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
Paul Bakker9af723c2014-05-01 13:03:14 +0200315
Paul Bakker2f5947e2011-05-18 15:47:11 +0000316 if( X->n * biL <= pos )
317 {
318 if( val == 0 )
Paul Bakkerd8bb8262014-06-17 14:06:49 +0200319 return( 0 );
Paul Bakker2f5947e2011-05-18 15:47:11 +0000320
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200321 MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, off + 1 ) );
Paul Bakker2f5947e2011-05-18 15:47:11 +0000322 }
323
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200324 X->p[off] &= ~( (mbedtls_mpi_uint) 0x01 << idx );
325 X->p[off] |= (mbedtls_mpi_uint) val << idx;
Paul Bakker2f5947e2011-05-18 15:47:11 +0000326
327cleanup:
Paul Bakker9af723c2014-05-01 13:03:14 +0200328
Paul Bakker2f5947e2011-05-18 15:47:11 +0000329 return( ret );
330}
331
332/*
Manuel Pégourié-Gonnardc0696c22015-06-18 16:47:17 +0200333 * Return the number of less significant zero-bits
Paul Bakker5121ce52009-01-03 21:22:43 +0000334 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200335size_t mbedtls_mpi_lsb( const mbedtls_mpi *X )
Paul Bakker5121ce52009-01-03 21:22:43 +0000336{
Paul Bakker23986e52011-04-24 08:57:21 +0000337 size_t i, j, count = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000338
339 for( i = 0; i < X->n; i++ )
Paul Bakkerf9688572011-05-05 10:00:45 +0000340 for( j = 0; j < biL; j++, count++ )
Paul Bakker5121ce52009-01-03 21:22:43 +0000341 if( ( ( X->p[i] >> j ) & 1 ) != 0 )
342 return( count );
343
344 return( 0 );
345}
346
347/*
Manuel Pégourié-Gonnardc0696c22015-06-18 16:47:17 +0200348 * Return the number of bits
Paul Bakker5121ce52009-01-03 21:22:43 +0000349 */
Manuel Pégourié-Gonnardc0696c22015-06-18 16:47:17 +0200350size_t mbedtls_mpi_bitlen( const mbedtls_mpi *X )
Paul Bakker5121ce52009-01-03 21:22:43 +0000351{
Paul Bakker23986e52011-04-24 08:57:21 +0000352 size_t i, j;
Paul Bakker5121ce52009-01-03 21:22:43 +0000353
Manuel Pégourié-Gonnard770b5e12015-04-29 17:02:01 +0200354 if( X->n == 0 )
355 return( 0 );
356
Paul Bakker5121ce52009-01-03 21:22:43 +0000357 for( i = X->n - 1; i > 0; i-- )
358 if( X->p[i] != 0 )
359 break;
360
Paul Bakker23986e52011-04-24 08:57:21 +0000361 for( j = biL; j > 0; j-- )
362 if( ( ( X->p[i] >> ( j - 1 ) ) & 1 ) != 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000363 break;
364
Paul Bakker23986e52011-04-24 08:57:21 +0000365 return( ( i * biL ) + j );
Paul Bakker5121ce52009-01-03 21:22:43 +0000366}
367
368/*
369 * Return the total size in bytes
370 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200371size_t mbedtls_mpi_size( const mbedtls_mpi *X )
Paul Bakker5121ce52009-01-03 21:22:43 +0000372{
Manuel Pégourié-Gonnardc0696c22015-06-18 16:47:17 +0200373 return( ( mbedtls_mpi_bitlen( X ) + 7 ) >> 3 );
Paul Bakker5121ce52009-01-03 21:22:43 +0000374}
375
376/*
377 * Convert an ASCII character to digit value
378 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200379static int mpi_get_digit( mbedtls_mpi_uint *d, int radix, char c )
Paul Bakker5121ce52009-01-03 21:22:43 +0000380{
381 *d = 255;
382
383 if( c >= 0x30 && c <= 0x39 ) *d = c - 0x30;
384 if( c >= 0x41 && c <= 0x46 ) *d = c - 0x37;
385 if( c >= 0x61 && c <= 0x66 ) *d = c - 0x57;
386
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200387 if( *d >= (mbedtls_mpi_uint) radix )
388 return( MBEDTLS_ERR_MPI_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000389
390 return( 0 );
391}
392
393/*
394 * Import from an ASCII string
395 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200396int mbedtls_mpi_read_string( mbedtls_mpi *X, int radix, const char *s )
Paul Bakker5121ce52009-01-03 21:22:43 +0000397{
Paul Bakker23986e52011-04-24 08:57:21 +0000398 int ret;
399 size_t i, j, slen, n;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200400 mbedtls_mpi_uint d;
401 mbedtls_mpi T;
Paul Bakker5121ce52009-01-03 21:22:43 +0000402
403 if( radix < 2 || radix > 16 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200404 return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
Paul Bakker5121ce52009-01-03 21:22:43 +0000405
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200406 mbedtls_mpi_init( &T );
Paul Bakker5121ce52009-01-03 21:22:43 +0000407
Paul Bakkerff60ee62010-03-16 21:09:09 +0000408 slen = strlen( s );
409
Paul Bakker5121ce52009-01-03 21:22:43 +0000410 if( radix == 16 )
411 {
Paul Bakkerff60ee62010-03-16 21:09:09 +0000412 n = BITS_TO_LIMBS( slen << 2 );
Paul Bakker5121ce52009-01-03 21:22:43 +0000413
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200414 MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, n ) );
415 MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) );
Paul Bakker5121ce52009-01-03 21:22:43 +0000416
Paul Bakker23986e52011-04-24 08:57:21 +0000417 for( i = slen, j = 0; i > 0; i--, j++ )
Paul Bakker5121ce52009-01-03 21:22:43 +0000418 {
Paul Bakker23986e52011-04-24 08:57:21 +0000419 if( i == 1 && s[i - 1] == '-' )
Paul Bakker5121ce52009-01-03 21:22:43 +0000420 {
421 X->s = -1;
422 break;
423 }
424
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200425 MBEDTLS_MPI_CHK( mpi_get_digit( &d, radix, s[i - 1] ) );
Paul Bakker66d5d072014-06-17 16:39:18 +0200426 X->p[j / ( 2 * ciL )] |= d << ( ( j % ( 2 * ciL ) ) << 2 );
Paul Bakker5121ce52009-01-03 21:22:43 +0000427 }
428 }
429 else
430 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200431 MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) );
Paul Bakker5121ce52009-01-03 21:22:43 +0000432
Paul Bakkerff60ee62010-03-16 21:09:09 +0000433 for( i = 0; i < slen; i++ )
Paul Bakker5121ce52009-01-03 21:22:43 +0000434 {
435 if( i == 0 && s[i] == '-' )
436 {
437 X->s = -1;
438 continue;
439 }
440
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200441 MBEDTLS_MPI_CHK( mpi_get_digit( &d, radix, s[i] ) );
442 MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &T, X, radix ) );
Paul Bakker05feca62009-06-20 08:22:43 +0000443
444 if( X->s == 1 )
445 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200446 MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, &T, d ) );
Paul Bakker05feca62009-06-20 08:22:43 +0000447 }
448 else
449 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200450 MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( X, &T, d ) );
Paul Bakker05feca62009-06-20 08:22:43 +0000451 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000452 }
453 }
454
455cleanup:
456
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200457 mbedtls_mpi_free( &T );
Paul Bakker5121ce52009-01-03 21:22:43 +0000458
459 return( ret );
460}
461
462/*
463 * Helper to write the digits high-order first
464 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200465static int mpi_write_hlp( mbedtls_mpi *X, int radix, char **p )
Paul Bakker5121ce52009-01-03 21:22:43 +0000466{
467 int ret;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200468 mbedtls_mpi_uint r;
Paul Bakker5121ce52009-01-03 21:22:43 +0000469
470 if( radix < 2 || radix > 16 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200471 return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
Paul Bakker5121ce52009-01-03 21:22:43 +0000472
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200473 MBEDTLS_MPI_CHK( mbedtls_mpi_mod_int( &r, X, radix ) );
474 MBEDTLS_MPI_CHK( mbedtls_mpi_div_int( X, NULL, X, radix ) );
Paul Bakker5121ce52009-01-03 21:22:43 +0000475
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200476 if( mbedtls_mpi_cmp_int( X, 0 ) != 0 )
477 MBEDTLS_MPI_CHK( mpi_write_hlp( X, radix, p ) );
Paul Bakker5121ce52009-01-03 21:22:43 +0000478
479 if( r < 10 )
480 *(*p)++ = (char)( r + 0x30 );
481 else
482 *(*p)++ = (char)( r + 0x37 );
483
484cleanup:
485
486 return( ret );
487}
488
489/*
490 * Export into an ASCII string
491 */
Manuel Pégourié-Gonnardf79b4252015-06-02 15:41:48 +0100492int mbedtls_mpi_write_string( const mbedtls_mpi *X, int radix,
493 char *buf, size_t buflen, size_t *olen )
Paul Bakker5121ce52009-01-03 21:22:43 +0000494{
Paul Bakker23986e52011-04-24 08:57:21 +0000495 int ret = 0;
496 size_t n;
Paul Bakker5121ce52009-01-03 21:22:43 +0000497 char *p;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200498 mbedtls_mpi T;
Paul Bakker5121ce52009-01-03 21:22:43 +0000499
500 if( radix < 2 || radix > 16 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200501 return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
Paul Bakker5121ce52009-01-03 21:22:43 +0000502
Manuel Pégourié-Gonnardc0696c22015-06-18 16:47:17 +0200503 n = mbedtls_mpi_bitlen( X );
Paul Bakker5121ce52009-01-03 21:22:43 +0000504 if( radix >= 4 ) n >>= 1;
505 if( radix >= 16 ) n >>= 1;
506 n += 3;
507
Manuel Pégourié-Gonnardf79b4252015-06-02 15:41:48 +0100508 if( buflen < n )
Paul Bakker5121ce52009-01-03 21:22:43 +0000509 {
Manuel Pégourié-Gonnardf79b4252015-06-02 15:41:48 +0100510 *olen = n;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200511 return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000512 }
513
Manuel Pégourié-Gonnardf79b4252015-06-02 15:41:48 +0100514 p = buf;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200515 mbedtls_mpi_init( &T );
Paul Bakker5121ce52009-01-03 21:22:43 +0000516
517 if( X->s == -1 )
518 *p++ = '-';
519
520 if( radix == 16 )
521 {
Paul Bakker23986e52011-04-24 08:57:21 +0000522 int c;
523 size_t i, j, k;
Paul Bakker5121ce52009-01-03 21:22:43 +0000524
Paul Bakker23986e52011-04-24 08:57:21 +0000525 for( i = X->n, k = 0; i > 0; i-- )
Paul Bakker5121ce52009-01-03 21:22:43 +0000526 {
Paul Bakker23986e52011-04-24 08:57:21 +0000527 for( j = ciL; j > 0; j-- )
Paul Bakker5121ce52009-01-03 21:22:43 +0000528 {
Paul Bakker23986e52011-04-24 08:57:21 +0000529 c = ( X->p[i - 1] >> ( ( j - 1 ) << 3) ) & 0xFF;
Paul Bakker5121ce52009-01-03 21:22:43 +0000530
Paul Bakker6c343d72014-07-10 14:36:19 +0200531 if( c == 0 && k == 0 && ( i + j ) != 2 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000532 continue;
533
Paul Bakker98fe5ea2012-10-24 11:17:48 +0000534 *(p++) = "0123456789ABCDEF" [c / 16];
Paul Bakkerd2c167e2012-10-30 07:49:19 +0000535 *(p++) = "0123456789ABCDEF" [c % 16];
Paul Bakker5121ce52009-01-03 21:22:43 +0000536 k = 1;
537 }
538 }
539 }
540 else
541 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200542 MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &T, X ) );
Paul Bakkerce40a6d2009-06-23 19:46:08 +0000543
544 if( T.s == -1 )
545 T.s = 1;
546
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200547 MBEDTLS_MPI_CHK( mpi_write_hlp( &T, radix, &p ) );
Paul Bakker5121ce52009-01-03 21:22:43 +0000548 }
549
550 *p++ = '\0';
Manuel Pégourié-Gonnardf79b4252015-06-02 15:41:48 +0100551 *olen = p - buf;
Paul Bakker5121ce52009-01-03 21:22:43 +0000552
553cleanup:
554
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200555 mbedtls_mpi_free( &T );
Paul Bakker5121ce52009-01-03 21:22:43 +0000556
557 return( ret );
558}
559
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200560#if defined(MBEDTLS_FS_IO)
Paul Bakker5121ce52009-01-03 21:22:43 +0000561/*
562 * Read X from an opened file
563 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200564int mbedtls_mpi_read_file( mbedtls_mpi *X, int radix, FILE *fin )
Paul Bakker5121ce52009-01-03 21:22:43 +0000565{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200566 mbedtls_mpi_uint d;
Paul Bakker23986e52011-04-24 08:57:21 +0000567 size_t slen;
Paul Bakker5121ce52009-01-03 21:22:43 +0000568 char *p;
Paul Bakkerfe3256e2011-11-25 12:11:43 +0000569 /*
Paul Bakkercb37aa52011-11-30 16:00:20 +0000570 * Buffer should have space for (short) label and decimal formatted MPI,
571 * newline characters and '\0'
Paul Bakkerfe3256e2011-11-25 12:11:43 +0000572 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200573 char s[ MBEDTLS_MPI_RW_BUFFER_SIZE ];
Paul Bakker5121ce52009-01-03 21:22:43 +0000574
575 memset( s, 0, sizeof( s ) );
576 if( fgets( s, sizeof( s ) - 1, fin ) == NULL )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200577 return( MBEDTLS_ERR_MPI_FILE_IO_ERROR );
Paul Bakker5121ce52009-01-03 21:22:43 +0000578
579 slen = strlen( s );
Paul Bakkercb37aa52011-11-30 16:00:20 +0000580 if( slen == sizeof( s ) - 2 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200581 return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL );
Paul Bakkercb37aa52011-11-30 16:00:20 +0000582
Paul Bakker5121ce52009-01-03 21:22:43 +0000583 if( s[slen - 1] == '\n' ) { slen--; s[slen] = '\0'; }
584 if( s[slen - 1] == '\r' ) { slen--; s[slen] = '\0'; }
585
586 p = s + slen;
587 while( --p >= s )
588 if( mpi_get_digit( &d, radix, *p ) != 0 )
589 break;
590
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200591 return( mbedtls_mpi_read_string( X, radix, p + 1 ) );
Paul Bakker5121ce52009-01-03 21:22:43 +0000592}
593
594/*
595 * Write X into an opened file (or stdout if fout == NULL)
596 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200597int mbedtls_mpi_write_file( const char *p, const mbedtls_mpi *X, int radix, FILE *fout )
Paul Bakker5121ce52009-01-03 21:22:43 +0000598{
Paul Bakker23986e52011-04-24 08:57:21 +0000599 int ret;
600 size_t n, slen, plen;
Paul Bakkerfe3256e2011-11-25 12:11:43 +0000601 /*
Paul Bakker5531c6d2012-09-26 19:20:46 +0000602 * Buffer should have space for (short) label and decimal formatted MPI,
603 * newline characters and '\0'
Paul Bakkerfe3256e2011-11-25 12:11:43 +0000604 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200605 char s[ MBEDTLS_MPI_RW_BUFFER_SIZE ];
Paul Bakker5121ce52009-01-03 21:22:43 +0000606
Manuel Pégourié-Gonnardf79b4252015-06-02 15:41:48 +0100607 memset( s, 0, sizeof( s ) );
Paul Bakker5121ce52009-01-03 21:22:43 +0000608
Manuel Pégourié-Gonnardf79b4252015-06-02 15:41:48 +0100609 MBEDTLS_MPI_CHK( mbedtls_mpi_write_string( X, radix, s, sizeof( s ) - 2, &n ) );
Paul Bakker5121ce52009-01-03 21:22:43 +0000610
611 if( p == NULL ) p = "";
612
613 plen = strlen( p );
614 slen = strlen( s );
615 s[slen++] = '\r';
616 s[slen++] = '\n';
617
618 if( fout != NULL )
619 {
620 if( fwrite( p, 1, plen, fout ) != plen ||
621 fwrite( s, 1, slen, fout ) != slen )
Manuel Pégourié-Gonnarda0d3a262014-04-11 15:31:02 +0200622 return( MBEDTLS_ERR_MPI_FILE_IO_ERROR ); // LCOV_EXCL_LINE
Paul Bakker5121ce52009-01-03 21:22:43 +0000623 }
624 else
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200625 mbedtls_printf( "%s%s", p, s );
Paul Bakker5121ce52009-01-03 21:22:43 +0000626
627cleanup:
628
629 return( ret );
630}
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200631#endif /* MBEDTLS_FS_IO */
Paul Bakker5121ce52009-01-03 21:22:43 +0000632
633/*
634 * Import X from unsigned binary data, big endian
635 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200636int mbedtls_mpi_read_binary( mbedtls_mpi *X, const unsigned char *buf, size_t buflen )
Paul Bakker5121ce52009-01-03 21:22:43 +0000637{
Paul Bakker23986e52011-04-24 08:57:21 +0000638 int ret;
639 size_t i, j, n;
Paul Bakker5121ce52009-01-03 21:22:43 +0000640
641 for( n = 0; n < buflen; n++ )
642 if( buf[n] != 0 )
643 break;
644
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200645 MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, CHARS_TO_LIMBS( buflen - n ) ) );
646 MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) );
Paul Bakker5121ce52009-01-03 21:22:43 +0000647
Paul Bakker23986e52011-04-24 08:57:21 +0000648 for( i = buflen, j = 0; i > n; i--, j++ )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200649 X->p[j / ciL] |= ((mbedtls_mpi_uint) buf[i - 1]) << ((j % ciL) << 3);
Paul Bakker5121ce52009-01-03 21:22:43 +0000650
651cleanup:
652
653 return( ret );
654}
655
656/*
657 * Export X into unsigned binary data, big endian
658 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200659int mbedtls_mpi_write_binary( const mbedtls_mpi *X, unsigned char *buf, size_t buflen )
Paul Bakker5121ce52009-01-03 21:22:43 +0000660{
Paul Bakker23986e52011-04-24 08:57:21 +0000661 size_t i, j, n;
Paul Bakker5121ce52009-01-03 21:22:43 +0000662
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200663 n = mbedtls_mpi_size( X );
Paul Bakker5121ce52009-01-03 21:22:43 +0000664
665 if( buflen < n )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200666 return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000667
668 memset( buf, 0, buflen );
669
670 for( i = buflen - 1, j = 0; n > 0; i--, j++, n-- )
671 buf[i] = (unsigned char)( X->p[j / ciL] >> ((j % ciL) << 3) );
672
673 return( 0 );
674}
675
676/*
677 * Left-shift: X <<= count
678 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200679int mbedtls_mpi_shift_l( mbedtls_mpi *X, size_t count )
Paul Bakker5121ce52009-01-03 21:22:43 +0000680{
Paul Bakker23986e52011-04-24 08:57:21 +0000681 int ret;
682 size_t i, v0, t1;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200683 mbedtls_mpi_uint r0 = 0, r1;
Paul Bakker5121ce52009-01-03 21:22:43 +0000684
685 v0 = count / (biL );
686 t1 = count & (biL - 1);
687
Manuel Pégourié-Gonnardc0696c22015-06-18 16:47:17 +0200688 i = mbedtls_mpi_bitlen( X ) + count;
Paul Bakker5121ce52009-01-03 21:22:43 +0000689
Paul Bakkerf9688572011-05-05 10:00:45 +0000690 if( X->n * biL < i )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200691 MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, BITS_TO_LIMBS( i ) ) );
Paul Bakker5121ce52009-01-03 21:22:43 +0000692
693 ret = 0;
694
695 /*
696 * shift by count / limb_size
697 */
698 if( v0 > 0 )
699 {
Paul Bakker23986e52011-04-24 08:57:21 +0000700 for( i = X->n; i > v0; i-- )
701 X->p[i - 1] = X->p[i - v0 - 1];
Paul Bakker5121ce52009-01-03 21:22:43 +0000702
Paul Bakker23986e52011-04-24 08:57:21 +0000703 for( ; i > 0; i-- )
704 X->p[i - 1] = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000705 }
706
707 /*
708 * shift by count % limb_size
709 */
710 if( t1 > 0 )
711 {
712 for( i = v0; i < X->n; i++ )
713 {
714 r1 = X->p[i] >> (biL - t1);
715 X->p[i] <<= t1;
716 X->p[i] |= r0;
717 r0 = r1;
718 }
719 }
720
721cleanup:
722
723 return( ret );
724}
725
726/*
727 * Right-shift: X >>= count
728 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200729int mbedtls_mpi_shift_r( mbedtls_mpi *X, size_t count )
Paul Bakker5121ce52009-01-03 21:22:43 +0000730{
Paul Bakker23986e52011-04-24 08:57:21 +0000731 size_t i, v0, v1;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200732 mbedtls_mpi_uint r0 = 0, r1;
Paul Bakker5121ce52009-01-03 21:22:43 +0000733
734 v0 = count / biL;
735 v1 = count & (biL - 1);
736
Manuel Pégourié-Gonnarde44ec102012-11-17 12:42:51 +0100737 if( v0 > X->n || ( v0 == X->n && v1 > 0 ) )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200738 return mbedtls_mpi_lset( X, 0 );
Manuel Pégourié-Gonnarde44ec102012-11-17 12:42:51 +0100739
Paul Bakker5121ce52009-01-03 21:22:43 +0000740 /*
741 * shift by count / limb_size
742 */
743 if( v0 > 0 )
744 {
745 for( i = 0; i < X->n - v0; i++ )
746 X->p[i] = X->p[i + v0];
747
748 for( ; i < X->n; i++ )
749 X->p[i] = 0;
750 }
751
752 /*
753 * shift by count % limb_size
754 */
755 if( v1 > 0 )
756 {
Paul Bakker23986e52011-04-24 08:57:21 +0000757 for( i = X->n; i > 0; i-- )
Paul Bakker5121ce52009-01-03 21:22:43 +0000758 {
Paul Bakker23986e52011-04-24 08:57:21 +0000759 r1 = X->p[i - 1] << (biL - v1);
760 X->p[i - 1] >>= v1;
761 X->p[i - 1] |= r0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000762 r0 = r1;
763 }
764 }
765
766 return( 0 );
767}
768
769/*
770 * Compare unsigned values
771 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200772int mbedtls_mpi_cmp_abs( const mbedtls_mpi *X, const mbedtls_mpi *Y )
Paul Bakker5121ce52009-01-03 21:22:43 +0000773{
Paul Bakker23986e52011-04-24 08:57:21 +0000774 size_t i, j;
Paul Bakker5121ce52009-01-03 21:22:43 +0000775
Paul Bakker23986e52011-04-24 08:57:21 +0000776 for( i = X->n; i > 0; i-- )
777 if( X->p[i - 1] != 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000778 break;
779
Paul Bakker23986e52011-04-24 08:57:21 +0000780 for( j = Y->n; j > 0; j-- )
781 if( Y->p[j - 1] != 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000782 break;
783
Paul Bakker23986e52011-04-24 08:57:21 +0000784 if( i == 0 && j == 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000785 return( 0 );
786
787 if( i > j ) return( 1 );
788 if( j > i ) return( -1 );
789
Paul Bakker23986e52011-04-24 08:57:21 +0000790 for( ; i > 0; i-- )
Paul Bakker5121ce52009-01-03 21:22:43 +0000791 {
Paul Bakker23986e52011-04-24 08:57:21 +0000792 if( X->p[i - 1] > Y->p[i - 1] ) return( 1 );
793 if( X->p[i - 1] < Y->p[i - 1] ) return( -1 );
Paul Bakker5121ce52009-01-03 21:22:43 +0000794 }
795
796 return( 0 );
797}
798
799/*
800 * Compare signed values
801 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200802int mbedtls_mpi_cmp_mpi( const mbedtls_mpi *X, const mbedtls_mpi *Y )
Paul Bakker5121ce52009-01-03 21:22:43 +0000803{
Paul Bakker23986e52011-04-24 08:57:21 +0000804 size_t i, j;
Paul Bakker5121ce52009-01-03 21:22:43 +0000805
Paul Bakker23986e52011-04-24 08:57:21 +0000806 for( i = X->n; i > 0; i-- )
807 if( X->p[i - 1] != 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000808 break;
809
Paul Bakker23986e52011-04-24 08:57:21 +0000810 for( j = Y->n; j > 0; j-- )
811 if( Y->p[j - 1] != 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000812 break;
813
Paul Bakker23986e52011-04-24 08:57:21 +0000814 if( i == 0 && j == 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000815 return( 0 );
816
817 if( i > j ) return( X->s );
Paul Bakker0c8f73b2012-03-22 14:08:57 +0000818 if( j > i ) return( -Y->s );
Paul Bakker5121ce52009-01-03 21:22:43 +0000819
820 if( X->s > 0 && Y->s < 0 ) return( 1 );
821 if( Y->s > 0 && X->s < 0 ) return( -1 );
822
Paul Bakker23986e52011-04-24 08:57:21 +0000823 for( ; i > 0; i-- )
Paul Bakker5121ce52009-01-03 21:22:43 +0000824 {
Paul Bakker23986e52011-04-24 08:57:21 +0000825 if( X->p[i - 1] > Y->p[i - 1] ) return( X->s );
826 if( X->p[i - 1] < Y->p[i - 1] ) return( -X->s );
Paul Bakker5121ce52009-01-03 21:22:43 +0000827 }
828
829 return( 0 );
830}
831
832/*
833 * Compare signed values
834 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200835int mbedtls_mpi_cmp_int( const mbedtls_mpi *X, mbedtls_mpi_sint z )
Paul Bakker5121ce52009-01-03 21:22:43 +0000836{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200837 mbedtls_mpi Y;
838 mbedtls_mpi_uint p[1];
Paul Bakker5121ce52009-01-03 21:22:43 +0000839
840 *p = ( z < 0 ) ? -z : z;
841 Y.s = ( z < 0 ) ? -1 : 1;
842 Y.n = 1;
843 Y.p = p;
844
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200845 return( mbedtls_mpi_cmp_mpi( X, &Y ) );
Paul Bakker5121ce52009-01-03 21:22:43 +0000846}
847
848/*
849 * Unsigned addition: X = |A| + |B| (HAC 14.7)
850 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200851int mbedtls_mpi_add_abs( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B )
Paul Bakker5121ce52009-01-03 21:22:43 +0000852{
Paul Bakker23986e52011-04-24 08:57:21 +0000853 int ret;
854 size_t i, j;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200855 mbedtls_mpi_uint *o, *p, c;
Paul Bakker5121ce52009-01-03 21:22:43 +0000856
857 if( X == B )
858 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200859 const mbedtls_mpi *T = A; A = X; B = T;
Paul Bakker5121ce52009-01-03 21:22:43 +0000860 }
861
862 if( X != A )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200863 MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, A ) );
Paul Bakker9af723c2014-05-01 13:03:14 +0200864
Paul Bakkerf7ca7b92009-06-20 10:31:06 +0000865 /*
866 * X should always be positive as a result of unsigned additions.
867 */
868 X->s = 1;
Paul Bakker5121ce52009-01-03 21:22:43 +0000869
Paul Bakker23986e52011-04-24 08:57:21 +0000870 for( j = B->n; j > 0; j-- )
871 if( B->p[j - 1] != 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000872 break;
873
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200874 MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, j ) );
Paul Bakker5121ce52009-01-03 21:22:43 +0000875
876 o = B->p; p = X->p; c = 0;
877
Paul Bakker23986e52011-04-24 08:57:21 +0000878 for( i = 0; i < j; i++, o++, p++ )
Paul Bakker5121ce52009-01-03 21:22:43 +0000879 {
880 *p += c; c = ( *p < c );
881 *p += *o; c += ( *p < *o );
882 }
883
884 while( c != 0 )
885 {
886 if( i >= X->n )
887 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200888 MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, i + 1 ) );
Paul Bakker5121ce52009-01-03 21:22:43 +0000889 p = X->p + i;
890 }
891
Paul Bakker2d319fd2012-09-16 21:34:26 +0000892 *p += c; c = ( *p < c ); i++; p++;
Paul Bakker5121ce52009-01-03 21:22:43 +0000893 }
894
895cleanup:
896
897 return( ret );
898}
899
900/*
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200901 * Helper for mbedtls_mpi subtraction
Paul Bakker5121ce52009-01-03 21:22:43 +0000902 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200903static void mpi_sub_hlp( size_t n, mbedtls_mpi_uint *s, mbedtls_mpi_uint *d )
Paul Bakker5121ce52009-01-03 21:22:43 +0000904{
Paul Bakker23986e52011-04-24 08:57:21 +0000905 size_t i;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200906 mbedtls_mpi_uint c, z;
Paul Bakker5121ce52009-01-03 21:22:43 +0000907
908 for( i = c = 0; i < n; i++, s++, d++ )
909 {
910 z = ( *d < c ); *d -= c;
911 c = ( *d < *s ) + z; *d -= *s;
912 }
913
914 while( c != 0 )
915 {
916 z = ( *d < c ); *d -= c;
917 c = z; i++; d++;
918 }
919}
920
921/*
Paul Bakker60b1d102013-10-29 10:02:51 +0100922 * Unsigned subtraction: X = |A| - |B| (HAC 14.9)
Paul Bakker5121ce52009-01-03 21:22:43 +0000923 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200924int mbedtls_mpi_sub_abs( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B )
Paul Bakker5121ce52009-01-03 21:22:43 +0000925{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200926 mbedtls_mpi TB;
Paul Bakker23986e52011-04-24 08:57:21 +0000927 int ret;
928 size_t n;
Paul Bakker5121ce52009-01-03 21:22:43 +0000929
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200930 if( mbedtls_mpi_cmp_abs( A, B ) < 0 )
931 return( MBEDTLS_ERR_MPI_NEGATIVE_VALUE );
Paul Bakker5121ce52009-01-03 21:22:43 +0000932
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200933 mbedtls_mpi_init( &TB );
Paul Bakker5121ce52009-01-03 21:22:43 +0000934
935 if( X == B )
936 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200937 MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, B ) );
Paul Bakker5121ce52009-01-03 21:22:43 +0000938 B = &TB;
939 }
940
941 if( X != A )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200942 MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, A ) );
Paul Bakker5121ce52009-01-03 21:22:43 +0000943
Paul Bakker1ef7a532009-06-20 10:50:55 +0000944 /*
Paul Bakker60b1d102013-10-29 10:02:51 +0100945 * X should always be positive as a result of unsigned subtractions.
Paul Bakker1ef7a532009-06-20 10:50:55 +0000946 */
947 X->s = 1;
948
Paul Bakker5121ce52009-01-03 21:22:43 +0000949 ret = 0;
950
Paul Bakker23986e52011-04-24 08:57:21 +0000951 for( n = B->n; n > 0; n-- )
952 if( B->p[n - 1] != 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000953 break;
954
Paul Bakker23986e52011-04-24 08:57:21 +0000955 mpi_sub_hlp( n, B->p, X->p );
Paul Bakker5121ce52009-01-03 21:22:43 +0000956
957cleanup:
958
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200959 mbedtls_mpi_free( &TB );
Paul Bakker5121ce52009-01-03 21:22:43 +0000960
961 return( ret );
962}
963
964/*
965 * Signed addition: X = A + B
966 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200967int mbedtls_mpi_add_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B )
Paul Bakker5121ce52009-01-03 21:22:43 +0000968{
969 int ret, s = A->s;
970
971 if( A->s * B->s < 0 )
972 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200973 if( mbedtls_mpi_cmp_abs( A, B ) >= 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000974 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200975 MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, A, B ) );
Paul Bakker5121ce52009-01-03 21:22:43 +0000976 X->s = s;
977 }
978 else
979 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200980 MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, B, A ) );
Paul Bakker5121ce52009-01-03 21:22:43 +0000981 X->s = -s;
982 }
983 }
984 else
985 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200986 MBEDTLS_MPI_CHK( mbedtls_mpi_add_abs( X, A, B ) );
Paul Bakker5121ce52009-01-03 21:22:43 +0000987 X->s = s;
988 }
989
990cleanup:
991
992 return( ret );
993}
994
995/*
Paul Bakker60b1d102013-10-29 10:02:51 +0100996 * Signed subtraction: X = A - B
Paul Bakker5121ce52009-01-03 21:22:43 +0000997 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200998int mbedtls_mpi_sub_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B )
Paul Bakker5121ce52009-01-03 21:22:43 +0000999{
1000 int ret, s = A->s;
1001
1002 if( A->s * B->s > 0 )
1003 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001004 if( mbedtls_mpi_cmp_abs( A, B ) >= 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +00001005 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001006 MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, A, B ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001007 X->s = s;
1008 }
1009 else
1010 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001011 MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, B, A ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001012 X->s = -s;
1013 }
1014 }
1015 else
1016 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001017 MBEDTLS_MPI_CHK( mbedtls_mpi_add_abs( X, A, B ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001018 X->s = s;
1019 }
1020
1021cleanup:
1022
1023 return( ret );
1024}
1025
1026/*
1027 * Signed addition: X = A + b
1028 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001029int mbedtls_mpi_add_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b )
Paul Bakker5121ce52009-01-03 21:22:43 +00001030{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001031 mbedtls_mpi _B;
1032 mbedtls_mpi_uint p[1];
Paul Bakker5121ce52009-01-03 21:22:43 +00001033
1034 p[0] = ( b < 0 ) ? -b : b;
1035 _B.s = ( b < 0 ) ? -1 : 1;
1036 _B.n = 1;
1037 _B.p = p;
1038
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001039 return( mbedtls_mpi_add_mpi( X, A, &_B ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001040}
1041
1042/*
Paul Bakker60b1d102013-10-29 10:02:51 +01001043 * Signed subtraction: X = A - b
Paul Bakker5121ce52009-01-03 21:22:43 +00001044 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001045int mbedtls_mpi_sub_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b )
Paul Bakker5121ce52009-01-03 21:22:43 +00001046{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001047 mbedtls_mpi _B;
1048 mbedtls_mpi_uint p[1];
Paul Bakker5121ce52009-01-03 21:22:43 +00001049
1050 p[0] = ( b < 0 ) ? -b : b;
1051 _B.s = ( b < 0 ) ? -1 : 1;
1052 _B.n = 1;
1053 _B.p = p;
1054
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001055 return( mbedtls_mpi_sub_mpi( X, A, &_B ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001056}
1057
1058/*
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001059 * Helper for mbedtls_mpi multiplication
Paul Bakkerfc4f46f2013-06-24 19:23:56 +02001060 */
1061static
1062#if defined(__APPLE__) && defined(__arm__)
1063/*
1064 * Apple LLVM version 4.2 (clang-425.0.24) (based on LLVM 3.2svn)
1065 * appears to need this to prevent bad ARM code generation at -O3.
1066 */
1067__attribute__ ((noinline))
1068#endif
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001069void mpi_mul_hlp( size_t i, mbedtls_mpi_uint *s, mbedtls_mpi_uint *d, mbedtls_mpi_uint b )
Paul Bakker5121ce52009-01-03 21:22:43 +00001070{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001071 mbedtls_mpi_uint c = 0, t = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +00001072
1073#if defined(MULADDC_HUIT)
1074 for( ; i >= 8; i -= 8 )
1075 {
1076 MULADDC_INIT
1077 MULADDC_HUIT
1078 MULADDC_STOP
1079 }
1080
1081 for( ; i > 0; i-- )
1082 {
1083 MULADDC_INIT
1084 MULADDC_CORE
1085 MULADDC_STOP
1086 }
Paul Bakker9af723c2014-05-01 13:03:14 +02001087#else /* MULADDC_HUIT */
Paul Bakker5121ce52009-01-03 21:22:43 +00001088 for( ; i >= 16; i -= 16 )
1089 {
1090 MULADDC_INIT
1091 MULADDC_CORE MULADDC_CORE
1092 MULADDC_CORE MULADDC_CORE
1093 MULADDC_CORE MULADDC_CORE
1094 MULADDC_CORE MULADDC_CORE
1095
1096 MULADDC_CORE MULADDC_CORE
1097 MULADDC_CORE MULADDC_CORE
1098 MULADDC_CORE MULADDC_CORE
1099 MULADDC_CORE MULADDC_CORE
1100 MULADDC_STOP
1101 }
1102
1103 for( ; i >= 8; i -= 8 )
1104 {
1105 MULADDC_INIT
1106 MULADDC_CORE MULADDC_CORE
1107 MULADDC_CORE MULADDC_CORE
1108
1109 MULADDC_CORE MULADDC_CORE
1110 MULADDC_CORE MULADDC_CORE
1111 MULADDC_STOP
1112 }
1113
1114 for( ; i > 0; i-- )
1115 {
1116 MULADDC_INIT
1117 MULADDC_CORE
1118 MULADDC_STOP
1119 }
Paul Bakker9af723c2014-05-01 13:03:14 +02001120#endif /* MULADDC_HUIT */
Paul Bakker5121ce52009-01-03 21:22:43 +00001121
1122 t++;
1123
1124 do {
1125 *d += c; c = ( *d < c ); d++;
1126 }
1127 while( c != 0 );
1128}
1129
1130/*
1131 * Baseline multiplication: X = A * B (HAC 14.12)
1132 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001133int mbedtls_mpi_mul_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B )
Paul Bakker5121ce52009-01-03 21:22:43 +00001134{
Paul Bakker23986e52011-04-24 08:57:21 +00001135 int ret;
1136 size_t i, j;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001137 mbedtls_mpi TA, TB;
Paul Bakker5121ce52009-01-03 21:22:43 +00001138
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001139 mbedtls_mpi_init( &TA ); mbedtls_mpi_init( &TB );
Paul Bakker5121ce52009-01-03 21:22:43 +00001140
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001141 if( X == A ) { MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TA, A ) ); A = &TA; }
1142 if( X == B ) { MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, B ) ); B = &TB; }
Paul Bakker5121ce52009-01-03 21:22:43 +00001143
Paul Bakker23986e52011-04-24 08:57:21 +00001144 for( i = A->n; i > 0; i-- )
1145 if( A->p[i - 1] != 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +00001146 break;
1147
Paul Bakker23986e52011-04-24 08:57:21 +00001148 for( j = B->n; j > 0; j-- )
1149 if( B->p[j - 1] != 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +00001150 break;
1151
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001152 MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, i + j ) );
1153 MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001154
Paul Bakker23986e52011-04-24 08:57:21 +00001155 for( i++; j > 0; j-- )
1156 mpi_mul_hlp( i - 1, A->p, X->p + j - 1, B->p[j - 1] );
Paul Bakker5121ce52009-01-03 21:22:43 +00001157
1158 X->s = A->s * B->s;
1159
1160cleanup:
1161
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001162 mbedtls_mpi_free( &TB ); mbedtls_mpi_free( &TA );
Paul Bakker5121ce52009-01-03 21:22:43 +00001163
1164 return( ret );
1165}
1166
1167/*
1168 * Baseline multiplication: X = A * b
1169 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001170int mbedtls_mpi_mul_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_uint b )
Paul Bakker5121ce52009-01-03 21:22:43 +00001171{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001172 mbedtls_mpi _B;
1173 mbedtls_mpi_uint p[1];
Paul Bakker5121ce52009-01-03 21:22:43 +00001174
1175 _B.s = 1;
1176 _B.n = 1;
1177 _B.p = p;
1178 p[0] = b;
1179
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001180 return( mbedtls_mpi_mul_mpi( X, A, &_B ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001181}
1182
1183/*
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001184 * Division by mbedtls_mpi: A = Q * B + R (HAC 14.20)
Paul Bakker5121ce52009-01-03 21:22:43 +00001185 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001186int mbedtls_mpi_div_mpi( mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B )
Paul Bakker5121ce52009-01-03 21:22:43 +00001187{
Paul Bakker23986e52011-04-24 08:57:21 +00001188 int ret;
1189 size_t i, n, t, k;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001190 mbedtls_mpi X, Y, Z, T1, T2;
Paul Bakker5121ce52009-01-03 21:22:43 +00001191
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001192 if( mbedtls_mpi_cmp_int( B, 0 ) == 0 )
1193 return( MBEDTLS_ERR_MPI_DIVISION_BY_ZERO );
Paul Bakker5121ce52009-01-03 21:22:43 +00001194
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001195 mbedtls_mpi_init( &X ); mbedtls_mpi_init( &Y ); mbedtls_mpi_init( &Z );
1196 mbedtls_mpi_init( &T1 ); mbedtls_mpi_init( &T2 );
Paul Bakker5121ce52009-01-03 21:22:43 +00001197
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001198 if( mbedtls_mpi_cmp_abs( A, B ) < 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +00001199 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001200 if( Q != NULL ) MBEDTLS_MPI_CHK( mbedtls_mpi_lset( Q, 0 ) );
1201 if( R != NULL ) MBEDTLS_MPI_CHK( mbedtls_mpi_copy( R, A ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001202 return( 0 );
1203 }
1204
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001205 MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &X, A ) );
1206 MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &Y, B ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001207 X.s = Y.s = 1;
1208
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001209 MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &Z, A->n + 2 ) );
1210 MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &Z, 0 ) );
1211 MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &T1, 2 ) );
1212 MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &T2, 3 ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001213
Manuel Pégourié-Gonnardc0696c22015-06-18 16:47:17 +02001214 k = mbedtls_mpi_bitlen( &Y ) % biL;
Paul Bakkerf9688572011-05-05 10:00:45 +00001215 if( k < biL - 1 )
Paul Bakker5121ce52009-01-03 21:22:43 +00001216 {
1217 k = biL - 1 - k;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001218 MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &X, k ) );
1219 MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &Y, k ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001220 }
1221 else k = 0;
1222
1223 n = X.n - 1;
1224 t = Y.n - 1;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001225 MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &Y, biL * ( n - t ) ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001226
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001227 while( mbedtls_mpi_cmp_mpi( &X, &Y ) >= 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +00001228 {
1229 Z.p[n - t]++;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001230 MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &X, &X, &Y ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001231 }
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001232 MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &Y, biL * ( n - t ) ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001233
1234 for( i = n; i > t ; i-- )
1235 {
1236 if( X.p[i] >= Y.p[t] )
1237 Z.p[i - t - 1] = ~0;
1238 else
1239 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001240#if defined(MBEDTLS_HAVE_UDBL)
1241 mbedtls_t_udbl r;
Paul Bakker5121ce52009-01-03 21:22:43 +00001242
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001243 r = (mbedtls_t_udbl) X.p[i] << biL;
1244 r |= (mbedtls_t_udbl) X.p[i - 1];
Paul Bakker5121ce52009-01-03 21:22:43 +00001245 r /= Y.p[t];
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001246 if( r > ( (mbedtls_t_udbl) 1 << biL ) - 1 )
1247 r = ( (mbedtls_t_udbl) 1 << biL ) - 1;
Paul Bakker5121ce52009-01-03 21:22:43 +00001248
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001249 Z.p[i - t - 1] = (mbedtls_mpi_uint) r;
Paul Bakker5121ce52009-01-03 21:22:43 +00001250#else
1251 /*
1252 * __udiv_qrnnd_c, from gmp/longlong.h
1253 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001254 mbedtls_mpi_uint q0, q1, r0, r1;
1255 mbedtls_mpi_uint d0, d1, d, m;
Paul Bakker5121ce52009-01-03 21:22:43 +00001256
1257 d = Y.p[t];
1258 d0 = ( d << biH ) >> biH;
1259 d1 = ( d >> biH );
1260
1261 q1 = X.p[i] / d1;
1262 r1 = X.p[i] - d1 * q1;
1263 r1 <<= biH;
1264 r1 |= ( X.p[i - 1] >> biH );
1265
1266 m = q1 * d0;
1267 if( r1 < m )
1268 {
1269 q1--, r1 += d;
1270 while( r1 >= d && r1 < m )
1271 q1--, r1 += d;
1272 }
1273 r1 -= m;
1274
1275 q0 = r1 / d1;
1276 r0 = r1 - d1 * q0;
1277 r0 <<= biH;
1278 r0 |= ( X.p[i - 1] << biH ) >> biH;
1279
1280 m = q0 * d0;
1281 if( r0 < m )
1282 {
1283 q0--, r0 += d;
1284 while( r0 >= d && r0 < m )
1285 q0--, r0 += d;
1286 }
1287 r0 -= m;
1288
1289 Z.p[i - t - 1] = ( q1 << biH ) | q0;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001290#endif /* MBEDTLS_HAVE_UDBL && !64-bit Apple with Clang 5.0 */
Paul Bakker5121ce52009-01-03 21:22:43 +00001291 }
1292
1293 Z.p[i - t - 1]++;
1294 do
1295 {
1296 Z.p[i - t - 1]--;
1297
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001298 MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &T1, 0 ) );
Paul Bakker66d5d072014-06-17 16:39:18 +02001299 T1.p[0] = ( t < 1 ) ? 0 : Y.p[t - 1];
Paul Bakker5121ce52009-01-03 21:22:43 +00001300 T1.p[1] = Y.p[t];
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001301 MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &T1, &T1, Z.p[i - t - 1] ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001302
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001303 MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &T2, 0 ) );
Paul Bakker66d5d072014-06-17 16:39:18 +02001304 T2.p[0] = ( i < 2 ) ? 0 : X.p[i - 2];
1305 T2.p[1] = ( i < 1 ) ? 0 : X.p[i - 1];
Paul Bakker5121ce52009-01-03 21:22:43 +00001306 T2.p[2] = X.p[i];
1307 }
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001308 while( mbedtls_mpi_cmp_mpi( &T1, &T2 ) > 0 );
Paul Bakker5121ce52009-01-03 21:22:43 +00001309
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001310 MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &T1, &Y, Z.p[i - t - 1] ) );
1311 MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &T1, biL * ( i - t - 1 ) ) );
1312 MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &X, &X, &T1 ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001313
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001314 if( mbedtls_mpi_cmp_int( &X, 0 ) < 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +00001315 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001316 MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &T1, &Y ) );
1317 MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &T1, biL * ( i - t - 1 ) ) );
1318 MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &X, &X, &T1 ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001319 Z.p[i - t - 1]--;
1320 }
1321 }
1322
1323 if( Q != NULL )
1324 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001325 MBEDTLS_MPI_CHK( mbedtls_mpi_copy( Q, &Z ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001326 Q->s = A->s * B->s;
1327 }
1328
1329 if( R != NULL )
1330 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001331 MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &X, k ) );
Paul Bakkerf02c5642012-11-13 10:25:21 +00001332 X.s = A->s;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001333 MBEDTLS_MPI_CHK( mbedtls_mpi_copy( R, &X ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001334
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001335 if( mbedtls_mpi_cmp_int( R, 0 ) == 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +00001336 R->s = 1;
1337 }
1338
1339cleanup:
1340
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001341 mbedtls_mpi_free( &X ); mbedtls_mpi_free( &Y ); mbedtls_mpi_free( &Z );
1342 mbedtls_mpi_free( &T1 ); mbedtls_mpi_free( &T2 );
Paul Bakker5121ce52009-01-03 21:22:43 +00001343
1344 return( ret );
1345}
1346
1347/*
1348 * Division by int: A = Q * b + R
Paul Bakker5121ce52009-01-03 21:22:43 +00001349 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001350int mbedtls_mpi_div_int( mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A, mbedtls_mpi_sint b )
Paul Bakker5121ce52009-01-03 21:22:43 +00001351{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001352 mbedtls_mpi _B;
1353 mbedtls_mpi_uint p[1];
Paul Bakker5121ce52009-01-03 21:22:43 +00001354
1355 p[0] = ( b < 0 ) ? -b : b;
1356 _B.s = ( b < 0 ) ? -1 : 1;
1357 _B.n = 1;
1358 _B.p = p;
1359
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001360 return( mbedtls_mpi_div_mpi( Q, R, A, &_B ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001361}
1362
1363/*
1364 * Modulo: R = A mod B
1365 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001366int mbedtls_mpi_mod_mpi( mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B )
Paul Bakker5121ce52009-01-03 21:22:43 +00001367{
1368 int ret;
1369
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001370 if( mbedtls_mpi_cmp_int( B, 0 ) < 0 )
1371 return( MBEDTLS_ERR_MPI_NEGATIVE_VALUE );
Paul Bakkerce40a6d2009-06-23 19:46:08 +00001372
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001373 MBEDTLS_MPI_CHK( mbedtls_mpi_div_mpi( NULL, R, A, B ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001374
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001375 while( mbedtls_mpi_cmp_int( R, 0 ) < 0 )
1376 MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( R, R, B ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001377
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001378 while( mbedtls_mpi_cmp_mpi( R, B ) >= 0 )
1379 MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( R, R, B ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001380
1381cleanup:
1382
1383 return( ret );
1384}
1385
1386/*
1387 * Modulo: r = A mod b
1388 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001389int mbedtls_mpi_mod_int( mbedtls_mpi_uint *r, const mbedtls_mpi *A, mbedtls_mpi_sint b )
Paul Bakker5121ce52009-01-03 21:22:43 +00001390{
Paul Bakker23986e52011-04-24 08:57:21 +00001391 size_t i;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001392 mbedtls_mpi_uint x, y, z;
Paul Bakker5121ce52009-01-03 21:22:43 +00001393
1394 if( b == 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001395 return( MBEDTLS_ERR_MPI_DIVISION_BY_ZERO );
Paul Bakker5121ce52009-01-03 21:22:43 +00001396
1397 if( b < 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001398 return( MBEDTLS_ERR_MPI_NEGATIVE_VALUE );
Paul Bakker5121ce52009-01-03 21:22:43 +00001399
1400 /*
1401 * handle trivial cases
1402 */
1403 if( b == 1 )
1404 {
1405 *r = 0;
1406 return( 0 );
1407 }
1408
1409 if( b == 2 )
1410 {
1411 *r = A->p[0] & 1;
1412 return( 0 );
1413 }
1414
1415 /*
1416 * general case
1417 */
Paul Bakker23986e52011-04-24 08:57:21 +00001418 for( i = A->n, y = 0; i > 0; i-- )
Paul Bakker5121ce52009-01-03 21:22:43 +00001419 {
Paul Bakker23986e52011-04-24 08:57:21 +00001420 x = A->p[i - 1];
Paul Bakker5121ce52009-01-03 21:22:43 +00001421 y = ( y << biH ) | ( x >> biH );
1422 z = y / b;
1423 y -= z * b;
1424
1425 x <<= biH;
1426 y = ( y << biH ) | ( x >> biH );
1427 z = y / b;
1428 y -= z * b;
1429 }
1430
Paul Bakkerce40a6d2009-06-23 19:46:08 +00001431 /*
1432 * If A is negative, then the current y represents a negative value.
1433 * Flipping it to the positive side.
1434 */
1435 if( A->s < 0 && y != 0 )
1436 y = b - y;
1437
Paul Bakker5121ce52009-01-03 21:22:43 +00001438 *r = y;
1439
1440 return( 0 );
1441}
1442
1443/*
1444 * Fast Montgomery initialization (thanks to Tom St Denis)
1445 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001446static void mpi_montg_init( mbedtls_mpi_uint *mm, const mbedtls_mpi *N )
Paul Bakker5121ce52009-01-03 21:22:43 +00001447{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001448 mbedtls_mpi_uint x, m0 = N->p[0];
Manuel Pégourié-Gonnardfdf3f0e2014-03-11 13:47:05 +01001449 unsigned int i;
Paul Bakker5121ce52009-01-03 21:22:43 +00001450
1451 x = m0;
1452 x += ( ( m0 + 2 ) & 4 ) << 1;
Paul Bakker5121ce52009-01-03 21:22:43 +00001453
Manuel Pégourié-Gonnardfdf3f0e2014-03-11 13:47:05 +01001454 for( i = biL; i >= 8; i /= 2 )
1455 x *= ( 2 - ( m0 * x ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001456
1457 *mm = ~x + 1;
1458}
1459
1460/*
1461 * Montgomery multiplication: A = A * B * R^-1 mod N (HAC 14.36)
1462 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001463static void mpi_montmul( mbedtls_mpi *A, const mbedtls_mpi *B, const mbedtls_mpi *N, mbedtls_mpi_uint mm,
1464 const mbedtls_mpi *T )
Paul Bakker5121ce52009-01-03 21:22:43 +00001465{
Paul Bakker23986e52011-04-24 08:57:21 +00001466 size_t i, n, m;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001467 mbedtls_mpi_uint u0, u1, *d;
Paul Bakker5121ce52009-01-03 21:22:43 +00001468
1469 memset( T->p, 0, T->n * ciL );
1470
1471 d = T->p;
1472 n = N->n;
1473 m = ( B->n < n ) ? B->n : n;
1474
1475 for( i = 0; i < n; i++ )
1476 {
1477 /*
1478 * T = (T + u0*B + u1*N) / 2^biL
1479 */
1480 u0 = A->p[i];
1481 u1 = ( d[0] + u0 * B->p[0] ) * mm;
1482
1483 mpi_mul_hlp( m, B->p, d, u0 );
1484 mpi_mul_hlp( n, N->p, d, u1 );
1485
1486 *d++ = u0; d[n + 1] = 0;
1487 }
1488
Paul Bakker66d5d072014-06-17 16:39:18 +02001489 memcpy( A->p, d, ( n + 1 ) * ciL );
Paul Bakker5121ce52009-01-03 21:22:43 +00001490
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001491 if( mbedtls_mpi_cmp_abs( A, N ) >= 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +00001492 mpi_sub_hlp( n, N->p, A->p );
1493 else
1494 /* prevent timing attacks */
1495 mpi_sub_hlp( n, A->p, T->p );
1496}
1497
1498/*
1499 * Montgomery reduction: A = A * R^-1 mod N
1500 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001501static void mpi_montred( mbedtls_mpi *A, const mbedtls_mpi *N, mbedtls_mpi_uint mm, const mbedtls_mpi *T )
Paul Bakker5121ce52009-01-03 21:22:43 +00001502{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001503 mbedtls_mpi_uint z = 1;
1504 mbedtls_mpi U;
Paul Bakker5121ce52009-01-03 21:22:43 +00001505
Paul Bakker8ddb6452013-02-27 14:56:33 +01001506 U.n = U.s = (int) z;
Paul Bakker5121ce52009-01-03 21:22:43 +00001507 U.p = &z;
1508
1509 mpi_montmul( A, &U, N, mm, T );
1510}
1511
1512/*
1513 * Sliding-window exponentiation: X = A^E mod N (HAC 14.85)
1514 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001515int mbedtls_mpi_exp_mod( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *E, const mbedtls_mpi *N, mbedtls_mpi *_RR )
Paul Bakker5121ce52009-01-03 21:22:43 +00001516{
Paul Bakker23986e52011-04-24 08:57:21 +00001517 int ret;
1518 size_t wbits, wsize, one = 1;
1519 size_t i, j, nblimbs;
1520 size_t bufsize, nbits;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001521 mbedtls_mpi_uint ei, mm, state;
1522 mbedtls_mpi RR, T, W[ 2 << MBEDTLS_MPI_WINDOW_SIZE ], Apos;
Paul Bakkerf6198c12012-05-16 08:02:29 +00001523 int neg;
Paul Bakker5121ce52009-01-03 21:22:43 +00001524
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001525 if( mbedtls_mpi_cmp_int( N, 0 ) < 0 || ( N->p[0] & 1 ) == 0 )
1526 return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
Paul Bakker5121ce52009-01-03 21:22:43 +00001527
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001528 if( mbedtls_mpi_cmp_int( E, 0 ) < 0 )
1529 return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
Paul Bakkerf6198c12012-05-16 08:02:29 +00001530
1531 /*
Paul Bakker5121ce52009-01-03 21:22:43 +00001532 * Init temps and window size
1533 */
1534 mpi_montg_init( &mm, N );
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001535 mbedtls_mpi_init( &RR ); mbedtls_mpi_init( &T );
1536 mbedtls_mpi_init( &Apos );
Paul Bakker5121ce52009-01-03 21:22:43 +00001537 memset( W, 0, sizeof( W ) );
1538
Manuel Pégourié-Gonnardc0696c22015-06-18 16:47:17 +02001539 i = mbedtls_mpi_bitlen( E );
Paul Bakker5121ce52009-01-03 21:22:43 +00001540
1541 wsize = ( i > 671 ) ? 6 : ( i > 239 ) ? 5 :
1542 ( i > 79 ) ? 4 : ( i > 23 ) ? 3 : 1;
1543
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001544 if( wsize > MBEDTLS_MPI_WINDOW_SIZE )
1545 wsize = MBEDTLS_MPI_WINDOW_SIZE;
Paul Bakkerb6d5f082011-11-25 11:52:11 +00001546
Paul Bakker5121ce52009-01-03 21:22:43 +00001547 j = N->n + 1;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001548 MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, j ) );
1549 MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[1], j ) );
1550 MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &T, j * 2 ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001551
1552 /*
Paul Bakker50546922012-05-19 08:40:49 +00001553 * Compensate for negative A (and correct at the end)
1554 */
1555 neg = ( A->s == -1 );
Paul Bakker50546922012-05-19 08:40:49 +00001556 if( neg )
1557 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001558 MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &Apos, A ) );
Paul Bakker50546922012-05-19 08:40:49 +00001559 Apos.s = 1;
1560 A = &Apos;
1561 }
1562
1563 /*
Paul Bakker5121ce52009-01-03 21:22:43 +00001564 * If 1st call, pre-compute R^2 mod N
1565 */
1566 if( _RR == NULL || _RR->p == NULL )
1567 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001568 MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &RR, 1 ) );
1569 MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &RR, N->n * 2 * biL ) );
1570 MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &RR, &RR, N ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001571
1572 if( _RR != NULL )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001573 memcpy( _RR, &RR, sizeof( mbedtls_mpi ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001574 }
1575 else
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001576 memcpy( &RR, _RR, sizeof( mbedtls_mpi ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001577
1578 /*
1579 * W[1] = A * R^2 * R^-1 mod N = A * R mod N
1580 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001581 if( mbedtls_mpi_cmp_mpi( A, N ) >= 0 )
1582 MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &W[1], A, N ) );
Paul Bakkerc2024f42014-01-23 20:38:35 +01001583 else
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001584 MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &W[1], A ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001585
1586 mpi_montmul( &W[1], &RR, N, mm, &T );
1587
1588 /*
1589 * X = R^2 * R^-1 mod N = R mod N
1590 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001591 MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, &RR ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001592 mpi_montred( X, N, mm, &T );
1593
1594 if( wsize > 1 )
1595 {
1596 /*
1597 * W[1 << (wsize - 1)] = W[1] ^ (wsize - 1)
1598 */
Paul Bakker66d5d072014-06-17 16:39:18 +02001599 j = one << ( wsize - 1 );
Paul Bakker5121ce52009-01-03 21:22:43 +00001600
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001601 MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[j], N->n + 1 ) );
1602 MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &W[j], &W[1] ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001603
1604 for( i = 0; i < wsize - 1; i++ )
1605 mpi_montmul( &W[j], &W[j], N, mm, &T );
Paul Bakker0d7702c2013-10-29 16:18:35 +01001606
Paul Bakker5121ce52009-01-03 21:22:43 +00001607 /*
1608 * W[i] = W[i - 1] * W[1]
1609 */
Paul Bakker66d5d072014-06-17 16:39:18 +02001610 for( i = j + 1; i < ( one << wsize ); i++ )
Paul Bakker5121ce52009-01-03 21:22:43 +00001611 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001612 MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[i], N->n + 1 ) );
1613 MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &W[i], &W[i - 1] ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001614
1615 mpi_montmul( &W[i], &W[1], N, mm, &T );
1616 }
1617 }
1618
1619 nblimbs = E->n;
1620 bufsize = 0;
1621 nbits = 0;
1622 wbits = 0;
1623 state = 0;
1624
1625 while( 1 )
1626 {
1627 if( bufsize == 0 )
1628 {
Paul Bakker0d7702c2013-10-29 16:18:35 +01001629 if( nblimbs == 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +00001630 break;
1631
Paul Bakker0d7702c2013-10-29 16:18:35 +01001632 nblimbs--;
1633
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001634 bufsize = sizeof( mbedtls_mpi_uint ) << 3;
Paul Bakker5121ce52009-01-03 21:22:43 +00001635 }
1636
1637 bufsize--;
1638
1639 ei = (E->p[nblimbs] >> bufsize) & 1;
1640
1641 /*
1642 * skip leading 0s
1643 */
1644 if( ei == 0 && state == 0 )
1645 continue;
1646
1647 if( ei == 0 && state == 1 )
1648 {
1649 /*
1650 * out of window, square X
1651 */
1652 mpi_montmul( X, X, N, mm, &T );
1653 continue;
1654 }
1655
1656 /*
1657 * add ei to current window
1658 */
1659 state = 2;
1660
1661 nbits++;
Paul Bakker66d5d072014-06-17 16:39:18 +02001662 wbits |= ( ei << ( wsize - nbits ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001663
1664 if( nbits == wsize )
1665 {
1666 /*
1667 * X = X^wsize R^-1 mod N
1668 */
1669 for( i = 0; i < wsize; i++ )
1670 mpi_montmul( X, X, N, mm, &T );
1671
1672 /*
1673 * X = X * W[wbits] R^-1 mod N
1674 */
1675 mpi_montmul( X, &W[wbits], N, mm, &T );
1676
1677 state--;
1678 nbits = 0;
1679 wbits = 0;
1680 }
1681 }
1682
1683 /*
1684 * process the remaining bits
1685 */
1686 for( i = 0; i < nbits; i++ )
1687 {
1688 mpi_montmul( X, X, N, mm, &T );
1689
1690 wbits <<= 1;
1691
Paul Bakker66d5d072014-06-17 16:39:18 +02001692 if( ( wbits & ( one << wsize ) ) != 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +00001693 mpi_montmul( X, &W[1], N, mm, &T );
1694 }
1695
1696 /*
1697 * X = A^E * R * R^-1 mod N = A^E mod N
1698 */
1699 mpi_montred( X, N, mm, &T );
1700
Paul Bakkerf6198c12012-05-16 08:02:29 +00001701 if( neg )
1702 {
1703 X->s = -1;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001704 MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( X, N, X ) );
Paul Bakkerf6198c12012-05-16 08:02:29 +00001705 }
1706
Paul Bakker5121ce52009-01-03 21:22:43 +00001707cleanup:
1708
Paul Bakker66d5d072014-06-17 16:39:18 +02001709 for( i = ( one << ( wsize - 1 ) ); i < ( one << wsize ); i++ )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001710 mbedtls_mpi_free( &W[i] );
Paul Bakker5121ce52009-01-03 21:22:43 +00001711
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001712 mbedtls_mpi_free( &W[1] ); mbedtls_mpi_free( &T ); mbedtls_mpi_free( &Apos );
Paul Bakker6c591fa2011-05-05 11:49:20 +00001713
Paul Bakker75a28602014-03-31 12:08:17 +02001714 if( _RR == NULL || _RR->p == NULL )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001715 mbedtls_mpi_free( &RR );
Paul Bakker5121ce52009-01-03 21:22:43 +00001716
1717 return( ret );
1718}
1719
Paul Bakker5121ce52009-01-03 21:22:43 +00001720/*
1721 * Greatest common divisor: G = gcd(A, B) (HAC 14.54)
1722 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001723int mbedtls_mpi_gcd( mbedtls_mpi *G, const mbedtls_mpi *A, const mbedtls_mpi *B )
Paul Bakker5121ce52009-01-03 21:22:43 +00001724{
Paul Bakker23986e52011-04-24 08:57:21 +00001725 int ret;
1726 size_t lz, lzt;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001727 mbedtls_mpi TG, TA, TB;
Paul Bakker5121ce52009-01-03 21:22:43 +00001728
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001729 mbedtls_mpi_init( &TG ); mbedtls_mpi_init( &TA ); mbedtls_mpi_init( &TB );
Paul Bakker5121ce52009-01-03 21:22:43 +00001730
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001731 MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TA, A ) );
1732 MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, B ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001733
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001734 lz = mbedtls_mpi_lsb( &TA );
1735 lzt = mbedtls_mpi_lsb( &TB );
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00001736
Paul Bakker66d5d072014-06-17 16:39:18 +02001737 if( lzt < lz )
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00001738 lz = lzt;
1739
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001740 MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TA, lz ) );
1741 MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TB, lz ) );
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00001742
Paul Bakker5121ce52009-01-03 21:22:43 +00001743 TA.s = TB.s = 1;
1744
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001745 while( mbedtls_mpi_cmp_int( &TA, 0 ) != 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +00001746 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001747 MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TA, mbedtls_mpi_lsb( &TA ) ) );
1748 MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TB, mbedtls_mpi_lsb( &TB ) ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001749
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001750 if( mbedtls_mpi_cmp_mpi( &TA, &TB ) >= 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +00001751 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001752 MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( &TA, &TA, &TB ) );
1753 MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TA, 1 ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001754 }
1755 else
1756 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001757 MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( &TB, &TB, &TA ) );
1758 MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TB, 1 ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001759 }
1760 }
1761
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001762 MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &TB, lz ) );
1763 MBEDTLS_MPI_CHK( mbedtls_mpi_copy( G, &TB ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001764
1765cleanup:
1766
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001767 mbedtls_mpi_free( &TG ); mbedtls_mpi_free( &TA ); mbedtls_mpi_free( &TB );
Paul Bakker5121ce52009-01-03 21:22:43 +00001768
1769 return( ret );
1770}
1771
Paul Bakker33dc46b2014-04-30 16:11:39 +02001772/*
1773 * Fill X with size bytes of random.
1774 *
1775 * Use a temporary bytes representation to make sure the result is the same
Paul Bakkerc37b0ac2014-05-01 14:19:23 +02001776 * regardless of the platform endianness (useful when f_rng is actually
Paul Bakker33dc46b2014-04-30 16:11:39 +02001777 * deterministic, eg for tests).
1778 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001779int mbedtls_mpi_fill_random( mbedtls_mpi *X, size_t size,
Paul Bakkera3d195c2011-11-27 21:07:34 +00001780 int (*f_rng)(void *, unsigned char *, size_t),
1781 void *p_rng )
Paul Bakker287781a2011-03-26 13:18:49 +00001782{
Paul Bakker23986e52011-04-24 08:57:21 +00001783 int ret;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001784 unsigned char buf[MBEDTLS_MPI_MAX_SIZE];
Paul Bakker33dc46b2014-04-30 16:11:39 +02001785
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001786 if( size > MBEDTLS_MPI_MAX_SIZE )
1787 return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
Paul Bakker287781a2011-03-26 13:18:49 +00001788
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001789 MBEDTLS_MPI_CHK( f_rng( p_rng, buf, size ) );
1790 MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( X, buf, size ) );
Paul Bakker287781a2011-03-26 13:18:49 +00001791
1792cleanup:
1793 return( ret );
1794}
1795
Paul Bakker5121ce52009-01-03 21:22:43 +00001796/*
1797 * Modular inverse: X = A^-1 mod N (HAC 14.61 / 14.64)
1798 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001799int mbedtls_mpi_inv_mod( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *N )
Paul Bakker5121ce52009-01-03 21:22:43 +00001800{
1801 int ret;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001802 mbedtls_mpi G, TA, TU, U1, U2, TB, TV, V1, V2;
Paul Bakker5121ce52009-01-03 21:22:43 +00001803
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001804 if( mbedtls_mpi_cmp_int( N, 0 ) <= 0 )
1805 return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
Paul Bakker5121ce52009-01-03 21:22:43 +00001806
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001807 mbedtls_mpi_init( &TA ); mbedtls_mpi_init( &TU ); mbedtls_mpi_init( &U1 ); mbedtls_mpi_init( &U2 );
1808 mbedtls_mpi_init( &G ); mbedtls_mpi_init( &TB ); mbedtls_mpi_init( &TV );
1809 mbedtls_mpi_init( &V1 ); mbedtls_mpi_init( &V2 );
Paul Bakker5121ce52009-01-03 21:22:43 +00001810
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001811 MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &G, A, N ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001812
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001813 if( mbedtls_mpi_cmp_int( &G, 1 ) != 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +00001814 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001815 ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
Paul Bakker5121ce52009-01-03 21:22:43 +00001816 goto cleanup;
1817 }
1818
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001819 MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &TA, A, N ) );
1820 MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TU, &TA ) );
1821 MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, N ) );
1822 MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TV, N ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001823
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001824 MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &U1, 1 ) );
1825 MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &U2, 0 ) );
1826 MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &V1, 0 ) );
1827 MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &V2, 1 ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001828
1829 do
1830 {
1831 while( ( TU.p[0] & 1 ) == 0 )
1832 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001833 MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TU, 1 ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001834
1835 if( ( U1.p[0] & 1 ) != 0 || ( U2.p[0] & 1 ) != 0 )
1836 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001837 MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &U1, &U1, &TB ) );
1838 MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &U2, &U2, &TA ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001839 }
1840
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001841 MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &U1, 1 ) );
1842 MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &U2, 1 ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001843 }
1844
1845 while( ( TV.p[0] & 1 ) == 0 )
1846 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001847 MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TV, 1 ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001848
1849 if( ( V1.p[0] & 1 ) != 0 || ( V2.p[0] & 1 ) != 0 )
1850 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001851 MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &V1, &V1, &TB ) );
1852 MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &V2, &V2, &TA ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001853 }
1854
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001855 MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &V1, 1 ) );
1856 MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &V2, 1 ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001857 }
1858
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001859 if( mbedtls_mpi_cmp_mpi( &TU, &TV ) >= 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +00001860 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001861 MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &TU, &TU, &TV ) );
1862 MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &U1, &U1, &V1 ) );
1863 MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &U2, &U2, &V2 ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001864 }
1865 else
1866 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001867 MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &TV, &TV, &TU ) );
1868 MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &V1, &V1, &U1 ) );
1869 MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &V2, &V2, &U2 ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001870 }
1871 }
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001872 while( mbedtls_mpi_cmp_int( &TU, 0 ) != 0 );
Paul Bakker5121ce52009-01-03 21:22:43 +00001873
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001874 while( mbedtls_mpi_cmp_int( &V1, 0 ) < 0 )
1875 MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &V1, &V1, N ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001876
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001877 while( mbedtls_mpi_cmp_mpi( &V1, N ) >= 0 )
1878 MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &V1, &V1, N ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001879
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001880 MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, &V1 ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001881
1882cleanup:
1883
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001884 mbedtls_mpi_free( &TA ); mbedtls_mpi_free( &TU ); mbedtls_mpi_free( &U1 ); mbedtls_mpi_free( &U2 );
1885 mbedtls_mpi_free( &G ); mbedtls_mpi_free( &TB ); mbedtls_mpi_free( &TV );
1886 mbedtls_mpi_free( &V1 ); mbedtls_mpi_free( &V2 );
Paul Bakker5121ce52009-01-03 21:22:43 +00001887
1888 return( ret );
1889}
1890
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001891#if defined(MBEDTLS_GENPRIME)
Paul Bakkerd9374b02012-11-02 11:02:58 +00001892
Paul Bakker5121ce52009-01-03 21:22:43 +00001893static const int small_prime[] =
1894{
1895 3, 5, 7, 11, 13, 17, 19, 23,
1896 29, 31, 37, 41, 43, 47, 53, 59,
1897 61, 67, 71, 73, 79, 83, 89, 97,
1898 101, 103, 107, 109, 113, 127, 131, 137,
1899 139, 149, 151, 157, 163, 167, 173, 179,
1900 181, 191, 193, 197, 199, 211, 223, 227,
1901 229, 233, 239, 241, 251, 257, 263, 269,
1902 271, 277, 281, 283, 293, 307, 311, 313,
1903 317, 331, 337, 347, 349, 353, 359, 367,
1904 373, 379, 383, 389, 397, 401, 409, 419,
1905 421, 431, 433, 439, 443, 449, 457, 461,
1906 463, 467, 479, 487, 491, 499, 503, 509,
1907 521, 523, 541, 547, 557, 563, 569, 571,
1908 577, 587, 593, 599, 601, 607, 613, 617,
1909 619, 631, 641, 643, 647, 653, 659, 661,
1910 673, 677, 683, 691, 701, 709, 719, 727,
1911 733, 739, 743, 751, 757, 761, 769, 773,
1912 787, 797, 809, 811, 821, 823, 827, 829,
1913 839, 853, 857, 859, 863, 877, 881, 883,
1914 887, 907, 911, 919, 929, 937, 941, 947,
1915 953, 967, 971, 977, 983, 991, 997, -103
1916};
1917
1918/*
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01001919 * Small divisors test (X must be positive)
1920 *
1921 * Return values:
1922 * 0: no small factor (possible prime, more tests needed)
1923 * 1: certain prime
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001924 * MBEDTLS_ERR_MPI_NOT_ACCEPTABLE: certain non-prime
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01001925 * other negative: error
Paul Bakker5121ce52009-01-03 21:22:43 +00001926 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001927static int mpi_check_small_factors( const mbedtls_mpi *X )
Paul Bakker5121ce52009-01-03 21:22:43 +00001928{
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01001929 int ret = 0;
1930 size_t i;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001931 mbedtls_mpi_uint r;
Paul Bakker5121ce52009-01-03 21:22:43 +00001932
Paul Bakker5121ce52009-01-03 21:22:43 +00001933 if( ( X->p[0] & 1 ) == 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001934 return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE );
Paul Bakker5121ce52009-01-03 21:22:43 +00001935
1936 for( i = 0; small_prime[i] > 0; i++ )
1937 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001938 if( mbedtls_mpi_cmp_int( X, small_prime[i] ) <= 0 )
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01001939 return( 1 );
Paul Bakker5121ce52009-01-03 21:22:43 +00001940
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001941 MBEDTLS_MPI_CHK( mbedtls_mpi_mod_int( &r, X, small_prime[i] ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001942
1943 if( r == 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001944 return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE );
Paul Bakker5121ce52009-01-03 21:22:43 +00001945 }
1946
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01001947cleanup:
1948 return( ret );
1949}
1950
1951/*
1952 * Miller-Rabin pseudo-primality test (HAC 4.24)
1953 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001954static int mpi_miller_rabin( const mbedtls_mpi *X,
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01001955 int (*f_rng)(void *, unsigned char *, size_t),
1956 void *p_rng )
1957{
Pascal Junodb99183d2015-03-11 16:49:45 +01001958 int ret, count;
1959 size_t i, j, k, n, s;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001960 mbedtls_mpi W, R, T, A, RR;
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01001961
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001962 mbedtls_mpi_init( &W ); mbedtls_mpi_init( &R ); mbedtls_mpi_init( &T ); mbedtls_mpi_init( &A );
1963 mbedtls_mpi_init( &RR );
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01001964
Paul Bakker5121ce52009-01-03 21:22:43 +00001965 /*
1966 * W = |X| - 1
1967 * R = W >> lsb( W )
1968 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001969 MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &W, X, 1 ) );
1970 s = mbedtls_mpi_lsb( &W );
1971 MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &R, &W ) );
1972 MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &R, s ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001973
Manuel Pégourié-Gonnardc0696c22015-06-18 16:47:17 +02001974 i = mbedtls_mpi_bitlen( X );
Paul Bakker5121ce52009-01-03 21:22:43 +00001975 /*
1976 * HAC, table 4.4
1977 */
1978 n = ( ( i >= 1300 ) ? 2 : ( i >= 850 ) ? 3 :
1979 ( i >= 650 ) ? 4 : ( i >= 350 ) ? 8 :
1980 ( i >= 250 ) ? 12 : ( i >= 150 ) ? 18 : 27 );
1981
1982 for( i = 0; i < n; i++ )
1983 {
1984 /*
1985 * pick a random A, 1 < A < |X| - 1
1986 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001987 MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &A, X->n * ciL, f_rng, p_rng ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00001988
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001989 if( mbedtls_mpi_cmp_mpi( &A, &W ) >= 0 )
Paul Bakkerb94081b2011-01-05 15:53:06 +00001990 {
Manuel Pégourié-Gonnardc0696c22015-06-18 16:47:17 +02001991 j = mbedtls_mpi_bitlen( &A ) - mbedtls_mpi_bitlen( &W );
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001992 MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &A, j + 1 ) );
Paul Bakkerb94081b2011-01-05 15:53:06 +00001993 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001994 A.p[0] |= 3;
1995
Pascal Junodb99183d2015-03-11 16:49:45 +01001996 count = 0;
1997 do {
Manuel Pégourié-Gonnard53c76c02015-04-17 20:15:36 +02001998 MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &A, X->n * ciL, f_rng, p_rng ) );
Pascal Junodb99183d2015-03-11 16:49:45 +01001999
Manuel Pégourié-Gonnardc0696c22015-06-18 16:47:17 +02002000 j = mbedtls_mpi_bitlen( &A );
2001 k = mbedtls_mpi_bitlen( &W );
Pascal Junodb99183d2015-03-11 16:49:45 +01002002 if (j > k) {
Manuel Pégourié-Gonnard53c76c02015-04-17 20:15:36 +02002003 MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &A, j - k ) );
Pascal Junodb99183d2015-03-11 16:49:45 +01002004 }
2005
2006 if (count++ > 30) {
Manuel Pégourié-Gonnard53c76c02015-04-17 20:15:36 +02002007 return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
Pascal Junodb99183d2015-03-11 16:49:45 +01002008 }
2009
Manuel Pégourié-Gonnard53c76c02015-04-17 20:15:36 +02002010 } while ( mbedtls_mpi_cmp_mpi( &A, &W ) >= 0 ||
2011 mbedtls_mpi_cmp_int( &A, 1 ) <= 0 );
Paul Bakker5121ce52009-01-03 21:22:43 +00002012
2013 /*
2014 * A = A^R mod |X|
2015 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002016 MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &A, &A, &R, X, &RR ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00002017
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002018 if( mbedtls_mpi_cmp_mpi( &A, &W ) == 0 ||
2019 mbedtls_mpi_cmp_int( &A, 1 ) == 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +00002020 continue;
2021
2022 j = 1;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002023 while( j < s && mbedtls_mpi_cmp_mpi( &A, &W ) != 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +00002024 {
2025 /*
2026 * A = A * A mod |X|
2027 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002028 MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T, &A, &A ) );
2029 MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &A, &T, X ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00002030
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002031 if( mbedtls_mpi_cmp_int( &A, 1 ) == 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +00002032 break;
2033
2034 j++;
2035 }
2036
2037 /*
2038 * not prime if A != |X| - 1 or A == 1
2039 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002040 if( mbedtls_mpi_cmp_mpi( &A, &W ) != 0 ||
2041 mbedtls_mpi_cmp_int( &A, 1 ) == 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +00002042 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002043 ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
Paul Bakker5121ce52009-01-03 21:22:43 +00002044 break;
2045 }
2046 }
2047
2048cleanup:
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002049 mbedtls_mpi_free( &W ); mbedtls_mpi_free( &R ); mbedtls_mpi_free( &T ); mbedtls_mpi_free( &A );
2050 mbedtls_mpi_free( &RR );
Paul Bakker5121ce52009-01-03 21:22:43 +00002051
2052 return( ret );
2053}
2054
2055/*
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002056 * Pseudo-primality test: small factors, then Miller-Rabin
2057 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002058int mbedtls_mpi_is_prime( const mbedtls_mpi *X,
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002059 int (*f_rng)(void *, unsigned char *, size_t),
2060 void *p_rng )
2061{
2062 int ret;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002063 mbedtls_mpi XX;
Manuel Pégourié-Gonnard7f4ed672014-10-14 20:56:02 +02002064
2065 XX.s = 1;
2066 XX.n = X->n;
2067 XX.p = X->p;
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002068
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002069 if( mbedtls_mpi_cmp_int( &XX, 0 ) == 0 ||
2070 mbedtls_mpi_cmp_int( &XX, 1 ) == 0 )
2071 return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE );
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002072
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002073 if( mbedtls_mpi_cmp_int( &XX, 2 ) == 0 )
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002074 return( 0 );
2075
2076 if( ( ret = mpi_check_small_factors( &XX ) ) != 0 )
2077 {
2078 if( ret == 1 )
2079 return( 0 );
2080
2081 return( ret );
2082 }
2083
2084 return( mpi_miller_rabin( &XX, f_rng, p_rng ) );
2085}
2086
2087/*
Paul Bakker5121ce52009-01-03 21:22:43 +00002088 * Prime number generation
2089 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002090int mbedtls_mpi_gen_prime( mbedtls_mpi *X, size_t nbits, int dh_flag,
Paul Bakkera3d195c2011-11-27 21:07:34 +00002091 int (*f_rng)(void *, unsigned char *, size_t),
2092 void *p_rng )
Paul Bakker5121ce52009-01-03 21:22:43 +00002093{
Paul Bakker23986e52011-04-24 08:57:21 +00002094 int ret;
2095 size_t k, n;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002096 mbedtls_mpi_uint r;
2097 mbedtls_mpi Y;
Paul Bakker5121ce52009-01-03 21:22:43 +00002098
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002099 if( nbits < 3 || nbits > MBEDTLS_MPI_MAX_BITS )
2100 return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
Paul Bakker5121ce52009-01-03 21:22:43 +00002101
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002102 mbedtls_mpi_init( &Y );
Paul Bakker5121ce52009-01-03 21:22:43 +00002103
2104 n = BITS_TO_LIMBS( nbits );
2105
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002106 MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( X, n * ciL, f_rng, p_rng ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00002107
Manuel Pégourié-Gonnardc0696c22015-06-18 16:47:17 +02002108 k = mbedtls_mpi_bitlen( X );
Manuel Pégourié-Gonnard53c76c02015-04-17 20:15:36 +02002109 if( k > nbits ) MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( X, k - nbits + 1 ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00002110
Manuel Pégourié-Gonnard53c76c02015-04-17 20:15:36 +02002111 mbedtls_mpi_set_bit( X, nbits-1, 1 );
Pascal Junodb99183d2015-03-11 16:49:45 +01002112
2113 X->p[0] |= 1;
Paul Bakker5121ce52009-01-03 21:22:43 +00002114
2115 if( dh_flag == 0 )
2116 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002117 while( ( ret = mbedtls_mpi_is_prime( X, f_rng, p_rng ) ) != 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +00002118 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002119 if( ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE )
Paul Bakker5121ce52009-01-03 21:22:43 +00002120 goto cleanup;
2121
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002122 MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, X, 2 ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00002123 }
2124 }
2125 else
2126 {
Manuel Pégourié-Gonnard0160eac2013-11-22 17:54:59 +01002127 /*
2128 * An necessary condition for Y and X = 2Y + 1 to be prime
2129 * is X = 2 mod 3 (which is equivalent to Y = 2 mod 3).
2130 * Make sure it is satisfied, while keeping X = 3 mod 4
2131 */
Pascal Junodb99183d2015-03-11 16:49:45 +01002132
2133 X->p[0] |= 2;
2134
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002135 MBEDTLS_MPI_CHK( mbedtls_mpi_mod_int( &r, X, 3 ) );
Manuel Pégourié-Gonnard0160eac2013-11-22 17:54:59 +01002136 if( r == 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002137 MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, X, 8 ) );
Manuel Pégourié-Gonnard0160eac2013-11-22 17:54:59 +01002138 else if( r == 1 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002139 MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, X, 4 ) );
Manuel Pégourié-Gonnard0160eac2013-11-22 17:54:59 +01002140
2141 /* Set Y = (X-1) / 2, which is X / 2 because X is odd */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002142 MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &Y, X ) );
2143 MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &Y, 1 ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00002144
2145 while( 1 )
2146 {
Manuel Pégourié-Gonnardddf76152013-11-22 19:58:22 +01002147 /*
2148 * First, check small factors for X and Y
2149 * before doing Miller-Rabin on any of them
2150 */
2151 if( ( ret = mpi_check_small_factors( X ) ) == 0 &&
2152 ( ret = mpi_check_small_factors( &Y ) ) == 0 &&
2153 ( ret = mpi_miller_rabin( X, f_rng, p_rng ) ) == 0 &&
2154 ( ret = mpi_miller_rabin( &Y, f_rng, p_rng ) ) == 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +00002155 {
Manuel Pégourié-Gonnardddf76152013-11-22 19:58:22 +01002156 break;
Paul Bakker5121ce52009-01-03 21:22:43 +00002157 }
2158
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002159 if( ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE )
Paul Bakker5121ce52009-01-03 21:22:43 +00002160 goto cleanup;
2161
Manuel Pégourié-Gonnard0160eac2013-11-22 17:54:59 +01002162 /*
Manuel Pégourié-Gonnardddf76152013-11-22 19:58:22 +01002163 * Next candidates. We want to preserve Y = (X-1) / 2 and
Manuel Pégourié-Gonnard0160eac2013-11-22 17:54:59 +01002164 * Y = 1 mod 2 and Y = 2 mod 3 (eq X = 3 mod 4 and X = 2 mod 3)
2165 * so up Y by 6 and X by 12.
2166 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002167 MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, X, 12 ) );
2168 MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( &Y, &Y, 6 ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00002169 }
2170 }
2171
2172cleanup:
2173
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002174 mbedtls_mpi_free( &Y );
Paul Bakker5121ce52009-01-03 21:22:43 +00002175
2176 return( ret );
2177}
2178
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002179#endif /* MBEDTLS_GENPRIME */
Paul Bakker5121ce52009-01-03 21:22:43 +00002180
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002181#if defined(MBEDTLS_SELF_TEST)
Paul Bakker5121ce52009-01-03 21:22:43 +00002182
Paul Bakker23986e52011-04-24 08:57:21 +00002183#define GCD_PAIR_COUNT 3
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002184
2185static const int gcd_pairs[GCD_PAIR_COUNT][3] =
2186{
2187 { 693, 609, 21 },
2188 { 1764, 868, 28 },
2189 { 768454923, 542167814, 1 }
2190};
2191
Paul Bakker5121ce52009-01-03 21:22:43 +00002192/*
2193 * Checkup routine
2194 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002195int mbedtls_mpi_self_test( int verbose )
Paul Bakker5121ce52009-01-03 21:22:43 +00002196{
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002197 int ret, i;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002198 mbedtls_mpi A, E, N, X, Y, U, V;
Paul Bakker5121ce52009-01-03 21:22:43 +00002199
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002200 mbedtls_mpi_init( &A ); mbedtls_mpi_init( &E ); mbedtls_mpi_init( &N ); mbedtls_mpi_init( &X );
2201 mbedtls_mpi_init( &Y ); mbedtls_mpi_init( &U ); mbedtls_mpi_init( &V );
Paul Bakker5121ce52009-01-03 21:22:43 +00002202
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002203 MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &A, 16,
Paul Bakker5121ce52009-01-03 21:22:43 +00002204 "EFE021C2645FD1DC586E69184AF4A31E" \
2205 "D5F53E93B5F123FA41680867BA110131" \
2206 "944FE7952E2517337780CB0DB80E61AA" \
2207 "E7C8DDC6C5C6AADEB34EB38A2F40D5E6" ) );
2208
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002209 MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &E, 16,
Paul Bakker5121ce52009-01-03 21:22:43 +00002210 "B2E7EFD37075B9F03FF989C7C5051C20" \
2211 "34D2A323810251127E7BF8625A4F49A5" \
2212 "F3E27F4DA8BD59C47D6DAABA4C8127BD" \
2213 "5B5C25763222FEFCCFC38B832366C29E" ) );
2214
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002215 MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &N, 16,
Paul Bakker5121ce52009-01-03 21:22:43 +00002216 "0066A198186C18C10B2F5ED9B522752A" \
2217 "9830B69916E535C8F047518A889A43A5" \
2218 "94B6BED27A168D31D4A52F88925AA8F5" ) );
2219
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002220 MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &X, &A, &N ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00002221
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002222 MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &U, 16,
Paul Bakker5121ce52009-01-03 21:22:43 +00002223 "602AB7ECA597A3D6B56FF9829A5E8B85" \
2224 "9E857EA95A03512E2BAE7391688D264A" \
2225 "A5663B0341DB9CCFD2C4C5F421FEC814" \
2226 "8001B72E848A38CAE1C65F78E56ABDEF" \
2227 "E12D3C039B8A02D6BE593F0BBBDA56F1" \
2228 "ECF677152EF804370C1A305CAF3B5BF1" \
2229 "30879B56C61DE584A0F53A2447A51E" ) );
2230
2231 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002232 mbedtls_printf( " MPI test #1 (mul_mpi): " );
Paul Bakker5121ce52009-01-03 21:22:43 +00002233
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002234 if( mbedtls_mpi_cmp_mpi( &X, &U ) != 0 )
Manuel Pégourié-Gonnarda0d3a262014-04-11 15:31:02 +02002235 { // LCOV_EXCL_START
Paul Bakker5121ce52009-01-03 21:22:43 +00002236 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002237 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +00002238
Manuel Pégourié-Gonnard9e987ed2014-01-20 10:03:15 +01002239 ret = 1;
2240 goto cleanup;
Manuel Pégourié-Gonnarda0d3a262014-04-11 15:31:02 +02002241 } // LCOV_EXCL_STOP
Paul Bakker5121ce52009-01-03 21:22:43 +00002242
2243 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002244 mbedtls_printf( "passed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +00002245
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002246 MBEDTLS_MPI_CHK( mbedtls_mpi_div_mpi( &X, &Y, &A, &N ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00002247
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002248 MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &U, 16,
Paul Bakker5121ce52009-01-03 21:22:43 +00002249 "256567336059E52CAE22925474705F39A94" ) );
2250
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002251 MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &V, 16,
Paul Bakker5121ce52009-01-03 21:22:43 +00002252 "6613F26162223DF488E9CD48CC132C7A" \
2253 "0AC93C701B001B092E4E5B9F73BCD27B" \
2254 "9EE50D0657C77F374E903CDFA4C642" ) );
2255
2256 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002257 mbedtls_printf( " MPI test #2 (div_mpi): " );
Paul Bakker5121ce52009-01-03 21:22:43 +00002258
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002259 if( mbedtls_mpi_cmp_mpi( &X, &U ) != 0 ||
2260 mbedtls_mpi_cmp_mpi( &Y, &V ) != 0 )
Manuel Pégourié-Gonnarda0d3a262014-04-11 15:31:02 +02002261 { // LCOV_EXCL_START
Paul Bakker5121ce52009-01-03 21:22:43 +00002262 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002263 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +00002264
Manuel Pégourié-Gonnard9e987ed2014-01-20 10:03:15 +01002265 ret = 1;
2266 goto cleanup;
Manuel Pégourié-Gonnarda0d3a262014-04-11 15:31:02 +02002267 } // LCOV_EXCL_STOP
Paul Bakker5121ce52009-01-03 21:22:43 +00002268
2269 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002270 mbedtls_printf( "passed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +00002271
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002272 MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &X, &A, &E, &N, NULL ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00002273
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002274 MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &U, 16,
Paul Bakker5121ce52009-01-03 21:22:43 +00002275 "36E139AEA55215609D2816998ED020BB" \
2276 "BD96C37890F65171D948E9BC7CBAA4D9" \
2277 "325D24D6A3C12710F10A09FA08AB87" ) );
2278
2279 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002280 mbedtls_printf( " MPI test #3 (exp_mod): " );
Paul Bakker5121ce52009-01-03 21:22:43 +00002281
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002282 if( mbedtls_mpi_cmp_mpi( &X, &U ) != 0 )
Manuel Pégourié-Gonnarda0d3a262014-04-11 15:31:02 +02002283 { // LCOV_EXCL_START
Paul Bakker5121ce52009-01-03 21:22:43 +00002284 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002285 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +00002286
Manuel Pégourié-Gonnard9e987ed2014-01-20 10:03:15 +01002287 ret = 1;
2288 goto cleanup;
Manuel Pégourié-Gonnarda0d3a262014-04-11 15:31:02 +02002289 } // LCOV_EXCL_STOP
Paul Bakker5121ce52009-01-03 21:22:43 +00002290
2291 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002292 mbedtls_printf( "passed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +00002293
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002294 MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &X, &A, &N ) );
Paul Bakker5121ce52009-01-03 21:22:43 +00002295
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002296 MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &U, 16,
Paul Bakker5121ce52009-01-03 21:22:43 +00002297 "003A0AAEDD7E784FC07D8F9EC6E3BFD5" \
2298 "C3DBA76456363A10869622EAC2DD84EC" \
2299 "C5B8A74DAC4D09E03B5E0BE779F2DF61" ) );
2300
2301 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002302 mbedtls_printf( " MPI test #4 (inv_mod): " );
Paul Bakker5121ce52009-01-03 21:22:43 +00002303
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002304 if( mbedtls_mpi_cmp_mpi( &X, &U ) != 0 )
Manuel Pégourié-Gonnarda0d3a262014-04-11 15:31:02 +02002305 { // LCOV_EXCL_START
Paul Bakker5121ce52009-01-03 21:22:43 +00002306 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002307 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +00002308
Manuel Pégourié-Gonnard9e987ed2014-01-20 10:03:15 +01002309 ret = 1;
2310 goto cleanup;
Manuel Pégourié-Gonnarda0d3a262014-04-11 15:31:02 +02002311 } // LCOV_EXCL_STOP
Paul Bakker5121ce52009-01-03 21:22:43 +00002312
2313 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002314 mbedtls_printf( "passed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +00002315
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002316 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002317 mbedtls_printf( " MPI test #5 (simple gcd): " );
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002318
Paul Bakker66d5d072014-06-17 16:39:18 +02002319 for( i = 0; i < GCD_PAIR_COUNT; i++ )
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002320 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002321 MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &X, gcd_pairs[i][0] ) );
2322 MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &Y, gcd_pairs[i][1] ) );
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002323
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002324 MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &A, &X, &Y ) );
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002325
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002326 if( mbedtls_mpi_cmp_int( &A, gcd_pairs[i][2] ) != 0 )
Manuel Pégourié-Gonnarda0d3a262014-04-11 15:31:02 +02002327 { // LCOV_EXCL_START
Manuel Pégourié-Gonnard9e987ed2014-01-20 10:03:15 +01002328 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002329 mbedtls_printf( "failed at %d\n", i );
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002330
Manuel Pégourié-Gonnard9e987ed2014-01-20 10:03:15 +01002331 ret = 1;
2332 goto cleanup;
Manuel Pégourié-Gonnarda0d3a262014-04-11 15:31:02 +02002333 } // LCOV_EXCL_STOP
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002334 }
2335
2336 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002337 mbedtls_printf( "passed\n" );
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002338
Paul Bakker5121ce52009-01-03 21:22:43 +00002339cleanup:
2340
2341 if( ret != 0 && verbose != 0 )
Manuel Pégourié-Gonnarda0d3a262014-04-11 15:31:02 +02002342 mbedtls_printf( "Unexpected error, return code = %08X\n", ret ); // LCOV_EXCL_LINE
Paul Bakker5121ce52009-01-03 21:22:43 +00002343
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002344 mbedtls_mpi_free( &A ); mbedtls_mpi_free( &E ); mbedtls_mpi_free( &N ); mbedtls_mpi_free( &X );
2345 mbedtls_mpi_free( &Y ); mbedtls_mpi_free( &U ); mbedtls_mpi_free( &V );
Paul Bakker5121ce52009-01-03 21:22:43 +00002346
2347 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002348 mbedtls_printf( "\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +00002349
2350 return( ret );
2351}
2352
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002353#endif /* MBEDTLS_SELF_TEST */
Paul Bakker5121ce52009-01-03 21:22:43 +00002354
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002355#endif /* MBEDTLS_BIGNUM_C */