1c6672fdcSEdison Ai // SPDX-License-Identifier: Apache-2.0 2817466cbSJens Wiklander /* 3817466cbSJens Wiklander * Multi-precision integer library 4817466cbSJens Wiklander * 5817466cbSJens Wiklander * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved 6817466cbSJens Wiklander * 7817466cbSJens Wiklander * Licensed under the Apache License, Version 2.0 (the "License"); you may 8817466cbSJens Wiklander * not use this file except in compliance with the License. 9817466cbSJens Wiklander * You may obtain a copy of the License at 10817466cbSJens Wiklander * 11817466cbSJens Wiklander * http://www.apache.org/licenses/LICENSE-2.0 12817466cbSJens Wiklander * 13817466cbSJens Wiklander * Unless required by applicable law or agreed to in writing, software 14817466cbSJens Wiklander * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 15817466cbSJens Wiklander * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16817466cbSJens Wiklander * See the License for the specific language governing permissions and 17817466cbSJens Wiklander * limitations under the License. 18817466cbSJens Wiklander * 19817466cbSJens Wiklander * This file is part of mbed TLS (https://tls.mbed.org) 20817466cbSJens Wiklander */ 21817466cbSJens Wiklander 22817466cbSJens Wiklander /* 23817466cbSJens Wiklander * The following sources were referenced in the design of this Multi-precision 24817466cbSJens Wiklander * Integer library: 25817466cbSJens Wiklander * 26817466cbSJens Wiklander * [1] Handbook of Applied Cryptography - 1997 27817466cbSJens Wiklander * Menezes, van Oorschot and Vanstone 28817466cbSJens Wiklander * 29817466cbSJens Wiklander * [2] Multi-Precision Math 30817466cbSJens Wiklander * Tom St Denis 31817466cbSJens Wiklander * https://github.com/libtom/libtommath/blob/develop/tommath.pdf 32817466cbSJens Wiklander * 33817466cbSJens Wiklander * [3] GNU Multi-Precision Arithmetic Library 34817466cbSJens Wiklander * https://gmplib.org/manual/index.html 35817466cbSJens Wiklander * 36817466cbSJens Wiklander */ 37817466cbSJens Wiklander 38817466cbSJens Wiklander #if !defined(MBEDTLS_CONFIG_FILE) 39817466cbSJens Wiklander #include "mbedtls/config.h" 40817466cbSJens Wiklander #else 41817466cbSJens Wiklander #include MBEDTLS_CONFIG_FILE 42817466cbSJens Wiklander #endif 43817466cbSJens Wiklander 44817466cbSJens Wiklander #if defined(MBEDTLS_BIGNUM_C) 45817466cbSJens Wiklander 46817466cbSJens Wiklander #include "mbedtls/bignum.h" 47817466cbSJens Wiklander #include "mbedtls/bn_mul.h" 483d3b0591SJens Wiklander #include "mbedtls/platform_util.h" 49817466cbSJens Wiklander 50817466cbSJens Wiklander #include <string.h> 51817466cbSJens Wiklander 52817466cbSJens Wiklander #if defined(MBEDTLS_PLATFORM_C) 53817466cbSJens Wiklander #include "mbedtls/platform.h" 54817466cbSJens Wiklander #else 55817466cbSJens Wiklander #include <stdio.h> 56817466cbSJens Wiklander #include <stdlib.h> 57817466cbSJens Wiklander #define mbedtls_printf printf 58817466cbSJens Wiklander #define mbedtls_calloc calloc 59817466cbSJens Wiklander #define mbedtls_free free 60817466cbSJens Wiklander #endif 61817466cbSJens Wiklander 6298bd5fe3SJens Wiklander #include <mempool.h> 63*b99a4a18SJens Wiklander #include <util.h> 6498bd5fe3SJens Wiklander 653d3b0591SJens Wiklander #define MPI_VALIDATE_RET( cond ) \ 663d3b0591SJens Wiklander MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_MPI_BAD_INPUT_DATA ) 673d3b0591SJens Wiklander #define MPI_VALIDATE( cond ) \ 683d3b0591SJens Wiklander MBEDTLS_INTERNAL_VALIDATE( cond ) 69817466cbSJens Wiklander 70817466cbSJens Wiklander #define ciL (sizeof(mbedtls_mpi_uint)) /* chars in limb */ 71817466cbSJens Wiklander #define biL (ciL << 3) /* bits in limb */ 72817466cbSJens Wiklander #define biH (ciL << 2) /* half limb size */ 73817466cbSJens Wiklander 74817466cbSJens Wiklander #define MPI_SIZE_T_MAX ( (size_t) -1 ) /* SIZE_T_MAX is not standard */ 75817466cbSJens Wiklander 76817466cbSJens Wiklander /* 77817466cbSJens Wiklander * Convert between bits/chars and number of limbs 78817466cbSJens Wiklander * Divide first in order to avoid potential overflows 79817466cbSJens Wiklander */ 80817466cbSJens Wiklander #define BITS_TO_LIMBS(i) ( (i) / biL + ( (i) % biL != 0 ) ) 81817466cbSJens Wiklander #define CHARS_TO_LIMBS(i) ( (i) / ciL + ( (i) % ciL != 0 ) ) 82817466cbSJens Wiklander 8398bd5fe3SJens Wiklander void *mbedtls_mpi_mempool; 8498bd5fe3SJens Wiklander 853d3b0591SJens Wiklander /* Implementation that should never be optimized out by the compiler */ 863d3b0591SJens Wiklander static void mbedtls_mpi_zeroize( mbedtls_mpi_uint *v, size_t n ) 873d3b0591SJens Wiklander { 883d3b0591SJens Wiklander mbedtls_platform_zeroize( v, ciL * n ); 893d3b0591SJens Wiklander } 903d3b0591SJens Wiklander 91817466cbSJens Wiklander /* 92817466cbSJens Wiklander * Initialize one MPI 93817466cbSJens Wiklander */ 943d3b0591SJens Wiklander static void mpi_init( mbedtls_mpi *X, short use_mempool ) 95817466cbSJens Wiklander { 963d3b0591SJens Wiklander MPI_VALIDATE( X != NULL ); 97817466cbSJens Wiklander 983d3b0591SJens Wiklander X->s = 1; 993d3b0591SJens Wiklander X->use_mempool = use_mempool; 1003d3b0591SJens Wiklander X->n = 0; 1013d3b0591SJens Wiklander X->p = NULL; 102817466cbSJens Wiklander } 103817466cbSJens Wiklander 10498bd5fe3SJens Wiklander void mbedtls_mpi_init( mbedtls_mpi *X ) 10598bd5fe3SJens Wiklander { 1063d3b0591SJens Wiklander mpi_init( X, 0 /*use_mempool*/ ); 10798bd5fe3SJens Wiklander } 10898bd5fe3SJens Wiklander 10998bd5fe3SJens Wiklander void mbedtls_mpi_init_mempool( mbedtls_mpi *X ) 11098bd5fe3SJens Wiklander { 1113d3b0591SJens Wiklander mpi_init( X, !!mbedtls_mpi_mempool /*use_mempool*/ ); 11298bd5fe3SJens Wiklander } 11398bd5fe3SJens Wiklander 114817466cbSJens Wiklander /* 115817466cbSJens Wiklander * Unallocate one MPI 116817466cbSJens Wiklander */ 117817466cbSJens Wiklander void mbedtls_mpi_free( mbedtls_mpi *X ) 118817466cbSJens Wiklander { 119817466cbSJens Wiklander if( X == NULL ) 120817466cbSJens Wiklander return; 121817466cbSJens Wiklander 122817466cbSJens Wiklander if( X->p != NULL ) 123817466cbSJens Wiklander { 124817466cbSJens Wiklander mbedtls_mpi_zeroize( X->p, X->n ); 1253d3b0591SJens Wiklander if( X->use_mempool ) 12618c5148dSJens Wiklander mempool_free( mbedtls_mpi_mempool, X->p ); 1273d3b0591SJens Wiklander else 1283d3b0591SJens Wiklander mbedtls_free( X->p ); 129817466cbSJens Wiklander } 130817466cbSJens Wiklander 131817466cbSJens Wiklander X->s = 1; 132817466cbSJens Wiklander X->n = 0; 1333d3b0591SJens Wiklander X->p = NULL; 134817466cbSJens Wiklander } 135817466cbSJens Wiklander 136817466cbSJens Wiklander /* 137817466cbSJens Wiklander * Enlarge to the specified number of limbs 138817466cbSJens Wiklander */ 139817466cbSJens Wiklander int mbedtls_mpi_grow( mbedtls_mpi *X, size_t nblimbs ) 140817466cbSJens Wiklander { 141817466cbSJens Wiklander mbedtls_mpi_uint *p; 1423d3b0591SJens Wiklander MPI_VALIDATE_RET( X != NULL ); 143817466cbSJens Wiklander 144817466cbSJens Wiklander if( nblimbs > MBEDTLS_MPI_MAX_LIMBS ) 145817466cbSJens Wiklander return( MBEDTLS_ERR_MPI_ALLOC_FAILED ); 146817466cbSJens Wiklander 1473d3b0591SJens Wiklander if( X->n < nblimbs ) 1483d3b0591SJens Wiklander { 1493d3b0591SJens Wiklander if( X->use_mempool ) 1503d3b0591SJens Wiklander { 1513d3b0591SJens Wiklander p = mempool_alloc( mbedtls_mpi_mempool, nblimbs * ciL ); 15218c5148dSJens Wiklander if( p == NULL ) 15318c5148dSJens Wiklander return( MBEDTLS_ERR_MPI_ALLOC_FAILED ); 1543d3b0591SJens Wiklander memset( p, 0, nblimbs * ciL ); 1553d3b0591SJens Wiklander } 1563d3b0591SJens Wiklander else 1573d3b0591SJens Wiklander { 1583d3b0591SJens Wiklander p = (mbedtls_mpi_uint*)mbedtls_calloc( nblimbs, ciL ); 1593d3b0591SJens Wiklander if( p == NULL ) 1603d3b0591SJens Wiklander return( MBEDTLS_ERR_MPI_ALLOC_FAILED ); 161817466cbSJens Wiklander } 162817466cbSJens Wiklander 1633d3b0591SJens Wiklander if( X->p != NULL ) 1643d3b0591SJens Wiklander { 1653d3b0591SJens Wiklander memcpy( p, X->p, X->n * ciL ); 1663d3b0591SJens Wiklander mbedtls_mpi_zeroize( X->p, X->n ); 1673d3b0591SJens Wiklander if( X->use_mempool ) 16818c5148dSJens Wiklander mempool_free( mbedtls_mpi_mempool, X->p); 1693d3b0591SJens Wiklander else 1703d3b0591SJens Wiklander mbedtls_free( X->p ); 1713d3b0591SJens Wiklander } 17218c5148dSJens Wiklander 17318c5148dSJens Wiklander X->n = nblimbs; 1743d3b0591SJens Wiklander X->p = p; 1753d3b0591SJens Wiklander } 176817466cbSJens Wiklander 177817466cbSJens Wiklander return( 0 ); 178817466cbSJens Wiklander } 179817466cbSJens Wiklander 180817466cbSJens Wiklander /* 181817466cbSJens Wiklander * Resize down as much as possible, 182817466cbSJens Wiklander * while keeping at least the specified number of limbs 183817466cbSJens Wiklander */ 184817466cbSJens Wiklander int mbedtls_mpi_shrink( mbedtls_mpi *X, size_t nblimbs ) 185817466cbSJens Wiklander { 186817466cbSJens Wiklander mbedtls_mpi_uint *p; 187817466cbSJens Wiklander size_t i; 1883d3b0591SJens Wiklander MPI_VALIDATE_RET( X != NULL ); 1893d3b0591SJens Wiklander 1903d3b0591SJens Wiklander if( nblimbs > MBEDTLS_MPI_MAX_LIMBS ) 1913d3b0591SJens Wiklander return( MBEDTLS_ERR_MPI_ALLOC_FAILED ); 192817466cbSJens Wiklander 193817466cbSJens Wiklander /* Actually resize up in this case */ 194817466cbSJens Wiklander if( X->n <= nblimbs ) 195817466cbSJens Wiklander return( mbedtls_mpi_grow( X, nblimbs ) ); 196817466cbSJens Wiklander 197817466cbSJens Wiklander for( i = X->n - 1; i > 0; i-- ) 198817466cbSJens Wiklander if( X->p[i] != 0 ) 199817466cbSJens Wiklander break; 200817466cbSJens Wiklander i++; 201817466cbSJens Wiklander 202817466cbSJens Wiklander if( i < nblimbs ) 203817466cbSJens Wiklander i = nblimbs; 204817466cbSJens Wiklander 2053d3b0591SJens Wiklander if( X->use_mempool ) 2063d3b0591SJens Wiklander { 2073d3b0591SJens Wiklander p = mempool_alloc( mbedtls_mpi_mempool, nblimbs * ciL ); 2083d3b0591SJens Wiklander if( p == NULL ) 20998bd5fe3SJens Wiklander return( MBEDTLS_ERR_MPI_ALLOC_FAILED ); 2103d3b0591SJens Wiklander memset( p, 0, nblimbs * ciL ); 21198bd5fe3SJens Wiklander } 2123d3b0591SJens Wiklander else 2133d3b0591SJens Wiklander { 2143d3b0591SJens Wiklander p = (mbedtls_mpi_uint*)mbedtls_calloc( nblimbs, ciL ); 2153d3b0591SJens Wiklander if( p == NULL ) 2163d3b0591SJens Wiklander return( MBEDTLS_ERR_MPI_ALLOC_FAILED ); 2173d3b0591SJens Wiklander } 21818c5148dSJens Wiklander 219817466cbSJens Wiklander if( X->p != NULL ) 220817466cbSJens Wiklander { 221817466cbSJens Wiklander memcpy( p, X->p, i * ciL ); 222817466cbSJens Wiklander mbedtls_mpi_zeroize( X->p, X->n ); 2233d3b0591SJens Wiklander if( X->use_mempool ) 22418c5148dSJens Wiklander mempool_free( mbedtls_mpi_mempool, X->p ); 2253d3b0591SJens Wiklander else 2263d3b0591SJens Wiklander mbedtls_free( X->p ); 227817466cbSJens Wiklander } 228817466cbSJens Wiklander 22918c5148dSJens Wiklander X->n = i; 2303d3b0591SJens Wiklander X->p = p; 231817466cbSJens Wiklander 232817466cbSJens Wiklander return( 0 ); 233817466cbSJens Wiklander } 234817466cbSJens Wiklander 235817466cbSJens Wiklander /* 236817466cbSJens Wiklander * Copy the contents of Y into X 237817466cbSJens Wiklander */ 238817466cbSJens Wiklander int mbedtls_mpi_copy( mbedtls_mpi *X, const mbedtls_mpi *Y ) 239817466cbSJens Wiklander { 2403d3b0591SJens Wiklander int ret = 0; 241817466cbSJens Wiklander size_t i; 2423d3b0591SJens Wiklander MPI_VALIDATE_RET( X != NULL ); 2433d3b0591SJens Wiklander MPI_VALIDATE_RET( Y != NULL ); 244817466cbSJens Wiklander 245817466cbSJens Wiklander if( X == Y ) 246817466cbSJens Wiklander return( 0 ); 247817466cbSJens Wiklander 248817466cbSJens Wiklander if( Y->p == NULL ) 249817466cbSJens Wiklander { 250817466cbSJens Wiklander mbedtls_mpi_free( X ); 251817466cbSJens Wiklander return( 0 ); 252817466cbSJens Wiklander } 253817466cbSJens Wiklander 254817466cbSJens Wiklander for( i = Y->n - 1; i > 0; i-- ) 255817466cbSJens Wiklander if( Y->p[i] != 0 ) 256817466cbSJens Wiklander break; 257817466cbSJens Wiklander i++; 258817466cbSJens Wiklander 259817466cbSJens Wiklander X->s = Y->s; 260817466cbSJens Wiklander 2613d3b0591SJens Wiklander if( X->n < i ) 2623d3b0591SJens Wiklander { 263817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, i ) ); 2643d3b0591SJens Wiklander } 2653d3b0591SJens Wiklander else 2663d3b0591SJens Wiklander { 2673d3b0591SJens Wiklander memset( X->p + i, 0, ( X->n - i ) * ciL ); 2683d3b0591SJens Wiklander } 269817466cbSJens Wiklander 270817466cbSJens Wiklander memcpy( X->p, Y->p, i * ciL ); 271817466cbSJens Wiklander 272817466cbSJens Wiklander cleanup: 273817466cbSJens Wiklander 274817466cbSJens Wiklander return( ret ); 275817466cbSJens Wiklander } 276817466cbSJens Wiklander 277817466cbSJens Wiklander /* 278817466cbSJens Wiklander * Swap the contents of X and Y 279817466cbSJens Wiklander */ 280817466cbSJens Wiklander void mbedtls_mpi_swap( mbedtls_mpi *X, mbedtls_mpi *Y ) 281817466cbSJens Wiklander { 282817466cbSJens Wiklander mbedtls_mpi T; 2833d3b0591SJens Wiklander MPI_VALIDATE( X != NULL ); 2843d3b0591SJens Wiklander MPI_VALIDATE( Y != NULL ); 285817466cbSJens Wiklander 286817466cbSJens Wiklander memcpy( &T, X, sizeof( mbedtls_mpi ) ); 287817466cbSJens Wiklander memcpy( X, Y, sizeof( mbedtls_mpi ) ); 288817466cbSJens Wiklander memcpy( Y, &T, sizeof( mbedtls_mpi ) ); 289817466cbSJens Wiklander } 290817466cbSJens Wiklander 291817466cbSJens Wiklander /* 292817466cbSJens Wiklander * Conditionally assign X = Y, without leaking information 293817466cbSJens Wiklander * about whether the assignment was made or not. 294817466cbSJens Wiklander * (Leaking information about the respective sizes of X and Y is ok however.) 295817466cbSJens Wiklander */ 296817466cbSJens Wiklander int mbedtls_mpi_safe_cond_assign( mbedtls_mpi *X, const mbedtls_mpi *Y, unsigned char assign ) 297817466cbSJens Wiklander { 298817466cbSJens Wiklander int ret = 0; 299817466cbSJens Wiklander size_t i; 3003d3b0591SJens Wiklander MPI_VALIDATE_RET( X != NULL ); 3013d3b0591SJens Wiklander MPI_VALIDATE_RET( Y != NULL ); 302817466cbSJens Wiklander 303817466cbSJens Wiklander /* make sure assign is 0 or 1 in a time-constant manner */ 304817466cbSJens Wiklander assign = (assign | (unsigned char)-assign) >> 7; 305817466cbSJens Wiklander 306817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, Y->n ) ); 307817466cbSJens Wiklander 308817466cbSJens Wiklander X->s = X->s * ( 1 - assign ) + Y->s * assign; 309817466cbSJens Wiklander 310817466cbSJens Wiklander for( i = 0; i < Y->n; i++ ) 311817466cbSJens Wiklander X->p[i] = X->p[i] * ( 1 - assign ) + Y->p[i] * assign; 312817466cbSJens Wiklander 313817466cbSJens Wiklander for( ; i < X->n; i++ ) 314817466cbSJens Wiklander X->p[i] *= ( 1 - assign ); 315817466cbSJens Wiklander 316817466cbSJens Wiklander cleanup: 317817466cbSJens Wiklander return( ret ); 318817466cbSJens Wiklander } 319817466cbSJens Wiklander 320817466cbSJens Wiklander /* 321817466cbSJens Wiklander * Conditionally swap X and Y, without leaking information 322817466cbSJens Wiklander * about whether the swap was made or not. 323817466cbSJens Wiklander * Here it is not ok to simply swap the pointers, which whould lead to 324817466cbSJens Wiklander * different memory access patterns when X and Y are used afterwards. 325817466cbSJens Wiklander */ 326817466cbSJens Wiklander int mbedtls_mpi_safe_cond_swap( mbedtls_mpi *X, mbedtls_mpi *Y, unsigned char swap ) 327817466cbSJens Wiklander { 328817466cbSJens Wiklander int ret, s; 329817466cbSJens Wiklander size_t i; 330817466cbSJens Wiklander mbedtls_mpi_uint tmp; 3313d3b0591SJens Wiklander MPI_VALIDATE_RET( X != NULL ); 3323d3b0591SJens Wiklander MPI_VALIDATE_RET( Y != NULL ); 333817466cbSJens Wiklander 334817466cbSJens Wiklander if( X == Y ) 335817466cbSJens Wiklander return( 0 ); 336817466cbSJens Wiklander 337817466cbSJens Wiklander /* make sure swap is 0 or 1 in a time-constant manner */ 338817466cbSJens Wiklander swap = (swap | (unsigned char)-swap) >> 7; 339817466cbSJens Wiklander 340817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, Y->n ) ); 341817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_grow( Y, X->n ) ); 342817466cbSJens Wiklander 343817466cbSJens Wiklander s = X->s; 344817466cbSJens Wiklander X->s = X->s * ( 1 - swap ) + Y->s * swap; 345817466cbSJens Wiklander Y->s = Y->s * ( 1 - swap ) + s * swap; 346817466cbSJens Wiklander 347817466cbSJens Wiklander 348817466cbSJens Wiklander for( i = 0; i < X->n; i++ ) 349817466cbSJens Wiklander { 350817466cbSJens Wiklander tmp = X->p[i]; 351817466cbSJens Wiklander X->p[i] = X->p[i] * ( 1 - swap ) + Y->p[i] * swap; 352817466cbSJens Wiklander Y->p[i] = Y->p[i] * ( 1 - swap ) + tmp * swap; 353817466cbSJens Wiklander } 354817466cbSJens Wiklander 355817466cbSJens Wiklander cleanup: 356817466cbSJens Wiklander return( ret ); 357817466cbSJens Wiklander } 358817466cbSJens Wiklander 359817466cbSJens Wiklander /* 360817466cbSJens Wiklander * Set value from integer 361817466cbSJens Wiklander */ 362817466cbSJens Wiklander int mbedtls_mpi_lset( mbedtls_mpi *X, mbedtls_mpi_sint z ) 363817466cbSJens Wiklander { 364817466cbSJens Wiklander int ret; 3653d3b0591SJens Wiklander MPI_VALIDATE_RET( X != NULL ); 366817466cbSJens Wiklander 367817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, 1 ) ); 368817466cbSJens Wiklander memset( X->p, 0, X->n * ciL ); 369817466cbSJens Wiklander 370817466cbSJens Wiklander X->p[0] = ( z < 0 ) ? -z : z; 371817466cbSJens Wiklander X->s = ( z < 0 ) ? -1 : 1; 372817466cbSJens Wiklander 373817466cbSJens Wiklander cleanup: 374817466cbSJens Wiklander 375817466cbSJens Wiklander return( ret ); 376817466cbSJens Wiklander } 377817466cbSJens Wiklander 378817466cbSJens Wiklander /* 379817466cbSJens Wiklander * Get a specific bit 380817466cbSJens Wiklander */ 381817466cbSJens Wiklander int mbedtls_mpi_get_bit( const mbedtls_mpi *X, size_t pos ) 382817466cbSJens Wiklander { 3833d3b0591SJens Wiklander MPI_VALIDATE_RET( X != NULL ); 3843d3b0591SJens Wiklander 385817466cbSJens Wiklander if( X->n * biL <= pos ) 386817466cbSJens Wiklander return( 0 ); 387817466cbSJens Wiklander 388817466cbSJens Wiklander return( ( X->p[pos / biL] >> ( pos % biL ) ) & 0x01 ); 389817466cbSJens Wiklander } 390817466cbSJens Wiklander 3913d3b0591SJens Wiklander /* Get a specific byte, without range checks. */ 3923d3b0591SJens Wiklander #define GET_BYTE( X, i ) \ 3933d3b0591SJens Wiklander ( ( ( X )->p[( i ) / ciL] >> ( ( ( i ) % ciL ) * 8 ) ) & 0xff ) 3943d3b0591SJens Wiklander 395817466cbSJens Wiklander /* 396817466cbSJens Wiklander * Set a bit to a specific value of 0 or 1 397817466cbSJens Wiklander */ 398817466cbSJens Wiklander int mbedtls_mpi_set_bit( mbedtls_mpi *X, size_t pos, unsigned char val ) 399817466cbSJens Wiklander { 400817466cbSJens Wiklander int ret = 0; 401817466cbSJens Wiklander size_t off = pos / biL; 402817466cbSJens Wiklander size_t idx = pos % biL; 4033d3b0591SJens Wiklander MPI_VALIDATE_RET( X != NULL ); 404817466cbSJens Wiklander 405817466cbSJens Wiklander if( val != 0 && val != 1 ) 406817466cbSJens Wiklander return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); 407817466cbSJens Wiklander 408817466cbSJens Wiklander if( X->n * biL <= pos ) 409817466cbSJens Wiklander { 410817466cbSJens Wiklander if( val == 0 ) 411817466cbSJens Wiklander return( 0 ); 412817466cbSJens Wiklander 413817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, off + 1 ) ); 414817466cbSJens Wiklander } 415817466cbSJens Wiklander 416817466cbSJens Wiklander X->p[off] &= ~( (mbedtls_mpi_uint) 0x01 << idx ); 417817466cbSJens Wiklander X->p[off] |= (mbedtls_mpi_uint) val << idx; 418817466cbSJens Wiklander 419817466cbSJens Wiklander cleanup: 420817466cbSJens Wiklander 421817466cbSJens Wiklander return( ret ); 422817466cbSJens Wiklander } 423817466cbSJens Wiklander 424817466cbSJens Wiklander /* 425817466cbSJens Wiklander * Return the number of less significant zero-bits 426817466cbSJens Wiklander */ 427817466cbSJens Wiklander size_t mbedtls_mpi_lsb( const mbedtls_mpi *X ) 428817466cbSJens Wiklander { 429817466cbSJens Wiklander size_t i, j, count = 0; 4303d3b0591SJens Wiklander MBEDTLS_INTERNAL_VALIDATE_RET( X != NULL, 0 ); 431817466cbSJens Wiklander 432817466cbSJens Wiklander for( i = 0; i < X->n; i++ ) 433817466cbSJens Wiklander for( j = 0; j < biL; j++, count++ ) 434817466cbSJens Wiklander if( ( ( X->p[i] >> j ) & 1 ) != 0 ) 435817466cbSJens Wiklander return( count ); 436817466cbSJens Wiklander 437817466cbSJens Wiklander return( 0 ); 438817466cbSJens Wiklander } 439817466cbSJens Wiklander 440817466cbSJens Wiklander /* 441817466cbSJens Wiklander * Count leading zero bits in a given integer 442817466cbSJens Wiklander */ 443817466cbSJens Wiklander static size_t mbedtls_clz( const mbedtls_mpi_uint x ) 444817466cbSJens Wiklander { 445817466cbSJens Wiklander size_t j; 446817466cbSJens Wiklander mbedtls_mpi_uint mask = (mbedtls_mpi_uint) 1 << (biL - 1); 447817466cbSJens Wiklander 448817466cbSJens Wiklander for( j = 0; j < biL; j++ ) 449817466cbSJens Wiklander { 450817466cbSJens Wiklander if( x & mask ) break; 451817466cbSJens Wiklander 452817466cbSJens Wiklander mask >>= 1; 453817466cbSJens Wiklander } 454817466cbSJens Wiklander 455817466cbSJens Wiklander return j; 456817466cbSJens Wiklander } 457817466cbSJens Wiklander 458817466cbSJens Wiklander /* 459817466cbSJens Wiklander * Return the number of bits 460817466cbSJens Wiklander */ 461817466cbSJens Wiklander size_t mbedtls_mpi_bitlen( const mbedtls_mpi *X ) 462817466cbSJens Wiklander { 463817466cbSJens Wiklander size_t i, j; 464817466cbSJens Wiklander 465817466cbSJens Wiklander if( X->n == 0 ) 466817466cbSJens Wiklander return( 0 ); 467817466cbSJens Wiklander 468817466cbSJens Wiklander for( i = X->n - 1; i > 0; i-- ) 469817466cbSJens Wiklander if( X->p[i] != 0 ) 470817466cbSJens Wiklander break; 471817466cbSJens Wiklander 472817466cbSJens Wiklander j = biL - mbedtls_clz( X->p[i] ); 473817466cbSJens Wiklander 474817466cbSJens Wiklander return( ( i * biL ) + j ); 475817466cbSJens Wiklander } 476817466cbSJens Wiklander 477817466cbSJens Wiklander /* 478817466cbSJens Wiklander * Return the total size in bytes 479817466cbSJens Wiklander */ 480817466cbSJens Wiklander size_t mbedtls_mpi_size( const mbedtls_mpi *X ) 481817466cbSJens Wiklander { 482817466cbSJens Wiklander return( ( mbedtls_mpi_bitlen( X ) + 7 ) >> 3 ); 483817466cbSJens Wiklander } 484817466cbSJens Wiklander 485817466cbSJens Wiklander /* 486817466cbSJens Wiklander * Convert an ASCII character to digit value 487817466cbSJens Wiklander */ 488817466cbSJens Wiklander static int mpi_get_digit( mbedtls_mpi_uint *d, int radix, char c ) 489817466cbSJens Wiklander { 490817466cbSJens Wiklander *d = 255; 491817466cbSJens Wiklander 492817466cbSJens Wiklander if( c >= 0x30 && c <= 0x39 ) *d = c - 0x30; 493817466cbSJens Wiklander if( c >= 0x41 && c <= 0x46 ) *d = c - 0x37; 494817466cbSJens Wiklander if( c >= 0x61 && c <= 0x66 ) *d = c - 0x57; 495817466cbSJens Wiklander 496817466cbSJens Wiklander if( *d >= (mbedtls_mpi_uint) radix ) 497817466cbSJens Wiklander return( MBEDTLS_ERR_MPI_INVALID_CHARACTER ); 498817466cbSJens Wiklander 499817466cbSJens Wiklander return( 0 ); 500817466cbSJens Wiklander } 501817466cbSJens Wiklander 502817466cbSJens Wiklander /* 503817466cbSJens Wiklander * Import from an ASCII string 504817466cbSJens Wiklander */ 505817466cbSJens Wiklander int mbedtls_mpi_read_string( mbedtls_mpi *X, int radix, const char *s ) 506817466cbSJens Wiklander { 507817466cbSJens Wiklander int ret; 508817466cbSJens Wiklander size_t i, j, slen, n; 509817466cbSJens Wiklander mbedtls_mpi_uint d; 510817466cbSJens Wiklander mbedtls_mpi T; 5113d3b0591SJens Wiklander MPI_VALIDATE_RET( X != NULL ); 5123d3b0591SJens Wiklander MPI_VALIDATE_RET( s != NULL ); 513817466cbSJens Wiklander 514817466cbSJens Wiklander if( radix < 2 || radix > 16 ) 515817466cbSJens Wiklander return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); 516817466cbSJens Wiklander 51798bd5fe3SJens Wiklander mbedtls_mpi_init_mempool( &T ); 518817466cbSJens Wiklander 519817466cbSJens Wiklander slen = strlen( s ); 520817466cbSJens Wiklander 521817466cbSJens Wiklander if( radix == 16 ) 522817466cbSJens Wiklander { 523817466cbSJens Wiklander if( slen > MPI_SIZE_T_MAX >> 2 ) 524817466cbSJens Wiklander return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); 525817466cbSJens Wiklander 526817466cbSJens Wiklander n = BITS_TO_LIMBS( slen << 2 ); 527817466cbSJens Wiklander 528817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, n ) ); 529817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) ); 530817466cbSJens Wiklander 531817466cbSJens Wiklander for( i = slen, j = 0; i > 0; i--, j++ ) 532817466cbSJens Wiklander { 533817466cbSJens Wiklander if( i == 1 && s[i - 1] == '-' ) 534817466cbSJens Wiklander { 535817466cbSJens Wiklander X->s = -1; 536817466cbSJens Wiklander break; 537817466cbSJens Wiklander } 538817466cbSJens Wiklander 539817466cbSJens Wiklander MBEDTLS_MPI_CHK( mpi_get_digit( &d, radix, s[i - 1] ) ); 540817466cbSJens Wiklander X->p[j / ( 2 * ciL )] |= d << ( ( j % ( 2 * ciL ) ) << 2 ); 541817466cbSJens Wiklander } 542817466cbSJens Wiklander } 543817466cbSJens Wiklander else 544817466cbSJens Wiklander { 545817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) ); 546817466cbSJens Wiklander 547817466cbSJens Wiklander for( i = 0; i < slen; i++ ) 548817466cbSJens Wiklander { 549817466cbSJens Wiklander if( i == 0 && s[i] == '-' ) 550817466cbSJens Wiklander { 551817466cbSJens Wiklander X->s = -1; 552817466cbSJens Wiklander continue; 553817466cbSJens Wiklander } 554817466cbSJens Wiklander 555817466cbSJens Wiklander MBEDTLS_MPI_CHK( mpi_get_digit( &d, radix, s[i] ) ); 556817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &T, X, radix ) ); 557817466cbSJens Wiklander 558817466cbSJens Wiklander if( X->s == 1 ) 559817466cbSJens Wiklander { 560817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, &T, d ) ); 561817466cbSJens Wiklander } 562817466cbSJens Wiklander else 563817466cbSJens Wiklander { 564817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( X, &T, d ) ); 565817466cbSJens Wiklander } 566817466cbSJens Wiklander } 567817466cbSJens Wiklander } 568817466cbSJens Wiklander 569817466cbSJens Wiklander cleanup: 570817466cbSJens Wiklander 571817466cbSJens Wiklander mbedtls_mpi_free( &T ); 572817466cbSJens Wiklander 573817466cbSJens Wiklander return( ret ); 574817466cbSJens Wiklander } 575817466cbSJens Wiklander 576817466cbSJens Wiklander /* 577817466cbSJens Wiklander * Helper to write the digits high-order first 578817466cbSJens Wiklander */ 579817466cbSJens Wiklander static int mpi_write_hlp( mbedtls_mpi *X, int radix, char **p ) 580817466cbSJens Wiklander { 581817466cbSJens Wiklander int ret; 582817466cbSJens Wiklander mbedtls_mpi_uint r; 583817466cbSJens Wiklander 584817466cbSJens Wiklander if( radix < 2 || radix > 16 ) 585817466cbSJens Wiklander return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); 586817466cbSJens Wiklander 587817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_mod_int( &r, X, radix ) ); 588817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_div_int( X, NULL, X, radix ) ); 589817466cbSJens Wiklander 590817466cbSJens Wiklander if( mbedtls_mpi_cmp_int( X, 0 ) != 0 ) 591817466cbSJens Wiklander MBEDTLS_MPI_CHK( mpi_write_hlp( X, radix, p ) ); 592817466cbSJens Wiklander 593817466cbSJens Wiklander if( r < 10 ) 594817466cbSJens Wiklander *(*p)++ = (char)( r + 0x30 ); 595817466cbSJens Wiklander else 596817466cbSJens Wiklander *(*p)++ = (char)( r + 0x37 ); 597817466cbSJens Wiklander 598817466cbSJens Wiklander cleanup: 599817466cbSJens Wiklander 600817466cbSJens Wiklander return( ret ); 601817466cbSJens Wiklander } 602817466cbSJens Wiklander 603817466cbSJens Wiklander /* 604817466cbSJens Wiklander * Export into an ASCII string 605817466cbSJens Wiklander */ 606817466cbSJens Wiklander int mbedtls_mpi_write_string( const mbedtls_mpi *X, int radix, 607817466cbSJens Wiklander char *buf, size_t buflen, size_t *olen ) 608817466cbSJens Wiklander { 609817466cbSJens Wiklander int ret = 0; 610817466cbSJens Wiklander size_t n; 611817466cbSJens Wiklander char *p; 612817466cbSJens Wiklander mbedtls_mpi T; 6133d3b0591SJens Wiklander MPI_VALIDATE_RET( X != NULL ); 6143d3b0591SJens Wiklander MPI_VALIDATE_RET( olen != NULL ); 6153d3b0591SJens Wiklander MPI_VALIDATE_RET( buflen == 0 || buf != NULL ); 616817466cbSJens Wiklander 617817466cbSJens Wiklander if( radix < 2 || radix > 16 ) 618817466cbSJens Wiklander return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); 619817466cbSJens Wiklander 620817466cbSJens Wiklander n = mbedtls_mpi_bitlen( X ); 621817466cbSJens Wiklander if( radix >= 4 ) n >>= 1; 622817466cbSJens Wiklander if( radix >= 16 ) n >>= 1; 623817466cbSJens Wiklander /* 624817466cbSJens Wiklander * Round up the buffer length to an even value to ensure that there is 625817466cbSJens Wiklander * enough room for hexadecimal values that can be represented in an odd 626817466cbSJens Wiklander * number of digits. 627817466cbSJens Wiklander */ 628817466cbSJens Wiklander n += 3 + ( ( n + 1 ) & 1 ); 629817466cbSJens Wiklander 630817466cbSJens Wiklander if( buflen < n ) 631817466cbSJens Wiklander { 632817466cbSJens Wiklander *olen = n; 633817466cbSJens Wiklander return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL ); 634817466cbSJens Wiklander } 635817466cbSJens Wiklander 636817466cbSJens Wiklander p = buf; 63798bd5fe3SJens Wiklander mbedtls_mpi_init_mempool( &T ); 638817466cbSJens Wiklander 639817466cbSJens Wiklander if( X->s == -1 ) 640817466cbSJens Wiklander *p++ = '-'; 641817466cbSJens Wiklander 642817466cbSJens Wiklander if( radix == 16 ) 643817466cbSJens Wiklander { 644817466cbSJens Wiklander int c; 645817466cbSJens Wiklander size_t i, j, k; 646817466cbSJens Wiklander 647817466cbSJens Wiklander for( i = X->n, k = 0; i > 0; i-- ) 648817466cbSJens Wiklander { 649817466cbSJens Wiklander for( j = ciL; j > 0; j-- ) 650817466cbSJens Wiklander { 651817466cbSJens Wiklander c = ( X->p[i - 1] >> ( ( j - 1 ) << 3) ) & 0xFF; 652817466cbSJens Wiklander 653817466cbSJens Wiklander if( c == 0 && k == 0 && ( i + j ) != 2 ) 654817466cbSJens Wiklander continue; 655817466cbSJens Wiklander 656817466cbSJens Wiklander *(p++) = "0123456789ABCDEF" [c / 16]; 657817466cbSJens Wiklander *(p++) = "0123456789ABCDEF" [c % 16]; 658817466cbSJens Wiklander k = 1; 659817466cbSJens Wiklander } 660817466cbSJens Wiklander } 661817466cbSJens Wiklander } 662817466cbSJens Wiklander else 663817466cbSJens Wiklander { 664817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &T, X ) ); 665817466cbSJens Wiklander 666817466cbSJens Wiklander if( T.s == -1 ) 667817466cbSJens Wiklander T.s = 1; 668817466cbSJens Wiklander 669817466cbSJens Wiklander MBEDTLS_MPI_CHK( mpi_write_hlp( &T, radix, &p ) ); 670817466cbSJens Wiklander } 671817466cbSJens Wiklander 672817466cbSJens Wiklander *p++ = '\0'; 673817466cbSJens Wiklander *olen = p - buf; 674817466cbSJens Wiklander 675817466cbSJens Wiklander cleanup: 676817466cbSJens Wiklander 677817466cbSJens Wiklander mbedtls_mpi_free( &T ); 678817466cbSJens Wiklander 679817466cbSJens Wiklander return( ret ); 680817466cbSJens Wiklander } 681817466cbSJens Wiklander 682817466cbSJens Wiklander #if defined(MBEDTLS_FS_IO) 683817466cbSJens Wiklander /* 684817466cbSJens Wiklander * Read X from an opened file 685817466cbSJens Wiklander */ 686817466cbSJens Wiklander int mbedtls_mpi_read_file( mbedtls_mpi *X, int radix, FILE *fin ) 687817466cbSJens Wiklander { 688817466cbSJens Wiklander mbedtls_mpi_uint d; 689817466cbSJens Wiklander size_t slen; 690817466cbSJens Wiklander char *p; 691817466cbSJens Wiklander /* 692817466cbSJens Wiklander * Buffer should have space for (short) label and decimal formatted MPI, 693817466cbSJens Wiklander * newline characters and '\0' 694817466cbSJens Wiklander */ 695817466cbSJens Wiklander char s[ MBEDTLS_MPI_RW_BUFFER_SIZE ]; 696817466cbSJens Wiklander 6973d3b0591SJens Wiklander MPI_VALIDATE_RET( X != NULL ); 6983d3b0591SJens Wiklander MPI_VALIDATE_RET( fin != NULL ); 6993d3b0591SJens Wiklander 7003d3b0591SJens Wiklander if( radix < 2 || radix > 16 ) 7013d3b0591SJens Wiklander return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); 7023d3b0591SJens Wiklander 703817466cbSJens Wiklander memset( s, 0, sizeof( s ) ); 704817466cbSJens Wiklander if( fgets( s, sizeof( s ) - 1, fin ) == NULL ) 705817466cbSJens Wiklander return( MBEDTLS_ERR_MPI_FILE_IO_ERROR ); 706817466cbSJens Wiklander 707817466cbSJens Wiklander slen = strlen( s ); 708817466cbSJens Wiklander if( slen == sizeof( s ) - 2 ) 709817466cbSJens Wiklander return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL ); 710817466cbSJens Wiklander 711817466cbSJens Wiklander if( slen > 0 && s[slen - 1] == '\n' ) { slen--; s[slen] = '\0'; } 712817466cbSJens Wiklander if( slen > 0 && s[slen - 1] == '\r' ) { slen--; s[slen] = '\0'; } 713817466cbSJens Wiklander 714817466cbSJens Wiklander p = s + slen; 715817466cbSJens Wiklander while( p-- > s ) 716817466cbSJens Wiklander if( mpi_get_digit( &d, radix, *p ) != 0 ) 717817466cbSJens Wiklander break; 718817466cbSJens Wiklander 719817466cbSJens Wiklander return( mbedtls_mpi_read_string( X, radix, p + 1 ) ); 720817466cbSJens Wiklander } 721817466cbSJens Wiklander 722817466cbSJens Wiklander /* 723817466cbSJens Wiklander * Write X into an opened file (or stdout if fout == NULL) 724817466cbSJens Wiklander */ 725817466cbSJens Wiklander int mbedtls_mpi_write_file( const char *p, const mbedtls_mpi *X, int radix, FILE *fout ) 726817466cbSJens Wiklander { 727817466cbSJens Wiklander int ret; 728817466cbSJens Wiklander size_t n, slen, plen; 729817466cbSJens Wiklander /* 730817466cbSJens Wiklander * Buffer should have space for (short) label and decimal formatted MPI, 731817466cbSJens Wiklander * newline characters and '\0' 732817466cbSJens Wiklander */ 733817466cbSJens Wiklander char s[ MBEDTLS_MPI_RW_BUFFER_SIZE ]; 7343d3b0591SJens Wiklander MPI_VALIDATE_RET( X != NULL ); 7353d3b0591SJens Wiklander 7363d3b0591SJens Wiklander if( radix < 2 || radix > 16 ) 7373d3b0591SJens Wiklander return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); 738817466cbSJens Wiklander 739817466cbSJens Wiklander memset( s, 0, sizeof( s ) ); 740817466cbSJens Wiklander 741817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_write_string( X, radix, s, sizeof( s ) - 2, &n ) ); 742817466cbSJens Wiklander 743817466cbSJens Wiklander if( p == NULL ) p = ""; 744817466cbSJens Wiklander 745817466cbSJens Wiklander plen = strlen( p ); 746817466cbSJens Wiklander slen = strlen( s ); 747817466cbSJens Wiklander s[slen++] = '\r'; 748817466cbSJens Wiklander s[slen++] = '\n'; 749817466cbSJens Wiklander 750817466cbSJens Wiklander if( fout != NULL ) 751817466cbSJens Wiklander { 752817466cbSJens Wiklander if( fwrite( p, 1, plen, fout ) != plen || 753817466cbSJens Wiklander fwrite( s, 1, slen, fout ) != slen ) 754817466cbSJens Wiklander return( MBEDTLS_ERR_MPI_FILE_IO_ERROR ); 755817466cbSJens Wiklander } 756817466cbSJens Wiklander else 757817466cbSJens Wiklander mbedtls_printf( "%s%s", p, s ); 758817466cbSJens Wiklander 759817466cbSJens Wiklander cleanup: 760817466cbSJens Wiklander 761817466cbSJens Wiklander return( ret ); 762817466cbSJens Wiklander } 763817466cbSJens Wiklander #endif /* MBEDTLS_FS_IO */ 764817466cbSJens Wiklander 765817466cbSJens Wiklander /* 766817466cbSJens Wiklander * Import X from unsigned binary data, big endian 767817466cbSJens Wiklander */ 768817466cbSJens Wiklander int mbedtls_mpi_read_binary( mbedtls_mpi *X, const unsigned char *buf, size_t buflen ) 769817466cbSJens Wiklander { 770817466cbSJens Wiklander int ret; 7713d3b0591SJens Wiklander size_t i, j; 7723d3b0591SJens Wiklander size_t const limbs = CHARS_TO_LIMBS( buflen ); 773817466cbSJens Wiklander 7743d3b0591SJens Wiklander MPI_VALIDATE_RET( X != NULL ); 7753d3b0591SJens Wiklander MPI_VALIDATE_RET( buflen == 0 || buf != NULL ); 776817466cbSJens Wiklander 7773d3b0591SJens Wiklander /* Ensure that target MPI has exactly the necessary number of limbs */ 7783d3b0591SJens Wiklander if( X->n != limbs ) 7793d3b0591SJens Wiklander { 7803d3b0591SJens Wiklander mbedtls_mpi_free( X ); 7813d3b0591SJens Wiklander mbedtls_mpi_init( X ); 7823d3b0591SJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, limbs ) ); 7833d3b0591SJens Wiklander } 7843d3b0591SJens Wiklander 785817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) ); 786817466cbSJens Wiklander 7873d3b0591SJens Wiklander for( i = buflen, j = 0; i > 0; i--, j++ ) 788817466cbSJens Wiklander X->p[j / ciL] |= ((mbedtls_mpi_uint) buf[i - 1]) << ((j % ciL) << 3); 789817466cbSJens Wiklander 790817466cbSJens Wiklander cleanup: 791817466cbSJens Wiklander 792817466cbSJens Wiklander return( ret ); 793817466cbSJens Wiklander } 794817466cbSJens Wiklander 795817466cbSJens Wiklander /* 796817466cbSJens Wiklander * Export X into unsigned binary data, big endian 797817466cbSJens Wiklander */ 7983d3b0591SJens Wiklander int mbedtls_mpi_write_binary( const mbedtls_mpi *X, 7993d3b0591SJens Wiklander unsigned char *buf, size_t buflen ) 800817466cbSJens Wiklander { 8013d3b0591SJens Wiklander size_t stored_bytes; 8023d3b0591SJens Wiklander size_t bytes_to_copy; 8033d3b0591SJens Wiklander unsigned char *p; 8043d3b0591SJens Wiklander size_t i; 805817466cbSJens Wiklander 8063d3b0591SJens Wiklander MPI_VALIDATE_RET( X != NULL ); 8073d3b0591SJens Wiklander MPI_VALIDATE_RET( buflen == 0 || buf != NULL ); 808817466cbSJens Wiklander 8093d3b0591SJens Wiklander stored_bytes = X->n * ciL; 8103d3b0591SJens Wiklander 8113d3b0591SJens Wiklander if( stored_bytes < buflen ) 8123d3b0591SJens Wiklander { 8133d3b0591SJens Wiklander /* There is enough space in the output buffer. Write initial 8143d3b0591SJens Wiklander * null bytes and record the position at which to start 8153d3b0591SJens Wiklander * writing the significant bytes. In this case, the execution 8163d3b0591SJens Wiklander * trace of this function does not depend on the value of the 8173d3b0591SJens Wiklander * number. */ 8183d3b0591SJens Wiklander bytes_to_copy = stored_bytes; 8193d3b0591SJens Wiklander p = buf + buflen - stored_bytes; 8203d3b0591SJens Wiklander memset( buf, 0, buflen - stored_bytes ); 8213d3b0591SJens Wiklander } 8223d3b0591SJens Wiklander else 8233d3b0591SJens Wiklander { 8243d3b0591SJens Wiklander /* The output buffer is smaller than the allocated size of X. 8253d3b0591SJens Wiklander * However X may fit if its leading bytes are zero. */ 8263d3b0591SJens Wiklander bytes_to_copy = buflen; 8273d3b0591SJens Wiklander p = buf; 8283d3b0591SJens Wiklander for( i = bytes_to_copy; i < stored_bytes; i++ ) 8293d3b0591SJens Wiklander { 8303d3b0591SJens Wiklander if( GET_BYTE( X, i ) != 0 ) 831817466cbSJens Wiklander return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL ); 8323d3b0591SJens Wiklander } 8333d3b0591SJens Wiklander } 834817466cbSJens Wiklander 8353d3b0591SJens Wiklander for( i = 0; i < bytes_to_copy; i++ ) 8363d3b0591SJens Wiklander p[bytes_to_copy - i - 1] = GET_BYTE( X, i ); 837817466cbSJens Wiklander 838817466cbSJens Wiklander return( 0 ); 839817466cbSJens Wiklander } 840817466cbSJens Wiklander 841817466cbSJens Wiklander /* 842817466cbSJens Wiklander * Left-shift: X <<= count 843817466cbSJens Wiklander */ 844817466cbSJens Wiklander int mbedtls_mpi_shift_l( mbedtls_mpi *X, size_t count ) 845817466cbSJens Wiklander { 846817466cbSJens Wiklander int ret; 847817466cbSJens Wiklander size_t i, v0, t1; 848817466cbSJens Wiklander mbedtls_mpi_uint r0 = 0, r1; 8493d3b0591SJens Wiklander MPI_VALIDATE_RET( X != NULL ); 850817466cbSJens Wiklander 851817466cbSJens Wiklander v0 = count / (biL ); 852817466cbSJens Wiklander t1 = count & (biL - 1); 853817466cbSJens Wiklander 854817466cbSJens Wiklander i = mbedtls_mpi_bitlen( X ) + count; 855817466cbSJens Wiklander 856817466cbSJens Wiklander if( X->n * biL < i ) 857817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, BITS_TO_LIMBS( i ) ) ); 858817466cbSJens Wiklander 859817466cbSJens Wiklander ret = 0; 860817466cbSJens Wiklander 861817466cbSJens Wiklander /* 862817466cbSJens Wiklander * shift by count / limb_size 863817466cbSJens Wiklander */ 864817466cbSJens Wiklander if( v0 > 0 ) 865817466cbSJens Wiklander { 866817466cbSJens Wiklander for( i = X->n; i > v0; i-- ) 867817466cbSJens Wiklander X->p[i - 1] = X->p[i - v0 - 1]; 868817466cbSJens Wiklander 869817466cbSJens Wiklander for( ; i > 0; i-- ) 870817466cbSJens Wiklander X->p[i - 1] = 0; 871817466cbSJens Wiklander } 872817466cbSJens Wiklander 873817466cbSJens Wiklander /* 874817466cbSJens Wiklander * shift by count % limb_size 875817466cbSJens Wiklander */ 876817466cbSJens Wiklander if( t1 > 0 ) 877817466cbSJens Wiklander { 878817466cbSJens Wiklander for( i = v0; i < X->n; i++ ) 879817466cbSJens Wiklander { 880817466cbSJens Wiklander r1 = X->p[i] >> (biL - t1); 881817466cbSJens Wiklander X->p[i] <<= t1; 882817466cbSJens Wiklander X->p[i] |= r0; 883817466cbSJens Wiklander r0 = r1; 884817466cbSJens Wiklander } 885817466cbSJens Wiklander } 886817466cbSJens Wiklander 887817466cbSJens Wiklander cleanup: 888817466cbSJens Wiklander 889817466cbSJens Wiklander return( ret ); 890817466cbSJens Wiklander } 891817466cbSJens Wiklander 892817466cbSJens Wiklander /* 893817466cbSJens Wiklander * Right-shift: X >>= count 894817466cbSJens Wiklander */ 895817466cbSJens Wiklander int mbedtls_mpi_shift_r( mbedtls_mpi *X, size_t count ) 896817466cbSJens Wiklander { 897817466cbSJens Wiklander size_t i, v0, v1; 898817466cbSJens Wiklander mbedtls_mpi_uint r0 = 0, r1; 8993d3b0591SJens Wiklander MPI_VALIDATE_RET( X != NULL ); 900817466cbSJens Wiklander 901817466cbSJens Wiklander v0 = count / biL; 902817466cbSJens Wiklander v1 = count & (biL - 1); 903817466cbSJens Wiklander 904817466cbSJens Wiklander if( v0 > X->n || ( v0 == X->n && v1 > 0 ) ) 905817466cbSJens Wiklander return mbedtls_mpi_lset( X, 0 ); 906817466cbSJens Wiklander 907817466cbSJens Wiklander /* 908817466cbSJens Wiklander * shift by count / limb_size 909817466cbSJens Wiklander */ 910817466cbSJens Wiklander if( v0 > 0 ) 911817466cbSJens Wiklander { 912817466cbSJens Wiklander for( i = 0; i < X->n - v0; i++ ) 913817466cbSJens Wiklander X->p[i] = X->p[i + v0]; 914817466cbSJens Wiklander 915817466cbSJens Wiklander for( ; i < X->n; i++ ) 916817466cbSJens Wiklander X->p[i] = 0; 917817466cbSJens Wiklander } 918817466cbSJens Wiklander 919817466cbSJens Wiklander /* 920817466cbSJens Wiklander * shift by count % limb_size 921817466cbSJens Wiklander */ 922817466cbSJens Wiklander if( v1 > 0 ) 923817466cbSJens Wiklander { 924817466cbSJens Wiklander for( i = X->n; i > 0; i-- ) 925817466cbSJens Wiklander { 926817466cbSJens Wiklander r1 = X->p[i - 1] << (biL - v1); 927817466cbSJens Wiklander X->p[i - 1] >>= v1; 928817466cbSJens Wiklander X->p[i - 1] |= r0; 929817466cbSJens Wiklander r0 = r1; 930817466cbSJens Wiklander } 931817466cbSJens Wiklander } 932817466cbSJens Wiklander 933817466cbSJens Wiklander return( 0 ); 934817466cbSJens Wiklander } 935817466cbSJens Wiklander 936817466cbSJens Wiklander /* 937817466cbSJens Wiklander * Compare unsigned values 938817466cbSJens Wiklander */ 939817466cbSJens Wiklander int mbedtls_mpi_cmp_abs( const mbedtls_mpi *X, const mbedtls_mpi *Y ) 940817466cbSJens Wiklander { 941817466cbSJens Wiklander size_t i, j; 9423d3b0591SJens Wiklander MPI_VALIDATE_RET( X != NULL ); 9433d3b0591SJens Wiklander MPI_VALIDATE_RET( Y != NULL ); 944817466cbSJens Wiklander 945817466cbSJens Wiklander for( i = X->n; i > 0; i-- ) 946817466cbSJens Wiklander if( X->p[i - 1] != 0 ) 947817466cbSJens Wiklander break; 948817466cbSJens Wiklander 949817466cbSJens Wiklander for( j = Y->n; j > 0; j-- ) 950817466cbSJens Wiklander if( Y->p[j - 1] != 0 ) 951817466cbSJens Wiklander break; 952817466cbSJens Wiklander 953817466cbSJens Wiklander if( i == 0 && j == 0 ) 954817466cbSJens Wiklander return( 0 ); 955817466cbSJens Wiklander 956817466cbSJens Wiklander if( i > j ) return( 1 ); 957817466cbSJens Wiklander if( j > i ) return( -1 ); 958817466cbSJens Wiklander 959817466cbSJens Wiklander for( ; i > 0; i-- ) 960817466cbSJens Wiklander { 961817466cbSJens Wiklander if( X->p[i - 1] > Y->p[i - 1] ) return( 1 ); 962817466cbSJens Wiklander if( X->p[i - 1] < Y->p[i - 1] ) return( -1 ); 963817466cbSJens Wiklander } 964817466cbSJens Wiklander 965817466cbSJens Wiklander return( 0 ); 966817466cbSJens Wiklander } 967817466cbSJens Wiklander 968817466cbSJens Wiklander /* 969817466cbSJens Wiklander * Compare signed values 970817466cbSJens Wiklander */ 971817466cbSJens Wiklander int mbedtls_mpi_cmp_mpi( const mbedtls_mpi *X, const mbedtls_mpi *Y ) 972817466cbSJens Wiklander { 973817466cbSJens Wiklander size_t i, j; 9743d3b0591SJens Wiklander MPI_VALIDATE_RET( X != NULL ); 9753d3b0591SJens Wiklander MPI_VALIDATE_RET( Y != NULL ); 976817466cbSJens Wiklander 977817466cbSJens Wiklander for( i = X->n; i > 0; i-- ) 978817466cbSJens Wiklander if( X->p[i - 1] != 0 ) 979817466cbSJens Wiklander break; 980817466cbSJens Wiklander 981817466cbSJens Wiklander for( j = Y->n; j > 0; j-- ) 982817466cbSJens Wiklander if( Y->p[j - 1] != 0 ) 983817466cbSJens Wiklander break; 984817466cbSJens Wiklander 985817466cbSJens Wiklander if( i == 0 && j == 0 ) 986817466cbSJens Wiklander return( 0 ); 987817466cbSJens Wiklander 988817466cbSJens Wiklander if( i > j ) return( X->s ); 989817466cbSJens Wiklander if( j > i ) return( -Y->s ); 990817466cbSJens Wiklander 991817466cbSJens Wiklander if( X->s > 0 && Y->s < 0 ) return( 1 ); 992817466cbSJens Wiklander if( Y->s > 0 && X->s < 0 ) return( -1 ); 993817466cbSJens Wiklander 994817466cbSJens Wiklander for( ; i > 0; i-- ) 995817466cbSJens Wiklander { 996817466cbSJens Wiklander if( X->p[i - 1] > Y->p[i - 1] ) return( X->s ); 997817466cbSJens Wiklander if( X->p[i - 1] < Y->p[i - 1] ) return( -X->s ); 998817466cbSJens Wiklander } 999817466cbSJens Wiklander 1000817466cbSJens Wiklander return( 0 ); 1001817466cbSJens Wiklander } 1002817466cbSJens Wiklander 1003817466cbSJens Wiklander /* 1004817466cbSJens Wiklander * Compare signed values 1005817466cbSJens Wiklander */ 1006817466cbSJens Wiklander int mbedtls_mpi_cmp_int( const mbedtls_mpi *X, mbedtls_mpi_sint z ) 1007817466cbSJens Wiklander { 1008817466cbSJens Wiklander mbedtls_mpi Y; 1009817466cbSJens Wiklander mbedtls_mpi_uint p[1]; 10103d3b0591SJens Wiklander MPI_VALIDATE_RET( X != NULL ); 1011817466cbSJens Wiklander 1012817466cbSJens Wiklander *p = ( z < 0 ) ? -z : z; 1013817466cbSJens Wiklander Y.s = ( z < 0 ) ? -1 : 1; 1014817466cbSJens Wiklander Y.n = 1; 1015817466cbSJens Wiklander Y.p = p; 1016817466cbSJens Wiklander 1017817466cbSJens Wiklander return( mbedtls_mpi_cmp_mpi( X, &Y ) ); 1018817466cbSJens Wiklander } 1019817466cbSJens Wiklander 1020817466cbSJens Wiklander /* 1021817466cbSJens Wiklander * Unsigned addition: X = |A| + |B| (HAC 14.7) 1022817466cbSJens Wiklander */ 1023817466cbSJens Wiklander int mbedtls_mpi_add_abs( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ) 1024817466cbSJens Wiklander { 1025817466cbSJens Wiklander int ret; 1026817466cbSJens Wiklander size_t i, j; 1027817466cbSJens Wiklander mbedtls_mpi_uint *o, *p, c, tmp; 10283d3b0591SJens Wiklander MPI_VALIDATE_RET( X != NULL ); 10293d3b0591SJens Wiklander MPI_VALIDATE_RET( A != NULL ); 10303d3b0591SJens Wiklander MPI_VALIDATE_RET( B != NULL ); 1031817466cbSJens Wiklander 1032817466cbSJens Wiklander if( X == B ) 1033817466cbSJens Wiklander { 1034817466cbSJens Wiklander const mbedtls_mpi *T = A; A = X; B = T; 1035817466cbSJens Wiklander } 1036817466cbSJens Wiklander 1037817466cbSJens Wiklander if( X != A ) 1038817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, A ) ); 1039817466cbSJens Wiklander 1040817466cbSJens Wiklander /* 1041817466cbSJens Wiklander * X should always be positive as a result of unsigned additions. 1042817466cbSJens Wiklander */ 1043817466cbSJens Wiklander X->s = 1; 1044817466cbSJens Wiklander 1045817466cbSJens Wiklander for( j = B->n; j > 0; j-- ) 1046817466cbSJens Wiklander if( B->p[j - 1] != 0 ) 1047817466cbSJens Wiklander break; 1048817466cbSJens Wiklander 1049817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, j ) ); 1050817466cbSJens Wiklander 1051817466cbSJens Wiklander o = B->p; p = X->p; c = 0; 1052817466cbSJens Wiklander 1053817466cbSJens Wiklander /* 1054817466cbSJens Wiklander * tmp is used because it might happen that p == o 1055817466cbSJens Wiklander */ 1056817466cbSJens Wiklander for( i = 0; i < j; i++, o++, p++ ) 1057817466cbSJens Wiklander { 1058817466cbSJens Wiklander tmp= *o; 1059817466cbSJens Wiklander *p += c; c = ( *p < c ); 1060817466cbSJens Wiklander *p += tmp; c += ( *p < tmp ); 1061817466cbSJens Wiklander } 1062817466cbSJens Wiklander 1063817466cbSJens Wiklander while( c != 0 ) 1064817466cbSJens Wiklander { 1065817466cbSJens Wiklander if( i >= X->n ) 1066817466cbSJens Wiklander { 1067817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, i + 1 ) ); 1068817466cbSJens Wiklander p = X->p + i; 1069817466cbSJens Wiklander } 1070817466cbSJens Wiklander 1071817466cbSJens Wiklander *p += c; c = ( *p < c ); i++; p++; 1072817466cbSJens Wiklander } 1073817466cbSJens Wiklander 1074817466cbSJens Wiklander cleanup: 1075817466cbSJens Wiklander 1076817466cbSJens Wiklander return( ret ); 1077817466cbSJens Wiklander } 1078817466cbSJens Wiklander 1079817466cbSJens Wiklander /* 1080817466cbSJens Wiklander * Helper for mbedtls_mpi subtraction 1081817466cbSJens Wiklander */ 1082817466cbSJens Wiklander static void mpi_sub_hlp( size_t n, mbedtls_mpi_uint *s, mbedtls_mpi_uint *d ) 1083817466cbSJens Wiklander { 1084817466cbSJens Wiklander size_t i; 1085817466cbSJens Wiklander mbedtls_mpi_uint c, z; 1086817466cbSJens Wiklander 1087817466cbSJens Wiklander for( i = c = 0; i < n; i++, s++, d++ ) 1088817466cbSJens Wiklander { 1089817466cbSJens Wiklander z = ( *d < c ); *d -= c; 1090817466cbSJens Wiklander c = ( *d < *s ) + z; *d -= *s; 1091817466cbSJens Wiklander } 1092817466cbSJens Wiklander 1093817466cbSJens Wiklander while( c != 0 ) 1094817466cbSJens Wiklander { 1095817466cbSJens Wiklander z = ( *d < c ); *d -= c; 10963d3b0591SJens Wiklander c = z; d++; 1097817466cbSJens Wiklander } 1098817466cbSJens Wiklander } 1099817466cbSJens Wiklander 1100817466cbSJens Wiklander /* 1101817466cbSJens Wiklander * Unsigned subtraction: X = |A| - |B| (HAC 14.9) 1102817466cbSJens Wiklander */ 1103817466cbSJens Wiklander int mbedtls_mpi_sub_abs( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ) 1104817466cbSJens Wiklander { 1105817466cbSJens Wiklander mbedtls_mpi TB; 1106817466cbSJens Wiklander int ret; 1107817466cbSJens Wiklander size_t n; 11083d3b0591SJens Wiklander MPI_VALIDATE_RET( X != NULL ); 11093d3b0591SJens Wiklander MPI_VALIDATE_RET( A != NULL ); 11103d3b0591SJens Wiklander MPI_VALIDATE_RET( B != NULL ); 1111817466cbSJens Wiklander 1112817466cbSJens Wiklander if( mbedtls_mpi_cmp_abs( A, B ) < 0 ) 1113817466cbSJens Wiklander return( MBEDTLS_ERR_MPI_NEGATIVE_VALUE ); 1114817466cbSJens Wiklander 111598bd5fe3SJens Wiklander mbedtls_mpi_init_mempool( &TB ); 1116817466cbSJens Wiklander 1117817466cbSJens Wiklander if( X == B ) 1118817466cbSJens Wiklander { 1119817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, B ) ); 1120817466cbSJens Wiklander B = &TB; 1121817466cbSJens Wiklander } 1122817466cbSJens Wiklander 1123817466cbSJens Wiklander if( X != A ) 1124817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, A ) ); 1125817466cbSJens Wiklander 1126817466cbSJens Wiklander /* 1127817466cbSJens Wiklander * X should always be positive as a result of unsigned subtractions. 1128817466cbSJens Wiklander */ 1129817466cbSJens Wiklander X->s = 1; 1130817466cbSJens Wiklander 1131817466cbSJens Wiklander ret = 0; 1132817466cbSJens Wiklander 1133817466cbSJens Wiklander for( n = B->n; n > 0; n-- ) 1134817466cbSJens Wiklander if( B->p[n - 1] != 0 ) 1135817466cbSJens Wiklander break; 1136817466cbSJens Wiklander 1137817466cbSJens Wiklander mpi_sub_hlp( n, B->p, X->p ); 1138817466cbSJens Wiklander 1139817466cbSJens Wiklander cleanup: 1140817466cbSJens Wiklander 1141817466cbSJens Wiklander mbedtls_mpi_free( &TB ); 1142817466cbSJens Wiklander 1143817466cbSJens Wiklander return( ret ); 1144817466cbSJens Wiklander } 1145817466cbSJens Wiklander 1146817466cbSJens Wiklander /* 1147817466cbSJens Wiklander * Signed addition: X = A + B 1148817466cbSJens Wiklander */ 1149817466cbSJens Wiklander int mbedtls_mpi_add_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ) 1150817466cbSJens Wiklander { 11513d3b0591SJens Wiklander int ret, s; 11523d3b0591SJens Wiklander MPI_VALIDATE_RET( X != NULL ); 11533d3b0591SJens Wiklander MPI_VALIDATE_RET( A != NULL ); 11543d3b0591SJens Wiklander MPI_VALIDATE_RET( B != NULL ); 1155817466cbSJens Wiklander 11563d3b0591SJens Wiklander s = A->s; 1157817466cbSJens Wiklander if( A->s * B->s < 0 ) 1158817466cbSJens Wiklander { 1159817466cbSJens Wiklander if( mbedtls_mpi_cmp_abs( A, B ) >= 0 ) 1160817466cbSJens Wiklander { 1161817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, A, B ) ); 1162817466cbSJens Wiklander X->s = s; 1163817466cbSJens Wiklander } 1164817466cbSJens Wiklander else 1165817466cbSJens Wiklander { 1166817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, B, A ) ); 1167817466cbSJens Wiklander X->s = -s; 1168817466cbSJens Wiklander } 1169817466cbSJens Wiklander } 1170817466cbSJens Wiklander else 1171817466cbSJens Wiklander { 1172817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_add_abs( X, A, B ) ); 1173817466cbSJens Wiklander X->s = s; 1174817466cbSJens Wiklander } 1175817466cbSJens Wiklander 1176817466cbSJens Wiklander cleanup: 1177817466cbSJens Wiklander 1178817466cbSJens Wiklander return( ret ); 1179817466cbSJens Wiklander } 1180817466cbSJens Wiklander 1181817466cbSJens Wiklander /* 1182817466cbSJens Wiklander * Signed subtraction: X = A - B 1183817466cbSJens Wiklander */ 1184817466cbSJens Wiklander int mbedtls_mpi_sub_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ) 1185817466cbSJens Wiklander { 11863d3b0591SJens Wiklander int ret, s; 11873d3b0591SJens Wiklander MPI_VALIDATE_RET( X != NULL ); 11883d3b0591SJens Wiklander MPI_VALIDATE_RET( A != NULL ); 11893d3b0591SJens Wiklander MPI_VALIDATE_RET( B != NULL ); 1190817466cbSJens Wiklander 11913d3b0591SJens Wiklander s = A->s; 1192817466cbSJens Wiklander if( A->s * B->s > 0 ) 1193817466cbSJens Wiklander { 1194817466cbSJens Wiklander if( mbedtls_mpi_cmp_abs( A, B ) >= 0 ) 1195817466cbSJens Wiklander { 1196817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, A, B ) ); 1197817466cbSJens Wiklander X->s = s; 1198817466cbSJens Wiklander } 1199817466cbSJens Wiklander else 1200817466cbSJens Wiklander { 1201817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, B, A ) ); 1202817466cbSJens Wiklander X->s = -s; 1203817466cbSJens Wiklander } 1204817466cbSJens Wiklander } 1205817466cbSJens Wiklander else 1206817466cbSJens Wiklander { 1207817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_add_abs( X, A, B ) ); 1208817466cbSJens Wiklander X->s = s; 1209817466cbSJens Wiklander } 1210817466cbSJens Wiklander 1211817466cbSJens Wiklander cleanup: 1212817466cbSJens Wiklander 1213817466cbSJens Wiklander return( ret ); 1214817466cbSJens Wiklander } 1215817466cbSJens Wiklander 1216817466cbSJens Wiklander /* 1217817466cbSJens Wiklander * Signed addition: X = A + b 1218817466cbSJens Wiklander */ 1219817466cbSJens Wiklander int mbedtls_mpi_add_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b ) 1220817466cbSJens Wiklander { 1221817466cbSJens Wiklander mbedtls_mpi _B; 1222817466cbSJens Wiklander mbedtls_mpi_uint p[1]; 12233d3b0591SJens Wiklander MPI_VALIDATE_RET( X != NULL ); 12243d3b0591SJens Wiklander MPI_VALIDATE_RET( A != NULL ); 1225817466cbSJens Wiklander 1226817466cbSJens Wiklander p[0] = ( b < 0 ) ? -b : b; 1227817466cbSJens Wiklander _B.s = ( b < 0 ) ? -1 : 1; 1228817466cbSJens Wiklander _B.n = 1; 1229817466cbSJens Wiklander _B.p = p; 1230817466cbSJens Wiklander 1231817466cbSJens Wiklander return( mbedtls_mpi_add_mpi( X, A, &_B ) ); 1232817466cbSJens Wiklander } 1233817466cbSJens Wiklander 1234817466cbSJens Wiklander /* 1235817466cbSJens Wiklander * Signed subtraction: X = A - b 1236817466cbSJens Wiklander */ 1237817466cbSJens Wiklander int mbedtls_mpi_sub_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b ) 1238817466cbSJens Wiklander { 1239817466cbSJens Wiklander mbedtls_mpi _B; 1240817466cbSJens Wiklander mbedtls_mpi_uint p[1]; 12413d3b0591SJens Wiklander MPI_VALIDATE_RET( X != NULL ); 12423d3b0591SJens Wiklander MPI_VALIDATE_RET( A != NULL ); 1243817466cbSJens Wiklander 1244817466cbSJens Wiklander p[0] = ( b < 0 ) ? -b : b; 1245817466cbSJens Wiklander _B.s = ( b < 0 ) ? -1 : 1; 1246817466cbSJens Wiklander _B.n = 1; 1247817466cbSJens Wiklander _B.p = p; 1248817466cbSJens Wiklander 1249817466cbSJens Wiklander return( mbedtls_mpi_sub_mpi( X, A, &_B ) ); 1250817466cbSJens Wiklander } 1251817466cbSJens Wiklander 1252817466cbSJens Wiklander /* 1253817466cbSJens Wiklander * Helper for mbedtls_mpi multiplication 1254817466cbSJens Wiklander */ 1255817466cbSJens Wiklander static 1256817466cbSJens Wiklander #if defined(__APPLE__) && defined(__arm__) 1257817466cbSJens Wiklander /* 1258817466cbSJens Wiklander * Apple LLVM version 4.2 (clang-425.0.24) (based on LLVM 3.2svn) 1259817466cbSJens Wiklander * appears to need this to prevent bad ARM code generation at -O3. 1260817466cbSJens Wiklander */ 1261817466cbSJens Wiklander __attribute__ ((noinline)) 1262817466cbSJens Wiklander #endif 1263817466cbSJens Wiklander void mpi_mul_hlp( size_t i, mbedtls_mpi_uint *s, mbedtls_mpi_uint *d, mbedtls_mpi_uint b ) 1264817466cbSJens Wiklander { 1265817466cbSJens Wiklander mbedtls_mpi_uint c = 0, t = 0; 1266817466cbSJens Wiklander 1267817466cbSJens Wiklander #if defined(MULADDC_HUIT) 1268817466cbSJens Wiklander for( ; i >= 8; i -= 8 ) 1269817466cbSJens Wiklander { 1270817466cbSJens Wiklander MULADDC_INIT 1271817466cbSJens Wiklander MULADDC_HUIT 1272817466cbSJens Wiklander MULADDC_STOP 1273817466cbSJens Wiklander } 1274817466cbSJens Wiklander 1275817466cbSJens Wiklander for( ; i > 0; i-- ) 1276817466cbSJens Wiklander { 1277817466cbSJens Wiklander MULADDC_INIT 1278817466cbSJens Wiklander MULADDC_CORE 1279817466cbSJens Wiklander MULADDC_STOP 1280817466cbSJens Wiklander } 1281817466cbSJens Wiklander #else /* MULADDC_HUIT */ 1282817466cbSJens Wiklander for( ; i >= 16; i -= 16 ) 1283817466cbSJens Wiklander { 1284817466cbSJens Wiklander MULADDC_INIT 1285817466cbSJens Wiklander MULADDC_CORE MULADDC_CORE 1286817466cbSJens Wiklander MULADDC_CORE MULADDC_CORE 1287817466cbSJens Wiklander MULADDC_CORE MULADDC_CORE 1288817466cbSJens Wiklander MULADDC_CORE MULADDC_CORE 1289817466cbSJens Wiklander 1290817466cbSJens Wiklander MULADDC_CORE MULADDC_CORE 1291817466cbSJens Wiklander MULADDC_CORE MULADDC_CORE 1292817466cbSJens Wiklander MULADDC_CORE MULADDC_CORE 1293817466cbSJens Wiklander MULADDC_CORE MULADDC_CORE 1294817466cbSJens Wiklander MULADDC_STOP 1295817466cbSJens Wiklander } 1296817466cbSJens Wiklander 1297817466cbSJens Wiklander for( ; i >= 8; i -= 8 ) 1298817466cbSJens Wiklander { 1299817466cbSJens Wiklander MULADDC_INIT 1300817466cbSJens Wiklander MULADDC_CORE MULADDC_CORE 1301817466cbSJens Wiklander MULADDC_CORE MULADDC_CORE 1302817466cbSJens Wiklander 1303817466cbSJens Wiklander MULADDC_CORE MULADDC_CORE 1304817466cbSJens Wiklander MULADDC_CORE MULADDC_CORE 1305817466cbSJens Wiklander MULADDC_STOP 1306817466cbSJens Wiklander } 1307817466cbSJens Wiklander 1308817466cbSJens Wiklander for( ; i > 0; i-- ) 1309817466cbSJens Wiklander { 1310817466cbSJens Wiklander MULADDC_INIT 1311817466cbSJens Wiklander MULADDC_CORE 1312817466cbSJens Wiklander MULADDC_STOP 1313817466cbSJens Wiklander } 1314817466cbSJens Wiklander #endif /* MULADDC_HUIT */ 1315817466cbSJens Wiklander 1316817466cbSJens Wiklander t++; 1317817466cbSJens Wiklander 1318817466cbSJens Wiklander do { 1319817466cbSJens Wiklander *d += c; c = ( *d < c ); d++; 1320817466cbSJens Wiklander } 1321817466cbSJens Wiklander while( c != 0 ); 1322817466cbSJens Wiklander } 1323817466cbSJens Wiklander 1324817466cbSJens Wiklander /* 1325817466cbSJens Wiklander * Baseline multiplication: X = A * B (HAC 14.12) 1326817466cbSJens Wiklander */ 1327817466cbSJens Wiklander int mbedtls_mpi_mul_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ) 1328817466cbSJens Wiklander { 1329817466cbSJens Wiklander int ret; 1330817466cbSJens Wiklander size_t i, j; 1331817466cbSJens Wiklander mbedtls_mpi TA, TB; 13323d3b0591SJens Wiklander MPI_VALIDATE_RET( X != NULL ); 13333d3b0591SJens Wiklander MPI_VALIDATE_RET( A != NULL ); 13343d3b0591SJens Wiklander MPI_VALIDATE_RET( B != NULL ); 1335817466cbSJens Wiklander 133698bd5fe3SJens Wiklander mbedtls_mpi_init_mempool( &TA ); mbedtls_mpi_init_mempool( &TB ); 1337817466cbSJens Wiklander 1338817466cbSJens Wiklander if( X == A ) { MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TA, A ) ); A = &TA; } 1339817466cbSJens Wiklander if( X == B ) { MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, B ) ); B = &TB; } 1340817466cbSJens Wiklander 1341817466cbSJens Wiklander for( i = A->n; i > 0; i-- ) 1342817466cbSJens Wiklander if( A->p[i - 1] != 0 ) 1343817466cbSJens Wiklander break; 1344817466cbSJens Wiklander 1345817466cbSJens Wiklander for( j = B->n; j > 0; j-- ) 1346817466cbSJens Wiklander if( B->p[j - 1] != 0 ) 1347817466cbSJens Wiklander break; 1348817466cbSJens Wiklander 1349817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, i + j ) ); 1350817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) ); 1351817466cbSJens Wiklander 13523d3b0591SJens Wiklander for( ; j > 0; j-- ) 13533d3b0591SJens Wiklander mpi_mul_hlp( i, A->p, X->p + j - 1, B->p[j - 1] ); 1354817466cbSJens Wiklander 1355817466cbSJens Wiklander X->s = A->s * B->s; 1356817466cbSJens Wiklander 1357817466cbSJens Wiklander cleanup: 1358817466cbSJens Wiklander 1359817466cbSJens Wiklander mbedtls_mpi_free( &TB ); mbedtls_mpi_free( &TA ); 1360817466cbSJens Wiklander 1361817466cbSJens Wiklander return( ret ); 1362817466cbSJens Wiklander } 1363817466cbSJens Wiklander 1364817466cbSJens Wiklander /* 1365817466cbSJens Wiklander * Baseline multiplication: X = A * b 1366817466cbSJens Wiklander */ 1367817466cbSJens Wiklander int mbedtls_mpi_mul_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_uint b ) 1368817466cbSJens Wiklander { 1369817466cbSJens Wiklander mbedtls_mpi _B; 1370817466cbSJens Wiklander mbedtls_mpi_uint p[1]; 13713d3b0591SJens Wiklander MPI_VALIDATE_RET( X != NULL ); 13723d3b0591SJens Wiklander MPI_VALIDATE_RET( A != NULL ); 1373817466cbSJens Wiklander 1374817466cbSJens Wiklander _B.s = 1; 1375817466cbSJens Wiklander _B.n = 1; 1376817466cbSJens Wiklander _B.p = p; 1377817466cbSJens Wiklander p[0] = b; 1378817466cbSJens Wiklander 1379817466cbSJens Wiklander return( mbedtls_mpi_mul_mpi( X, A, &_B ) ); 1380817466cbSJens Wiklander } 1381817466cbSJens Wiklander 1382817466cbSJens Wiklander /* 1383817466cbSJens Wiklander * Unsigned integer divide - double mbedtls_mpi_uint dividend, u1/u0, and 1384817466cbSJens Wiklander * mbedtls_mpi_uint divisor, d 1385817466cbSJens Wiklander */ 1386817466cbSJens Wiklander static mbedtls_mpi_uint mbedtls_int_div_int( mbedtls_mpi_uint u1, 1387817466cbSJens Wiklander mbedtls_mpi_uint u0, mbedtls_mpi_uint d, mbedtls_mpi_uint *r ) 1388817466cbSJens Wiklander { 1389817466cbSJens Wiklander #if defined(MBEDTLS_HAVE_UDBL) 1390817466cbSJens Wiklander mbedtls_t_udbl dividend, quotient; 1391817466cbSJens Wiklander #else 1392817466cbSJens Wiklander const mbedtls_mpi_uint radix = (mbedtls_mpi_uint) 1 << biH; 1393817466cbSJens Wiklander const mbedtls_mpi_uint uint_halfword_mask = ( (mbedtls_mpi_uint) 1 << biH ) - 1; 1394817466cbSJens Wiklander mbedtls_mpi_uint d0, d1, q0, q1, rAX, r0, quotient; 1395817466cbSJens Wiklander mbedtls_mpi_uint u0_msw, u0_lsw; 1396817466cbSJens Wiklander size_t s; 1397817466cbSJens Wiklander #endif 1398817466cbSJens Wiklander 1399817466cbSJens Wiklander /* 1400817466cbSJens Wiklander * Check for overflow 1401817466cbSJens Wiklander */ 1402817466cbSJens Wiklander if( 0 == d || u1 >= d ) 1403817466cbSJens Wiklander { 1404817466cbSJens Wiklander if (r != NULL) *r = ~0; 1405817466cbSJens Wiklander 1406817466cbSJens Wiklander return ( ~0 ); 1407817466cbSJens Wiklander } 1408817466cbSJens Wiklander 1409817466cbSJens Wiklander #if defined(MBEDTLS_HAVE_UDBL) 1410817466cbSJens Wiklander dividend = (mbedtls_t_udbl) u1 << biL; 1411817466cbSJens Wiklander dividend |= (mbedtls_t_udbl) u0; 1412817466cbSJens Wiklander quotient = dividend / d; 1413817466cbSJens Wiklander if( quotient > ( (mbedtls_t_udbl) 1 << biL ) - 1 ) 1414817466cbSJens Wiklander quotient = ( (mbedtls_t_udbl) 1 << biL ) - 1; 1415817466cbSJens Wiklander 1416817466cbSJens Wiklander if( r != NULL ) 1417817466cbSJens Wiklander *r = (mbedtls_mpi_uint)( dividend - (quotient * d ) ); 1418817466cbSJens Wiklander 1419817466cbSJens Wiklander return (mbedtls_mpi_uint) quotient; 1420817466cbSJens Wiklander #else 1421817466cbSJens Wiklander 1422817466cbSJens Wiklander /* 1423817466cbSJens Wiklander * Algorithm D, Section 4.3.1 - The Art of Computer Programming 1424817466cbSJens Wiklander * Vol. 2 - Seminumerical Algorithms, Knuth 1425817466cbSJens Wiklander */ 1426817466cbSJens Wiklander 1427817466cbSJens Wiklander /* 1428817466cbSJens Wiklander * Normalize the divisor, d, and dividend, u0, u1 1429817466cbSJens Wiklander */ 1430817466cbSJens Wiklander s = mbedtls_clz( d ); 1431817466cbSJens Wiklander d = d << s; 1432817466cbSJens Wiklander 1433817466cbSJens Wiklander u1 = u1 << s; 1434817466cbSJens Wiklander u1 |= ( u0 >> ( biL - s ) ) & ( -(mbedtls_mpi_sint)s >> ( biL - 1 ) ); 1435817466cbSJens Wiklander u0 = u0 << s; 1436817466cbSJens Wiklander 1437817466cbSJens Wiklander d1 = d >> biH; 1438817466cbSJens Wiklander d0 = d & uint_halfword_mask; 1439817466cbSJens Wiklander 1440817466cbSJens Wiklander u0_msw = u0 >> biH; 1441817466cbSJens Wiklander u0_lsw = u0 & uint_halfword_mask; 1442817466cbSJens Wiklander 1443817466cbSJens Wiklander /* 1444817466cbSJens Wiklander * Find the first quotient and remainder 1445817466cbSJens Wiklander */ 1446817466cbSJens Wiklander q1 = u1 / d1; 1447817466cbSJens Wiklander r0 = u1 - d1 * q1; 1448817466cbSJens Wiklander 1449817466cbSJens Wiklander while( q1 >= radix || ( q1 * d0 > radix * r0 + u0_msw ) ) 1450817466cbSJens Wiklander { 1451817466cbSJens Wiklander q1 -= 1; 1452817466cbSJens Wiklander r0 += d1; 1453817466cbSJens Wiklander 1454817466cbSJens Wiklander if ( r0 >= radix ) break; 1455817466cbSJens Wiklander } 1456817466cbSJens Wiklander 1457817466cbSJens Wiklander rAX = ( u1 * radix ) + ( u0_msw - q1 * d ); 1458817466cbSJens Wiklander q0 = rAX / d1; 1459817466cbSJens Wiklander r0 = rAX - q0 * d1; 1460817466cbSJens Wiklander 1461817466cbSJens Wiklander while( q0 >= radix || ( q0 * d0 > radix * r0 + u0_lsw ) ) 1462817466cbSJens Wiklander { 1463817466cbSJens Wiklander q0 -= 1; 1464817466cbSJens Wiklander r0 += d1; 1465817466cbSJens Wiklander 1466817466cbSJens Wiklander if ( r0 >= radix ) break; 1467817466cbSJens Wiklander } 1468817466cbSJens Wiklander 1469817466cbSJens Wiklander if (r != NULL) 1470817466cbSJens Wiklander *r = ( rAX * radix + u0_lsw - q0 * d ) >> s; 1471817466cbSJens Wiklander 1472817466cbSJens Wiklander quotient = q1 * radix + q0; 1473817466cbSJens Wiklander 1474817466cbSJens Wiklander return quotient; 1475817466cbSJens Wiklander #endif 1476817466cbSJens Wiklander } 1477817466cbSJens Wiklander 1478817466cbSJens Wiklander /* 1479817466cbSJens Wiklander * Division by mbedtls_mpi: A = Q * B + R (HAC 14.20) 1480817466cbSJens Wiklander */ 14813d3b0591SJens Wiklander int mbedtls_mpi_div_mpi( mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A, 14823d3b0591SJens Wiklander const mbedtls_mpi *B ) 1483817466cbSJens Wiklander { 1484817466cbSJens Wiklander int ret; 1485817466cbSJens Wiklander size_t i, n, t, k; 1486817466cbSJens Wiklander mbedtls_mpi X, Y, Z, T1, T2; 14873d3b0591SJens Wiklander MPI_VALIDATE_RET( A != NULL ); 14883d3b0591SJens Wiklander MPI_VALIDATE_RET( B != NULL ); 1489817466cbSJens Wiklander 1490817466cbSJens Wiklander if( mbedtls_mpi_cmp_int( B, 0 ) == 0 ) 1491817466cbSJens Wiklander return( MBEDTLS_ERR_MPI_DIVISION_BY_ZERO ); 1492817466cbSJens Wiklander 149398bd5fe3SJens Wiklander mbedtls_mpi_init_mempool( &X ); mbedtls_mpi_init_mempool( &Y ); 149498bd5fe3SJens Wiklander mbedtls_mpi_init_mempool( &Z ); mbedtls_mpi_init_mempool( &T1 ); 149598bd5fe3SJens Wiklander mbedtls_mpi_init_mempool( &T2 ); 1496817466cbSJens Wiklander 1497817466cbSJens Wiklander if( mbedtls_mpi_cmp_abs( A, B ) < 0 ) 1498817466cbSJens Wiklander { 1499817466cbSJens Wiklander if( Q != NULL ) MBEDTLS_MPI_CHK( mbedtls_mpi_lset( Q, 0 ) ); 1500817466cbSJens Wiklander if( R != NULL ) MBEDTLS_MPI_CHK( mbedtls_mpi_copy( R, A ) ); 1501817466cbSJens Wiklander return( 0 ); 1502817466cbSJens Wiklander } 1503817466cbSJens Wiklander 1504817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &X, A ) ); 1505817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &Y, B ) ); 1506817466cbSJens Wiklander X.s = Y.s = 1; 1507817466cbSJens Wiklander 1508817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &Z, A->n + 2 ) ); 1509817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &Z, 0 ) ); 1510817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &T1, 2 ) ); 1511817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &T2, 3 ) ); 1512817466cbSJens Wiklander 1513817466cbSJens Wiklander k = mbedtls_mpi_bitlen( &Y ) % biL; 1514817466cbSJens Wiklander if( k < biL - 1 ) 1515817466cbSJens Wiklander { 1516817466cbSJens Wiklander k = biL - 1 - k; 1517817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &X, k ) ); 1518817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &Y, k ) ); 1519817466cbSJens Wiklander } 1520817466cbSJens Wiklander else k = 0; 1521817466cbSJens Wiklander 1522817466cbSJens Wiklander n = X.n - 1; 1523817466cbSJens Wiklander t = Y.n - 1; 1524817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &Y, biL * ( n - t ) ) ); 1525817466cbSJens Wiklander 1526817466cbSJens Wiklander while( mbedtls_mpi_cmp_mpi( &X, &Y ) >= 0 ) 1527817466cbSJens Wiklander { 1528817466cbSJens Wiklander Z.p[n - t]++; 1529817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &X, &X, &Y ) ); 1530817466cbSJens Wiklander } 1531817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &Y, biL * ( n - t ) ) ); 1532817466cbSJens Wiklander 1533817466cbSJens Wiklander for( i = n; i > t ; i-- ) 1534817466cbSJens Wiklander { 1535817466cbSJens Wiklander if( X.p[i] >= Y.p[t] ) 1536817466cbSJens Wiklander Z.p[i - t - 1] = ~0; 1537817466cbSJens Wiklander else 1538817466cbSJens Wiklander { 1539817466cbSJens Wiklander Z.p[i - t - 1] = mbedtls_int_div_int( X.p[i], X.p[i - 1], 1540817466cbSJens Wiklander Y.p[t], NULL); 1541817466cbSJens Wiklander } 1542817466cbSJens Wiklander 1543817466cbSJens Wiklander Z.p[i - t - 1]++; 1544817466cbSJens Wiklander do 1545817466cbSJens Wiklander { 1546817466cbSJens Wiklander Z.p[i - t - 1]--; 1547817466cbSJens Wiklander 1548817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &T1, 0 ) ); 1549817466cbSJens Wiklander T1.p[0] = ( t < 1 ) ? 0 : Y.p[t - 1]; 1550817466cbSJens Wiklander T1.p[1] = Y.p[t]; 1551817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &T1, &T1, Z.p[i - t - 1] ) ); 1552817466cbSJens Wiklander 1553817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &T2, 0 ) ); 1554817466cbSJens Wiklander T2.p[0] = ( i < 2 ) ? 0 : X.p[i - 2]; 1555817466cbSJens Wiklander T2.p[1] = ( i < 1 ) ? 0 : X.p[i - 1]; 1556817466cbSJens Wiklander T2.p[2] = X.p[i]; 1557817466cbSJens Wiklander } 1558817466cbSJens Wiklander while( mbedtls_mpi_cmp_mpi( &T1, &T2 ) > 0 ); 1559817466cbSJens Wiklander 1560817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &T1, &Y, Z.p[i - t - 1] ) ); 1561817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &T1, biL * ( i - t - 1 ) ) ); 1562817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &X, &X, &T1 ) ); 1563817466cbSJens Wiklander 1564817466cbSJens Wiklander if( mbedtls_mpi_cmp_int( &X, 0 ) < 0 ) 1565817466cbSJens Wiklander { 1566817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &T1, &Y ) ); 1567817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &T1, biL * ( i - t - 1 ) ) ); 1568817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &X, &X, &T1 ) ); 1569817466cbSJens Wiklander Z.p[i - t - 1]--; 1570817466cbSJens Wiklander } 1571817466cbSJens Wiklander } 1572817466cbSJens Wiklander 1573817466cbSJens Wiklander if( Q != NULL ) 1574817466cbSJens Wiklander { 1575817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_copy( Q, &Z ) ); 1576817466cbSJens Wiklander Q->s = A->s * B->s; 1577817466cbSJens Wiklander } 1578817466cbSJens Wiklander 1579817466cbSJens Wiklander if( R != NULL ) 1580817466cbSJens Wiklander { 1581817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &X, k ) ); 1582817466cbSJens Wiklander X.s = A->s; 1583817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_copy( R, &X ) ); 1584817466cbSJens Wiklander 1585817466cbSJens Wiklander if( mbedtls_mpi_cmp_int( R, 0 ) == 0 ) 1586817466cbSJens Wiklander R->s = 1; 1587817466cbSJens Wiklander } 1588817466cbSJens Wiklander 1589817466cbSJens Wiklander cleanup: 1590817466cbSJens Wiklander 1591817466cbSJens Wiklander mbedtls_mpi_free( &X ); mbedtls_mpi_free( &Y ); mbedtls_mpi_free( &Z ); 1592817466cbSJens Wiklander mbedtls_mpi_free( &T1 ); mbedtls_mpi_free( &T2 ); 1593817466cbSJens Wiklander 1594817466cbSJens Wiklander return( ret ); 1595817466cbSJens Wiklander } 1596817466cbSJens Wiklander 1597817466cbSJens Wiklander /* 1598817466cbSJens Wiklander * Division by int: A = Q * b + R 1599817466cbSJens Wiklander */ 16003d3b0591SJens Wiklander int mbedtls_mpi_div_int( mbedtls_mpi *Q, mbedtls_mpi *R, 16013d3b0591SJens Wiklander const mbedtls_mpi *A, 16023d3b0591SJens Wiklander mbedtls_mpi_sint b ) 1603817466cbSJens Wiklander { 1604817466cbSJens Wiklander mbedtls_mpi _B; 1605817466cbSJens Wiklander mbedtls_mpi_uint p[1]; 16063d3b0591SJens Wiklander MPI_VALIDATE_RET( A != NULL ); 1607817466cbSJens Wiklander 1608817466cbSJens Wiklander p[0] = ( b < 0 ) ? -b : b; 1609817466cbSJens Wiklander _B.s = ( b < 0 ) ? -1 : 1; 1610817466cbSJens Wiklander _B.n = 1; 1611817466cbSJens Wiklander _B.p = p; 1612817466cbSJens Wiklander 1613817466cbSJens Wiklander return( mbedtls_mpi_div_mpi( Q, R, A, &_B ) ); 1614817466cbSJens Wiklander } 1615817466cbSJens Wiklander 1616817466cbSJens Wiklander /* 1617817466cbSJens Wiklander * Modulo: R = A mod B 1618817466cbSJens Wiklander */ 1619817466cbSJens Wiklander int mbedtls_mpi_mod_mpi( mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B ) 1620817466cbSJens Wiklander { 1621817466cbSJens Wiklander int ret; 16223d3b0591SJens Wiklander MPI_VALIDATE_RET( R != NULL ); 16233d3b0591SJens Wiklander MPI_VALIDATE_RET( A != NULL ); 16243d3b0591SJens Wiklander MPI_VALIDATE_RET( B != NULL ); 1625817466cbSJens Wiklander 1626817466cbSJens Wiklander if( mbedtls_mpi_cmp_int( B, 0 ) < 0 ) 1627817466cbSJens Wiklander return( MBEDTLS_ERR_MPI_NEGATIVE_VALUE ); 1628817466cbSJens Wiklander 1629817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_div_mpi( NULL, R, A, B ) ); 1630817466cbSJens Wiklander 1631817466cbSJens Wiklander while( mbedtls_mpi_cmp_int( R, 0 ) < 0 ) 1632817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( R, R, B ) ); 1633817466cbSJens Wiklander 1634817466cbSJens Wiklander while( mbedtls_mpi_cmp_mpi( R, B ) >= 0 ) 1635817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( R, R, B ) ); 1636817466cbSJens Wiklander 1637817466cbSJens Wiklander cleanup: 1638817466cbSJens Wiklander 1639817466cbSJens Wiklander return( ret ); 1640817466cbSJens Wiklander } 1641817466cbSJens Wiklander 1642817466cbSJens Wiklander /* 1643817466cbSJens Wiklander * Modulo: r = A mod b 1644817466cbSJens Wiklander */ 1645817466cbSJens Wiklander int mbedtls_mpi_mod_int( mbedtls_mpi_uint *r, const mbedtls_mpi *A, mbedtls_mpi_sint b ) 1646817466cbSJens Wiklander { 1647817466cbSJens Wiklander size_t i; 1648817466cbSJens Wiklander mbedtls_mpi_uint x, y, z; 16493d3b0591SJens Wiklander MPI_VALIDATE_RET( r != NULL ); 16503d3b0591SJens Wiklander MPI_VALIDATE_RET( A != NULL ); 1651817466cbSJens Wiklander 1652817466cbSJens Wiklander if( b == 0 ) 1653817466cbSJens Wiklander return( MBEDTLS_ERR_MPI_DIVISION_BY_ZERO ); 1654817466cbSJens Wiklander 1655817466cbSJens Wiklander if( b < 0 ) 1656817466cbSJens Wiklander return( MBEDTLS_ERR_MPI_NEGATIVE_VALUE ); 1657817466cbSJens Wiklander 1658817466cbSJens Wiklander /* 1659817466cbSJens Wiklander * handle trivial cases 1660817466cbSJens Wiklander */ 1661817466cbSJens Wiklander if( b == 1 ) 1662817466cbSJens Wiklander { 1663817466cbSJens Wiklander *r = 0; 1664817466cbSJens Wiklander return( 0 ); 1665817466cbSJens Wiklander } 1666817466cbSJens Wiklander 1667817466cbSJens Wiklander if( b == 2 ) 1668817466cbSJens Wiklander { 1669817466cbSJens Wiklander *r = A->p[0] & 1; 1670817466cbSJens Wiklander return( 0 ); 1671817466cbSJens Wiklander } 1672817466cbSJens Wiklander 1673817466cbSJens Wiklander /* 1674817466cbSJens Wiklander * general case 1675817466cbSJens Wiklander */ 1676817466cbSJens Wiklander for( i = A->n, y = 0; i > 0; i-- ) 1677817466cbSJens Wiklander { 1678817466cbSJens Wiklander x = A->p[i - 1]; 1679817466cbSJens Wiklander y = ( y << biH ) | ( x >> biH ); 1680817466cbSJens Wiklander z = y / b; 1681817466cbSJens Wiklander y -= z * b; 1682817466cbSJens Wiklander 1683817466cbSJens Wiklander x <<= biH; 1684817466cbSJens Wiklander y = ( y << biH ) | ( x >> biH ); 1685817466cbSJens Wiklander z = y / b; 1686817466cbSJens Wiklander y -= z * b; 1687817466cbSJens Wiklander } 1688817466cbSJens Wiklander 1689817466cbSJens Wiklander /* 1690817466cbSJens Wiklander * If A is negative, then the current y represents a negative value. 1691817466cbSJens Wiklander * Flipping it to the positive side. 1692817466cbSJens Wiklander */ 1693817466cbSJens Wiklander if( A->s < 0 && y != 0 ) 1694817466cbSJens Wiklander y = b - y; 1695817466cbSJens Wiklander 1696817466cbSJens Wiklander *r = y; 1697817466cbSJens Wiklander 1698817466cbSJens Wiklander return( 0 ); 1699817466cbSJens Wiklander } 1700817466cbSJens Wiklander 1701817466cbSJens Wiklander /* 1702817466cbSJens Wiklander * Fast Montgomery initialization (thanks to Tom St Denis) 1703817466cbSJens Wiklander */ 170462f21181SJens Wiklander void mbedtls_mpi_montg_init( mbedtls_mpi_uint *mm, const mbedtls_mpi *N ) 1705817466cbSJens Wiklander { 1706817466cbSJens Wiklander mbedtls_mpi_uint x, m0 = N->p[0]; 1707817466cbSJens Wiklander unsigned int i; 1708817466cbSJens Wiklander 1709817466cbSJens Wiklander x = m0; 1710817466cbSJens Wiklander x += ( ( m0 + 2 ) & 4 ) << 1; 1711817466cbSJens Wiklander 1712817466cbSJens Wiklander for( i = biL; i >= 8; i /= 2 ) 1713817466cbSJens Wiklander x *= ( 2 - ( m0 * x ) ); 1714817466cbSJens Wiklander 1715817466cbSJens Wiklander *mm = ~x + 1; 1716817466cbSJens Wiklander } 1717817466cbSJens Wiklander 1718817466cbSJens Wiklander /* 1719817466cbSJens Wiklander * Montgomery multiplication: A = A * B * R^-1 mod N (HAC 14.36) 1720817466cbSJens Wiklander */ 172162f21181SJens Wiklander int mbedtls_mpi_montmul( mbedtls_mpi *A, const mbedtls_mpi *B, 172262f21181SJens Wiklander const mbedtls_mpi *N, mbedtls_mpi_uint mm, 1723817466cbSJens Wiklander const mbedtls_mpi *T ) 1724817466cbSJens Wiklander { 1725817466cbSJens Wiklander size_t i, n, m; 1726817466cbSJens Wiklander mbedtls_mpi_uint u0, u1, *d; 1727817466cbSJens Wiklander 1728817466cbSJens Wiklander if( T->n < N->n + 1 || T->p == NULL ) 1729817466cbSJens Wiklander return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); 1730817466cbSJens Wiklander 1731817466cbSJens Wiklander memset( T->p, 0, T->n * ciL ); 1732817466cbSJens Wiklander 1733817466cbSJens Wiklander d = T->p; 1734817466cbSJens Wiklander n = N->n; 1735817466cbSJens Wiklander m = ( B->n < n ) ? B->n : n; 1736817466cbSJens Wiklander 1737817466cbSJens Wiklander for( i = 0; i < n; i++ ) 1738817466cbSJens Wiklander { 1739817466cbSJens Wiklander /* 1740817466cbSJens Wiklander * T = (T + u0*B + u1*N) / 2^biL 1741817466cbSJens Wiklander */ 1742817466cbSJens Wiklander u0 = A->p[i]; 1743817466cbSJens Wiklander u1 = ( d[0] + u0 * B->p[0] ) * mm; 1744817466cbSJens Wiklander 1745817466cbSJens Wiklander mpi_mul_hlp( m, B->p, d, u0 ); 1746817466cbSJens Wiklander mpi_mul_hlp( n, N->p, d, u1 ); 1747817466cbSJens Wiklander 1748817466cbSJens Wiklander *d++ = u0; d[n + 1] = 0; 1749817466cbSJens Wiklander } 1750817466cbSJens Wiklander 1751817466cbSJens Wiklander memcpy( A->p, d, ( n + 1 ) * ciL ); 1752817466cbSJens Wiklander 1753817466cbSJens Wiklander if( mbedtls_mpi_cmp_abs( A, N ) >= 0 ) 1754817466cbSJens Wiklander mpi_sub_hlp( n, N->p, A->p ); 1755817466cbSJens Wiklander else 1756817466cbSJens Wiklander /* prevent timing attacks */ 1757817466cbSJens Wiklander mpi_sub_hlp( n, A->p, T->p ); 1758817466cbSJens Wiklander 1759817466cbSJens Wiklander return( 0 ); 1760817466cbSJens Wiklander } 1761817466cbSJens Wiklander 1762817466cbSJens Wiklander /* 1763817466cbSJens Wiklander * Montgomery reduction: A = A * R^-1 mod N 1764817466cbSJens Wiklander */ 176562f21181SJens Wiklander int mbedtls_mpi_montred( mbedtls_mpi *A, const mbedtls_mpi *N, 176662f21181SJens Wiklander mbedtls_mpi_uint mm, const mbedtls_mpi *T ) 1767817466cbSJens Wiklander { 1768817466cbSJens Wiklander mbedtls_mpi_uint z = 1; 1769817466cbSJens Wiklander mbedtls_mpi U; 1770817466cbSJens Wiklander 1771817466cbSJens Wiklander U.n = U.s = (int) z; 1772817466cbSJens Wiklander U.p = &z; 1773817466cbSJens Wiklander 177462f21181SJens Wiklander return( mbedtls_mpi_montmul( A, &U, N, mm, T ) ); 1775817466cbSJens Wiklander } 1776817466cbSJens Wiklander 1777817466cbSJens Wiklander /* 1778817466cbSJens Wiklander * Sliding-window exponentiation: X = A^E mod N (HAC 14.85) 1779817466cbSJens Wiklander */ 17803d3b0591SJens Wiklander int mbedtls_mpi_exp_mod( mbedtls_mpi *X, const mbedtls_mpi *A, 17813d3b0591SJens Wiklander const mbedtls_mpi *E, const mbedtls_mpi *N, 17823d3b0591SJens Wiklander mbedtls_mpi *_RR ) 1783817466cbSJens Wiklander { 1784817466cbSJens Wiklander int ret; 1785817466cbSJens Wiklander size_t wbits, wsize, one = 1; 1786817466cbSJens Wiklander size_t i, j, nblimbs; 1787817466cbSJens Wiklander size_t bufsize, nbits; 1788817466cbSJens Wiklander mbedtls_mpi_uint ei, mm, state; 1789817466cbSJens Wiklander mbedtls_mpi RR, T, W[ 2 << MBEDTLS_MPI_WINDOW_SIZE ], Apos; 1790817466cbSJens Wiklander int neg; 1791817466cbSJens Wiklander 17923d3b0591SJens Wiklander MPI_VALIDATE_RET( X != NULL ); 17933d3b0591SJens Wiklander MPI_VALIDATE_RET( A != NULL ); 17943d3b0591SJens Wiklander MPI_VALIDATE_RET( E != NULL ); 17953d3b0591SJens Wiklander MPI_VALIDATE_RET( N != NULL ); 17963d3b0591SJens Wiklander 17973d3b0591SJens Wiklander if( mbedtls_mpi_cmp_int( N, 0 ) <= 0 || ( N->p[0] & 1 ) == 0 ) 1798817466cbSJens Wiklander return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); 1799817466cbSJens Wiklander 1800817466cbSJens Wiklander if( mbedtls_mpi_cmp_int( E, 0 ) < 0 ) 1801817466cbSJens Wiklander return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); 1802817466cbSJens Wiklander 1803817466cbSJens Wiklander /* 1804817466cbSJens Wiklander * Init temps and window size 1805817466cbSJens Wiklander */ 180662f21181SJens Wiklander mbedtls_mpi_montg_init( &mm, N ); 180798bd5fe3SJens Wiklander mbedtls_mpi_init_mempool( &RR ); mbedtls_mpi_init_mempool( &T ); 180898bd5fe3SJens Wiklander mbedtls_mpi_init_mempool( &Apos ); 1809*b99a4a18SJens Wiklander for( i = 0; i < ARRAY_SIZE(W); i++ ) 1810*b99a4a18SJens Wiklander mbedtls_mpi_init_mempool( W + i ); 1811817466cbSJens Wiklander 1812817466cbSJens Wiklander i = mbedtls_mpi_bitlen( E ); 1813817466cbSJens Wiklander 1814817466cbSJens Wiklander wsize = ( i > 671 ) ? 6 : ( i > 239 ) ? 5 : 1815817466cbSJens Wiklander ( i > 79 ) ? 4 : ( i > 23 ) ? 3 : 1; 1816817466cbSJens Wiklander 1817817466cbSJens Wiklander if( wsize > MBEDTLS_MPI_WINDOW_SIZE ) 1818817466cbSJens Wiklander wsize = MBEDTLS_MPI_WINDOW_SIZE; 1819817466cbSJens Wiklander 1820817466cbSJens Wiklander j = N->n + 1; 1821817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, j ) ); 1822817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[1], j ) ); 1823817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &T, j * 2 ) ); 1824817466cbSJens Wiklander 1825817466cbSJens Wiklander /* 1826817466cbSJens Wiklander * Compensate for negative A (and correct at the end) 1827817466cbSJens Wiklander */ 1828817466cbSJens Wiklander neg = ( A->s == -1 ); 1829817466cbSJens Wiklander if( neg ) 1830817466cbSJens Wiklander { 1831817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &Apos, A ) ); 1832817466cbSJens Wiklander Apos.s = 1; 1833817466cbSJens Wiklander A = &Apos; 1834817466cbSJens Wiklander } 1835817466cbSJens Wiklander 1836817466cbSJens Wiklander /* 1837817466cbSJens Wiklander * If 1st call, pre-compute R^2 mod N 1838817466cbSJens Wiklander */ 1839817466cbSJens Wiklander if( _RR == NULL || _RR->p == NULL ) 1840817466cbSJens Wiklander { 1841817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &RR, 1 ) ); 1842817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &RR, N->n * 2 * biL ) ); 1843817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &RR, &RR, N ) ); 1844817466cbSJens Wiklander 1845817466cbSJens Wiklander if( _RR != NULL ) 1846817466cbSJens Wiklander memcpy( _RR, &RR, sizeof( mbedtls_mpi ) ); 1847817466cbSJens Wiklander } 1848817466cbSJens Wiklander else 1849817466cbSJens Wiklander memcpy( &RR, _RR, sizeof( mbedtls_mpi ) ); 1850817466cbSJens Wiklander 1851817466cbSJens Wiklander /* 1852817466cbSJens Wiklander * W[1] = A * R^2 * R^-1 mod N = A * R mod N 1853817466cbSJens Wiklander */ 1854817466cbSJens Wiklander if( mbedtls_mpi_cmp_mpi( A, N ) >= 0 ) 1855817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &W[1], A, N ) ); 1856817466cbSJens Wiklander else 1857817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &W[1], A ) ); 1858817466cbSJens Wiklander 185962f21181SJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_montmul( &W[1], &RR, N, mm, &T ) ); 1860817466cbSJens Wiklander 1861817466cbSJens Wiklander /* 1862817466cbSJens Wiklander * X = R^2 * R^-1 mod N = R mod N 1863817466cbSJens Wiklander */ 1864817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, &RR ) ); 186562f21181SJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_montred( X, N, mm, &T ) ); 1866817466cbSJens Wiklander 1867817466cbSJens Wiklander if( wsize > 1 ) 1868817466cbSJens Wiklander { 1869817466cbSJens Wiklander /* 1870817466cbSJens Wiklander * W[1 << (wsize - 1)] = W[1] ^ (wsize - 1) 1871817466cbSJens Wiklander */ 1872817466cbSJens Wiklander j = one << ( wsize - 1 ); 1873817466cbSJens Wiklander 1874817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[j], N->n + 1 ) ); 1875817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &W[j], &W[1] ) ); 1876817466cbSJens Wiklander 1877817466cbSJens Wiklander for( i = 0; i < wsize - 1; i++ ) 187862f21181SJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_montmul( &W[j], &W[j], N, mm, &T ) ); 1879817466cbSJens Wiklander 1880817466cbSJens Wiklander /* 1881817466cbSJens Wiklander * W[i] = W[i - 1] * W[1] 1882817466cbSJens Wiklander */ 1883817466cbSJens Wiklander for( i = j + 1; i < ( one << wsize ); i++ ) 1884817466cbSJens Wiklander { 1885817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[i], N->n + 1 ) ); 1886817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &W[i], &W[i - 1] ) ); 1887817466cbSJens Wiklander 188862f21181SJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_montmul( &W[i], &W[1], N, mm, &T ) ); 1889817466cbSJens Wiklander } 1890817466cbSJens Wiklander } 1891817466cbSJens Wiklander 1892817466cbSJens Wiklander nblimbs = E->n; 1893817466cbSJens Wiklander bufsize = 0; 1894817466cbSJens Wiklander nbits = 0; 1895817466cbSJens Wiklander wbits = 0; 1896817466cbSJens Wiklander state = 0; 1897817466cbSJens Wiklander 1898817466cbSJens Wiklander while( 1 ) 1899817466cbSJens Wiklander { 1900817466cbSJens Wiklander if( bufsize == 0 ) 1901817466cbSJens Wiklander { 1902817466cbSJens Wiklander if( nblimbs == 0 ) 1903817466cbSJens Wiklander break; 1904817466cbSJens Wiklander 1905817466cbSJens Wiklander nblimbs--; 1906817466cbSJens Wiklander 1907817466cbSJens Wiklander bufsize = sizeof( mbedtls_mpi_uint ) << 3; 1908817466cbSJens Wiklander } 1909817466cbSJens Wiklander 1910817466cbSJens Wiklander bufsize--; 1911817466cbSJens Wiklander 1912817466cbSJens Wiklander ei = (E->p[nblimbs] >> bufsize) & 1; 1913817466cbSJens Wiklander 1914817466cbSJens Wiklander /* 1915817466cbSJens Wiklander * skip leading 0s 1916817466cbSJens Wiklander */ 1917817466cbSJens Wiklander if( ei == 0 && state == 0 ) 1918817466cbSJens Wiklander continue; 1919817466cbSJens Wiklander 1920817466cbSJens Wiklander if( ei == 0 && state == 1 ) 1921817466cbSJens Wiklander { 1922817466cbSJens Wiklander /* 1923817466cbSJens Wiklander * out of window, square X 1924817466cbSJens Wiklander */ 192562f21181SJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_montmul( X, X, N, mm, &T ) ); 1926817466cbSJens Wiklander continue; 1927817466cbSJens Wiklander } 1928817466cbSJens Wiklander 1929817466cbSJens Wiklander /* 1930817466cbSJens Wiklander * add ei to current window 1931817466cbSJens Wiklander */ 1932817466cbSJens Wiklander state = 2; 1933817466cbSJens Wiklander 1934817466cbSJens Wiklander nbits++; 1935817466cbSJens Wiklander wbits |= ( ei << ( wsize - nbits ) ); 1936817466cbSJens Wiklander 1937817466cbSJens Wiklander if( nbits == wsize ) 1938817466cbSJens Wiklander { 1939817466cbSJens Wiklander /* 1940817466cbSJens Wiklander * X = X^wsize R^-1 mod N 1941817466cbSJens Wiklander */ 1942817466cbSJens Wiklander for( i = 0; i < wsize; i++ ) 194362f21181SJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_montmul( X, X, N, mm, &T ) ); 1944817466cbSJens Wiklander 1945817466cbSJens Wiklander /* 1946817466cbSJens Wiklander * X = X * W[wbits] R^-1 mod N 1947817466cbSJens Wiklander */ 194862f21181SJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_montmul( X, &W[wbits], N, mm, &T ) ); 1949817466cbSJens Wiklander 1950817466cbSJens Wiklander state--; 1951817466cbSJens Wiklander nbits = 0; 1952817466cbSJens Wiklander wbits = 0; 1953817466cbSJens Wiklander } 1954817466cbSJens Wiklander } 1955817466cbSJens Wiklander 1956817466cbSJens Wiklander /* 1957817466cbSJens Wiklander * process the remaining bits 1958817466cbSJens Wiklander */ 1959817466cbSJens Wiklander for( i = 0; i < nbits; i++ ) 1960817466cbSJens Wiklander { 196162f21181SJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_montmul( X, X, N, mm, &T ) ); 1962817466cbSJens Wiklander 1963817466cbSJens Wiklander wbits <<= 1; 1964817466cbSJens Wiklander 1965817466cbSJens Wiklander if( ( wbits & ( one << wsize ) ) != 0 ) 196662f21181SJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_montmul( X, &W[1], N, mm, &T ) ); 1967817466cbSJens Wiklander } 1968817466cbSJens Wiklander 1969817466cbSJens Wiklander /* 1970817466cbSJens Wiklander * X = A^E * R * R^-1 mod N = A^E mod N 1971817466cbSJens Wiklander */ 197262f21181SJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_montred( X, N, mm, &T ) ); 1973817466cbSJens Wiklander 1974817466cbSJens Wiklander if( neg && E->n != 0 && ( E->p[0] & 1 ) != 0 ) 1975817466cbSJens Wiklander { 1976817466cbSJens Wiklander X->s = -1; 1977817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( X, N, X ) ); 1978817466cbSJens Wiklander } 1979817466cbSJens Wiklander 1980817466cbSJens Wiklander cleanup: 1981817466cbSJens Wiklander 1982*b99a4a18SJens Wiklander for( i = 0; i < ARRAY_SIZE(W); i++ ) 1983*b99a4a18SJens Wiklander mbedtls_mpi_free( W + i ); 1984817466cbSJens Wiklander 1985*b99a4a18SJens Wiklander mbedtls_mpi_free( &T ); mbedtls_mpi_free( &Apos ); 1986817466cbSJens Wiklander 1987817466cbSJens Wiklander if( _RR == NULL || _RR->p == NULL ) 1988817466cbSJens Wiklander mbedtls_mpi_free( &RR ); 1989817466cbSJens Wiklander 1990817466cbSJens Wiklander return( ret ); 1991817466cbSJens Wiklander } 1992817466cbSJens Wiklander 1993817466cbSJens Wiklander /* 1994817466cbSJens Wiklander * Greatest common divisor: G = gcd(A, B) (HAC 14.54) 1995817466cbSJens Wiklander */ 1996817466cbSJens Wiklander int mbedtls_mpi_gcd( mbedtls_mpi *G, const mbedtls_mpi *A, const mbedtls_mpi *B ) 1997817466cbSJens Wiklander { 1998817466cbSJens Wiklander int ret; 1999817466cbSJens Wiklander size_t lz, lzt; 2000817466cbSJens Wiklander mbedtls_mpi TG, TA, TB; 2001817466cbSJens Wiklander 20023d3b0591SJens Wiklander MPI_VALIDATE_RET( G != NULL ); 20033d3b0591SJens Wiklander MPI_VALIDATE_RET( A != NULL ); 20043d3b0591SJens Wiklander MPI_VALIDATE_RET( B != NULL ); 20053d3b0591SJens Wiklander 200698bd5fe3SJens Wiklander mbedtls_mpi_init_mempool( &TG ); mbedtls_mpi_init_mempool( &TA ); 200798bd5fe3SJens Wiklander mbedtls_mpi_init_mempool( &TB ); 2008817466cbSJens Wiklander 2009817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TA, A ) ); 2010817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, B ) ); 2011817466cbSJens Wiklander 2012817466cbSJens Wiklander lz = mbedtls_mpi_lsb( &TA ); 2013817466cbSJens Wiklander lzt = mbedtls_mpi_lsb( &TB ); 2014817466cbSJens Wiklander 2015817466cbSJens Wiklander if( lzt < lz ) 2016817466cbSJens Wiklander lz = lzt; 2017817466cbSJens Wiklander 2018817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TA, lz ) ); 2019817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TB, lz ) ); 2020817466cbSJens Wiklander 2021817466cbSJens Wiklander TA.s = TB.s = 1; 2022817466cbSJens Wiklander 2023817466cbSJens Wiklander while( mbedtls_mpi_cmp_int( &TA, 0 ) != 0 ) 2024817466cbSJens Wiklander { 2025817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TA, mbedtls_mpi_lsb( &TA ) ) ); 2026817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TB, mbedtls_mpi_lsb( &TB ) ) ); 2027817466cbSJens Wiklander 2028817466cbSJens Wiklander if( mbedtls_mpi_cmp_mpi( &TA, &TB ) >= 0 ) 2029817466cbSJens Wiklander { 2030817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( &TA, &TA, &TB ) ); 2031817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TA, 1 ) ); 2032817466cbSJens Wiklander } 2033817466cbSJens Wiklander else 2034817466cbSJens Wiklander { 2035817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( &TB, &TB, &TA ) ); 2036817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TB, 1 ) ); 2037817466cbSJens Wiklander } 2038817466cbSJens Wiklander } 2039817466cbSJens Wiklander 2040817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &TB, lz ) ); 2041817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_copy( G, &TB ) ); 2042817466cbSJens Wiklander 2043817466cbSJens Wiklander cleanup: 2044817466cbSJens Wiklander 2045817466cbSJens Wiklander mbedtls_mpi_free( &TG ); mbedtls_mpi_free( &TA ); mbedtls_mpi_free( &TB ); 2046817466cbSJens Wiklander 2047817466cbSJens Wiklander return( ret ); 2048817466cbSJens Wiklander } 2049817466cbSJens Wiklander 2050817466cbSJens Wiklander /* 2051817466cbSJens Wiklander * Fill X with size bytes of random. 2052817466cbSJens Wiklander * 2053817466cbSJens Wiklander * Use a temporary bytes representation to make sure the result is the same 2054817466cbSJens Wiklander * regardless of the platform endianness (useful when f_rng is actually 2055817466cbSJens Wiklander * deterministic, eg for tests). 2056817466cbSJens Wiklander */ 2057817466cbSJens Wiklander int mbedtls_mpi_fill_random( mbedtls_mpi *X, size_t size, 2058817466cbSJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), 2059817466cbSJens Wiklander void *p_rng ) 2060817466cbSJens Wiklander { 2061817466cbSJens Wiklander int ret; 2062817466cbSJens Wiklander unsigned char buf[MBEDTLS_MPI_MAX_SIZE]; 20633d3b0591SJens Wiklander MPI_VALIDATE_RET( X != NULL ); 20643d3b0591SJens Wiklander MPI_VALIDATE_RET( f_rng != NULL ); 2065817466cbSJens Wiklander 2066817466cbSJens Wiklander if( size > MBEDTLS_MPI_MAX_SIZE ) 2067817466cbSJens Wiklander return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); 2068817466cbSJens Wiklander 2069817466cbSJens Wiklander MBEDTLS_MPI_CHK( f_rng( p_rng, buf, size ) ); 2070817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( X, buf, size ) ); 2071817466cbSJens Wiklander 2072817466cbSJens Wiklander cleanup: 20733d3b0591SJens Wiklander mbedtls_platform_zeroize( buf, sizeof( buf ) ); 2074817466cbSJens Wiklander return( ret ); 2075817466cbSJens Wiklander } 2076817466cbSJens Wiklander 2077817466cbSJens Wiklander /* 2078817466cbSJens Wiklander * Modular inverse: X = A^-1 mod N (HAC 14.61 / 14.64) 2079817466cbSJens Wiklander */ 2080817466cbSJens Wiklander int mbedtls_mpi_inv_mod( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *N ) 2081817466cbSJens Wiklander { 2082817466cbSJens Wiklander int ret; 2083817466cbSJens Wiklander mbedtls_mpi G, TA, TU, U1, U2, TB, TV, V1, V2; 20843d3b0591SJens Wiklander MPI_VALIDATE_RET( X != NULL ); 20853d3b0591SJens Wiklander MPI_VALIDATE_RET( A != NULL ); 20863d3b0591SJens Wiklander MPI_VALIDATE_RET( N != NULL ); 2087817466cbSJens Wiklander 2088817466cbSJens Wiklander if( mbedtls_mpi_cmp_int( N, 1 ) <= 0 ) 2089817466cbSJens Wiklander return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); 2090817466cbSJens Wiklander 209198bd5fe3SJens Wiklander mbedtls_mpi_init_mempool( &TA ); mbedtls_mpi_init_mempool( &TU ); 209298bd5fe3SJens Wiklander mbedtls_mpi_init_mempool( &U1 ); mbedtls_mpi_init_mempool( &U2 ); 209398bd5fe3SJens Wiklander mbedtls_mpi_init_mempool( &G ); mbedtls_mpi_init_mempool( &TB ); 209498bd5fe3SJens Wiklander mbedtls_mpi_init_mempool( &TV ); mbedtls_mpi_init_mempool( &V1 ); 209598bd5fe3SJens Wiklander mbedtls_mpi_init_mempool( &V2 ); 2096817466cbSJens Wiklander 2097817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &G, A, N ) ); 2098817466cbSJens Wiklander 2099817466cbSJens Wiklander if( mbedtls_mpi_cmp_int( &G, 1 ) != 0 ) 2100817466cbSJens Wiklander { 2101817466cbSJens Wiklander ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE; 2102817466cbSJens Wiklander goto cleanup; 2103817466cbSJens Wiklander } 2104817466cbSJens Wiklander 2105817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &TA, A, N ) ); 2106817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TU, &TA ) ); 2107817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, N ) ); 2108817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TV, N ) ); 2109817466cbSJens Wiklander 2110817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &U1, 1 ) ); 2111817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &U2, 0 ) ); 2112817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &V1, 0 ) ); 2113817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &V2, 1 ) ); 2114817466cbSJens Wiklander 2115817466cbSJens Wiklander do 2116817466cbSJens Wiklander { 2117817466cbSJens Wiklander while( ( TU.p[0] & 1 ) == 0 ) 2118817466cbSJens Wiklander { 2119817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TU, 1 ) ); 2120817466cbSJens Wiklander 2121817466cbSJens Wiklander if( ( U1.p[0] & 1 ) != 0 || ( U2.p[0] & 1 ) != 0 ) 2122817466cbSJens Wiklander { 2123817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &U1, &U1, &TB ) ); 2124817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &U2, &U2, &TA ) ); 2125817466cbSJens Wiklander } 2126817466cbSJens Wiklander 2127817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &U1, 1 ) ); 2128817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &U2, 1 ) ); 2129817466cbSJens Wiklander } 2130817466cbSJens Wiklander 2131817466cbSJens Wiklander while( ( TV.p[0] & 1 ) == 0 ) 2132817466cbSJens Wiklander { 2133817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TV, 1 ) ); 2134817466cbSJens Wiklander 2135817466cbSJens Wiklander if( ( V1.p[0] & 1 ) != 0 || ( V2.p[0] & 1 ) != 0 ) 2136817466cbSJens Wiklander { 2137817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &V1, &V1, &TB ) ); 2138817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &V2, &V2, &TA ) ); 2139817466cbSJens Wiklander } 2140817466cbSJens Wiklander 2141817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &V1, 1 ) ); 2142817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &V2, 1 ) ); 2143817466cbSJens Wiklander } 2144817466cbSJens Wiklander 2145817466cbSJens Wiklander if( mbedtls_mpi_cmp_mpi( &TU, &TV ) >= 0 ) 2146817466cbSJens Wiklander { 2147817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &TU, &TU, &TV ) ); 2148817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &U1, &U1, &V1 ) ); 2149817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &U2, &U2, &V2 ) ); 2150817466cbSJens Wiklander } 2151817466cbSJens Wiklander else 2152817466cbSJens Wiklander { 2153817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &TV, &TV, &TU ) ); 2154817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &V1, &V1, &U1 ) ); 2155817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &V2, &V2, &U2 ) ); 2156817466cbSJens Wiklander } 2157817466cbSJens Wiklander } 2158817466cbSJens Wiklander while( mbedtls_mpi_cmp_int( &TU, 0 ) != 0 ); 2159817466cbSJens Wiklander 2160817466cbSJens Wiklander while( mbedtls_mpi_cmp_int( &V1, 0 ) < 0 ) 2161817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &V1, &V1, N ) ); 2162817466cbSJens Wiklander 2163817466cbSJens Wiklander while( mbedtls_mpi_cmp_mpi( &V1, N ) >= 0 ) 2164817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &V1, &V1, N ) ); 2165817466cbSJens Wiklander 2166817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, &V1 ) ); 2167817466cbSJens Wiklander 2168817466cbSJens Wiklander cleanup: 2169817466cbSJens Wiklander 2170817466cbSJens Wiklander mbedtls_mpi_free( &TA ); mbedtls_mpi_free( &TU ); mbedtls_mpi_free( &U1 ); mbedtls_mpi_free( &U2 ); 2171817466cbSJens Wiklander mbedtls_mpi_free( &G ); mbedtls_mpi_free( &TB ); mbedtls_mpi_free( &TV ); 2172817466cbSJens Wiklander mbedtls_mpi_free( &V1 ); mbedtls_mpi_free( &V2 ); 2173817466cbSJens Wiklander 2174817466cbSJens Wiklander return( ret ); 2175817466cbSJens Wiklander } 2176817466cbSJens Wiklander 2177817466cbSJens Wiklander #if defined(MBEDTLS_GENPRIME) 2178817466cbSJens Wiklander 2179817466cbSJens Wiklander static const int small_prime[] = 2180817466cbSJens Wiklander { 2181817466cbSJens Wiklander 3, 5, 7, 11, 13, 17, 19, 23, 2182817466cbSJens Wiklander 29, 31, 37, 41, 43, 47, 53, 59, 2183817466cbSJens Wiklander 61, 67, 71, 73, 79, 83, 89, 97, 2184817466cbSJens Wiklander 101, 103, 107, 109, 113, 127, 131, 137, 2185817466cbSJens Wiklander 139, 149, 151, 157, 163, 167, 173, 179, 2186817466cbSJens Wiklander 181, 191, 193, 197, 199, 211, 223, 227, 2187817466cbSJens Wiklander 229, 233, 239, 241, 251, 257, 263, 269, 2188817466cbSJens Wiklander 271, 277, 281, 283, 293, 307, 311, 313, 2189817466cbSJens Wiklander 317, 331, 337, 347, 349, 353, 359, 367, 2190817466cbSJens Wiklander 373, 379, 383, 389, 397, 401, 409, 419, 2191817466cbSJens Wiklander 421, 431, 433, 439, 443, 449, 457, 461, 2192817466cbSJens Wiklander 463, 467, 479, 487, 491, 499, 503, 509, 2193817466cbSJens Wiklander 521, 523, 541, 547, 557, 563, 569, 571, 2194817466cbSJens Wiklander 577, 587, 593, 599, 601, 607, 613, 617, 2195817466cbSJens Wiklander 619, 631, 641, 643, 647, 653, 659, 661, 2196817466cbSJens Wiklander 673, 677, 683, 691, 701, 709, 719, 727, 2197817466cbSJens Wiklander 733, 739, 743, 751, 757, 761, 769, 773, 2198817466cbSJens Wiklander 787, 797, 809, 811, 821, 823, 827, 829, 2199817466cbSJens Wiklander 839, 853, 857, 859, 863, 877, 881, 883, 2200817466cbSJens Wiklander 887, 907, 911, 919, 929, 937, 941, 947, 2201817466cbSJens Wiklander 953, 967, 971, 977, 983, 991, 997, -103 2202817466cbSJens Wiklander }; 2203817466cbSJens Wiklander 2204817466cbSJens Wiklander /* 2205817466cbSJens Wiklander * Small divisors test (X must be positive) 2206817466cbSJens Wiklander * 2207817466cbSJens Wiklander * Return values: 2208817466cbSJens Wiklander * 0: no small factor (possible prime, more tests needed) 2209817466cbSJens Wiklander * 1: certain prime 2210817466cbSJens Wiklander * MBEDTLS_ERR_MPI_NOT_ACCEPTABLE: certain non-prime 2211817466cbSJens Wiklander * other negative: error 2212817466cbSJens Wiklander */ 2213817466cbSJens Wiklander static int mpi_check_small_factors( const mbedtls_mpi *X ) 2214817466cbSJens Wiklander { 2215817466cbSJens Wiklander int ret = 0; 2216817466cbSJens Wiklander size_t i; 2217817466cbSJens Wiklander mbedtls_mpi_uint r; 2218817466cbSJens Wiklander 2219817466cbSJens Wiklander if( ( X->p[0] & 1 ) == 0 ) 2220817466cbSJens Wiklander return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE ); 2221817466cbSJens Wiklander 2222817466cbSJens Wiklander for( i = 0; small_prime[i] > 0; i++ ) 2223817466cbSJens Wiklander { 2224817466cbSJens Wiklander if( mbedtls_mpi_cmp_int( X, small_prime[i] ) <= 0 ) 2225817466cbSJens Wiklander return( 1 ); 2226817466cbSJens Wiklander 2227817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_mod_int( &r, X, small_prime[i] ) ); 2228817466cbSJens Wiklander 2229817466cbSJens Wiklander if( r == 0 ) 2230817466cbSJens Wiklander return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE ); 2231817466cbSJens Wiklander } 2232817466cbSJens Wiklander 2233817466cbSJens Wiklander cleanup: 2234817466cbSJens Wiklander return( ret ); 2235817466cbSJens Wiklander } 2236817466cbSJens Wiklander 2237817466cbSJens Wiklander /* 2238817466cbSJens Wiklander * Miller-Rabin pseudo-primality test (HAC 4.24) 2239817466cbSJens Wiklander */ 22403d3b0591SJens Wiklander static int mpi_miller_rabin( const mbedtls_mpi *X, size_t rounds, 2241817466cbSJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), 2242817466cbSJens Wiklander void *p_rng ) 2243817466cbSJens Wiklander { 2244817466cbSJens Wiklander int ret, count; 22453d3b0591SJens Wiklander size_t i, j, k, s; 2246817466cbSJens Wiklander mbedtls_mpi W, R, T, A, RR; 2247817466cbSJens Wiklander 22483d3b0591SJens Wiklander MPI_VALIDATE_RET( X != NULL ); 22493d3b0591SJens Wiklander MPI_VALIDATE_RET( f_rng != NULL ); 22503d3b0591SJens Wiklander 225198bd5fe3SJens Wiklander mbedtls_mpi_init_mempool( &W ); mbedtls_mpi_init_mempool( &R ); 225298bd5fe3SJens Wiklander mbedtls_mpi_init_mempool( &T ); mbedtls_mpi_init_mempool( &A ); 225398bd5fe3SJens Wiklander mbedtls_mpi_init_mempool( &RR ); 2254817466cbSJens Wiklander 2255817466cbSJens Wiklander /* 2256817466cbSJens Wiklander * W = |X| - 1 2257817466cbSJens Wiklander * R = W >> lsb( W ) 2258817466cbSJens Wiklander */ 2259817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &W, X, 1 ) ); 2260817466cbSJens Wiklander s = mbedtls_mpi_lsb( &W ); 2261817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &R, &W ) ); 2262817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &R, s ) ); 2263817466cbSJens Wiklander 2264817466cbSJens Wiklander i = mbedtls_mpi_bitlen( X ); 2265817466cbSJens Wiklander 22663d3b0591SJens Wiklander for( i = 0; i < rounds; i++ ) 2267817466cbSJens Wiklander { 2268817466cbSJens Wiklander /* 2269817466cbSJens Wiklander * pick a random A, 1 < A < |X| - 1 2270817466cbSJens Wiklander */ 2271817466cbSJens Wiklander count = 0; 2272817466cbSJens Wiklander do { 2273817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &A, X->n * ciL, f_rng, p_rng ) ); 2274817466cbSJens Wiklander 2275817466cbSJens Wiklander j = mbedtls_mpi_bitlen( &A ); 2276817466cbSJens Wiklander k = mbedtls_mpi_bitlen( &W ); 2277817466cbSJens Wiklander if (j > k) { 22783d3b0591SJens Wiklander A.p[A.n - 1] &= ( (mbedtls_mpi_uint) 1 << ( k - ( A.n - 1 ) * biL - 1 ) ) - 1; 2279817466cbSJens Wiklander } 2280817466cbSJens Wiklander 2281117cce93SJens Wiklander if (count++ > 300) { 2282336e3299SJens Wiklander ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE; 2283336e3299SJens Wiklander goto cleanup; 2284817466cbSJens Wiklander } 2285817466cbSJens Wiklander 2286817466cbSJens Wiklander } while ( mbedtls_mpi_cmp_mpi( &A, &W ) >= 0 || 2287817466cbSJens Wiklander mbedtls_mpi_cmp_int( &A, 1 ) <= 0 ); 2288817466cbSJens Wiklander 2289817466cbSJens Wiklander /* 2290817466cbSJens Wiklander * A = A^R mod |X| 2291817466cbSJens Wiklander */ 2292817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &A, &A, &R, X, &RR ) ); 2293817466cbSJens Wiklander 2294817466cbSJens Wiklander if( mbedtls_mpi_cmp_mpi( &A, &W ) == 0 || 2295817466cbSJens Wiklander mbedtls_mpi_cmp_int( &A, 1 ) == 0 ) 2296817466cbSJens Wiklander continue; 2297817466cbSJens Wiklander 2298817466cbSJens Wiklander j = 1; 2299817466cbSJens Wiklander while( j < s && mbedtls_mpi_cmp_mpi( &A, &W ) != 0 ) 2300817466cbSJens Wiklander { 2301817466cbSJens Wiklander /* 2302817466cbSJens Wiklander * A = A * A mod |X| 2303817466cbSJens Wiklander */ 2304817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T, &A, &A ) ); 2305817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &A, &T, X ) ); 2306817466cbSJens Wiklander 2307817466cbSJens Wiklander if( mbedtls_mpi_cmp_int( &A, 1 ) == 0 ) 2308817466cbSJens Wiklander break; 2309817466cbSJens Wiklander 2310817466cbSJens Wiklander j++; 2311817466cbSJens Wiklander } 2312817466cbSJens Wiklander 2313817466cbSJens Wiklander /* 2314817466cbSJens Wiklander * not prime if A != |X| - 1 or A == 1 2315817466cbSJens Wiklander */ 2316817466cbSJens Wiklander if( mbedtls_mpi_cmp_mpi( &A, &W ) != 0 || 2317817466cbSJens Wiklander mbedtls_mpi_cmp_int( &A, 1 ) == 0 ) 2318817466cbSJens Wiklander { 2319817466cbSJens Wiklander ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE; 2320817466cbSJens Wiklander break; 2321817466cbSJens Wiklander } 2322817466cbSJens Wiklander } 2323817466cbSJens Wiklander 2324817466cbSJens Wiklander cleanup: 23253d3b0591SJens Wiklander mbedtls_mpi_free( &W ); mbedtls_mpi_free( &R ); 23263d3b0591SJens Wiklander mbedtls_mpi_free( &T ); mbedtls_mpi_free( &A ); 2327817466cbSJens Wiklander mbedtls_mpi_free( &RR ); 2328817466cbSJens Wiklander 2329817466cbSJens Wiklander return( ret ); 2330817466cbSJens Wiklander } 2331817466cbSJens Wiklander 2332817466cbSJens Wiklander /* 2333817466cbSJens Wiklander * Pseudo-primality test: small factors, then Miller-Rabin 2334817466cbSJens Wiklander */ 23353d3b0591SJens Wiklander int mbedtls_mpi_is_prime_ext( const mbedtls_mpi *X, int rounds, 2336817466cbSJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), 2337817466cbSJens Wiklander void *p_rng ) 2338817466cbSJens Wiklander { 2339817466cbSJens Wiklander int ret; 2340817466cbSJens Wiklander mbedtls_mpi XX; 23413d3b0591SJens Wiklander MPI_VALIDATE_RET( X != NULL ); 23423d3b0591SJens Wiklander MPI_VALIDATE_RET( f_rng != NULL ); 2343817466cbSJens Wiklander 2344817466cbSJens Wiklander XX.s = 1; 2345817466cbSJens Wiklander XX.n = X->n; 2346817466cbSJens Wiklander XX.p = X->p; 2347817466cbSJens Wiklander 2348817466cbSJens Wiklander if( mbedtls_mpi_cmp_int( &XX, 0 ) == 0 || 2349817466cbSJens Wiklander mbedtls_mpi_cmp_int( &XX, 1 ) == 0 ) 2350817466cbSJens Wiklander return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE ); 2351817466cbSJens Wiklander 2352817466cbSJens Wiklander if( mbedtls_mpi_cmp_int( &XX, 2 ) == 0 ) 2353817466cbSJens Wiklander return( 0 ); 2354817466cbSJens Wiklander 2355817466cbSJens Wiklander if( ( ret = mpi_check_small_factors( &XX ) ) != 0 ) 2356817466cbSJens Wiklander { 2357817466cbSJens Wiklander if( ret == 1 ) 2358817466cbSJens Wiklander return( 0 ); 2359817466cbSJens Wiklander 2360817466cbSJens Wiklander return( ret ); 2361817466cbSJens Wiklander } 2362817466cbSJens Wiklander 23633d3b0591SJens Wiklander return( mpi_miller_rabin( &XX, rounds, f_rng, p_rng ) ); 2364817466cbSJens Wiklander } 2365817466cbSJens Wiklander 23663d3b0591SJens Wiklander #if !defined(MBEDTLS_DEPRECATED_REMOVED) 2367817466cbSJens Wiklander /* 23683d3b0591SJens Wiklander * Pseudo-primality test, error probability 2^-80 2369817466cbSJens Wiklander */ 23703d3b0591SJens Wiklander int mbedtls_mpi_is_prime( const mbedtls_mpi *X, 2371817466cbSJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), 2372817466cbSJens Wiklander void *p_rng ) 2373817466cbSJens Wiklander { 23743d3b0591SJens Wiklander MPI_VALIDATE_RET( X != NULL ); 23753d3b0591SJens Wiklander MPI_VALIDATE_RET( f_rng != NULL ); 23763d3b0591SJens Wiklander 23773d3b0591SJens Wiklander /* 23783d3b0591SJens Wiklander * In the past our key generation aimed for an error rate of at most 23793d3b0591SJens Wiklander * 2^-80. Since this function is deprecated, aim for the same certainty 23803d3b0591SJens Wiklander * here as well. 23813d3b0591SJens Wiklander */ 23823d3b0591SJens Wiklander return( mbedtls_mpi_is_prime_ext( X, 40, f_rng, p_rng ) ); 23833d3b0591SJens Wiklander } 23843d3b0591SJens Wiklander #endif 23853d3b0591SJens Wiklander 23863d3b0591SJens Wiklander /* 23873d3b0591SJens Wiklander * Prime number generation 23883d3b0591SJens Wiklander * 23893d3b0591SJens Wiklander * To generate an RSA key in a way recommended by FIPS 186-4, both primes must 23903d3b0591SJens Wiklander * be either 1024 bits or 1536 bits long, and flags must contain 23913d3b0591SJens Wiklander * MBEDTLS_MPI_GEN_PRIME_FLAG_LOW_ERR. 23923d3b0591SJens Wiklander */ 23933d3b0591SJens Wiklander int mbedtls_mpi_gen_prime( mbedtls_mpi *X, size_t nbits, int flags, 23943d3b0591SJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), 23953d3b0591SJens Wiklander void *p_rng ) 23963d3b0591SJens Wiklander { 23973d3b0591SJens Wiklander #ifdef MBEDTLS_HAVE_INT64 23983d3b0591SJens Wiklander // ceil(2^63.5) 23993d3b0591SJens Wiklander #define CEIL_MAXUINT_DIV_SQRT2 0xb504f333f9de6485ULL 24003d3b0591SJens Wiklander #else 24013d3b0591SJens Wiklander // ceil(2^31.5) 24023d3b0591SJens Wiklander #define CEIL_MAXUINT_DIV_SQRT2 0xb504f334U 24033d3b0591SJens Wiklander #endif 24043d3b0591SJens Wiklander int ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE; 2405817466cbSJens Wiklander size_t k, n; 24063d3b0591SJens Wiklander int rounds; 2407817466cbSJens Wiklander mbedtls_mpi_uint r; 2408817466cbSJens Wiklander mbedtls_mpi Y; 2409817466cbSJens Wiklander 24103d3b0591SJens Wiklander MPI_VALIDATE_RET( X != NULL ); 24113d3b0591SJens Wiklander MPI_VALIDATE_RET( f_rng != NULL ); 24123d3b0591SJens Wiklander 2413817466cbSJens Wiklander if( nbits < 3 || nbits > MBEDTLS_MPI_MAX_BITS ) 2414817466cbSJens Wiklander return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); 2415817466cbSJens Wiklander 241698bd5fe3SJens Wiklander mbedtls_mpi_init_mempool( &Y ); 2417817466cbSJens Wiklander 2418817466cbSJens Wiklander n = BITS_TO_LIMBS( nbits ); 2419817466cbSJens Wiklander 24203d3b0591SJens Wiklander if( ( flags & MBEDTLS_MPI_GEN_PRIME_FLAG_LOW_ERR ) == 0 ) 24213d3b0591SJens Wiklander { 24223d3b0591SJens Wiklander /* 24233d3b0591SJens Wiklander * 2^-80 error probability, number of rounds chosen per HAC, table 4.4 24243d3b0591SJens Wiklander */ 24253d3b0591SJens Wiklander rounds = ( ( nbits >= 1300 ) ? 2 : ( nbits >= 850 ) ? 3 : 24263d3b0591SJens Wiklander ( nbits >= 650 ) ? 4 : ( nbits >= 350 ) ? 8 : 24273d3b0591SJens Wiklander ( nbits >= 250 ) ? 12 : ( nbits >= 150 ) ? 18 : 27 ); 24283d3b0591SJens Wiklander } 24293d3b0591SJens Wiklander else 24303d3b0591SJens Wiklander { 24313d3b0591SJens Wiklander /* 24323d3b0591SJens Wiklander * 2^-100 error probability, number of rounds computed based on HAC, 24333d3b0591SJens Wiklander * fact 4.48 24343d3b0591SJens Wiklander */ 24353d3b0591SJens Wiklander rounds = ( ( nbits >= 1450 ) ? 4 : ( nbits >= 1150 ) ? 5 : 24363d3b0591SJens Wiklander ( nbits >= 1000 ) ? 6 : ( nbits >= 850 ) ? 7 : 24373d3b0591SJens Wiklander ( nbits >= 750 ) ? 8 : ( nbits >= 500 ) ? 13 : 24383d3b0591SJens Wiklander ( nbits >= 250 ) ? 28 : ( nbits >= 150 ) ? 40 : 51 ); 24393d3b0591SJens Wiklander } 24403d3b0591SJens Wiklander 24413d3b0591SJens Wiklander while( 1 ) 24423d3b0591SJens Wiklander { 2443817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( X, n * ciL, f_rng, p_rng ) ); 24443d3b0591SJens Wiklander /* make sure generated number is at least (nbits-1)+0.5 bits (FIPS 186-4 §B.3.3 steps 4.4, 5.5) */ 24453d3b0591SJens Wiklander if( X->p[n-1] < CEIL_MAXUINT_DIV_SQRT2 ) continue; 2446817466cbSJens Wiklander 24473d3b0591SJens Wiklander k = n * biL; 24483d3b0591SJens Wiklander if( k > nbits ) MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( X, k - nbits ) ); 2449817466cbSJens Wiklander X->p[0] |= 1; 2450817466cbSJens Wiklander 24513d3b0591SJens Wiklander if( ( flags & MBEDTLS_MPI_GEN_PRIME_FLAG_DH ) == 0 ) 2452817466cbSJens Wiklander { 24533d3b0591SJens Wiklander ret = mbedtls_mpi_is_prime_ext( X, rounds, f_rng, p_rng ); 24543d3b0591SJens Wiklander 2455817466cbSJens Wiklander if( ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE ) 2456817466cbSJens Wiklander goto cleanup; 2457817466cbSJens Wiklander } 2458817466cbSJens Wiklander else 2459817466cbSJens Wiklander { 2460817466cbSJens Wiklander /* 2461817466cbSJens Wiklander * An necessary condition for Y and X = 2Y + 1 to be prime 2462817466cbSJens Wiklander * is X = 2 mod 3 (which is equivalent to Y = 2 mod 3). 2463817466cbSJens Wiklander * Make sure it is satisfied, while keeping X = 3 mod 4 2464817466cbSJens Wiklander */ 2465817466cbSJens Wiklander 2466817466cbSJens Wiklander X->p[0] |= 2; 2467817466cbSJens Wiklander 2468817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_mod_int( &r, X, 3 ) ); 2469817466cbSJens Wiklander if( r == 0 ) 2470817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, X, 8 ) ); 2471817466cbSJens Wiklander else if( r == 1 ) 2472817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, X, 4 ) ); 2473817466cbSJens Wiklander 2474817466cbSJens Wiklander /* Set Y = (X-1) / 2, which is X / 2 because X is odd */ 2475817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &Y, X ) ); 2476817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &Y, 1 ) ); 2477817466cbSJens Wiklander 2478817466cbSJens Wiklander while( 1 ) 2479817466cbSJens Wiklander { 2480817466cbSJens Wiklander /* 2481817466cbSJens Wiklander * First, check small factors for X and Y 2482817466cbSJens Wiklander * before doing Miller-Rabin on any of them 2483817466cbSJens Wiklander */ 2484817466cbSJens Wiklander if( ( ret = mpi_check_small_factors( X ) ) == 0 && 2485817466cbSJens Wiklander ( ret = mpi_check_small_factors( &Y ) ) == 0 && 24863d3b0591SJens Wiklander ( ret = mpi_miller_rabin( X, rounds, f_rng, p_rng ) ) 24873d3b0591SJens Wiklander == 0 && 24883d3b0591SJens Wiklander ( ret = mpi_miller_rabin( &Y, rounds, f_rng, p_rng ) ) 24893d3b0591SJens Wiklander == 0 ) 24903d3b0591SJens Wiklander goto cleanup; 2491817466cbSJens Wiklander 2492817466cbSJens Wiklander if( ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE ) 2493817466cbSJens Wiklander goto cleanup; 2494817466cbSJens Wiklander 2495817466cbSJens Wiklander /* 2496817466cbSJens Wiklander * Next candidates. We want to preserve Y = (X-1) / 2 and 2497817466cbSJens Wiklander * Y = 1 mod 2 and Y = 2 mod 3 (eq X = 3 mod 4 and X = 2 mod 3) 2498817466cbSJens Wiklander * so up Y by 6 and X by 12. 2499817466cbSJens Wiklander */ 2500817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, X, 12 ) ); 2501817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( &Y, &Y, 6 ) ); 2502817466cbSJens Wiklander } 2503817466cbSJens Wiklander } 25043d3b0591SJens Wiklander } 2505817466cbSJens Wiklander 2506817466cbSJens Wiklander cleanup: 2507817466cbSJens Wiklander 2508817466cbSJens Wiklander mbedtls_mpi_free( &Y ); 2509817466cbSJens Wiklander 2510817466cbSJens Wiklander return( ret ); 2511817466cbSJens Wiklander } 2512817466cbSJens Wiklander 2513817466cbSJens Wiklander #endif /* MBEDTLS_GENPRIME */ 2514817466cbSJens Wiklander 2515817466cbSJens Wiklander #if defined(MBEDTLS_SELF_TEST) 2516817466cbSJens Wiklander 2517817466cbSJens Wiklander #define GCD_PAIR_COUNT 3 2518817466cbSJens Wiklander 2519817466cbSJens Wiklander static const int gcd_pairs[GCD_PAIR_COUNT][3] = 2520817466cbSJens Wiklander { 2521817466cbSJens Wiklander { 693, 609, 21 }, 2522817466cbSJens Wiklander { 1764, 868, 28 }, 2523817466cbSJens Wiklander { 768454923, 542167814, 1 } 2524817466cbSJens Wiklander }; 2525817466cbSJens Wiklander 2526817466cbSJens Wiklander /* 2527817466cbSJens Wiklander * Checkup routine 2528817466cbSJens Wiklander */ 2529817466cbSJens Wiklander int mbedtls_mpi_self_test( int verbose ) 2530817466cbSJens Wiklander { 2531817466cbSJens Wiklander int ret, i; 2532817466cbSJens Wiklander mbedtls_mpi A, E, N, X, Y, U, V; 2533817466cbSJens Wiklander 253498bd5fe3SJens Wiklander mbedtls_mpi_init_mempool( &A ); mbedtls_mpi_init_mempool( &E ); 253598bd5fe3SJens Wiklander mbedtls_mpi_init_mempool( &N ); mbedtls_mpi_init_mempool( &X ); 253698bd5fe3SJens Wiklander mbedtls_mpi_init_mempool( &Y ); mbedtls_mpi_init_mempool( &U ); 253798bd5fe3SJens Wiklander mbedtls_mpi_init_mempool( &V ); 2538817466cbSJens Wiklander 2539817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &A, 16, 2540817466cbSJens Wiklander "EFE021C2645FD1DC586E69184AF4A31E" \ 2541817466cbSJens Wiklander "D5F53E93B5F123FA41680867BA110131" \ 2542817466cbSJens Wiklander "944FE7952E2517337780CB0DB80E61AA" \ 2543817466cbSJens Wiklander "E7C8DDC6C5C6AADEB34EB38A2F40D5E6" ) ); 2544817466cbSJens Wiklander 2545817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &E, 16, 2546817466cbSJens Wiklander "B2E7EFD37075B9F03FF989C7C5051C20" \ 2547817466cbSJens Wiklander "34D2A323810251127E7BF8625A4F49A5" \ 2548817466cbSJens Wiklander "F3E27F4DA8BD59C47D6DAABA4C8127BD" \ 2549817466cbSJens Wiklander "5B5C25763222FEFCCFC38B832366C29E" ) ); 2550817466cbSJens Wiklander 2551817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &N, 16, 2552817466cbSJens Wiklander "0066A198186C18C10B2F5ED9B522752A" \ 2553817466cbSJens Wiklander "9830B69916E535C8F047518A889A43A5" \ 2554817466cbSJens Wiklander "94B6BED27A168D31D4A52F88925AA8F5" ) ); 2555817466cbSJens Wiklander 2556817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &X, &A, &N ) ); 2557817466cbSJens Wiklander 2558817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &U, 16, 2559817466cbSJens Wiklander "602AB7ECA597A3D6B56FF9829A5E8B85" \ 2560817466cbSJens Wiklander "9E857EA95A03512E2BAE7391688D264A" \ 2561817466cbSJens Wiklander "A5663B0341DB9CCFD2C4C5F421FEC814" \ 2562817466cbSJens Wiklander "8001B72E848A38CAE1C65F78E56ABDEF" \ 2563817466cbSJens Wiklander "E12D3C039B8A02D6BE593F0BBBDA56F1" \ 2564817466cbSJens Wiklander "ECF677152EF804370C1A305CAF3B5BF1" \ 2565817466cbSJens Wiklander "30879B56C61DE584A0F53A2447A51E" ) ); 2566817466cbSJens Wiklander 2567817466cbSJens Wiklander if( verbose != 0 ) 2568817466cbSJens Wiklander mbedtls_printf( " MPI test #1 (mul_mpi): " ); 2569817466cbSJens Wiklander 2570817466cbSJens Wiklander if( mbedtls_mpi_cmp_mpi( &X, &U ) != 0 ) 2571817466cbSJens Wiklander { 2572817466cbSJens Wiklander if( verbose != 0 ) 2573817466cbSJens Wiklander mbedtls_printf( "failed\n" ); 2574817466cbSJens Wiklander 2575817466cbSJens Wiklander ret = 1; 2576817466cbSJens Wiklander goto cleanup; 2577817466cbSJens Wiklander } 2578817466cbSJens Wiklander 2579817466cbSJens Wiklander if( verbose != 0 ) 2580817466cbSJens Wiklander mbedtls_printf( "passed\n" ); 2581817466cbSJens Wiklander 2582817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_div_mpi( &X, &Y, &A, &N ) ); 2583817466cbSJens Wiklander 2584817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &U, 16, 2585817466cbSJens Wiklander "256567336059E52CAE22925474705F39A94" ) ); 2586817466cbSJens Wiklander 2587817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &V, 16, 2588817466cbSJens Wiklander "6613F26162223DF488E9CD48CC132C7A" \ 2589817466cbSJens Wiklander "0AC93C701B001B092E4E5B9F73BCD27B" \ 2590817466cbSJens Wiklander "9EE50D0657C77F374E903CDFA4C642" ) ); 2591817466cbSJens Wiklander 2592817466cbSJens Wiklander if( verbose != 0 ) 2593817466cbSJens Wiklander mbedtls_printf( " MPI test #2 (div_mpi): " ); 2594817466cbSJens Wiklander 2595817466cbSJens Wiklander if( mbedtls_mpi_cmp_mpi( &X, &U ) != 0 || 2596817466cbSJens Wiklander mbedtls_mpi_cmp_mpi( &Y, &V ) != 0 ) 2597817466cbSJens Wiklander { 2598817466cbSJens Wiklander if( verbose != 0 ) 2599817466cbSJens Wiklander mbedtls_printf( "failed\n" ); 2600817466cbSJens Wiklander 2601817466cbSJens Wiklander ret = 1; 2602817466cbSJens Wiklander goto cleanup; 2603817466cbSJens Wiklander } 2604817466cbSJens Wiklander 2605817466cbSJens Wiklander if( verbose != 0 ) 2606817466cbSJens Wiklander mbedtls_printf( "passed\n" ); 2607817466cbSJens Wiklander 2608817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &X, &A, &E, &N, NULL ) ); 2609817466cbSJens Wiklander 2610817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &U, 16, 2611817466cbSJens Wiklander "36E139AEA55215609D2816998ED020BB" \ 2612817466cbSJens Wiklander "BD96C37890F65171D948E9BC7CBAA4D9" \ 2613817466cbSJens Wiklander "325D24D6A3C12710F10A09FA08AB87" ) ); 2614817466cbSJens Wiklander 2615817466cbSJens Wiklander if( verbose != 0 ) 2616817466cbSJens Wiklander mbedtls_printf( " MPI test #3 (exp_mod): " ); 2617817466cbSJens Wiklander 2618817466cbSJens Wiklander if( mbedtls_mpi_cmp_mpi( &X, &U ) != 0 ) 2619817466cbSJens Wiklander { 2620817466cbSJens Wiklander if( verbose != 0 ) 2621817466cbSJens Wiklander mbedtls_printf( "failed\n" ); 2622817466cbSJens Wiklander 2623817466cbSJens Wiklander ret = 1; 2624817466cbSJens Wiklander goto cleanup; 2625817466cbSJens Wiklander } 2626817466cbSJens Wiklander 2627817466cbSJens Wiklander if( verbose != 0 ) 2628817466cbSJens Wiklander mbedtls_printf( "passed\n" ); 2629817466cbSJens Wiklander 2630817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &X, &A, &N ) ); 2631817466cbSJens Wiklander 2632817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &U, 16, 2633817466cbSJens Wiklander "003A0AAEDD7E784FC07D8F9EC6E3BFD5" \ 2634817466cbSJens Wiklander "C3DBA76456363A10869622EAC2DD84EC" \ 2635817466cbSJens Wiklander "C5B8A74DAC4D09E03B5E0BE779F2DF61" ) ); 2636817466cbSJens Wiklander 2637817466cbSJens Wiklander if( verbose != 0 ) 2638817466cbSJens Wiklander mbedtls_printf( " MPI test #4 (inv_mod): " ); 2639817466cbSJens Wiklander 2640817466cbSJens Wiklander if( mbedtls_mpi_cmp_mpi( &X, &U ) != 0 ) 2641817466cbSJens Wiklander { 2642817466cbSJens Wiklander if( verbose != 0 ) 2643817466cbSJens Wiklander mbedtls_printf( "failed\n" ); 2644817466cbSJens Wiklander 2645817466cbSJens Wiklander ret = 1; 2646817466cbSJens Wiklander goto cleanup; 2647817466cbSJens Wiklander } 2648817466cbSJens Wiklander 2649817466cbSJens Wiklander if( verbose != 0 ) 2650817466cbSJens Wiklander mbedtls_printf( "passed\n" ); 2651817466cbSJens Wiklander 2652817466cbSJens Wiklander if( verbose != 0 ) 2653817466cbSJens Wiklander mbedtls_printf( " MPI test #5 (simple gcd): " ); 2654817466cbSJens Wiklander 2655817466cbSJens Wiklander for( i = 0; i < GCD_PAIR_COUNT; i++ ) 2656817466cbSJens Wiklander { 2657817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &X, gcd_pairs[i][0] ) ); 2658817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &Y, gcd_pairs[i][1] ) ); 2659817466cbSJens Wiklander 2660817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &A, &X, &Y ) ); 2661817466cbSJens Wiklander 2662817466cbSJens Wiklander if( mbedtls_mpi_cmp_int( &A, gcd_pairs[i][2] ) != 0 ) 2663817466cbSJens Wiklander { 2664817466cbSJens Wiklander if( verbose != 0 ) 2665817466cbSJens Wiklander mbedtls_printf( "failed at %d\n", i ); 2666817466cbSJens Wiklander 2667817466cbSJens Wiklander ret = 1; 2668817466cbSJens Wiklander goto cleanup; 2669817466cbSJens Wiklander } 2670817466cbSJens Wiklander } 2671817466cbSJens Wiklander 2672817466cbSJens Wiklander if( verbose != 0 ) 2673817466cbSJens Wiklander mbedtls_printf( "passed\n" ); 2674817466cbSJens Wiklander 2675817466cbSJens Wiklander cleanup: 2676817466cbSJens Wiklander 2677817466cbSJens Wiklander if( ret != 0 && verbose != 0 ) 2678817466cbSJens Wiklander mbedtls_printf( "Unexpected error, return code = %08X\n", ret ); 2679817466cbSJens Wiklander 2680817466cbSJens Wiklander mbedtls_mpi_free( &A ); mbedtls_mpi_free( &E ); mbedtls_mpi_free( &N ); mbedtls_mpi_free( &X ); 2681817466cbSJens Wiklander mbedtls_mpi_free( &Y ); mbedtls_mpi_free( &U ); mbedtls_mpi_free( &V ); 2682817466cbSJens Wiklander 2683817466cbSJens Wiklander if( verbose != 0 ) 2684817466cbSJens Wiklander mbedtls_printf( "\n" ); 2685817466cbSJens Wiklander 2686817466cbSJens Wiklander return( ret ); 2687817466cbSJens Wiklander } 2688817466cbSJens Wiklander 2689817466cbSJens Wiklander #endif /* MBEDTLS_SELF_TEST */ 2690817466cbSJens Wiklander 2691817466cbSJens Wiklander #endif /* MBEDTLS_BIGNUM_C */ 2692