1817466cbSJens Wiklander /* 2817466cbSJens Wiklander * Multi-precision integer library 3817466cbSJens Wiklander * 47901324dSJerome Forissier * Copyright The Mbed TLS Contributors 57901324dSJerome Forissier * SPDX-License-Identifier: Apache-2.0 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 20817466cbSJens Wiklander /* 21817466cbSJens Wiklander * The following sources were referenced in the design of this Multi-precision 22817466cbSJens Wiklander * Integer library: 23817466cbSJens Wiklander * 24817466cbSJens Wiklander * [1] Handbook of Applied Cryptography - 1997 25817466cbSJens Wiklander * Menezes, van Oorschot and Vanstone 26817466cbSJens Wiklander * 27817466cbSJens Wiklander * [2] Multi-Precision Math 28817466cbSJens Wiklander * Tom St Denis 29817466cbSJens Wiklander * https://github.com/libtom/libtommath/blob/develop/tommath.pdf 30817466cbSJens Wiklander * 31817466cbSJens Wiklander * [3] GNU Multi-Precision Arithmetic Library 32817466cbSJens Wiklander * https://gmplib.org/manual/index.html 33817466cbSJens Wiklander * 34817466cbSJens Wiklander */ 35817466cbSJens Wiklander 367901324dSJerome Forissier #include "common.h" 37817466cbSJens Wiklander 38817466cbSJens Wiklander #if defined(MBEDTLS_BIGNUM_C) 39817466cbSJens Wiklander 40817466cbSJens Wiklander #include "mbedtls/bignum.h" 41*32b31808SJens Wiklander #include "bignum_core.h" 42*32b31808SJens Wiklander #include "bn_mul.h" 433d3b0591SJens Wiklander #include "mbedtls/platform_util.h" 4411fa71b9SJerome Forissier #include "mbedtls/error.h" 45039e02dfSJerome Forissier #include "constant_time_internal.h" 46817466cbSJens Wiklander 47039e02dfSJerome Forissier #include <limits.h> 48817466cbSJens Wiklander #include <string.h> 49817466cbSJens Wiklander 50817466cbSJens Wiklander #include "mbedtls/platform.h" 51817466cbSJens Wiklander 5298bd5fe3SJens Wiklander #include <mempool.h> 53b99a4a18SJens Wiklander #include <util.h> 5498bd5fe3SJens Wiklander 553d3b0591SJens Wiklander #define MPI_VALIDATE_RET(cond) \ 563d3b0591SJens Wiklander MBEDTLS_INTERNAL_VALIDATE_RET(cond, MBEDTLS_ERR_MPI_BAD_INPUT_DATA) 573d3b0591SJens Wiklander #define MPI_VALIDATE(cond) \ 583d3b0591SJens Wiklander MBEDTLS_INTERNAL_VALIDATE(cond) 59817466cbSJens Wiklander 60817466cbSJens Wiklander #define MPI_SIZE_T_MAX ((size_t) -1) /* SIZE_T_MAX is not standard */ 61817466cbSJens Wiklander 6298bd5fe3SJens Wiklander void *mbedtls_mpi_mempool; 6398bd5fe3SJens Wiklander 643d3b0591SJens Wiklander /* Implementation that should never be optimized out by the compiler */ 653d3b0591SJens Wiklander static void mbedtls_mpi_zeroize(mbedtls_mpi_uint *v, size_t n) 663d3b0591SJens Wiklander { 673d3b0591SJens Wiklander mbedtls_platform_zeroize(v, ciL * n); 683d3b0591SJens Wiklander } 693d3b0591SJens Wiklander 70817466cbSJens Wiklander /* 71817466cbSJens Wiklander * Initialize one MPI 72817466cbSJens Wiklander */ 733d3b0591SJens Wiklander static void mpi_init(mbedtls_mpi *X, short use_mempool) 74817466cbSJens Wiklander { 753d3b0591SJens Wiklander MPI_VALIDATE(X != NULL); 76817466cbSJens Wiklander 773d3b0591SJens Wiklander X->s = 1; 783d3b0591SJens Wiklander X->use_mempool = use_mempool; 793d3b0591SJens Wiklander X->n = 0; 803d3b0591SJens Wiklander X->p = NULL; 81817466cbSJens Wiklander } 82817466cbSJens Wiklander 8398bd5fe3SJens Wiklander void mbedtls_mpi_init(mbedtls_mpi *X) 8498bd5fe3SJens Wiklander { 853d3b0591SJens Wiklander mpi_init(X, 0 /*use_mempool*/); 8698bd5fe3SJens Wiklander } 8798bd5fe3SJens Wiklander 8898bd5fe3SJens Wiklander void mbedtls_mpi_init_mempool(mbedtls_mpi *X) 8998bd5fe3SJens Wiklander { 903d3b0591SJens Wiklander mpi_init(X, !!mbedtls_mpi_mempool /*use_mempool*/); 9198bd5fe3SJens Wiklander } 9298bd5fe3SJens Wiklander 93817466cbSJens Wiklander /* 94817466cbSJens Wiklander * Unallocate one MPI 95817466cbSJens Wiklander */ 96817466cbSJens Wiklander void mbedtls_mpi_free(mbedtls_mpi *X) 97817466cbSJens Wiklander { 98*32b31808SJens Wiklander if (X == NULL) { 99817466cbSJens Wiklander return; 100*32b31808SJens Wiklander } 101817466cbSJens Wiklander 102*32b31808SJens Wiklander if (X->p != NULL) { 103817466cbSJens Wiklander mbedtls_mpi_zeroize(X->p, X->n); 1043d3b0591SJens Wiklander if(X->use_mempool) 10518c5148dSJens Wiklander mempool_free(mbedtls_mpi_mempool, X->p); 1063d3b0591SJens Wiklander else 1073d3b0591SJens Wiklander mbedtls_free(X->p); 108817466cbSJens Wiklander } 109817466cbSJens Wiklander 110817466cbSJens Wiklander X->s = 1; 111817466cbSJens Wiklander X->n = 0; 1123d3b0591SJens Wiklander X->p = NULL; 113817466cbSJens Wiklander } 114817466cbSJens Wiklander 115817466cbSJens Wiklander /* 116817466cbSJens Wiklander * Enlarge to the specified number of limbs 117817466cbSJens Wiklander */ 118817466cbSJens Wiklander int mbedtls_mpi_grow(mbedtls_mpi *X, size_t nblimbs) 119817466cbSJens Wiklander { 120817466cbSJens Wiklander mbedtls_mpi_uint *p; 1213d3b0591SJens Wiklander MPI_VALIDATE_RET(X != NULL); 122817466cbSJens Wiklander 123*32b31808SJens Wiklander if (nblimbs > MBEDTLS_MPI_MAX_LIMBS) { 124*32b31808SJens Wiklander return MBEDTLS_ERR_MPI_ALLOC_FAILED; 125*32b31808SJens Wiklander } 126817466cbSJens Wiklander 127*32b31808SJens Wiklander if (X->n < nblimbs) { 128*32b31808SJens Wiklander if(X->use_mempool) { 1293d3b0591SJens Wiklander p = mempool_alloc(mbedtls_mpi_mempool, nblimbs * ciL); 13018c5148dSJens Wiklander if(p == NULL) 131*32b31808SJens Wiklander return MBEDTLS_ERR_MPI_ALLOC_FAILED; 1323d3b0591SJens Wiklander memset(p, 0, nblimbs * ciL); 133*32b31808SJens Wiklander } else { 1343d3b0591SJens Wiklander p = (mbedtls_mpi_uint *) mbedtls_calloc(nblimbs, ciL); 1353d3b0591SJens Wiklander if (p == NULL) 136*32b31808SJens Wiklander return MBEDTLS_ERR_MPI_ALLOC_FAILED; 137817466cbSJens Wiklander } 138817466cbSJens Wiklander 139*32b31808SJens Wiklander if (X->p != NULL) { 1403d3b0591SJens Wiklander memcpy(p, X->p, X->n * ciL); 1413d3b0591SJens Wiklander mbedtls_mpi_zeroize(X->p, X->n); 1423d3b0591SJens Wiklander if (X->use_mempool) 14318c5148dSJens Wiklander mempool_free(mbedtls_mpi_mempool, X->p); 1443d3b0591SJens Wiklander else 1453d3b0591SJens Wiklander mbedtls_free(X->p); 1463d3b0591SJens Wiklander } 14718c5148dSJens Wiklander 14818c5148dSJens Wiklander X->n = nblimbs; 1493d3b0591SJens Wiklander X->p = p; 1503d3b0591SJens Wiklander } 151817466cbSJens Wiklander 152*32b31808SJens Wiklander return 0; 153817466cbSJens Wiklander } 154817466cbSJens Wiklander 155817466cbSJens Wiklander /* 156817466cbSJens Wiklander * Resize down as much as possible, 157817466cbSJens Wiklander * while keeping at least the specified number of limbs 158817466cbSJens Wiklander */ 159817466cbSJens Wiklander int mbedtls_mpi_shrink(mbedtls_mpi *X, size_t nblimbs) 160817466cbSJens Wiklander { 161817466cbSJens Wiklander mbedtls_mpi_uint *p; 162817466cbSJens Wiklander size_t i; 1633d3b0591SJens Wiklander MPI_VALIDATE_RET(X != NULL); 1643d3b0591SJens Wiklander 165*32b31808SJens Wiklander if (nblimbs > MBEDTLS_MPI_MAX_LIMBS) { 166*32b31808SJens Wiklander return MBEDTLS_ERR_MPI_ALLOC_FAILED; 167*32b31808SJens Wiklander } 168817466cbSJens Wiklander 1695b25c76aSJerome Forissier /* Actually resize up if there are currently fewer than nblimbs limbs. */ 170*32b31808SJens Wiklander if (X->n <= nblimbs) { 171*32b31808SJens Wiklander return mbedtls_mpi_grow(X, nblimbs); 172*32b31808SJens Wiklander } 1735b25c76aSJerome Forissier /* After this point, then X->n > nblimbs and in particular X->n > 0. */ 174817466cbSJens Wiklander 175*32b31808SJens Wiklander for (i = X->n - 1; i > 0; i--) { 176*32b31808SJens Wiklander if (X->p[i] != 0) { 177817466cbSJens Wiklander break; 178*32b31808SJens Wiklander } 179*32b31808SJens Wiklander } 180817466cbSJens Wiklander i++; 181817466cbSJens Wiklander 182*32b31808SJens Wiklander if (i < nblimbs) { 183817466cbSJens Wiklander i = nblimbs; 184*32b31808SJens Wiklander } 185817466cbSJens Wiklander 186*32b31808SJens Wiklander if (X->use_mempool) { 187ed3fa831SJerome Forissier p = mempool_alloc(mbedtls_mpi_mempool, i * ciL); 1883d3b0591SJens Wiklander if (p == NULL) 189*32b31808SJens Wiklander return MBEDTLS_ERR_MPI_ALLOC_FAILED; 190ed3fa831SJerome Forissier memset(p, 0, i * ciL); 191*32b31808SJens Wiklander } else { 192*32b31808SJens Wiklander if ((p = (mbedtls_mpi_uint *) mbedtls_calloc(i, ciL)) == NULL) 193*32b31808SJens Wiklander return MBEDTLS_ERR_MPI_ALLOC_FAILED; 1943d3b0591SJens Wiklander } 19518c5148dSJens Wiklander 196*32b31808SJens Wiklander if (X->p != NULL) { 197817466cbSJens Wiklander memcpy(p, X->p, i * ciL); 198817466cbSJens Wiklander mbedtls_mpi_zeroize(X->p, X->n); 1993d3b0591SJens Wiklander if (X->use_mempool) 20018c5148dSJens Wiklander mempool_free(mbedtls_mpi_mempool, X->p); 2013d3b0591SJens Wiklander else 2023d3b0591SJens Wiklander mbedtls_free(X->p); 203817466cbSJens Wiklander } 204817466cbSJens Wiklander 20518c5148dSJens Wiklander X->n = i; 2063d3b0591SJens Wiklander X->p = p; 207817466cbSJens Wiklander 208*32b31808SJens Wiklander return 0; 209817466cbSJens Wiklander } 210817466cbSJens Wiklander 2117901324dSJerome Forissier /* Resize X to have exactly n limbs and set it to 0. */ 2127901324dSJerome Forissier static int mbedtls_mpi_resize_clear(mbedtls_mpi *X, size_t limbs) 2137901324dSJerome Forissier { 214*32b31808SJens Wiklander if (limbs == 0) { 2157901324dSJerome Forissier mbedtls_mpi_free(X); 216*32b31808SJens Wiklander return 0; 217*32b31808SJens Wiklander } else if (X->n == limbs) { 2187901324dSJerome Forissier memset(X->p, 0, limbs * ciL); 2197901324dSJerome Forissier X->s = 1; 220*32b31808SJens Wiklander return 0; 221*32b31808SJens Wiklander } else { 2227901324dSJerome Forissier mbedtls_mpi_free(X); 223*32b31808SJens Wiklander return mbedtls_mpi_grow(X, limbs); 2247901324dSJerome Forissier } 2257901324dSJerome Forissier } 2267901324dSJerome Forissier 227817466cbSJens Wiklander /* 2287901324dSJerome Forissier * Copy the contents of Y into X. 2297901324dSJerome Forissier * 2307901324dSJerome Forissier * This function is not constant-time. Leading zeros in Y may be removed. 2317901324dSJerome Forissier * 2327901324dSJerome Forissier * Ensure that X does not shrink. This is not guaranteed by the public API, 2337901324dSJerome Forissier * but some code in the bignum module relies on this property, for example 2347901324dSJerome Forissier * in mbedtls_mpi_exp_mod(). 235817466cbSJens Wiklander */ 236817466cbSJens Wiklander int mbedtls_mpi_copy(mbedtls_mpi *X, const mbedtls_mpi *Y) 237817466cbSJens Wiklander { 2383d3b0591SJens Wiklander int ret = 0; 239817466cbSJens Wiklander size_t i; 2403d3b0591SJens Wiklander MPI_VALIDATE_RET(X != NULL); 2413d3b0591SJens Wiklander MPI_VALIDATE_RET(Y != NULL); 242817466cbSJens Wiklander 243*32b31808SJens Wiklander if (X == Y) { 244*32b31808SJens Wiklander return 0; 245*32b31808SJens Wiklander } 246817466cbSJens Wiklander 247*32b31808SJens Wiklander if (Y->n == 0) { 248*32b31808SJens Wiklander if (X->n != 0) { 2497901324dSJerome Forissier X->s = 1; 2507901324dSJerome Forissier memset(X->p, 0, X->n * ciL); 2517901324dSJerome Forissier } 252*32b31808SJens Wiklander return 0; 253817466cbSJens Wiklander } 254817466cbSJens Wiklander 255*32b31808SJens Wiklander for (i = Y->n - 1; i > 0; i--) { 256*32b31808SJens Wiklander if (Y->p[i] != 0) { 257817466cbSJens Wiklander break; 258*32b31808SJens Wiklander } 259*32b31808SJens Wiklander } 260817466cbSJens Wiklander i++; 261817466cbSJens Wiklander 262817466cbSJens Wiklander X->s = Y->s; 263817466cbSJens Wiklander 264*32b31808SJens Wiklander if (X->n < i) { 265817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, i)); 266*32b31808SJens Wiklander } else { 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 274*32b31808SJens 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 291*32b31808SJens Wiklander static inline mbedtls_mpi_uint mpi_sint_abs(mbedtls_mpi_sint z) 292*32b31808SJens Wiklander { 293*32b31808SJens Wiklander if (z >= 0) { 294*32b31808SJens Wiklander return z; 295*32b31808SJens Wiklander } 296*32b31808SJens Wiklander /* Take care to handle the most negative value (-2^(biL-1)) correctly. 297*32b31808SJens Wiklander * A naive -z would have undefined behavior. 298*32b31808SJens Wiklander * Write this in a way that makes popular compilers happy (GCC, Clang, 299*32b31808SJens Wiklander * MSVC). */ 300*32b31808SJens Wiklander return (mbedtls_mpi_uint) 0 - (mbedtls_mpi_uint) z; 301*32b31808SJens Wiklander } 302*32b31808SJens Wiklander 303817466cbSJens Wiklander /* 304817466cbSJens Wiklander * Set value from integer 305817466cbSJens Wiklander */ 306817466cbSJens Wiklander int mbedtls_mpi_lset(mbedtls_mpi *X, mbedtls_mpi_sint z) 307817466cbSJens Wiklander { 30811fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 3093d3b0591SJens Wiklander MPI_VALIDATE_RET(X != NULL); 310817466cbSJens Wiklander 311817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, 1)); 312817466cbSJens Wiklander memset(X->p, 0, X->n * ciL); 313817466cbSJens Wiklander 314*32b31808SJens Wiklander X->p[0] = mpi_sint_abs(z); 315817466cbSJens Wiklander X->s = (z < 0) ? -1 : 1; 316817466cbSJens Wiklander 317817466cbSJens Wiklander cleanup: 318817466cbSJens Wiklander 319*32b31808SJens Wiklander return ret; 320817466cbSJens Wiklander } 321817466cbSJens Wiklander 322817466cbSJens Wiklander /* 323817466cbSJens Wiklander * Get a specific bit 324817466cbSJens Wiklander */ 325817466cbSJens Wiklander int mbedtls_mpi_get_bit(const mbedtls_mpi *X, size_t pos) 326817466cbSJens Wiklander { 3273d3b0591SJens Wiklander MPI_VALIDATE_RET(X != NULL); 3283d3b0591SJens Wiklander 329*32b31808SJens Wiklander if (X->n * biL <= pos) { 330*32b31808SJens Wiklander return 0; 331817466cbSJens Wiklander } 332817466cbSJens Wiklander 333*32b31808SJens Wiklander return (X->p[pos / biL] >> (pos % biL)) & 0x01; 334*32b31808SJens Wiklander } 3353d3b0591SJens Wiklander 336817466cbSJens Wiklander /* 337817466cbSJens Wiklander * Set a bit to a specific value of 0 or 1 338817466cbSJens Wiklander */ 339817466cbSJens Wiklander int mbedtls_mpi_set_bit(mbedtls_mpi *X, size_t pos, unsigned char val) 340817466cbSJens Wiklander { 341817466cbSJens Wiklander int ret = 0; 342817466cbSJens Wiklander size_t off = pos / biL; 343817466cbSJens Wiklander size_t idx = pos % biL; 3443d3b0591SJens Wiklander MPI_VALIDATE_RET(X != NULL); 345817466cbSJens Wiklander 346*32b31808SJens Wiklander if (val != 0 && val != 1) { 347*32b31808SJens Wiklander return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; 348*32b31808SJens Wiklander } 349817466cbSJens Wiklander 350*32b31808SJens Wiklander if (X->n * biL <= pos) { 351*32b31808SJens Wiklander if (val == 0) { 352*32b31808SJens Wiklander return 0; 353*32b31808SJens Wiklander } 354817466cbSJens Wiklander 355817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, off + 1)); 356817466cbSJens Wiklander } 357817466cbSJens Wiklander 358817466cbSJens Wiklander X->p[off] &= ~((mbedtls_mpi_uint) 0x01 << idx); 359817466cbSJens Wiklander X->p[off] |= (mbedtls_mpi_uint) val << idx; 360817466cbSJens Wiklander 361817466cbSJens Wiklander cleanup: 362817466cbSJens Wiklander 363*32b31808SJens Wiklander return ret; 364817466cbSJens Wiklander } 365817466cbSJens Wiklander 366817466cbSJens Wiklander /* 367817466cbSJens Wiklander * Return the number of less significant zero-bits 368817466cbSJens Wiklander */ 369817466cbSJens Wiklander size_t mbedtls_mpi_lsb(const mbedtls_mpi *X) 370817466cbSJens Wiklander { 371817466cbSJens Wiklander size_t i, j, count = 0; 3723d3b0591SJens Wiklander MBEDTLS_INTERNAL_VALIDATE_RET(X != NULL, 0); 373817466cbSJens Wiklander 374*32b31808SJens Wiklander for (i = 0; i < X->n; i++) { 375*32b31808SJens Wiklander for (j = 0; j < biL; j++, count++) { 376*32b31808SJens Wiklander if (((X->p[i] >> j) & 1) != 0) { 377*32b31808SJens Wiklander return count; 378*32b31808SJens Wiklander } 379*32b31808SJens Wiklander } 380817466cbSJens Wiklander } 381817466cbSJens Wiklander 382*32b31808SJens Wiklander return 0; 383817466cbSJens Wiklander } 384817466cbSJens Wiklander 385817466cbSJens Wiklander /* 386817466cbSJens Wiklander * Return the number of bits 387817466cbSJens Wiklander */ 388817466cbSJens Wiklander size_t mbedtls_mpi_bitlen(const mbedtls_mpi *X) 389817466cbSJens Wiklander { 390*32b31808SJens Wiklander return mbedtls_mpi_core_bitlen(X->p, X->n); 391817466cbSJens Wiklander } 392817466cbSJens Wiklander 393817466cbSJens Wiklander /* 394817466cbSJens Wiklander * Return the total size in bytes 395817466cbSJens Wiklander */ 396817466cbSJens Wiklander size_t mbedtls_mpi_size(const mbedtls_mpi *X) 397817466cbSJens Wiklander { 398*32b31808SJens Wiklander return (mbedtls_mpi_bitlen(X) + 7) >> 3; 399817466cbSJens Wiklander } 400817466cbSJens Wiklander 401817466cbSJens Wiklander /* 402817466cbSJens Wiklander * Convert an ASCII character to digit value 403817466cbSJens Wiklander */ 404817466cbSJens Wiklander static int mpi_get_digit(mbedtls_mpi_uint *d, int radix, char c) 405817466cbSJens Wiklander { 406817466cbSJens Wiklander *d = 255; 407817466cbSJens Wiklander 408*32b31808SJens Wiklander if (c >= 0x30 && c <= 0x39) { 409*32b31808SJens Wiklander *d = c - 0x30; 410*32b31808SJens Wiklander } 411*32b31808SJens Wiklander if (c >= 0x41 && c <= 0x46) { 412*32b31808SJens Wiklander *d = c - 0x37; 413*32b31808SJens Wiklander } 414*32b31808SJens Wiklander if (c >= 0x61 && c <= 0x66) { 415*32b31808SJens Wiklander *d = c - 0x57; 416*32b31808SJens Wiklander } 417817466cbSJens Wiklander 418*32b31808SJens Wiklander if (*d >= (mbedtls_mpi_uint) radix) { 419*32b31808SJens Wiklander return MBEDTLS_ERR_MPI_INVALID_CHARACTER; 420*32b31808SJens Wiklander } 421817466cbSJens Wiklander 422*32b31808SJens Wiklander return 0; 423817466cbSJens Wiklander } 424817466cbSJens Wiklander 425817466cbSJens Wiklander /* 426817466cbSJens Wiklander * Import from an ASCII string 427817466cbSJens Wiklander */ 428817466cbSJens Wiklander int mbedtls_mpi_read_string(mbedtls_mpi *X, int radix, const char *s) 429817466cbSJens Wiklander { 43011fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 431817466cbSJens Wiklander size_t i, j, slen, n; 4327901324dSJerome Forissier int sign = 1; 433817466cbSJens Wiklander mbedtls_mpi_uint d; 434817466cbSJens Wiklander mbedtls_mpi T; 4353d3b0591SJens Wiklander MPI_VALIDATE_RET(X != NULL); 4363d3b0591SJens Wiklander MPI_VALIDATE_RET(s != NULL); 437817466cbSJens Wiklander 438*32b31808SJens Wiklander if (radix < 2 || radix > 16) { 439*32b31808SJens Wiklander return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; 440*32b31808SJens Wiklander } 441817466cbSJens Wiklander 44298bd5fe3SJens Wiklander mbedtls_mpi_init_mempool(&T); 443817466cbSJens Wiklander 444*32b31808SJens Wiklander if (s[0] == 0) { 4457901324dSJerome Forissier mbedtls_mpi_free(X); 446*32b31808SJens Wiklander return 0; 4477901324dSJerome Forissier } 4487901324dSJerome Forissier 449*32b31808SJens Wiklander if (s[0] == '-') { 4507901324dSJerome Forissier ++s; 4517901324dSJerome Forissier sign = -1; 4527901324dSJerome Forissier } 4537901324dSJerome Forissier 454817466cbSJens Wiklander slen = strlen(s); 455817466cbSJens Wiklander 456*32b31808SJens Wiklander if (radix == 16) { 457*32b31808SJens Wiklander if (slen > MPI_SIZE_T_MAX >> 2) { 458*32b31808SJens Wiklander return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; 459*32b31808SJens Wiklander } 460817466cbSJens Wiklander 461817466cbSJens Wiklander n = BITS_TO_LIMBS(slen << 2); 462817466cbSJens Wiklander 463817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, n)); 464817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_lset(X, 0)); 465817466cbSJens Wiklander 466*32b31808SJens Wiklander for (i = slen, j = 0; i > 0; i--, j++) { 467817466cbSJens Wiklander MBEDTLS_MPI_CHK(mpi_get_digit(&d, radix, s[i - 1])); 468817466cbSJens Wiklander X->p[j / (2 * ciL)] |= d << ((j % (2 * ciL)) << 2); 469817466cbSJens Wiklander } 470*32b31808SJens Wiklander } else { 471817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_lset(X, 0)); 472817466cbSJens Wiklander 473*32b31808SJens Wiklander for (i = 0; i < slen; i++) { 474817466cbSJens Wiklander MBEDTLS_MPI_CHK(mpi_get_digit(&d, radix, s[i])); 475817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_mul_int(&T, X, radix)); 476817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(X, &T, d)); 477817466cbSJens Wiklander } 478817466cbSJens Wiklander } 4797901324dSJerome Forissier 480*32b31808SJens Wiklander if (sign < 0 && mbedtls_mpi_bitlen(X) != 0) { 4817901324dSJerome Forissier X->s = -1; 482*32b31808SJens Wiklander } 483817466cbSJens Wiklander 484817466cbSJens Wiklander cleanup: 485817466cbSJens Wiklander 486817466cbSJens Wiklander mbedtls_mpi_free(&T); 487817466cbSJens Wiklander 488*32b31808SJens Wiklander return ret; 489817466cbSJens Wiklander } 490817466cbSJens Wiklander 491817466cbSJens Wiklander /* 4925b25c76aSJerome Forissier * Helper to write the digits high-order first. 493817466cbSJens Wiklander */ 4945b25c76aSJerome Forissier static int mpi_write_hlp(mbedtls_mpi *X, int radix, 4955b25c76aSJerome Forissier char **p, const size_t buflen) 496817466cbSJens Wiklander { 49711fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 498817466cbSJens Wiklander mbedtls_mpi_uint r; 4995b25c76aSJerome Forissier size_t length = 0; 5005b25c76aSJerome Forissier char *p_end = *p + buflen; 501817466cbSJens Wiklander 502*32b31808SJens Wiklander do { 503*32b31808SJens Wiklander if (length >= buflen) { 504*32b31808SJens Wiklander return MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL; 5055b25c76aSJerome Forissier } 506817466cbSJens Wiklander 507817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_mod_int(&r, X, radix)); 508817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_div_int(X, NULL, X, radix)); 5095b25c76aSJerome Forissier /* 5105b25c76aSJerome Forissier * Write the residue in the current position, as an ASCII character. 5115b25c76aSJerome Forissier */ 512*32b31808SJens Wiklander if (r < 0xA) { 5135b25c76aSJerome Forissier *(--p_end) = (char) ('0' + r); 514*32b31808SJens Wiklander } else { 5155b25c76aSJerome Forissier *(--p_end) = (char) ('A' + (r - 0xA)); 516*32b31808SJens Wiklander } 5175b25c76aSJerome Forissier 5185b25c76aSJerome Forissier length++; 5195b25c76aSJerome Forissier } while (mbedtls_mpi_cmp_int(X, 0) != 0); 5205b25c76aSJerome Forissier 5215b25c76aSJerome Forissier memmove(*p, p_end, length); 5225b25c76aSJerome Forissier *p += length; 523817466cbSJens Wiklander 524817466cbSJens Wiklander cleanup: 525817466cbSJens Wiklander 526*32b31808SJens Wiklander return ret; 527817466cbSJens Wiklander } 528817466cbSJens Wiklander 529817466cbSJens Wiklander /* 530817466cbSJens Wiklander * Export into an ASCII string 531817466cbSJens Wiklander */ 532817466cbSJens Wiklander int mbedtls_mpi_write_string(const mbedtls_mpi *X, int radix, 533817466cbSJens Wiklander char *buf, size_t buflen, size_t *olen) 534817466cbSJens Wiklander { 535817466cbSJens Wiklander int ret = 0; 536817466cbSJens Wiklander size_t n; 537817466cbSJens Wiklander char *p; 538817466cbSJens Wiklander mbedtls_mpi T; 5393d3b0591SJens Wiklander MPI_VALIDATE_RET(X != NULL); 5403d3b0591SJens Wiklander MPI_VALIDATE_RET(olen != NULL); 5413d3b0591SJens Wiklander MPI_VALIDATE_RET(buflen == 0 || buf != NULL); 542817466cbSJens Wiklander 543*32b31808SJens Wiklander if (radix < 2 || radix > 16) { 544*32b31808SJens Wiklander return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; 545*32b31808SJens Wiklander } 546817466cbSJens Wiklander 5475b25c76aSJerome Forissier n = mbedtls_mpi_bitlen(X); /* Number of bits necessary to present `n`. */ 548*32b31808SJens Wiklander if (radix >= 4) { 549*32b31808SJens Wiklander n >>= 1; /* Number of 4-adic digits necessary to present 5505b25c76aSJerome Forissier * `n`. If radix > 4, this might be a strict 5515b25c76aSJerome Forissier * overapproximation of the number of 5525b25c76aSJerome Forissier * radix-adic digits needed to present `n`. */ 553*32b31808SJens Wiklander } 554*32b31808SJens Wiklander if (radix >= 16) { 555*32b31808SJens Wiklander n >>= 1; /* Number of hexadecimal digits necessary to 5565b25c76aSJerome Forissier * present `n`. */ 5575b25c76aSJerome Forissier 558*32b31808SJens Wiklander } 5595b25c76aSJerome Forissier n += 1; /* Terminating null byte */ 5605b25c76aSJerome Forissier n += 1; /* Compensate for the divisions above, which round down `n` 5615b25c76aSJerome Forissier * in case it's not even. */ 5625b25c76aSJerome Forissier n += 1; /* Potential '-'-sign. */ 5635b25c76aSJerome Forissier n += (n & 1); /* Make n even to have enough space for hexadecimal writing, 5645b25c76aSJerome Forissier * which always uses an even number of hex-digits. */ 565817466cbSJens Wiklander 566*32b31808SJens Wiklander if (buflen < n) { 567817466cbSJens Wiklander *olen = n; 568*32b31808SJens Wiklander return MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL; 569817466cbSJens Wiklander } 570817466cbSJens Wiklander 571817466cbSJens Wiklander p = buf; 57298bd5fe3SJens Wiklander mbedtls_mpi_init_mempool(&T); 573817466cbSJens Wiklander 574*32b31808SJens Wiklander if (X->s == -1) { 575817466cbSJens Wiklander *p++ = '-'; 5765b25c76aSJerome Forissier buflen--; 5775b25c76aSJerome Forissier } 578817466cbSJens Wiklander 579*32b31808SJens Wiklander if (radix == 16) { 580817466cbSJens Wiklander int c; 581817466cbSJens Wiklander size_t i, j, k; 582817466cbSJens Wiklander 583*32b31808SJens Wiklander for (i = X->n, k = 0; i > 0; i--) { 584*32b31808SJens Wiklander for (j = ciL; j > 0; j--) { 585817466cbSJens Wiklander c = (X->p[i - 1] >> ((j - 1) << 3)) & 0xFF; 586817466cbSJens Wiklander 587*32b31808SJens Wiklander if (c == 0 && k == 0 && (i + j) != 2) { 588817466cbSJens Wiklander continue; 589*32b31808SJens Wiklander } 590817466cbSJens Wiklander 591817466cbSJens Wiklander *(p++) = "0123456789ABCDEF" [c / 16]; 592817466cbSJens Wiklander *(p++) = "0123456789ABCDEF" [c % 16]; 593817466cbSJens Wiklander k = 1; 594817466cbSJens Wiklander } 595817466cbSJens Wiklander } 596*32b31808SJens Wiklander } else { 597817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&T, X)); 598817466cbSJens Wiklander 599*32b31808SJens Wiklander if (T.s == -1) { 600817466cbSJens Wiklander T.s = 1; 601*32b31808SJens Wiklander } 602817466cbSJens Wiklander 6035b25c76aSJerome Forissier MBEDTLS_MPI_CHK(mpi_write_hlp(&T, radix, &p, buflen)); 604817466cbSJens Wiklander } 605817466cbSJens Wiklander 606817466cbSJens Wiklander *p++ = '\0'; 607817466cbSJens Wiklander *olen = p - buf; 608817466cbSJens Wiklander 609817466cbSJens Wiklander cleanup: 610817466cbSJens Wiklander 611817466cbSJens Wiklander mbedtls_mpi_free(&T); 612817466cbSJens Wiklander 613*32b31808SJens Wiklander return ret; 614817466cbSJens Wiklander } 615817466cbSJens Wiklander 616817466cbSJens Wiklander #if defined(MBEDTLS_FS_IO) 617817466cbSJens Wiklander /* 618817466cbSJens Wiklander * Read X from an opened file 619817466cbSJens Wiklander */ 620817466cbSJens Wiklander int mbedtls_mpi_read_file(mbedtls_mpi *X, int radix, FILE *fin) 621817466cbSJens Wiklander { 622817466cbSJens Wiklander mbedtls_mpi_uint d; 623817466cbSJens Wiklander size_t slen; 624817466cbSJens Wiklander char *p; 625817466cbSJens Wiklander /* 626817466cbSJens Wiklander * Buffer should have space for (short) label and decimal formatted MPI, 627817466cbSJens Wiklander * newline characters and '\0' 628817466cbSJens Wiklander */ 629817466cbSJens Wiklander char s[MBEDTLS_MPI_RW_BUFFER_SIZE]; 630817466cbSJens Wiklander 6313d3b0591SJens Wiklander MPI_VALIDATE_RET(X != NULL); 6323d3b0591SJens Wiklander MPI_VALIDATE_RET(fin != NULL); 6333d3b0591SJens Wiklander 634*32b31808SJens Wiklander if (radix < 2 || radix > 16) { 635*32b31808SJens Wiklander return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; 636*32b31808SJens Wiklander } 6373d3b0591SJens Wiklander 638817466cbSJens Wiklander memset(s, 0, sizeof(s)); 639*32b31808SJens Wiklander if (fgets(s, sizeof(s) - 1, fin) == NULL) { 640*32b31808SJens Wiklander return MBEDTLS_ERR_MPI_FILE_IO_ERROR; 641*32b31808SJens Wiklander } 642817466cbSJens Wiklander 643817466cbSJens Wiklander slen = strlen(s); 644*32b31808SJens Wiklander if (slen == sizeof(s) - 2) { 645*32b31808SJens Wiklander return MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL; 646*32b31808SJens Wiklander } 647817466cbSJens Wiklander 648*32b31808SJens Wiklander if (slen > 0 && s[slen - 1] == '\n') { 649*32b31808SJens Wiklander slen--; s[slen] = '\0'; 650*32b31808SJens Wiklander } 651*32b31808SJens Wiklander if (slen > 0 && s[slen - 1] == '\r') { 652*32b31808SJens Wiklander slen--; s[slen] = '\0'; 653*32b31808SJens Wiklander } 654817466cbSJens Wiklander 655817466cbSJens Wiklander p = s + slen; 656*32b31808SJens Wiklander while (p-- > s) { 657*32b31808SJens Wiklander if (mpi_get_digit(&d, radix, *p) != 0) { 658817466cbSJens Wiklander break; 659*32b31808SJens Wiklander } 660*32b31808SJens Wiklander } 661817466cbSJens Wiklander 662*32b31808SJens Wiklander return mbedtls_mpi_read_string(X, radix, p + 1); 663817466cbSJens Wiklander } 664817466cbSJens Wiklander 665817466cbSJens Wiklander /* 666817466cbSJens Wiklander * Write X into an opened file (or stdout if fout == NULL) 667817466cbSJens Wiklander */ 668817466cbSJens Wiklander int mbedtls_mpi_write_file(const char *p, const mbedtls_mpi *X, int radix, FILE *fout) 669817466cbSJens Wiklander { 67011fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 671817466cbSJens Wiklander size_t n, slen, plen; 672817466cbSJens Wiklander /* 673817466cbSJens Wiklander * Buffer should have space for (short) label and decimal formatted MPI, 674817466cbSJens Wiklander * newline characters and '\0' 675817466cbSJens Wiklander */ 676817466cbSJens Wiklander char s[MBEDTLS_MPI_RW_BUFFER_SIZE]; 6773d3b0591SJens Wiklander MPI_VALIDATE_RET(X != NULL); 6783d3b0591SJens Wiklander 679*32b31808SJens Wiklander if (radix < 2 || radix > 16) { 680*32b31808SJens Wiklander return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; 681*32b31808SJens Wiklander } 682817466cbSJens Wiklander 683817466cbSJens Wiklander memset(s, 0, sizeof(s)); 684817466cbSJens Wiklander 685817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_write_string(X, radix, s, sizeof(s) - 2, &n)); 686817466cbSJens Wiklander 687*32b31808SJens Wiklander if (p == NULL) { 688*32b31808SJens Wiklander p = ""; 689*32b31808SJens Wiklander } 690817466cbSJens Wiklander 691817466cbSJens Wiklander plen = strlen(p); 692817466cbSJens Wiklander slen = strlen(s); 693817466cbSJens Wiklander s[slen++] = '\r'; 694817466cbSJens Wiklander s[slen++] = '\n'; 695817466cbSJens Wiklander 696*32b31808SJens Wiklander if (fout != NULL) { 697817466cbSJens Wiklander if (fwrite(p, 1, plen, fout) != plen || 698*32b31808SJens Wiklander fwrite(s, 1, slen, fout) != slen) { 699*32b31808SJens Wiklander return MBEDTLS_ERR_MPI_FILE_IO_ERROR; 700817466cbSJens Wiklander } 701*32b31808SJens Wiklander } else { 702817466cbSJens Wiklander mbedtls_printf("%s%s", p, s); 703*32b31808SJens Wiklander } 704817466cbSJens Wiklander 705817466cbSJens Wiklander cleanup: 706817466cbSJens Wiklander 707*32b31808SJens Wiklander return ret; 708817466cbSJens Wiklander } 709817466cbSJens Wiklander #endif /* MBEDTLS_FS_IO */ 710817466cbSJens Wiklander 711817466cbSJens Wiklander /* 71211fa71b9SJerome Forissier * Import X from unsigned binary data, little endian 713*32b31808SJens Wiklander * 714*32b31808SJens Wiklander * This function is guaranteed to return an MPI with exactly the necessary 715*32b31808SJens Wiklander * number of limbs (in particular, it does not skip 0s in the input). 71611fa71b9SJerome Forissier */ 71711fa71b9SJerome Forissier int mbedtls_mpi_read_binary_le(mbedtls_mpi *X, 71811fa71b9SJerome Forissier const unsigned char *buf, size_t buflen) 71911fa71b9SJerome Forissier { 72011fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 721*32b31808SJens Wiklander const size_t limbs = CHARS_TO_LIMBS(buflen); 72211fa71b9SJerome Forissier 72311fa71b9SJerome Forissier /* Ensure that target MPI has exactly the necessary number of limbs */ 7247901324dSJerome Forissier MBEDTLS_MPI_CHK(mbedtls_mpi_resize_clear(X, limbs)); 72511fa71b9SJerome Forissier 726*32b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_core_read_le(X->p, X->n, buf, buflen)); 72711fa71b9SJerome Forissier 72811fa71b9SJerome Forissier cleanup: 72911fa71b9SJerome Forissier 73011fa71b9SJerome Forissier /* 73111fa71b9SJerome Forissier * This function is also used to import keys. However, wiping the buffers 73211fa71b9SJerome Forissier * upon failure is not necessary because failure only can happen before any 73311fa71b9SJerome Forissier * input is copied. 73411fa71b9SJerome Forissier */ 735*32b31808SJens Wiklander return ret; 73611fa71b9SJerome Forissier } 73711fa71b9SJerome Forissier 73811fa71b9SJerome Forissier /* 739817466cbSJens Wiklander * Import X from unsigned binary data, big endian 740*32b31808SJens Wiklander * 741*32b31808SJens Wiklander * This function is guaranteed to return an MPI with exactly the necessary 742*32b31808SJens Wiklander * number of limbs (in particular, it does not skip 0s in the input). 743817466cbSJens Wiklander */ 744817466cbSJens Wiklander int mbedtls_mpi_read_binary(mbedtls_mpi *X, const unsigned char *buf, size_t buflen) 745817466cbSJens Wiklander { 74611fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 747*32b31808SJens Wiklander const size_t limbs = CHARS_TO_LIMBS(buflen); 748817466cbSJens Wiklander 7493d3b0591SJens Wiklander MPI_VALIDATE_RET(X != NULL); 7503d3b0591SJens Wiklander MPI_VALIDATE_RET(buflen == 0 || buf != NULL); 751817466cbSJens Wiklander 7523d3b0591SJens Wiklander /* Ensure that target MPI has exactly the necessary number of limbs */ 7537901324dSJerome Forissier MBEDTLS_MPI_CHK(mbedtls_mpi_resize_clear(X, limbs)); 7542976273fSJens Wiklander 755*32b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_core_read_be(X->p, X->n, buf, buflen)); 756817466cbSJens Wiklander 757817466cbSJens Wiklander cleanup: 758817466cbSJens Wiklander 75911fa71b9SJerome Forissier /* 76011fa71b9SJerome Forissier * This function is also used to import keys. However, wiping the buffers 76111fa71b9SJerome Forissier * upon failure is not necessary because failure only can happen before any 76211fa71b9SJerome Forissier * input is copied. 76311fa71b9SJerome Forissier */ 764*32b31808SJens Wiklander return ret; 765817466cbSJens Wiklander } 766817466cbSJens Wiklander 767817466cbSJens Wiklander /* 76811fa71b9SJerome Forissier * Export X into unsigned binary data, little endian 76911fa71b9SJerome Forissier */ 77011fa71b9SJerome Forissier int mbedtls_mpi_write_binary_le(const mbedtls_mpi *X, 77111fa71b9SJerome Forissier unsigned char *buf, size_t buflen) 77211fa71b9SJerome Forissier { 773*32b31808SJens Wiklander return mbedtls_mpi_core_write_le(X->p, X->n, buf, buflen); 77411fa71b9SJerome Forissier } 77511fa71b9SJerome Forissier 77611fa71b9SJerome Forissier /* 777817466cbSJens Wiklander * Export X into unsigned binary data, big endian 778817466cbSJens Wiklander */ 7793d3b0591SJens Wiklander int mbedtls_mpi_write_binary(const mbedtls_mpi *X, 7803d3b0591SJens Wiklander unsigned char *buf, size_t buflen) 781817466cbSJens Wiklander { 782*32b31808SJens Wiklander return mbedtls_mpi_core_write_be(X->p, X->n, buf, buflen); 783817466cbSJens Wiklander } 784817466cbSJens Wiklander 785817466cbSJens Wiklander /* 786817466cbSJens Wiklander * Left-shift: X <<= count 787817466cbSJens Wiklander */ 788817466cbSJens Wiklander int mbedtls_mpi_shift_l(mbedtls_mpi *X, size_t count) 789817466cbSJens Wiklander { 79011fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 791817466cbSJens Wiklander size_t i, v0, t1; 792817466cbSJens Wiklander mbedtls_mpi_uint r0 = 0, r1; 7933d3b0591SJens Wiklander MPI_VALIDATE_RET(X != NULL); 794817466cbSJens Wiklander 795817466cbSJens Wiklander v0 = count / (biL); 796817466cbSJens Wiklander t1 = count & (biL - 1); 797817466cbSJens Wiklander 798817466cbSJens Wiklander i = mbedtls_mpi_bitlen(X) + count; 799817466cbSJens Wiklander 800*32b31808SJens Wiklander if (X->n * biL < i) { 801817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, BITS_TO_LIMBS(i))); 802*32b31808SJens Wiklander } 803817466cbSJens Wiklander 804817466cbSJens Wiklander ret = 0; 805817466cbSJens Wiklander 806817466cbSJens Wiklander /* 807817466cbSJens Wiklander * shift by count / limb_size 808817466cbSJens Wiklander */ 809*32b31808SJens Wiklander if (v0 > 0) { 810*32b31808SJens Wiklander for (i = X->n; i > v0; i--) { 811817466cbSJens Wiklander X->p[i - 1] = X->p[i - v0 - 1]; 812*32b31808SJens Wiklander } 813817466cbSJens Wiklander 814*32b31808SJens Wiklander for (; i > 0; i--) { 815817466cbSJens Wiklander X->p[i - 1] = 0; 816817466cbSJens Wiklander } 817*32b31808SJens Wiklander } 818817466cbSJens Wiklander 819817466cbSJens Wiklander /* 820817466cbSJens Wiklander * shift by count % limb_size 821817466cbSJens Wiklander */ 822*32b31808SJens Wiklander if (t1 > 0) { 823*32b31808SJens Wiklander for (i = v0; i < X->n; i++) { 824817466cbSJens Wiklander r1 = X->p[i] >> (biL - t1); 825817466cbSJens Wiklander X->p[i] <<= t1; 826817466cbSJens Wiklander X->p[i] |= r0; 827817466cbSJens Wiklander r0 = r1; 828817466cbSJens Wiklander } 829817466cbSJens Wiklander } 830817466cbSJens Wiklander 831817466cbSJens Wiklander cleanup: 832817466cbSJens Wiklander 833*32b31808SJens Wiklander return ret; 834817466cbSJens Wiklander } 835817466cbSJens Wiklander 836817466cbSJens Wiklander /* 837817466cbSJens Wiklander * Right-shift: X >>= count 838817466cbSJens Wiklander */ 839817466cbSJens Wiklander int mbedtls_mpi_shift_r(mbedtls_mpi *X, size_t count) 840817466cbSJens Wiklander { 8413d3b0591SJens Wiklander MPI_VALIDATE_RET(X != NULL); 842*32b31808SJens Wiklander if (X->n != 0) { 843*32b31808SJens Wiklander mbedtls_mpi_core_shift_r(X->p, X->n, count); 844817466cbSJens Wiklander } 845*32b31808SJens Wiklander return 0; 846817466cbSJens Wiklander } 847817466cbSJens Wiklander 848817466cbSJens Wiklander /* 849817466cbSJens Wiklander * Compare unsigned values 850817466cbSJens Wiklander */ 851817466cbSJens Wiklander int mbedtls_mpi_cmp_abs(const mbedtls_mpi *X, const mbedtls_mpi *Y) 852817466cbSJens Wiklander { 853817466cbSJens Wiklander size_t i, j; 8543d3b0591SJens Wiklander MPI_VALIDATE_RET(X != NULL); 8553d3b0591SJens Wiklander MPI_VALIDATE_RET(Y != NULL); 856817466cbSJens Wiklander 857*32b31808SJens Wiklander for (i = X->n; i > 0; i--) { 858*32b31808SJens Wiklander if (X->p[i - 1] != 0) { 859817466cbSJens Wiklander break; 860*32b31808SJens Wiklander } 861817466cbSJens Wiklander } 862817466cbSJens Wiklander 863*32b31808SJens Wiklander for (j = Y->n; j > 0; j--) { 864*32b31808SJens Wiklander if (Y->p[j - 1] != 0) { 865*32b31808SJens Wiklander break; 866*32b31808SJens Wiklander } 867*32b31808SJens Wiklander } 868*32b31808SJens Wiklander 869*32b31808SJens Wiklander if (i == 0 && j == 0) { 870*32b31808SJens Wiklander return 0; 871*32b31808SJens Wiklander } 872*32b31808SJens Wiklander 873*32b31808SJens Wiklander if (i > j) { 874*32b31808SJens Wiklander return 1; 875*32b31808SJens Wiklander } 876*32b31808SJens Wiklander if (j > i) { 877*32b31808SJens Wiklander return -1; 878*32b31808SJens Wiklander } 879*32b31808SJens Wiklander 880*32b31808SJens Wiklander for (; i > 0; i--) { 881*32b31808SJens Wiklander if (X->p[i - 1] > Y->p[i - 1]) { 882*32b31808SJens Wiklander return 1; 883*32b31808SJens Wiklander } 884*32b31808SJens Wiklander if (X->p[i - 1] < Y->p[i - 1]) { 885*32b31808SJens Wiklander return -1; 886*32b31808SJens Wiklander } 887*32b31808SJens Wiklander } 888*32b31808SJens Wiklander 889*32b31808SJens Wiklander return 0; 890817466cbSJens Wiklander } 891817466cbSJens Wiklander 892817466cbSJens Wiklander /* 893817466cbSJens Wiklander * Compare signed values 894817466cbSJens Wiklander */ 895817466cbSJens Wiklander int mbedtls_mpi_cmp_mpi(const mbedtls_mpi *X, const mbedtls_mpi *Y) 896817466cbSJens Wiklander { 897817466cbSJens Wiklander size_t i, j; 8983d3b0591SJens Wiklander MPI_VALIDATE_RET(X != NULL); 8993d3b0591SJens Wiklander MPI_VALIDATE_RET(Y != NULL); 900817466cbSJens Wiklander 901*32b31808SJens Wiklander for (i = X->n; i > 0; i--) { 902*32b31808SJens Wiklander if (X->p[i - 1] != 0) { 903817466cbSJens Wiklander break; 904*32b31808SJens Wiklander } 905817466cbSJens Wiklander } 906817466cbSJens Wiklander 907*32b31808SJens Wiklander for (j = Y->n; j > 0; j--) { 908*32b31808SJens Wiklander if (Y->p[j - 1] != 0) { 909*32b31808SJens Wiklander break; 910*32b31808SJens Wiklander } 911*32b31808SJens Wiklander } 912*32b31808SJens Wiklander 913*32b31808SJens Wiklander if (i == 0 && j == 0) { 914*32b31808SJens Wiklander return 0; 915*32b31808SJens Wiklander } 916*32b31808SJens Wiklander 917*32b31808SJens Wiklander if (i > j) { 918*32b31808SJens Wiklander return X->s; 919*32b31808SJens Wiklander } 920*32b31808SJens Wiklander if (j > i) { 921*32b31808SJens Wiklander return -Y->s; 922*32b31808SJens Wiklander } 923*32b31808SJens Wiklander 924*32b31808SJens Wiklander if (X->s > 0 && Y->s < 0) { 925*32b31808SJens Wiklander return 1; 926*32b31808SJens Wiklander } 927*32b31808SJens Wiklander if (Y->s > 0 && X->s < 0) { 928*32b31808SJens Wiklander return -1; 929*32b31808SJens Wiklander } 930*32b31808SJens Wiklander 931*32b31808SJens Wiklander for (; i > 0; i--) { 932*32b31808SJens Wiklander if (X->p[i - 1] > Y->p[i - 1]) { 933*32b31808SJens Wiklander return X->s; 934*32b31808SJens Wiklander } 935*32b31808SJens Wiklander if (X->p[i - 1] < Y->p[i - 1]) { 936*32b31808SJens Wiklander return -X->s; 937*32b31808SJens Wiklander } 938*32b31808SJens Wiklander } 939*32b31808SJens Wiklander 940*32b31808SJens Wiklander return 0; 941817466cbSJens Wiklander } 942817466cbSJens Wiklander 943817466cbSJens Wiklander /* 944817466cbSJens Wiklander * Compare signed values 945817466cbSJens Wiklander */ 946817466cbSJens Wiklander int mbedtls_mpi_cmp_int(const mbedtls_mpi *X, mbedtls_mpi_sint z) 947817466cbSJens Wiklander { 948817466cbSJens Wiklander mbedtls_mpi Y; 949817466cbSJens Wiklander mbedtls_mpi_uint p[1]; 9503d3b0591SJens Wiklander MPI_VALIDATE_RET(X != NULL); 951817466cbSJens Wiklander 952*32b31808SJens Wiklander *p = mpi_sint_abs(z); 953817466cbSJens Wiklander Y.s = (z < 0) ? -1 : 1; 954817466cbSJens Wiklander Y.n = 1; 955817466cbSJens Wiklander Y.p = p; 956817466cbSJens Wiklander 957*32b31808SJens Wiklander return mbedtls_mpi_cmp_mpi(X, &Y); 958817466cbSJens Wiklander } 959817466cbSJens Wiklander 960817466cbSJens Wiklander /* 961817466cbSJens Wiklander * Unsigned addition: X = |A| + |B| (HAC 14.7) 962817466cbSJens Wiklander */ 963817466cbSJens Wiklander int mbedtls_mpi_add_abs(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B) 964817466cbSJens Wiklander { 96511fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 966*32b31808SJens Wiklander size_t j; 9673d3b0591SJens Wiklander MPI_VALIDATE_RET(X != NULL); 9683d3b0591SJens Wiklander MPI_VALIDATE_RET(A != NULL); 9693d3b0591SJens Wiklander MPI_VALIDATE_RET(B != NULL); 970817466cbSJens Wiklander 971*32b31808SJens Wiklander if (X == B) { 972817466cbSJens Wiklander const mbedtls_mpi *T = A; A = X; B = T; 973817466cbSJens Wiklander } 974817466cbSJens Wiklander 975*32b31808SJens Wiklander if (X != A) { 976817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_copy(X, A)); 977*32b31808SJens Wiklander } 978817466cbSJens Wiklander 979817466cbSJens Wiklander /* 980*32b31808SJens Wiklander * X must always be positive as a result of unsigned additions. 981817466cbSJens Wiklander */ 982817466cbSJens Wiklander X->s = 1; 983817466cbSJens Wiklander 984*32b31808SJens Wiklander for (j = B->n; j > 0; j--) { 985*32b31808SJens Wiklander if (B->p[j - 1] != 0) { 986817466cbSJens Wiklander break; 987*32b31808SJens Wiklander } 988*32b31808SJens Wiklander } 989*32b31808SJens Wiklander 990*32b31808SJens Wiklander /* Exit early to avoid undefined behavior on NULL+0 when X->n == 0 991*32b31808SJens Wiklander * and B is 0 (of any size). */ 992*32b31808SJens Wiklander if (j == 0) { 993*32b31808SJens Wiklander return 0; 994*32b31808SJens Wiklander } 995817466cbSJens Wiklander 996817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, j)); 997817466cbSJens Wiklander 998*32b31808SJens Wiklander /* j is the number of non-zero limbs of B. Add those to X. */ 999817466cbSJens Wiklander 1000*32b31808SJens Wiklander mbedtls_mpi_uint *p = X->p; 1001*32b31808SJens Wiklander 1002*32b31808SJens Wiklander mbedtls_mpi_uint c = mbedtls_mpi_core_add(p, p, B->p, j); 1003*32b31808SJens Wiklander 1004*32b31808SJens Wiklander p += j; 1005*32b31808SJens Wiklander 1006*32b31808SJens Wiklander /* Now propagate any carry */ 1007*32b31808SJens Wiklander 1008*32b31808SJens Wiklander while (c != 0) { 1009*32b31808SJens Wiklander if (j >= X->n) { 1010*32b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, j + 1)); 1011*32b31808SJens Wiklander p = X->p + j; 1012817466cbSJens Wiklander } 1013817466cbSJens Wiklander 1014*32b31808SJens Wiklander *p += c; c = (*p < c); j++; p++; 1015817466cbSJens Wiklander } 1016817466cbSJens Wiklander 1017817466cbSJens Wiklander cleanup: 1018817466cbSJens Wiklander 1019*32b31808SJens Wiklander return ret; 1020817466cbSJens Wiklander } 1021817466cbSJens Wiklander 1022817466cbSJens Wiklander /* 10237901324dSJerome Forissier * Unsigned subtraction: X = |A| - |B| (HAC 14.9, 14.10) 1024817466cbSJens Wiklander */ 1025817466cbSJens Wiklander int mbedtls_mpi_sub_abs(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B) 1026817466cbSJens Wiklander { 102711fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1028817466cbSJens Wiklander size_t n; 10297901324dSJerome Forissier mbedtls_mpi_uint carry; 10303d3b0591SJens Wiklander MPI_VALIDATE_RET(X != NULL); 10313d3b0591SJens Wiklander MPI_VALIDATE_RET(A != NULL); 10323d3b0591SJens Wiklander MPI_VALIDATE_RET(B != NULL); 1033817466cbSJens Wiklander 1034*32b31808SJens Wiklander for (n = B->n; n > 0; n--) { 1035*32b31808SJens Wiklander if (B->p[n - 1] != 0) { 1036817466cbSJens Wiklander break; 1037*32b31808SJens Wiklander } 1038*32b31808SJens Wiklander } 1039*32b31808SJens Wiklander if (n > A->n) { 10407901324dSJerome Forissier /* B >= (2^ciL)^n > A */ 10417901324dSJerome Forissier ret = MBEDTLS_ERR_MPI_NEGATIVE_VALUE; 10427901324dSJerome Forissier goto cleanup; 10437901324dSJerome Forissier } 1044817466cbSJens Wiklander 10457901324dSJerome Forissier MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, A->n)); 10467901324dSJerome Forissier 10477901324dSJerome Forissier /* Set the high limbs of X to match A. Don't touch the lower limbs 10487901324dSJerome Forissier * because X might be aliased to B, and we must not overwrite the 10497901324dSJerome Forissier * significant digits of B. */ 1050*32b31808SJens Wiklander if (A->n > n && A != X) { 10517901324dSJerome Forissier memcpy(X->p + n, A->p + n, (A->n - n) * ciL); 1052*32b31808SJens Wiklander } 1053*32b31808SJens Wiklander if (X->n > A->n) { 10547901324dSJerome Forissier memset(X->p + A->n, 0, (X->n - A->n) * ciL); 1055*32b31808SJens Wiklander } 10567901324dSJerome Forissier 1057*32b31808SJens Wiklander carry = mbedtls_mpi_core_sub(X->p, A->p, B->p, n); 1058*32b31808SJens Wiklander if (carry != 0) { 1059*32b31808SJens Wiklander /* Propagate the carry through the rest of X. */ 1060*32b31808SJens Wiklander carry = mbedtls_mpi_core_sub_int(X->p + n, X->p + n, carry, X->n - n); 1061*32b31808SJens Wiklander 1062*32b31808SJens Wiklander /* If we have further carry/borrow, the result is negative. */ 1063*32b31808SJens Wiklander if (carry != 0) { 10647901324dSJerome Forissier ret = MBEDTLS_ERR_MPI_NEGATIVE_VALUE; 10657901324dSJerome Forissier goto cleanup; 10667901324dSJerome Forissier } 10677901324dSJerome Forissier } 10687901324dSJerome Forissier 10697901324dSJerome Forissier /* X should always be positive as a result of unsigned subtractions. */ 10707901324dSJerome Forissier X->s = 1; 1071817466cbSJens Wiklander 1072817466cbSJens Wiklander cleanup: 1073*32b31808SJens Wiklander return ret; 1074*32b31808SJens Wiklander } 1075*32b31808SJens Wiklander 1076*32b31808SJens Wiklander /* Common function for signed addition and subtraction. 1077*32b31808SJens Wiklander * Calculate A + B * flip_B where flip_B is 1 or -1. 1078*32b31808SJens Wiklander */ 1079*32b31808SJens Wiklander static int add_sub_mpi(mbedtls_mpi *X, 1080*32b31808SJens Wiklander const mbedtls_mpi *A, const mbedtls_mpi *B, 1081*32b31808SJens Wiklander int flip_B) 1082*32b31808SJens Wiklander { 1083*32b31808SJens Wiklander int ret, s; 1084*32b31808SJens Wiklander MPI_VALIDATE_RET(X != NULL); 1085*32b31808SJens Wiklander MPI_VALIDATE_RET(A != NULL); 1086*32b31808SJens Wiklander MPI_VALIDATE_RET(B != NULL); 1087*32b31808SJens Wiklander 1088*32b31808SJens Wiklander s = A->s; 1089*32b31808SJens Wiklander if (A->s * B->s * flip_B < 0) { 1090*32b31808SJens Wiklander int cmp = mbedtls_mpi_cmp_abs(A, B); 1091*32b31808SJens Wiklander if (cmp >= 0) { 1092*32b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_sub_abs(X, A, B)); 1093*32b31808SJens Wiklander /* If |A| = |B|, the result is 0 and we must set the sign bit 1094*32b31808SJens Wiklander * to +1 regardless of which of A or B was negative. Otherwise, 1095*32b31808SJens Wiklander * since |A| > |B|, the sign is the sign of A. */ 1096*32b31808SJens Wiklander X->s = cmp == 0 ? 1 : s; 1097*32b31808SJens Wiklander } else { 1098*32b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_sub_abs(X, B, A)); 1099*32b31808SJens Wiklander /* Since |A| < |B|, the sign is the opposite of A. */ 1100*32b31808SJens Wiklander X->s = -s; 1101*32b31808SJens Wiklander } 1102*32b31808SJens Wiklander } else { 1103*32b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_add_abs(X, A, B)); 1104*32b31808SJens Wiklander X->s = s; 1105*32b31808SJens Wiklander } 1106*32b31808SJens Wiklander 1107*32b31808SJens Wiklander cleanup: 1108*32b31808SJens Wiklander 1109*32b31808SJens Wiklander return ret; 1110817466cbSJens Wiklander } 1111817466cbSJens Wiklander 1112817466cbSJens Wiklander /* 1113817466cbSJens Wiklander * Signed addition: X = A + B 1114817466cbSJens Wiklander */ 1115817466cbSJens Wiklander int mbedtls_mpi_add_mpi(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B) 1116817466cbSJens Wiklander { 1117*32b31808SJens Wiklander return add_sub_mpi(X, A, B, 1); 1118817466cbSJens Wiklander } 1119817466cbSJens Wiklander 1120817466cbSJens Wiklander /* 1121817466cbSJens Wiklander * Signed subtraction: X = A - B 1122817466cbSJens Wiklander */ 1123817466cbSJens Wiklander int mbedtls_mpi_sub_mpi(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B) 1124817466cbSJens Wiklander { 1125*32b31808SJens Wiklander return add_sub_mpi(X, A, B, -1); 1126817466cbSJens Wiklander } 1127817466cbSJens Wiklander 1128817466cbSJens Wiklander /* 1129817466cbSJens Wiklander * Signed addition: X = A + b 1130817466cbSJens Wiklander */ 1131817466cbSJens Wiklander int mbedtls_mpi_add_int(mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b) 1132817466cbSJens Wiklander { 1133039e02dfSJerome Forissier mbedtls_mpi B; 1134817466cbSJens Wiklander mbedtls_mpi_uint p[1]; 11353d3b0591SJens Wiklander MPI_VALIDATE_RET(X != NULL); 11363d3b0591SJens Wiklander MPI_VALIDATE_RET(A != NULL); 1137817466cbSJens Wiklander 1138*32b31808SJens Wiklander p[0] = mpi_sint_abs(b); 1139039e02dfSJerome Forissier B.s = (b < 0) ? -1 : 1; 1140039e02dfSJerome Forissier B.n = 1; 1141039e02dfSJerome Forissier B.p = p; 1142817466cbSJens Wiklander 1143*32b31808SJens Wiklander return mbedtls_mpi_add_mpi(X, A, &B); 1144817466cbSJens Wiklander } 1145817466cbSJens Wiklander 1146817466cbSJens Wiklander /* 1147817466cbSJens Wiklander * Signed subtraction: X = A - b 1148817466cbSJens Wiklander */ 1149817466cbSJens Wiklander int mbedtls_mpi_sub_int(mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b) 1150817466cbSJens Wiklander { 1151039e02dfSJerome Forissier mbedtls_mpi B; 1152817466cbSJens Wiklander mbedtls_mpi_uint p[1]; 11533d3b0591SJens Wiklander MPI_VALIDATE_RET(X != NULL); 11543d3b0591SJens Wiklander MPI_VALIDATE_RET(A != NULL); 1155817466cbSJens Wiklander 1156*32b31808SJens Wiklander p[0] = mpi_sint_abs(b); 1157039e02dfSJerome Forissier B.s = (b < 0) ? -1 : 1; 1158039e02dfSJerome Forissier B.n = 1; 1159039e02dfSJerome Forissier B.p = p; 1160817466cbSJens Wiklander 1161*32b31808SJens Wiklander return mbedtls_mpi_sub_mpi(X, A, &B); 1162817466cbSJens Wiklander } 1163817466cbSJens Wiklander 1164817466cbSJens Wiklander /* 1165817466cbSJens Wiklander * Baseline multiplication: X = A * B (HAC 14.12) 1166817466cbSJens Wiklander */ 1167817466cbSJens Wiklander int mbedtls_mpi_mul_mpi(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B) 1168817466cbSJens Wiklander { 116911fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1170817466cbSJens Wiklander size_t i, j; 1171817466cbSJens Wiklander mbedtls_mpi TA, TB; 11727901324dSJerome Forissier int result_is_zero = 0; 11733d3b0591SJens Wiklander MPI_VALIDATE_RET(X != NULL); 11743d3b0591SJens Wiklander MPI_VALIDATE_RET(A != NULL); 11753d3b0591SJens Wiklander MPI_VALIDATE_RET(B != NULL); 1176817466cbSJens Wiklander 117798bd5fe3SJens Wiklander mbedtls_mpi_init_mempool(&TA); mbedtls_mpi_init_mempool(&TB); 1178817466cbSJens Wiklander 1179*32b31808SJens Wiklander if (X == A) { 1180*32b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TA, A)); A = &TA; 1181*32b31808SJens Wiklander } 1182*32b31808SJens Wiklander if (X == B) { 1183*32b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TB, B)); B = &TB; 1184*32b31808SJens Wiklander } 1185817466cbSJens Wiklander 1186*32b31808SJens Wiklander for (i = A->n; i > 0; i--) { 1187*32b31808SJens Wiklander if (A->p[i - 1] != 0) { 1188817466cbSJens Wiklander break; 1189*32b31808SJens Wiklander } 1190*32b31808SJens Wiklander } 1191*32b31808SJens Wiklander if (i == 0) { 11927901324dSJerome Forissier result_is_zero = 1; 1193*32b31808SJens Wiklander } 1194817466cbSJens Wiklander 1195*32b31808SJens Wiklander for (j = B->n; j > 0; j--) { 1196*32b31808SJens Wiklander if (B->p[j - 1] != 0) { 1197817466cbSJens Wiklander break; 1198*32b31808SJens Wiklander } 1199*32b31808SJens Wiklander } 1200*32b31808SJens Wiklander if (j == 0) { 12017901324dSJerome Forissier result_is_zero = 1; 1202*32b31808SJens Wiklander } 1203817466cbSJens Wiklander 1204817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, i + j)); 1205817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_lset(X, 0)); 1206817466cbSJens Wiklander 1207*32b31808SJens Wiklander for (size_t k = 0; k < j; k++) { 1208*32b31808SJens Wiklander /* We know that there cannot be any carry-out since we're 1209*32b31808SJens Wiklander * iterating from bottom to top. */ 1210*32b31808SJens Wiklander (void) mbedtls_mpi_core_mla(X->p + k, i + 1, 1211*32b31808SJens Wiklander A->p, i, 1212*32b31808SJens Wiklander B->p[k]); 1213*32b31808SJens Wiklander } 1214817466cbSJens Wiklander 12157901324dSJerome Forissier /* If the result is 0, we don't shortcut the operation, which reduces 12167901324dSJerome Forissier * but does not eliminate side channels leaking the zero-ness. We do 12177901324dSJerome Forissier * need to take care to set the sign bit properly since the library does 12187901324dSJerome Forissier * not fully support an MPI object with a value of 0 and s == -1. */ 1219*32b31808SJens Wiklander if (result_is_zero) { 12207901324dSJerome Forissier X->s = 1; 1221*32b31808SJens Wiklander } else { 1222817466cbSJens Wiklander X->s = A->s * B->s; 1223*32b31808SJens Wiklander } 1224817466cbSJens Wiklander 1225817466cbSJens Wiklander cleanup: 1226817466cbSJens Wiklander 1227817466cbSJens Wiklander mbedtls_mpi_free(&TB); mbedtls_mpi_free(&TA); 1228817466cbSJens Wiklander 1229*32b31808SJens Wiklander return ret; 1230817466cbSJens Wiklander } 1231817466cbSJens Wiklander 1232817466cbSJens Wiklander /* 1233817466cbSJens Wiklander * Baseline multiplication: X = A * b 1234817466cbSJens Wiklander */ 1235817466cbSJens Wiklander int mbedtls_mpi_mul_int(mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_uint b) 1236817466cbSJens Wiklander { 12373d3b0591SJens Wiklander MPI_VALIDATE_RET(X != NULL); 12383d3b0591SJens Wiklander MPI_VALIDATE_RET(A != NULL); 1239817466cbSJens Wiklander 12407901324dSJerome Forissier size_t n = A->n; 1241*32b31808SJens Wiklander while (n > 0 && A->p[n - 1] == 0) { 12427901324dSJerome Forissier --n; 12437901324dSJerome Forissier } 12447901324dSJerome Forissier 1245*32b31808SJens Wiklander /* The general method below doesn't work if b==0. */ 1246*32b31808SJens Wiklander if (b == 0 || n == 0) { 1247*32b31808SJens Wiklander return mbedtls_mpi_lset(X, 0); 1248*32b31808SJens Wiklander } 1249*32b31808SJens Wiklander 1250*32b31808SJens Wiklander /* Calculate A*b as A + A*(b-1) to take advantage of mbedtls_mpi_core_mla */ 12517901324dSJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 12527901324dSJerome Forissier /* In general, A * b requires 1 limb more than b. If 12537901324dSJerome Forissier * A->p[n - 1] * b / b == A->p[n - 1], then A * b fits in the same 12547901324dSJerome Forissier * number of limbs as A and the call to grow() is not required since 12557901324dSJerome Forissier * copy() will take care of the growth if needed. However, experimentally, 12567901324dSJerome Forissier * making the call to grow() unconditional causes slightly fewer 12577901324dSJerome Forissier * calls to calloc() in ECP code, presumably because it reuses the 12587901324dSJerome Forissier * same mpi for a while and this way the mpi is more likely to directly 1259*32b31808SJens Wiklander * grow to its final size. 1260*32b31808SJens Wiklander * 1261*32b31808SJens Wiklander * Note that calculating A*b as 0 + A*b doesn't work as-is because 1262*32b31808SJens Wiklander * A,X can be the same. */ 12637901324dSJerome Forissier MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, n + 1)); 12647901324dSJerome Forissier MBEDTLS_MPI_CHK(mbedtls_mpi_copy(X, A)); 1265*32b31808SJens Wiklander mbedtls_mpi_core_mla(X->p, X->n, A->p, n, b - 1); 12667901324dSJerome Forissier 12677901324dSJerome Forissier cleanup: 1268*32b31808SJens Wiklander return ret; 1269817466cbSJens Wiklander } 1270817466cbSJens Wiklander 1271817466cbSJens Wiklander /* 1272817466cbSJens Wiklander * Unsigned integer divide - double mbedtls_mpi_uint dividend, u1/u0, and 1273817466cbSJens Wiklander * mbedtls_mpi_uint divisor, d 1274817466cbSJens Wiklander */ 1275817466cbSJens Wiklander static mbedtls_mpi_uint mbedtls_int_div_int(mbedtls_mpi_uint u1, 1276*32b31808SJens Wiklander mbedtls_mpi_uint u0, 1277*32b31808SJens Wiklander mbedtls_mpi_uint d, 1278*32b31808SJens Wiklander mbedtls_mpi_uint *r) 1279817466cbSJens Wiklander { 1280817466cbSJens Wiklander #if defined(MBEDTLS_HAVE_UDBL) 1281817466cbSJens Wiklander mbedtls_t_udbl dividend, quotient; 1282817466cbSJens Wiklander #else 1283817466cbSJens Wiklander const mbedtls_mpi_uint radix = (mbedtls_mpi_uint) 1 << biH; 1284817466cbSJens Wiklander const mbedtls_mpi_uint uint_halfword_mask = ((mbedtls_mpi_uint) 1 << biH) - 1; 1285817466cbSJens Wiklander mbedtls_mpi_uint d0, d1, q0, q1, rAX, r0, quotient; 1286817466cbSJens Wiklander mbedtls_mpi_uint u0_msw, u0_lsw; 1287817466cbSJens Wiklander size_t s; 1288817466cbSJens Wiklander #endif 1289817466cbSJens Wiklander 1290817466cbSJens Wiklander /* 1291817466cbSJens Wiklander * Check for overflow 1292817466cbSJens Wiklander */ 1293*32b31808SJens Wiklander if (0 == d || u1 >= d) { 1294*32b31808SJens Wiklander if (r != NULL) { 1295*32b31808SJens Wiklander *r = ~(mbedtls_mpi_uint) 0u; 1296*32b31808SJens Wiklander } 1297817466cbSJens Wiklander 1298*32b31808SJens Wiklander return ~(mbedtls_mpi_uint) 0u; 1299817466cbSJens Wiklander } 1300817466cbSJens Wiklander 1301817466cbSJens Wiklander #if defined(MBEDTLS_HAVE_UDBL) 1302817466cbSJens Wiklander dividend = (mbedtls_t_udbl) u1 << biL; 1303817466cbSJens Wiklander dividend |= (mbedtls_t_udbl) u0; 1304817466cbSJens Wiklander quotient = dividend / d; 1305*32b31808SJens Wiklander if (quotient > ((mbedtls_t_udbl) 1 << biL) - 1) { 1306817466cbSJens Wiklander quotient = ((mbedtls_t_udbl) 1 << biL) - 1; 1307*32b31808SJens Wiklander } 1308817466cbSJens Wiklander 1309*32b31808SJens Wiklander if (r != NULL) { 1310817466cbSJens Wiklander *r = (mbedtls_mpi_uint) (dividend - (quotient * d)); 1311*32b31808SJens Wiklander } 1312817466cbSJens Wiklander 1313817466cbSJens Wiklander return (mbedtls_mpi_uint) quotient; 1314817466cbSJens Wiklander #else 1315817466cbSJens Wiklander 1316817466cbSJens Wiklander /* 1317817466cbSJens Wiklander * Algorithm D, Section 4.3.1 - The Art of Computer Programming 1318817466cbSJens Wiklander * Vol. 2 - Seminumerical Algorithms, Knuth 1319817466cbSJens Wiklander */ 1320817466cbSJens Wiklander 1321817466cbSJens Wiklander /* 1322817466cbSJens Wiklander * Normalize the divisor, d, and dividend, u0, u1 1323817466cbSJens Wiklander */ 1324*32b31808SJens Wiklander s = mbedtls_mpi_core_clz(d); 1325817466cbSJens Wiklander d = d << s; 1326817466cbSJens Wiklander 1327817466cbSJens Wiklander u1 = u1 << s; 1328817466cbSJens Wiklander u1 |= (u0 >> (biL - s)) & (-(mbedtls_mpi_sint) s >> (biL - 1)); 1329817466cbSJens Wiklander u0 = u0 << s; 1330817466cbSJens Wiklander 1331817466cbSJens Wiklander d1 = d >> biH; 1332817466cbSJens Wiklander d0 = d & uint_halfword_mask; 1333817466cbSJens Wiklander 1334817466cbSJens Wiklander u0_msw = u0 >> biH; 1335817466cbSJens Wiklander u0_lsw = u0 & uint_halfword_mask; 1336817466cbSJens Wiklander 1337817466cbSJens Wiklander /* 1338817466cbSJens Wiklander * Find the first quotient and remainder 1339817466cbSJens Wiklander */ 1340817466cbSJens Wiklander q1 = u1 / d1; 1341817466cbSJens Wiklander r0 = u1 - d1 * q1; 1342817466cbSJens Wiklander 1343*32b31808SJens Wiklander while (q1 >= radix || (q1 * d0 > radix * r0 + u0_msw)) { 1344817466cbSJens Wiklander q1 -= 1; 1345817466cbSJens Wiklander r0 += d1; 1346817466cbSJens Wiklander 1347*32b31808SJens Wiklander if (r0 >= radix) { 1348*32b31808SJens Wiklander break; 1349*32b31808SJens Wiklander } 1350817466cbSJens Wiklander } 1351817466cbSJens Wiklander 1352817466cbSJens Wiklander rAX = (u1 * radix) + (u0_msw - q1 * d); 1353817466cbSJens Wiklander q0 = rAX / d1; 1354817466cbSJens Wiklander r0 = rAX - q0 * d1; 1355817466cbSJens Wiklander 1356*32b31808SJens Wiklander while (q0 >= radix || (q0 * d0 > radix * r0 + u0_lsw)) { 1357817466cbSJens Wiklander q0 -= 1; 1358817466cbSJens Wiklander r0 += d1; 1359817466cbSJens Wiklander 1360*32b31808SJens Wiklander if (r0 >= radix) { 1361*32b31808SJens Wiklander break; 1362*32b31808SJens Wiklander } 1363817466cbSJens Wiklander } 1364817466cbSJens Wiklander 1365*32b31808SJens Wiklander if (r != NULL) { 1366817466cbSJens Wiklander *r = (rAX * radix + u0_lsw - q0 * d) >> s; 1367*32b31808SJens Wiklander } 1368817466cbSJens Wiklander 1369817466cbSJens Wiklander quotient = q1 * radix + q0; 1370817466cbSJens Wiklander 1371817466cbSJens Wiklander return quotient; 1372817466cbSJens Wiklander #endif 1373817466cbSJens Wiklander } 1374817466cbSJens Wiklander 1375817466cbSJens Wiklander /* 1376817466cbSJens Wiklander * Division by mbedtls_mpi: A = Q * B + R (HAC 14.20) 1377817466cbSJens Wiklander */ 13783d3b0591SJens Wiklander int mbedtls_mpi_div_mpi(mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A, 13793d3b0591SJens Wiklander const mbedtls_mpi *B) 1380817466cbSJens Wiklander { 138111fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1382817466cbSJens Wiklander size_t i, n, t, k; 1383817466cbSJens Wiklander mbedtls_mpi X, Y, Z, T1, T2; 138411fa71b9SJerome Forissier mbedtls_mpi_uint TP2[3]; 13853d3b0591SJens Wiklander MPI_VALIDATE_RET(A != NULL); 13863d3b0591SJens Wiklander MPI_VALIDATE_RET(B != NULL); 1387817466cbSJens Wiklander 1388*32b31808SJens Wiklander if (mbedtls_mpi_cmp_int(B, 0) == 0) { 1389*32b31808SJens Wiklander return MBEDTLS_ERR_MPI_DIVISION_BY_ZERO; 1390*32b31808SJens Wiklander } 1391817466cbSJens Wiklander 139298bd5fe3SJens Wiklander mbedtls_mpi_init_mempool(&X); mbedtls_mpi_init_mempool(&Y); 139398bd5fe3SJens Wiklander mbedtls_mpi_init_mempool(&Z); mbedtls_mpi_init_mempool(&T1); 139411fa71b9SJerome Forissier /* 139511fa71b9SJerome Forissier * Avoid dynamic memory allocations for constant-size T2. 139611fa71b9SJerome Forissier * 139711fa71b9SJerome Forissier * T2 is used for comparison only and the 3 limbs are assigned explicitly, 139811fa71b9SJerome Forissier * so nobody increase the size of the MPI and we're safe to use an on-stack 139911fa71b9SJerome Forissier * buffer. 140011fa71b9SJerome Forissier */ 140111fa71b9SJerome Forissier T2.s = 1; 140211fa71b9SJerome Forissier T2.n = sizeof(TP2) / sizeof(*TP2); 140311fa71b9SJerome Forissier T2.p = TP2; 1404817466cbSJens Wiklander 1405*32b31808SJens Wiklander if (mbedtls_mpi_cmp_abs(A, B) < 0) { 1406*32b31808SJens Wiklander if (Q != NULL) { 1407*32b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_lset(Q, 0)); 1408*32b31808SJens Wiklander } 1409*32b31808SJens Wiklander if (R != NULL) { 1410*32b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_copy(R, A)); 1411*32b31808SJens Wiklander } 1412*32b31808SJens Wiklander return 0; 1413817466cbSJens Wiklander } 1414817466cbSJens Wiklander 1415817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&X, A)); 1416817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&Y, B)); 1417817466cbSJens Wiklander X.s = Y.s = 1; 1418817466cbSJens Wiklander 1419817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_grow(&Z, A->n + 2)); 1420817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&Z, 0)); 14217901324dSJerome Forissier MBEDTLS_MPI_CHK(mbedtls_mpi_grow(&T1, A->n + 2)); 1422817466cbSJens Wiklander 1423817466cbSJens Wiklander k = mbedtls_mpi_bitlen(&Y) % biL; 1424*32b31808SJens Wiklander if (k < biL - 1) { 1425817466cbSJens Wiklander k = biL - 1 - k; 1426817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&X, k)); 1427817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&Y, k)); 1428*32b31808SJens Wiklander } else { 1429*32b31808SJens Wiklander k = 0; 1430817466cbSJens Wiklander } 1431817466cbSJens Wiklander 1432817466cbSJens Wiklander n = X.n - 1; 1433817466cbSJens Wiklander t = Y.n - 1; 1434817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&Y, biL * (n - t))); 1435817466cbSJens Wiklander 1436*32b31808SJens Wiklander while (mbedtls_mpi_cmp_mpi(&X, &Y) >= 0) { 1437817466cbSJens Wiklander Z.p[n - t]++; 1438817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&X, &X, &Y)); 1439817466cbSJens Wiklander } 1440817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&Y, biL * (n - t))); 1441817466cbSJens Wiklander 1442*32b31808SJens Wiklander for (i = n; i > t; i--) { 1443*32b31808SJens Wiklander if (X.p[i] >= Y.p[t]) { 1444*32b31808SJens Wiklander Z.p[i - t - 1] = ~(mbedtls_mpi_uint) 0u; 1445*32b31808SJens Wiklander } else { 1446817466cbSJens Wiklander Z.p[i - t - 1] = mbedtls_int_div_int(X.p[i], X.p[i - 1], 1447817466cbSJens Wiklander Y.p[t], NULL); 1448817466cbSJens Wiklander } 1449817466cbSJens Wiklander 145011fa71b9SJerome Forissier T2.p[0] = (i < 2) ? 0 : X.p[i - 2]; 145111fa71b9SJerome Forissier T2.p[1] = (i < 1) ? 0 : X.p[i - 1]; 145211fa71b9SJerome Forissier T2.p[2] = X.p[i]; 145311fa71b9SJerome Forissier 1454817466cbSJens Wiklander Z.p[i - t - 1]++; 1455*32b31808SJens Wiklander do { 1456817466cbSJens Wiklander Z.p[i - t - 1]--; 1457817466cbSJens Wiklander 1458817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&T1, 0)); 1459817466cbSJens Wiklander T1.p[0] = (t < 1) ? 0 : Y.p[t - 1]; 1460817466cbSJens Wiklander T1.p[1] = Y.p[t]; 1461817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_mul_int(&T1, &T1, Z.p[i - t - 1])); 1462*32b31808SJens Wiklander } while (mbedtls_mpi_cmp_mpi(&T1, &T2) > 0); 1463817466cbSJens Wiklander 1464817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_mul_int(&T1, &Y, Z.p[i - t - 1])); 1465817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&T1, biL * (i - t - 1))); 1466817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&X, &X, &T1)); 1467817466cbSJens Wiklander 1468*32b31808SJens Wiklander if (mbedtls_mpi_cmp_int(&X, 0) < 0) { 1469817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&T1, &Y)); 1470817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&T1, biL * (i - t - 1))); 1471817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&X, &X, &T1)); 1472817466cbSJens Wiklander Z.p[i - t - 1]--; 1473817466cbSJens Wiklander } 1474817466cbSJens Wiklander } 1475817466cbSJens Wiklander 1476*32b31808SJens Wiklander if (Q != NULL) { 1477817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_copy(Q, &Z)); 1478817466cbSJens Wiklander Q->s = A->s * B->s; 1479817466cbSJens Wiklander } 1480817466cbSJens Wiklander 1481*32b31808SJens Wiklander if (R != NULL) { 1482817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&X, k)); 1483817466cbSJens Wiklander X.s = A->s; 1484817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_copy(R, &X)); 1485817466cbSJens Wiklander 1486*32b31808SJens Wiklander if (mbedtls_mpi_cmp_int(R, 0) == 0) { 1487817466cbSJens Wiklander R->s = 1; 1488817466cbSJens Wiklander } 1489*32b31808SJens Wiklander } 1490817466cbSJens Wiklander 1491817466cbSJens Wiklander cleanup: 1492817466cbSJens Wiklander 1493817466cbSJens Wiklander mbedtls_mpi_free(&X); mbedtls_mpi_free(&Y); mbedtls_mpi_free(&Z); 149411fa71b9SJerome Forissier mbedtls_mpi_free(&T1); 149511fa71b9SJerome Forissier mbedtls_platform_zeroize(TP2, sizeof(TP2)); 1496817466cbSJens Wiklander 1497*32b31808SJens Wiklander return ret; 1498817466cbSJens Wiklander } 1499817466cbSJens Wiklander 1500817466cbSJens Wiklander /* 1501817466cbSJens Wiklander * Division by int: A = Q * b + R 1502817466cbSJens Wiklander */ 15033d3b0591SJens Wiklander int mbedtls_mpi_div_int(mbedtls_mpi *Q, mbedtls_mpi *R, 15043d3b0591SJens Wiklander const mbedtls_mpi *A, 15053d3b0591SJens Wiklander mbedtls_mpi_sint b) 1506817466cbSJens Wiklander { 1507039e02dfSJerome Forissier mbedtls_mpi B; 1508817466cbSJens Wiklander mbedtls_mpi_uint p[1]; 15093d3b0591SJens Wiklander MPI_VALIDATE_RET(A != NULL); 1510817466cbSJens Wiklander 1511*32b31808SJens Wiklander p[0] = mpi_sint_abs(b); 1512039e02dfSJerome Forissier B.s = (b < 0) ? -1 : 1; 1513039e02dfSJerome Forissier B.n = 1; 1514039e02dfSJerome Forissier B.p = p; 1515817466cbSJens Wiklander 1516*32b31808SJens Wiklander return mbedtls_mpi_div_mpi(Q, R, A, &B); 1517817466cbSJens Wiklander } 1518817466cbSJens Wiklander 1519817466cbSJens Wiklander /* 1520817466cbSJens Wiklander * Modulo: R = A mod B 1521817466cbSJens Wiklander */ 1522817466cbSJens Wiklander int mbedtls_mpi_mod_mpi(mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B) 1523817466cbSJens Wiklander { 152411fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 15253d3b0591SJens Wiklander MPI_VALIDATE_RET(R != NULL); 15263d3b0591SJens Wiklander MPI_VALIDATE_RET(A != NULL); 15273d3b0591SJens Wiklander MPI_VALIDATE_RET(B != NULL); 1528817466cbSJens Wiklander 1529*32b31808SJens Wiklander if (mbedtls_mpi_cmp_int(B, 0) < 0) { 1530*32b31808SJens Wiklander return MBEDTLS_ERR_MPI_NEGATIVE_VALUE; 1531*32b31808SJens Wiklander } 1532817466cbSJens Wiklander 1533817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_div_mpi(NULL, R, A, B)); 1534817466cbSJens Wiklander 1535*32b31808SJens Wiklander while (mbedtls_mpi_cmp_int(R, 0) < 0) { 1536817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(R, R, B)); 1537*32b31808SJens Wiklander } 1538817466cbSJens Wiklander 1539*32b31808SJens Wiklander while (mbedtls_mpi_cmp_mpi(R, B) >= 0) { 1540817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(R, R, B)); 1541*32b31808SJens Wiklander } 1542817466cbSJens Wiklander 1543817466cbSJens Wiklander cleanup: 1544817466cbSJens Wiklander 1545*32b31808SJens Wiklander return ret; 1546817466cbSJens Wiklander } 1547817466cbSJens Wiklander 1548817466cbSJens Wiklander /* 1549817466cbSJens Wiklander * Modulo: r = A mod b 1550817466cbSJens Wiklander */ 1551817466cbSJens Wiklander int mbedtls_mpi_mod_int(mbedtls_mpi_uint *r, const mbedtls_mpi *A, mbedtls_mpi_sint b) 1552817466cbSJens Wiklander { 1553817466cbSJens Wiklander size_t i; 1554817466cbSJens Wiklander mbedtls_mpi_uint x, y, z; 15553d3b0591SJens Wiklander MPI_VALIDATE_RET(r != NULL); 15563d3b0591SJens Wiklander MPI_VALIDATE_RET(A != NULL); 1557817466cbSJens Wiklander 1558*32b31808SJens Wiklander if (b == 0) { 1559*32b31808SJens Wiklander return MBEDTLS_ERR_MPI_DIVISION_BY_ZERO; 1560*32b31808SJens Wiklander } 1561817466cbSJens Wiklander 1562*32b31808SJens Wiklander if (b < 0) { 1563*32b31808SJens Wiklander return MBEDTLS_ERR_MPI_NEGATIVE_VALUE; 1564*32b31808SJens Wiklander } 1565817466cbSJens Wiklander 1566817466cbSJens Wiklander /* 1567817466cbSJens Wiklander * handle trivial cases 1568817466cbSJens Wiklander */ 1569*32b31808SJens Wiklander if (b == 1 || A->n == 0) { 1570817466cbSJens Wiklander *r = 0; 1571*32b31808SJens Wiklander return 0; 1572817466cbSJens Wiklander } 1573817466cbSJens Wiklander 1574*32b31808SJens Wiklander if (b == 2) { 1575817466cbSJens Wiklander *r = A->p[0] & 1; 1576*32b31808SJens Wiklander return 0; 1577817466cbSJens Wiklander } 1578817466cbSJens Wiklander 1579817466cbSJens Wiklander /* 1580817466cbSJens Wiklander * general case 1581817466cbSJens Wiklander */ 1582*32b31808SJens Wiklander for (i = A->n, y = 0; i > 0; i--) { 1583817466cbSJens Wiklander x = A->p[i - 1]; 1584817466cbSJens Wiklander y = (y << biH) | (x >> biH); 1585817466cbSJens Wiklander z = y / b; 1586817466cbSJens Wiklander y -= z * b; 1587817466cbSJens Wiklander 1588817466cbSJens Wiklander x <<= biH; 1589817466cbSJens Wiklander y = (y << biH) | (x >> biH); 1590817466cbSJens Wiklander z = y / b; 1591817466cbSJens Wiklander y -= z * b; 1592817466cbSJens Wiklander } 1593817466cbSJens Wiklander 1594817466cbSJens Wiklander /* 1595817466cbSJens Wiklander * If A is negative, then the current y represents a negative value. 1596817466cbSJens Wiklander * Flipping it to the positive side. 1597817466cbSJens Wiklander */ 1598*32b31808SJens Wiklander if (A->s < 0 && y != 0) { 1599817466cbSJens Wiklander y = b - y; 1600*32b31808SJens Wiklander } 1601817466cbSJens Wiklander 1602817466cbSJens Wiklander *r = y; 1603817466cbSJens Wiklander 1604*32b31808SJens Wiklander return 0; 1605817466cbSJens Wiklander } 1606817466cbSJens Wiklander 16077901324dSJerome Forissier static void mpi_montg_init(mbedtls_mpi_uint *mm, const mbedtls_mpi *N) 1608817466cbSJens Wiklander { 1609*32b31808SJens Wiklander *mm = mbedtls_mpi_core_montmul_init(N->p); 1610817466cbSJens Wiklander } 1611817466cbSJens Wiklander 16127901324dSJerome Forissier void mbedtls_mpi_montg_init( mbedtls_mpi_uint *mm, const mbedtls_mpi *N ) 16137901324dSJerome Forissier { 16147901324dSJerome Forissier mpi_montg_init( mm, N ); 16157901324dSJerome Forissier } 16167901324dSJerome Forissier 16177901324dSJerome Forissier /** Montgomery multiplication: A = A * B * R^-1 mod N (HAC 14.36) 16187901324dSJerome Forissier * 16197901324dSJerome Forissier * \param[in,out] A One of the numbers to multiply. 16207901324dSJerome Forissier * It must have at least as many limbs as N 16217901324dSJerome Forissier * (A->n >= N->n), and any limbs beyond n are ignored. 16227901324dSJerome Forissier * On successful completion, A contains the result of 16237901324dSJerome Forissier * the multiplication A * B * R^-1 mod N where 16247901324dSJerome Forissier * R = (2^ciL)^n. 16257901324dSJerome Forissier * \param[in] B One of the numbers to multiply. 16267901324dSJerome Forissier * It must be nonzero and must not have more limbs than N 16277901324dSJerome Forissier * (B->n <= N->n). 1628*32b31808SJens Wiklander * \param[in] N The modulus. \p N must be odd. 16297901324dSJerome Forissier * \param mm The value calculated by `mpi_montg_init(&mm, N)`. 16307901324dSJerome Forissier * This is -N^-1 mod 2^ciL. 16317901324dSJerome Forissier * \param[in,out] T A bignum for temporary storage. 1632*32b31808SJens Wiklander * It must be at least twice the limb size of N plus 1 1633*32b31808SJens Wiklander * (T->n >= 2 * N->n + 1). 16347901324dSJerome Forissier * Its initial content is unused and 16357901324dSJerome Forissier * its final content is indeterminate. 1636*32b31808SJens Wiklander * It does not get reallocated. 1637817466cbSJens Wiklander */ 1638*32b31808SJens Wiklander static void mpi_montmul(mbedtls_mpi *A, const mbedtls_mpi *B, 1639*32b31808SJens Wiklander const mbedtls_mpi *N, mbedtls_mpi_uint mm, 1640*32b31808SJens Wiklander mbedtls_mpi *T) 1641817466cbSJens Wiklander { 1642*32b31808SJens Wiklander mbedtls_mpi_core_montmul(A->p, A->p, B->p, B->n, N->p, N->n, mm, T->p); 1643817466cbSJens Wiklander } 1644817466cbSJens Wiklander 1645*32b31808SJens Wiklander void mbedtls_mpi_montmul(mbedtls_mpi *A, const mbedtls_mpi *B, 1646*32b31808SJens Wiklander const mbedtls_mpi *N, mbedtls_mpi_uint mm, 1647*32b31808SJens Wiklander mbedtls_mpi *T ) 16487901324dSJerome Forissier { 16497901324dSJerome Forissier mpi_montmul( A, B, N, mm, T); 1650817466cbSJens Wiklander } 1651817466cbSJens Wiklander 1652817466cbSJens Wiklander /* 1653817466cbSJens Wiklander * Montgomery reduction: A = A * R^-1 mod N 16547901324dSJerome Forissier * 16557901324dSJerome Forissier * See mpi_montmul() regarding constraints and guarantees on the parameters. 1656817466cbSJens Wiklander */ 16577901324dSJerome Forissier static void mpi_montred(mbedtls_mpi *A, const mbedtls_mpi *N, 1658*32b31808SJens Wiklander mbedtls_mpi_uint mm, mbedtls_mpi *T) 1659817466cbSJens Wiklander { 1660817466cbSJens Wiklander mbedtls_mpi_uint z = 1; 1661817466cbSJens Wiklander mbedtls_mpi U; 1662817466cbSJens Wiklander 1663817466cbSJens Wiklander U.n = U.s = (int) z; 1664817466cbSJens Wiklander U.p = &z; 1665817466cbSJens Wiklander 16667901324dSJerome Forissier mpi_montmul(A, &U, N, mm, T); 16677901324dSJerome Forissier } 16687901324dSJerome Forissier 16697901324dSJerome Forissier void mbedtls_mpi_montred(mbedtls_mpi *A, const mbedtls_mpi *N, 1670*32b31808SJens Wiklander mbedtls_mpi_uint mm, mbedtls_mpi *T) 16717901324dSJerome Forissier { 16727901324dSJerome Forissier mpi_montred(A, N, mm, T); 16737901324dSJerome Forissier } 16747901324dSJerome Forissier 16757901324dSJerome Forissier /** 16767901324dSJerome Forissier * Select an MPI from a table without leaking the index. 16777901324dSJerome Forissier * 16787901324dSJerome Forissier * This is functionally equivalent to mbedtls_mpi_copy(R, T[idx]) except it 16797901324dSJerome Forissier * reads the entire table in order to avoid leaking the value of idx to an 16807901324dSJerome Forissier * attacker able to observe memory access patterns. 16817901324dSJerome Forissier * 16827901324dSJerome Forissier * \param[out] R Where to write the selected MPI. 16837901324dSJerome Forissier * \param[in] T The table to read from. 16847901324dSJerome Forissier * \param[in] T_size The number of elements in the table. 16857901324dSJerome Forissier * \param[in] idx The index of the element to select; 16867901324dSJerome Forissier * this must satisfy 0 <= idx < T_size. 16877901324dSJerome Forissier * 16887901324dSJerome Forissier * \return \c 0 on success, or a negative error code. 16897901324dSJerome Forissier */ 16907901324dSJerome Forissier static int mpi_select(mbedtls_mpi *R, const mbedtls_mpi *T, size_t T_size, size_t idx) 16917901324dSJerome Forissier { 16927901324dSJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 16937901324dSJerome Forissier 1694*32b31808SJens Wiklander for (size_t i = 0; i < T_size; i++) { 16957901324dSJerome Forissier MBEDTLS_MPI_CHK(mbedtls_mpi_safe_cond_assign(R, &T[i], 1696*32b31808SJens Wiklander (unsigned char) mbedtls_ct_size_bool_eq(i, 1697*32b31808SJens Wiklander idx))); 16987901324dSJerome Forissier } 16997901324dSJerome Forissier 17007901324dSJerome Forissier cleanup: 1701*32b31808SJens Wiklander return ret; 1702817466cbSJens Wiklander } 1703817466cbSJens Wiklander 1704817466cbSJens Wiklander /* 1705817466cbSJens Wiklander * Sliding-window exponentiation: X = A^E mod N (HAC 14.85) 1706817466cbSJens Wiklander */ 17073d3b0591SJens Wiklander int mbedtls_mpi_exp_mod(mbedtls_mpi *X, const mbedtls_mpi *A, 17083d3b0591SJens Wiklander const mbedtls_mpi *E, const mbedtls_mpi *N, 1709039e02dfSJerome Forissier mbedtls_mpi *prec_RR) 1710817466cbSJens Wiklander { 171111fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1712*32b31808SJens Wiklander size_t window_bitsize; 1713817466cbSJens Wiklander size_t i, j, nblimbs; 1714817466cbSJens Wiklander size_t bufsize, nbits; 1715*32b31808SJens Wiklander size_t exponent_bits_in_window = 0; 1716817466cbSJens Wiklander mbedtls_mpi_uint ei, mm, state; 17177901324dSJerome Forissier mbedtls_mpi RR, T, WW, Apos; 1718*32b31808SJens Wiklander mbedtls_mpi *W; 171941e5aa8fSJens Wiklander const size_t array_size_W = 2 << MBEDTLS_MPI_WINDOW_SIZE; 1720817466cbSJens Wiklander int neg; 1721817466cbSJens Wiklander 17223d3b0591SJens Wiklander MPI_VALIDATE_RET(X != NULL); 17233d3b0591SJens Wiklander MPI_VALIDATE_RET(A != NULL); 17243d3b0591SJens Wiklander MPI_VALIDATE_RET(E != NULL); 17253d3b0591SJens Wiklander MPI_VALIDATE_RET(N != NULL); 17263d3b0591SJens Wiklander 1727*32b31808SJens Wiklander if (mbedtls_mpi_cmp_int(N, 0) <= 0 || (N->p[0] & 1) == 0) { 1728*32b31808SJens Wiklander return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; 1729*32b31808SJens Wiklander } 1730817466cbSJens Wiklander 1731*32b31808SJens Wiklander if (mbedtls_mpi_cmp_int(E, 0) < 0) { 1732*32b31808SJens Wiklander return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; 1733*32b31808SJens Wiklander } 1734817466cbSJens Wiklander 17357901324dSJerome Forissier if (mbedtls_mpi_bitlen(E) > MBEDTLS_MPI_MAX_BITS || 1736*32b31808SJens Wiklander mbedtls_mpi_bitlen(N) > MBEDTLS_MPI_MAX_BITS) { 1737*32b31808SJens Wiklander return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; 1738*32b31808SJens Wiklander } 17397901324dSJerome Forissier 1740817466cbSJens Wiklander /* 1741817466cbSJens Wiklander * Init temps and window size 1742817466cbSJens Wiklander */ 17437901324dSJerome Forissier mpi_montg_init(&mm, N); 17447901324dSJerome Forissier mbedtls_mpi_init_mempool(&RR); mbedtls_mpi_init(&T); 174598bd5fe3SJens Wiklander mbedtls_mpi_init_mempool(&Apos); 17467901324dSJerome Forissier mbedtls_mpi_init_mempool(&WW); 1747817466cbSJens Wiklander 1748817466cbSJens Wiklander i = mbedtls_mpi_bitlen(E); 1749817466cbSJens Wiklander 1750*32b31808SJens Wiklander window_bitsize = (i > 671) ? 6 : (i > 239) ? 5 : 1751817466cbSJens Wiklander (i > 79) ? 4 : (i > 23) ? 3 : 1; 1752817466cbSJens Wiklander 17535b25c76aSJerome Forissier #if (MBEDTLS_MPI_WINDOW_SIZE < 6) 1754*32b31808SJens Wiklander if (window_bitsize > MBEDTLS_MPI_WINDOW_SIZE) { 1755*32b31808SJens Wiklander window_bitsize = MBEDTLS_MPI_WINDOW_SIZE; 1756*32b31808SJens Wiklander } 17575b25c76aSJerome Forissier #endif 1758817466cbSJens Wiklander 1759*32b31808SJens Wiklander const size_t w_table_used_size = (size_t) 1 << window_bitsize; 1760817466cbSJens Wiklander 1761ad443200SJens Wiklander W = mempool_alloc(mbedtls_mpi_mempool, 1762ad443200SJens Wiklander sizeof( mbedtls_mpi ) * array_size_W); 1763ad443200SJens Wiklander if (W == NULL) { 1764ad443200SJens Wiklander ret = MBEDTLS_ERR_MPI_ALLOC_FAILED; 1765ad443200SJens Wiklander goto cleanup; 1766ad443200SJens Wiklander } 1767ad443200SJens Wiklander for (i = 0; i < array_size_W; i++) 1768ad443200SJens Wiklander mbedtls_mpi_init_mempool(W + i); 1769*32b31808SJens Wiklander /* 1770*32b31808SJens Wiklander * This function is not constant-trace: its memory accesses depend on the 1771*32b31808SJens Wiklander * exponent value. To defend against timing attacks, callers (such as RSA 1772*32b31808SJens Wiklander * and DHM) should use exponent blinding. However this is not enough if the 1773*32b31808SJens Wiklander * adversary can find the exponent in a single trace, so this function 1774*32b31808SJens Wiklander * takes extra precautions against adversaries who can observe memory 1775*32b31808SJens Wiklander * access patterns. 1776*32b31808SJens Wiklander * 1777*32b31808SJens Wiklander * This function performs a series of multiplications by table elements and 1778*32b31808SJens Wiklander * squarings, and we want the prevent the adversary from finding out which 1779*32b31808SJens Wiklander * table element was used, and from distinguishing between multiplications 1780*32b31808SJens Wiklander * and squarings. Firstly, when multiplying by an element of the window 1781*32b31808SJens Wiklander * W[i], we do a constant-trace table lookup to obfuscate i. This leaves 1782*32b31808SJens Wiklander * squarings as having a different memory access patterns from other 1783*32b31808SJens Wiklander * multiplications. So secondly, we put the accumulator X in the table as 1784*32b31808SJens Wiklander * well, and also do a constant-trace table lookup to multiply by X. 1785*32b31808SJens Wiklander * 1786*32b31808SJens Wiklander * This way, all multiplications take the form of a lookup-and-multiply. 1787*32b31808SJens Wiklander * The number of lookup-and-multiply operations inside each iteration of 1788*32b31808SJens Wiklander * the main loop still depends on the bits of the exponent, but since the 1789*32b31808SJens Wiklander * other operations in the loop don't have an easily recognizable memory 1790*32b31808SJens Wiklander * trace, an adversary is unlikely to be able to observe the exact 1791*32b31808SJens Wiklander * patterns. 1792*32b31808SJens Wiklander * 1793*32b31808SJens Wiklander * An adversary may still be able to recover the exponent if they can 1794*32b31808SJens Wiklander * observe both memory accesses and branches. However, branch prediction 1795*32b31808SJens Wiklander * exploitation typically requires many traces of execution over the same 1796*32b31808SJens Wiklander * data, which is defeated by randomized blinding. 1797*32b31808SJens Wiklander * 1798*32b31808SJens Wiklander * To achieve this, we make a copy of X and we use the table entry in each 1799*32b31808SJens Wiklander * calculation from this point on. 1800*32b31808SJens Wiklander */ 1801*32b31808SJens Wiklander const size_t x_index = 0; 1802*32b31808SJens Wiklander mbedtls_mpi_copy(&W[x_index], X); 1803*32b31808SJens Wiklander 1804*32b31808SJens Wiklander j = N->n + 1; 1805*32b31808SJens Wiklander /* All W[i] and X must have at least N->n limbs for the mpi_montmul() 1806*32b31808SJens Wiklander * and mpi_montred() calls later. Here we ensure that W[1] and X are 1807*32b31808SJens Wiklander * large enough, and later we'll grow other W[i] to the same length. 1808*32b31808SJens Wiklander * They must not be shrunk midway through this function! 1809*32b31808SJens Wiklander */ 1810*32b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_grow(&W[x_index], j)); 1811*32b31808SJens Wiklander 1812*32b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_grow(&T, j * 2)); 1813*32b31808SJens Wiklander 1814*32b31808SJens Wiklander /* 1815*32b31808SJens Wiklander * Compensate for negative A (and correct at the end) 1816*32b31808SJens Wiklander */ 1817*32b31808SJens Wiklander neg = (A->s == -1); 1818*32b31808SJens Wiklander if (neg) { 1819*32b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&Apos, A)); 1820*32b31808SJens Wiklander Apos.s = 1; 1821*32b31808SJens Wiklander A = &Apos; 1822*32b31808SJens Wiklander } 1823*32b31808SJens Wiklander 1824*32b31808SJens Wiklander /* 1825*32b31808SJens Wiklander * If 1st call, pre-compute R^2 mod N 1826*32b31808SJens Wiklander */ 1827*32b31808SJens Wiklander if (prec_RR == NULL || prec_RR->p == NULL) { 1828*32b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&RR, 1)); 1829*32b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&RR, N->n * 2 * biL)); 1830*32b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&RR, &RR, N)); 1831*32b31808SJens Wiklander 1832*32b31808SJens Wiklander if (prec_RR != NULL) { 1833*32b31808SJens Wiklander memcpy(prec_RR, &RR, sizeof(mbedtls_mpi)); 1834*32b31808SJens Wiklander } 1835*32b31808SJens Wiklander } else { 1836*32b31808SJens Wiklander memcpy(&RR, prec_RR, sizeof(mbedtls_mpi)); 1837*32b31808SJens Wiklander } 1838*32b31808SJens Wiklander 1839ad443200SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_grow(&W[1], j)); 1840ad443200SJens Wiklander 1841817466cbSJens Wiklander /* 1842817466cbSJens Wiklander * W[1] = A * R^2 * R^-1 mod N = A * R mod N 1843817466cbSJens Wiklander */ 1844*32b31808SJens Wiklander if (mbedtls_mpi_cmp_mpi(A, N) >= 0) { 1845817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&W[1], A, N)); 18467901324dSJerome Forissier /* This should be a no-op because W[1] is already that large before 18477901324dSJerome Forissier * mbedtls_mpi_mod_mpi(), but it's necessary to avoid an overflow 18487901324dSJerome Forissier * in mpi_montmul() below, so let's make sure. */ 18497901324dSJerome Forissier MBEDTLS_MPI_CHK(mbedtls_mpi_grow(&W[1], N->n + 1)); 1850*32b31808SJens Wiklander } else { 1851817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&W[1], A)); 1852*32b31808SJens Wiklander } 1853817466cbSJens Wiklander 18547901324dSJerome Forissier /* Note that this is safe because W[1] always has at least N->n limbs 18557901324dSJerome Forissier * (it grew above and was preserved by mbedtls_mpi_copy()). */ 18567901324dSJerome Forissier mpi_montmul(&W[1], &RR, N, mm, &T); 1857817466cbSJens Wiklander 1858817466cbSJens Wiklander /* 1859*32b31808SJens Wiklander * W[x_index] = R^2 * R^-1 mod N = R mod N 1860817466cbSJens Wiklander */ 1861*32b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&W[x_index], &RR)); 1862*32b31808SJens Wiklander mpi_montred(&W[x_index], N, mm, &T); 1863817466cbSJens Wiklander 1864*32b31808SJens Wiklander 1865*32b31808SJens Wiklander if (window_bitsize > 1) { 1866817466cbSJens Wiklander /* 1867*32b31808SJens Wiklander * W[i] = W[1] ^ i 1868*32b31808SJens Wiklander * 1869*32b31808SJens Wiklander * The first bit of the sliding window is always 1 and therefore we 1870*32b31808SJens Wiklander * only need to store the second half of the table. 1871*32b31808SJens Wiklander * 1872*32b31808SJens Wiklander * (There are two special elements in the table: W[0] for the 1873*32b31808SJens Wiklander * accumulator/result and W[1] for A in Montgomery form. Both of these 1874*32b31808SJens Wiklander * are already set at this point.) 1875817466cbSJens Wiklander */ 1876*32b31808SJens Wiklander j = w_table_used_size / 2; 1877817466cbSJens Wiklander 1878817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_grow(&W[j], N->n + 1)); 1879817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&W[j], &W[1])); 1880817466cbSJens Wiklander 1881*32b31808SJens Wiklander for (i = 0; i < window_bitsize - 1; i++) { 18827901324dSJerome Forissier mpi_montmul(&W[j], &W[j], N, mm, &T); 1883*32b31808SJens Wiklander } 1884817466cbSJens Wiklander 1885817466cbSJens Wiklander /* 1886817466cbSJens Wiklander * W[i] = W[i - 1] * W[1] 1887817466cbSJens Wiklander */ 1888*32b31808SJens Wiklander for (i = j + 1; i < w_table_used_size; i++) { 1889817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_grow(&W[i], N->n + 1)); 1890817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&W[i], &W[i - 1])); 1891817466cbSJens Wiklander 18927901324dSJerome Forissier mpi_montmul(&W[i], &W[1], N, mm, &T); 1893817466cbSJens Wiklander } 1894817466cbSJens Wiklander } 1895817466cbSJens Wiklander 1896817466cbSJens Wiklander nblimbs = E->n; 1897817466cbSJens Wiklander bufsize = 0; 1898817466cbSJens Wiklander nbits = 0; 1899817466cbSJens Wiklander state = 0; 1900817466cbSJens Wiklander 1901*32b31808SJens Wiklander while (1) { 1902*32b31808SJens Wiklander if (bufsize == 0) { 1903*32b31808SJens Wiklander if (nblimbs == 0) { 1904817466cbSJens Wiklander break; 1905*32b31808SJens Wiklander } 1906817466cbSJens Wiklander 1907817466cbSJens Wiklander nblimbs--; 1908817466cbSJens Wiklander 1909817466cbSJens Wiklander bufsize = sizeof(mbedtls_mpi_uint) << 3; 1910817466cbSJens Wiklander } 1911817466cbSJens Wiklander 1912817466cbSJens Wiklander bufsize--; 1913817466cbSJens Wiklander 1914817466cbSJens Wiklander ei = (E->p[nblimbs] >> bufsize) & 1; 1915817466cbSJens Wiklander 1916817466cbSJens Wiklander /* 1917817466cbSJens Wiklander * skip leading 0s 1918817466cbSJens Wiklander */ 1919*32b31808SJens Wiklander if (ei == 0 && state == 0) { 1920817466cbSJens Wiklander continue; 1921*32b31808SJens Wiklander } 1922817466cbSJens Wiklander 1923*32b31808SJens Wiklander if (ei == 0 && state == 1) { 1924817466cbSJens Wiklander /* 1925*32b31808SJens Wiklander * out of window, square W[x_index] 1926817466cbSJens Wiklander */ 1927*32b31808SJens Wiklander MBEDTLS_MPI_CHK(mpi_select(&WW, W, w_table_used_size, x_index)); 1928*32b31808SJens Wiklander mpi_montmul(&W[x_index], &WW, N, mm, &T); 1929817466cbSJens Wiklander continue; 1930817466cbSJens Wiklander } 1931817466cbSJens Wiklander 1932817466cbSJens Wiklander /* 1933817466cbSJens Wiklander * add ei to current window 1934817466cbSJens Wiklander */ 1935817466cbSJens Wiklander state = 2; 1936817466cbSJens Wiklander 1937817466cbSJens Wiklander nbits++; 1938*32b31808SJens Wiklander exponent_bits_in_window |= (ei << (window_bitsize - nbits)); 1939817466cbSJens Wiklander 1940*32b31808SJens Wiklander if (nbits == window_bitsize) { 1941817466cbSJens Wiklander /* 1942*32b31808SJens Wiklander * W[x_index] = W[x_index]^window_bitsize R^-1 mod N 1943817466cbSJens Wiklander */ 1944*32b31808SJens Wiklander for (i = 0; i < window_bitsize; i++) { 1945*32b31808SJens Wiklander MBEDTLS_MPI_CHK(mpi_select(&WW, W, w_table_used_size, 1946*32b31808SJens Wiklander x_index)); 1947*32b31808SJens Wiklander mpi_montmul(&W[x_index], &WW, N, mm, &T); 1948*32b31808SJens Wiklander } 1949817466cbSJens Wiklander 1950817466cbSJens Wiklander /* 1951*32b31808SJens Wiklander * W[x_index] = W[x_index] * W[exponent_bits_in_window] R^-1 mod N 1952817466cbSJens Wiklander */ 1953*32b31808SJens Wiklander MBEDTLS_MPI_CHK(mpi_select(&WW, W, w_table_used_size, 1954*32b31808SJens Wiklander exponent_bits_in_window)); 1955*32b31808SJens Wiklander mpi_montmul(&W[x_index], &WW, N, mm, &T); 1956817466cbSJens Wiklander 1957817466cbSJens Wiklander state--; 1958817466cbSJens Wiklander nbits = 0; 1959*32b31808SJens Wiklander exponent_bits_in_window = 0; 1960817466cbSJens Wiklander } 1961817466cbSJens Wiklander } 1962817466cbSJens Wiklander 1963817466cbSJens Wiklander /* 1964817466cbSJens Wiklander * process the remaining bits 1965817466cbSJens Wiklander */ 1966*32b31808SJens Wiklander for (i = 0; i < nbits; i++) { 1967*32b31808SJens Wiklander MBEDTLS_MPI_CHK(mpi_select(&WW, W, w_table_used_size, x_index)); 1968*32b31808SJens Wiklander mpi_montmul(&W[x_index], &WW, N, mm, &T); 1969817466cbSJens Wiklander 1970*32b31808SJens Wiklander exponent_bits_in_window <<= 1; 1971817466cbSJens Wiklander 1972*32b31808SJens Wiklander if ((exponent_bits_in_window & ((size_t) 1 << window_bitsize)) != 0) { 1973*32b31808SJens Wiklander MBEDTLS_MPI_CHK(mpi_select(&WW, W, w_table_used_size, 1)); 1974*32b31808SJens Wiklander mpi_montmul(&W[x_index], &WW, N, mm, &T); 1975*32b31808SJens Wiklander } 1976817466cbSJens Wiklander } 1977817466cbSJens Wiklander 1978817466cbSJens Wiklander /* 1979*32b31808SJens Wiklander * W[x_index] = A^E * R * R^-1 mod N = A^E mod N 1980817466cbSJens Wiklander */ 1981*32b31808SJens Wiklander mpi_montred(&W[x_index], N, mm, &T); 1982817466cbSJens Wiklander 1983*32b31808SJens Wiklander if (neg && E->n != 0 && (E->p[0] & 1) != 0) { 1984*32b31808SJens Wiklander W[x_index].s = -1; 1985*32b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&W[x_index], N, &W[x_index])); 1986817466cbSJens Wiklander } 1987817466cbSJens Wiklander 1988*32b31808SJens Wiklander /* 1989*32b31808SJens Wiklander * Load the result in the output variable. 1990*32b31808SJens Wiklander */ 1991*32b31808SJens Wiklander mbedtls_mpi_copy(X, &W[x_index]); 1992*32b31808SJens Wiklander 1993817466cbSJens Wiklander cleanup: 1994817466cbSJens Wiklander 1995ad443200SJens Wiklander if (W) 199641e5aa8fSJens Wiklander for (i = 0; i < array_size_W; i++) 1997b99a4a18SJens Wiklander mbedtls_mpi_free(W + i); 199841e5aa8fSJens Wiklander mempool_free(mbedtls_mpi_mempool , W); 1999817466cbSJens Wiklander 2000*32b31808SJens Wiklander mbedtls_mpi_free(&T); 2001*32b31808SJens Wiklander mbedtls_mpi_free(&Apos); 20027901324dSJerome Forissier mbedtls_mpi_free(&WW); 2003817466cbSJens Wiklander 2004*32b31808SJens Wiklander if (prec_RR == NULL || prec_RR->p == NULL) { 2005817466cbSJens Wiklander mbedtls_mpi_free(&RR); 2006*32b31808SJens Wiklander } 2007817466cbSJens Wiklander 2008*32b31808SJens Wiklander return ret; 2009817466cbSJens Wiklander } 2010817466cbSJens Wiklander 2011817466cbSJens Wiklander /* 2012817466cbSJens Wiklander * Greatest common divisor: G = gcd(A, B) (HAC 14.54) 2013817466cbSJens Wiklander */ 2014817466cbSJens Wiklander int mbedtls_mpi_gcd(mbedtls_mpi *G, const mbedtls_mpi *A, const mbedtls_mpi *B) 2015817466cbSJens Wiklander { 201611fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 2017817466cbSJens Wiklander size_t lz, lzt; 201811fa71b9SJerome Forissier mbedtls_mpi TA, TB; 2019817466cbSJens Wiklander 20203d3b0591SJens Wiklander MPI_VALIDATE_RET(G != NULL); 20213d3b0591SJens Wiklander MPI_VALIDATE_RET(A != NULL); 20223d3b0591SJens Wiklander MPI_VALIDATE_RET(B != NULL); 20233d3b0591SJens Wiklander 202411fa71b9SJerome Forissier mbedtls_mpi_init_mempool(&TA); mbedtls_mpi_init_mempool(&TB); 2025817466cbSJens Wiklander 2026817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TA, A)); 2027817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TB, B)); 2028817466cbSJens Wiklander 2029817466cbSJens Wiklander lz = mbedtls_mpi_lsb(&TA); 2030817466cbSJens Wiklander lzt = mbedtls_mpi_lsb(&TB); 2031817466cbSJens Wiklander 20327901324dSJerome Forissier /* The loop below gives the correct result when A==0 but not when B==0. 20337901324dSJerome Forissier * So have a special case for B==0. Leverage the fact that we just 20347901324dSJerome Forissier * calculated the lsb and lsb(B)==0 iff B is odd or 0 to make the test 20357901324dSJerome Forissier * slightly more efficient than cmp_int(). */ 2036*32b31808SJens Wiklander if (lzt == 0 && mbedtls_mpi_get_bit(&TB, 0) == 0) { 20377901324dSJerome Forissier ret = mbedtls_mpi_copy(G, A); 20387901324dSJerome Forissier goto cleanup; 20397901324dSJerome Forissier } 20407901324dSJerome Forissier 2041*32b31808SJens Wiklander if (lzt < lz) { 2042817466cbSJens Wiklander lz = lzt; 2043*32b31808SJens Wiklander } 2044817466cbSJens Wiklander 2045817466cbSJens Wiklander TA.s = TB.s = 1; 2046817466cbSJens Wiklander 20477901324dSJerome Forissier /* We mostly follow the procedure described in HAC 14.54, but with some 20487901324dSJerome Forissier * minor differences: 20497901324dSJerome Forissier * - Sequences of multiplications or divisions by 2 are grouped into a 20507901324dSJerome Forissier * single shift operation. 20517901324dSJerome Forissier * - The procedure in HAC assumes that 0 < TB <= TA. 20527901324dSJerome Forissier * - The condition TB <= TA is not actually necessary for correctness. 20537901324dSJerome Forissier * TA and TB have symmetric roles except for the loop termination 20547901324dSJerome Forissier * condition, and the shifts at the beginning of the loop body 20557901324dSJerome Forissier * remove any significance from the ordering of TA vs TB before 20567901324dSJerome Forissier * the shifts. 20577901324dSJerome Forissier * - If TA = 0, the loop goes through 0 iterations and the result is 20587901324dSJerome Forissier * correctly TB. 20597901324dSJerome Forissier * - The case TB = 0 was short-circuited above. 20607901324dSJerome Forissier * 20617901324dSJerome Forissier * For the correctness proof below, decompose the original values of 20627901324dSJerome Forissier * A and B as 20637901324dSJerome Forissier * A = sa * 2^a * A' with A'=0 or A' odd, and sa = +-1 20647901324dSJerome Forissier * B = sb * 2^b * B' with B'=0 or B' odd, and sb = +-1 20657901324dSJerome Forissier * Then gcd(A, B) = 2^{min(a,b)} * gcd(A',B'), 20667901324dSJerome Forissier * and gcd(A',B') is odd or 0. 20677901324dSJerome Forissier * 20687901324dSJerome Forissier * At the beginning, we have TA = |A| and TB = |B| so gcd(A,B) = gcd(TA,TB). 20697901324dSJerome Forissier * The code maintains the following invariant: 20707901324dSJerome Forissier * gcd(A,B) = 2^k * gcd(TA,TB) for some k (I) 20717901324dSJerome Forissier */ 20727901324dSJerome Forissier 20737901324dSJerome Forissier /* Proof that the loop terminates: 20747901324dSJerome Forissier * At each iteration, either the right-shift by 1 is made on a nonzero 20757901324dSJerome Forissier * value and the nonnegative integer bitlen(TA) + bitlen(TB) decreases 20767901324dSJerome Forissier * by at least 1, or the right-shift by 1 is made on zero and then 20777901324dSJerome Forissier * TA becomes 0 which ends the loop (TB cannot be 0 if it is right-shifted 20787901324dSJerome Forissier * since in that case TB is calculated from TB-TA with the condition TB>TA). 20797901324dSJerome Forissier */ 2080*32b31808SJens Wiklander while (mbedtls_mpi_cmp_int(&TA, 0) != 0) { 20817901324dSJerome Forissier /* Divisions by 2 preserve the invariant (I). */ 2082817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TA, mbedtls_mpi_lsb(&TA))); 2083817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TB, mbedtls_mpi_lsb(&TB))); 2084817466cbSJens Wiklander 20857901324dSJerome Forissier /* Set either TA or TB to |TA-TB|/2. Since TA and TB are both odd, 20867901324dSJerome Forissier * TA-TB is even so the division by 2 has an integer result. 20877901324dSJerome Forissier * Invariant (I) is preserved since any odd divisor of both TA and TB 20887901324dSJerome Forissier * also divides |TA-TB|/2, and any odd divisor of both TA and |TA-TB|/2 2089039e02dfSJerome Forissier * also divides TB, and any odd divisor of both TB and |TA-TB|/2 also 20907901324dSJerome Forissier * divides TA. 20917901324dSJerome Forissier */ 2092*32b31808SJens Wiklander if (mbedtls_mpi_cmp_mpi(&TA, &TB) >= 0) { 2093817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_sub_abs(&TA, &TA, &TB)); 2094817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TA, 1)); 2095*32b31808SJens Wiklander } else { 2096817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_sub_abs(&TB, &TB, &TA)); 2097817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TB, 1)); 2098817466cbSJens Wiklander } 20997901324dSJerome Forissier /* Note that one of TA or TB is still odd. */ 2100817466cbSJens Wiklander } 2101817466cbSJens Wiklander 21027901324dSJerome Forissier /* By invariant (I), gcd(A,B) = 2^k * gcd(TA,TB) for some k. 21037901324dSJerome Forissier * At the loop exit, TA = 0, so gcd(TA,TB) = TB. 21047901324dSJerome Forissier * - If there was at least one loop iteration, then one of TA or TB is odd, 21057901324dSJerome Forissier * and TA = 0, so TB is odd and gcd(TA,TB) = gcd(A',B'). In this case, 21067901324dSJerome Forissier * lz = min(a,b) so gcd(A,B) = 2^lz * TB. 21077901324dSJerome Forissier * - If there was no loop iteration, then A was 0, and gcd(A,B) = B. 21087901324dSJerome Forissier * In this case, lz = 0 and B = TB so gcd(A,B) = B = 2^lz * TB as well. 21097901324dSJerome Forissier */ 21107901324dSJerome Forissier 2111817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&TB, lz)); 2112817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_copy(G, &TB)); 2113817466cbSJens Wiklander 2114817466cbSJens Wiklander cleanup: 2115817466cbSJens Wiklander 211611fa71b9SJerome Forissier mbedtls_mpi_free(&TA); mbedtls_mpi_free(&TB); 2117817466cbSJens Wiklander 2118*32b31808SJens Wiklander return ret; 21197901324dSJerome Forissier } 21207901324dSJerome Forissier 2121817466cbSJens Wiklander /* 2122817466cbSJens Wiklander * Fill X with size bytes of random. 2123*32b31808SJens Wiklander * The bytes returned from the RNG are used in a specific order which 2124*32b31808SJens Wiklander * is suitable for deterministic ECDSA (see the specification of 2125*32b31808SJens Wiklander * mbedtls_mpi_random() and the implementation in mbedtls_mpi_fill_random()). 2126817466cbSJens Wiklander */ 2127817466cbSJens Wiklander int mbedtls_mpi_fill_random(mbedtls_mpi *X, size_t size, 2128817466cbSJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), 2129817466cbSJens Wiklander void *p_rng) 2130817466cbSJens Wiklander { 213111fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 2132*32b31808SJens Wiklander const size_t limbs = CHARS_TO_LIMBS(size); 21335b25c76aSJerome Forissier 21343d3b0591SJens Wiklander MPI_VALIDATE_RET(X != NULL); 21353d3b0591SJens Wiklander MPI_VALIDATE_RET(f_rng != NULL); 2136817466cbSJens Wiklander 21375b25c76aSJerome Forissier /* Ensure that target MPI has exactly the necessary number of limbs */ 21387901324dSJerome Forissier MBEDTLS_MPI_CHK(mbedtls_mpi_resize_clear(X, limbs)); 2139*32b31808SJens Wiklander if (size == 0) { 2140*32b31808SJens Wiklander return 0; 2141*32b31808SJens Wiklander } 2142817466cbSJens Wiklander 2143*32b31808SJens Wiklander ret = mbedtls_mpi_core_fill_random(X->p, X->n, size, f_rng, p_rng); 2144817466cbSJens Wiklander 2145817466cbSJens Wiklander cleanup: 2146*32b31808SJens Wiklander return ret; 2147817466cbSJens Wiklander } 2148817466cbSJens Wiklander 21497901324dSJerome Forissier int mbedtls_mpi_random(mbedtls_mpi *X, 21507901324dSJerome Forissier mbedtls_mpi_sint min, 21517901324dSJerome Forissier const mbedtls_mpi *N, 21527901324dSJerome Forissier int (*f_rng)(void *, unsigned char *, size_t), 21537901324dSJerome Forissier void *p_rng) 21547901324dSJerome Forissier { 2155*32b31808SJens Wiklander if (min < 0) { 2156*32b31808SJens Wiklander return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; 2157*32b31808SJens Wiklander } 2158*32b31808SJens Wiklander if (mbedtls_mpi_cmp_int(N, min) <= 0) { 2159*32b31808SJens Wiklander return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; 2160*32b31808SJens Wiklander } 21617901324dSJerome Forissier 21627901324dSJerome Forissier /* Ensure that target MPI has exactly the same number of limbs 21637901324dSJerome Forissier * as the upper bound, even if the upper bound has leading zeros. 2164*32b31808SJens Wiklander * This is necessary for mbedtls_mpi_core_random. */ 2165*32b31808SJens Wiklander int ret = mbedtls_mpi_resize_clear(X, N->n); 2166*32b31808SJens Wiklander if (ret != 0) { 2167*32b31808SJens Wiklander return ret; 21687901324dSJerome Forissier } 21697901324dSJerome Forissier 2170*32b31808SJens Wiklander return mbedtls_mpi_core_random(X->p, min, N->p, X->n, f_rng, p_rng); 21717901324dSJerome Forissier } 21727901324dSJerome Forissier 2173817466cbSJens Wiklander /* 2174817466cbSJens Wiklander * Modular inverse: X = A^-1 mod N (HAC 14.61 / 14.64) 2175817466cbSJens Wiklander */ 2176817466cbSJens Wiklander int mbedtls_mpi_inv_mod(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *N) 2177817466cbSJens Wiklander { 217811fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 2179817466cbSJens Wiklander mbedtls_mpi G, TA, TU, U1, U2, TB, TV, V1, V2; 21803d3b0591SJens Wiklander MPI_VALIDATE_RET(X != NULL); 21813d3b0591SJens Wiklander MPI_VALIDATE_RET(A != NULL); 21823d3b0591SJens Wiklander MPI_VALIDATE_RET(N != NULL); 2183817466cbSJens Wiklander 2184*32b31808SJens Wiklander if (mbedtls_mpi_cmp_int(N, 1) <= 0) { 2185*32b31808SJens Wiklander return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; 2186*32b31808SJens Wiklander } 2187817466cbSJens Wiklander 218898bd5fe3SJens Wiklander mbedtls_mpi_init_mempool(&TA); mbedtls_mpi_init_mempool(&TU); 218998bd5fe3SJens Wiklander mbedtls_mpi_init_mempool(&U1); mbedtls_mpi_init_mempool(&U2); 219098bd5fe3SJens Wiklander mbedtls_mpi_init_mempool(&G); mbedtls_mpi_init_mempool(&TB); 219198bd5fe3SJens Wiklander mbedtls_mpi_init_mempool(&TV); mbedtls_mpi_init_mempool(&V1); 219298bd5fe3SJens Wiklander mbedtls_mpi_init_mempool(&V2); 2193817466cbSJens Wiklander 2194817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_gcd(&G, A, N)); 2195817466cbSJens Wiklander 2196*32b31808SJens Wiklander if (mbedtls_mpi_cmp_int(&G, 1) != 0) { 2197817466cbSJens Wiklander ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE; 2198817466cbSJens Wiklander goto cleanup; 2199817466cbSJens Wiklander } 2200817466cbSJens Wiklander 2201817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&TA, A, N)); 2202817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TU, &TA)); 2203817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TB, N)); 2204817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TV, N)); 2205817466cbSJens Wiklander 2206817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&U1, 1)); 2207817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&U2, 0)); 2208817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&V1, 0)); 2209817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&V2, 1)); 2210817466cbSJens Wiklander 2211*32b31808SJens Wiklander do { 2212*32b31808SJens Wiklander while ((TU.p[0] & 1) == 0) { 2213817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TU, 1)); 2214817466cbSJens Wiklander 2215*32b31808SJens Wiklander if ((U1.p[0] & 1) != 0 || (U2.p[0] & 1) != 0) { 2216817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&U1, &U1, &TB)); 2217817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&U2, &U2, &TA)); 2218817466cbSJens Wiklander } 2219817466cbSJens Wiklander 2220817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&U1, 1)); 2221817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&U2, 1)); 2222817466cbSJens Wiklander } 2223817466cbSJens Wiklander 2224*32b31808SJens Wiklander while ((TV.p[0] & 1) == 0) { 2225817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TV, 1)); 2226817466cbSJens Wiklander 2227*32b31808SJens Wiklander if ((V1.p[0] & 1) != 0 || (V2.p[0] & 1) != 0) { 2228817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&V1, &V1, &TB)); 2229817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&V2, &V2, &TA)); 2230817466cbSJens Wiklander } 2231817466cbSJens Wiklander 2232817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&V1, 1)); 2233817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&V2, 1)); 2234817466cbSJens Wiklander } 2235817466cbSJens Wiklander 2236*32b31808SJens Wiklander if (mbedtls_mpi_cmp_mpi(&TU, &TV) >= 0) { 2237817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&TU, &TU, &TV)); 2238817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&U1, &U1, &V1)); 2239817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&U2, &U2, &V2)); 2240*32b31808SJens Wiklander } else { 2241817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&TV, &TV, &TU)); 2242817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&V1, &V1, &U1)); 2243817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&V2, &V2, &U2)); 2244817466cbSJens Wiklander } 2245*32b31808SJens Wiklander } while (mbedtls_mpi_cmp_int(&TU, 0) != 0); 2246817466cbSJens Wiklander 2247*32b31808SJens Wiklander while (mbedtls_mpi_cmp_int(&V1, 0) < 0) { 2248817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&V1, &V1, N)); 2249*32b31808SJens Wiklander } 2250817466cbSJens Wiklander 2251*32b31808SJens Wiklander while (mbedtls_mpi_cmp_mpi(&V1, N) >= 0) { 2252817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&V1, &V1, N)); 2253*32b31808SJens Wiklander } 2254817466cbSJens Wiklander 2255817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_copy(X, &V1)); 2256817466cbSJens Wiklander 2257817466cbSJens Wiklander cleanup: 2258817466cbSJens Wiklander 2259817466cbSJens Wiklander mbedtls_mpi_free(&TA); mbedtls_mpi_free(&TU); mbedtls_mpi_free(&U1); mbedtls_mpi_free(&U2); 2260817466cbSJens Wiklander mbedtls_mpi_free(&G); mbedtls_mpi_free(&TB); mbedtls_mpi_free(&TV); 2261817466cbSJens Wiklander mbedtls_mpi_free(&V1); mbedtls_mpi_free(&V2); 2262817466cbSJens Wiklander 2263*32b31808SJens Wiklander return ret; 2264817466cbSJens Wiklander } 2265817466cbSJens Wiklander 2266817466cbSJens Wiklander #if defined(MBEDTLS_GENPRIME) 2267817466cbSJens Wiklander 2268817466cbSJens Wiklander static const int small_prime[] = 2269817466cbSJens Wiklander { 2270817466cbSJens Wiklander 3, 5, 7, 11, 13, 17, 19, 23, 2271817466cbSJens Wiklander 29, 31, 37, 41, 43, 47, 53, 59, 2272817466cbSJens Wiklander 61, 67, 71, 73, 79, 83, 89, 97, 2273817466cbSJens Wiklander 101, 103, 107, 109, 113, 127, 131, 137, 2274817466cbSJens Wiklander 139, 149, 151, 157, 163, 167, 173, 179, 2275817466cbSJens Wiklander 181, 191, 193, 197, 199, 211, 223, 227, 2276817466cbSJens Wiklander 229, 233, 239, 241, 251, 257, 263, 269, 2277817466cbSJens Wiklander 271, 277, 281, 283, 293, 307, 311, 313, 2278817466cbSJens Wiklander 317, 331, 337, 347, 349, 353, 359, 367, 2279817466cbSJens Wiklander 373, 379, 383, 389, 397, 401, 409, 419, 2280817466cbSJens Wiklander 421, 431, 433, 439, 443, 449, 457, 461, 2281817466cbSJens Wiklander 463, 467, 479, 487, 491, 499, 503, 509, 2282817466cbSJens Wiklander 521, 523, 541, 547, 557, 563, 569, 571, 2283817466cbSJens Wiklander 577, 587, 593, 599, 601, 607, 613, 617, 2284817466cbSJens Wiklander 619, 631, 641, 643, 647, 653, 659, 661, 2285817466cbSJens Wiklander 673, 677, 683, 691, 701, 709, 719, 727, 2286817466cbSJens Wiklander 733, 739, 743, 751, 757, 761, 769, 773, 2287817466cbSJens Wiklander 787, 797, 809, 811, 821, 823, 827, 829, 2288817466cbSJens Wiklander 839, 853, 857, 859, 863, 877, 881, 883, 2289817466cbSJens Wiklander 887, 907, 911, 919, 929, 937, 941, 947, 2290817466cbSJens Wiklander 953, 967, 971, 977, 983, 991, 997, -103 2291817466cbSJens Wiklander }; 2292817466cbSJens Wiklander 2293817466cbSJens Wiklander /* 2294817466cbSJens Wiklander * Small divisors test (X must be positive) 2295817466cbSJens Wiklander * 2296817466cbSJens Wiklander * Return values: 2297817466cbSJens Wiklander * 0: no small factor (possible prime, more tests needed) 2298817466cbSJens Wiklander * 1: certain prime 2299817466cbSJens Wiklander * MBEDTLS_ERR_MPI_NOT_ACCEPTABLE: certain non-prime 2300817466cbSJens Wiklander * other negative: error 2301817466cbSJens Wiklander */ 2302817466cbSJens Wiklander static int mpi_check_small_factors(const mbedtls_mpi *X) 2303817466cbSJens Wiklander { 2304817466cbSJens Wiklander int ret = 0; 2305817466cbSJens Wiklander size_t i; 2306817466cbSJens Wiklander mbedtls_mpi_uint r; 2307817466cbSJens Wiklander 2308*32b31808SJens Wiklander if ((X->p[0] & 1) == 0) { 2309*32b31808SJens Wiklander return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE; 2310*32b31808SJens Wiklander } 2311817466cbSJens Wiklander 2312*32b31808SJens Wiklander for (i = 0; small_prime[i] > 0; i++) { 2313*32b31808SJens Wiklander if (mbedtls_mpi_cmp_int(X, small_prime[i]) <= 0) { 2314*32b31808SJens Wiklander return 1; 2315*32b31808SJens Wiklander } 2316817466cbSJens Wiklander 2317817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_mod_int(&r, X, small_prime[i])); 2318817466cbSJens Wiklander 2319*32b31808SJens Wiklander if (r == 0) { 2320*32b31808SJens Wiklander return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE; 2321*32b31808SJens Wiklander } 2322817466cbSJens Wiklander } 2323817466cbSJens Wiklander 2324817466cbSJens Wiklander cleanup: 2325*32b31808SJens Wiklander return ret; 2326817466cbSJens Wiklander } 2327817466cbSJens Wiklander 2328817466cbSJens Wiklander /* 2329817466cbSJens Wiklander * Miller-Rabin pseudo-primality test (HAC 4.24) 2330817466cbSJens Wiklander */ 23313d3b0591SJens Wiklander static int mpi_miller_rabin(const mbedtls_mpi *X, size_t rounds, 2332817466cbSJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), 2333817466cbSJens Wiklander void *p_rng) 2334817466cbSJens Wiklander { 2335817466cbSJens Wiklander int ret, count; 23363d3b0591SJens Wiklander size_t i, j, k, s; 2337817466cbSJens Wiklander mbedtls_mpi W, R, T, A, RR; 2338817466cbSJens Wiklander 23393d3b0591SJens Wiklander MPI_VALIDATE_RET(X != NULL); 23403d3b0591SJens Wiklander MPI_VALIDATE_RET(f_rng != NULL); 23413d3b0591SJens Wiklander 234298bd5fe3SJens Wiklander mbedtls_mpi_init_mempool(&W); mbedtls_mpi_init_mempool(&R); 234398bd5fe3SJens Wiklander mbedtls_mpi_init_mempool(&T); mbedtls_mpi_init_mempool(&A); 234498bd5fe3SJens Wiklander mbedtls_mpi_init_mempool(&RR); 2345817466cbSJens Wiklander 2346817466cbSJens Wiklander /* 2347817466cbSJens Wiklander * W = |X| - 1 2348817466cbSJens Wiklander * R = W >> lsb( W ) 2349817466cbSJens Wiklander */ 2350817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(&W, X, 1)); 2351817466cbSJens Wiklander s = mbedtls_mpi_lsb(&W); 2352817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&R, &W)); 2353817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&R, s)); 2354817466cbSJens Wiklander 2355*32b31808SJens Wiklander for (i = 0; i < rounds; i++) { 2356817466cbSJens Wiklander /* 2357817466cbSJens Wiklander * pick a random A, 1 < A < |X| - 1 2358817466cbSJens Wiklander */ 2359817466cbSJens Wiklander count = 0; 2360817466cbSJens Wiklander do { 2361817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_fill_random(&A, X->n * ciL, f_rng, p_rng)); 2362817466cbSJens Wiklander 2363817466cbSJens Wiklander j = mbedtls_mpi_bitlen(&A); 2364817466cbSJens Wiklander k = mbedtls_mpi_bitlen(&W); 2365817466cbSJens Wiklander if (j > k) { 23663d3b0591SJens Wiklander A.p[A.n - 1] &= ((mbedtls_mpi_uint) 1 << (k - (A.n - 1) * biL - 1)) - 1; 2367817466cbSJens Wiklander } 2368817466cbSJens Wiklander 2369117cce93SJens Wiklander if (count++ > 300) { 2370336e3299SJens Wiklander ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE; 2371336e3299SJens Wiklander goto cleanup; 2372817466cbSJens Wiklander } 2373817466cbSJens Wiklander 2374817466cbSJens Wiklander } while (mbedtls_mpi_cmp_mpi(&A, &W) >= 0 || 2375817466cbSJens Wiklander mbedtls_mpi_cmp_int(&A, 1) <= 0); 2376817466cbSJens Wiklander 2377817466cbSJens Wiklander /* 2378817466cbSJens Wiklander * A = A^R mod |X| 2379817466cbSJens Wiklander */ 2380817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&A, &A, &R, X, &RR)); 2381817466cbSJens Wiklander 2382817466cbSJens Wiklander if (mbedtls_mpi_cmp_mpi(&A, &W) == 0 || 2383*32b31808SJens Wiklander mbedtls_mpi_cmp_int(&A, 1) == 0) { 2384817466cbSJens Wiklander continue; 2385*32b31808SJens Wiklander } 2386817466cbSJens Wiklander 2387817466cbSJens Wiklander j = 1; 2388*32b31808SJens Wiklander while (j < s && mbedtls_mpi_cmp_mpi(&A, &W) != 0) { 2389817466cbSJens Wiklander /* 2390817466cbSJens Wiklander * A = A * A mod |X| 2391817466cbSJens Wiklander */ 2392817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&T, &A, &A)); 2393817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&A, &T, X)); 2394817466cbSJens Wiklander 2395*32b31808SJens Wiklander if (mbedtls_mpi_cmp_int(&A, 1) == 0) { 2396817466cbSJens Wiklander break; 2397*32b31808SJens Wiklander } 2398817466cbSJens Wiklander 2399817466cbSJens Wiklander j++; 2400817466cbSJens Wiklander } 2401817466cbSJens Wiklander 2402817466cbSJens Wiklander /* 2403817466cbSJens Wiklander * not prime if A != |X| - 1 or A == 1 2404817466cbSJens Wiklander */ 2405817466cbSJens Wiklander if (mbedtls_mpi_cmp_mpi(&A, &W) != 0 || 2406*32b31808SJens Wiklander mbedtls_mpi_cmp_int(&A, 1) == 0) { 2407817466cbSJens Wiklander ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE; 2408817466cbSJens Wiklander break; 2409817466cbSJens Wiklander } 2410817466cbSJens Wiklander } 2411817466cbSJens Wiklander 2412817466cbSJens Wiklander cleanup: 24133d3b0591SJens Wiklander mbedtls_mpi_free(&W); mbedtls_mpi_free(&R); 24143d3b0591SJens Wiklander mbedtls_mpi_free(&T); mbedtls_mpi_free(&A); 2415817466cbSJens Wiklander mbedtls_mpi_free(&RR); 2416817466cbSJens Wiklander 2417*32b31808SJens Wiklander return ret; 2418817466cbSJens Wiklander } 2419817466cbSJens Wiklander 2420817466cbSJens Wiklander /* 2421817466cbSJens Wiklander * Pseudo-primality test: small factors, then Miller-Rabin 2422817466cbSJens Wiklander */ 24233d3b0591SJens Wiklander int mbedtls_mpi_is_prime_ext(const mbedtls_mpi *X, int rounds, 2424817466cbSJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), 2425817466cbSJens Wiklander void *p_rng) 2426817466cbSJens Wiklander { 242711fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 2428817466cbSJens Wiklander mbedtls_mpi XX; 24293d3b0591SJens Wiklander MPI_VALIDATE_RET(X != NULL); 24303d3b0591SJens Wiklander MPI_VALIDATE_RET(f_rng != NULL); 2431817466cbSJens Wiklander 2432817466cbSJens Wiklander XX.s = 1; 2433817466cbSJens Wiklander XX.n = X->n; 2434817466cbSJens Wiklander XX.p = X->p; 2435817466cbSJens Wiklander 2436817466cbSJens Wiklander if (mbedtls_mpi_cmp_int(&XX, 0) == 0 || 2437*32b31808SJens Wiklander mbedtls_mpi_cmp_int(&XX, 1) == 0) { 2438*32b31808SJens Wiklander return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE; 2439817466cbSJens Wiklander } 2440817466cbSJens Wiklander 2441*32b31808SJens Wiklander if (mbedtls_mpi_cmp_int(&XX, 2) == 0) { 2442*32b31808SJens Wiklander return 0; 2443817466cbSJens Wiklander } 2444817466cbSJens Wiklander 2445*32b31808SJens Wiklander if ((ret = mpi_check_small_factors(&XX)) != 0) { 2446*32b31808SJens Wiklander if (ret == 1) { 2447*32b31808SJens Wiklander return 0; 24483d3b0591SJens Wiklander } 2449*32b31808SJens Wiklander 2450*32b31808SJens Wiklander return ret; 2451*32b31808SJens Wiklander } 2452*32b31808SJens Wiklander 2453*32b31808SJens Wiklander return mpi_miller_rabin(&XX, rounds, f_rng, p_rng); 2454*32b31808SJens Wiklander } 24553d3b0591SJens Wiklander 24563d3b0591SJens Wiklander /* 24573d3b0591SJens Wiklander * Prime number generation 24583d3b0591SJens Wiklander * 24593d3b0591SJens Wiklander * To generate an RSA key in a way recommended by FIPS 186-4, both primes must 24603d3b0591SJens Wiklander * be either 1024 bits or 1536 bits long, and flags must contain 24613d3b0591SJens Wiklander * MBEDTLS_MPI_GEN_PRIME_FLAG_LOW_ERR. 24623d3b0591SJens Wiklander */ 24633d3b0591SJens Wiklander int mbedtls_mpi_gen_prime(mbedtls_mpi *X, size_t nbits, int flags, 24643d3b0591SJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), 24653d3b0591SJens Wiklander void *p_rng) 24663d3b0591SJens Wiklander { 24673d3b0591SJens Wiklander #ifdef MBEDTLS_HAVE_INT64 24683d3b0591SJens Wiklander // ceil(2^63.5) 24693d3b0591SJens Wiklander #define CEIL_MAXUINT_DIV_SQRT2 0xb504f333f9de6485ULL 24703d3b0591SJens Wiklander #else 24713d3b0591SJens Wiklander // ceil(2^31.5) 24723d3b0591SJens Wiklander #define CEIL_MAXUINT_DIV_SQRT2 0xb504f334U 24733d3b0591SJens Wiklander #endif 24743d3b0591SJens Wiklander int ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE; 2475817466cbSJens Wiklander size_t k, n; 24763d3b0591SJens Wiklander int rounds; 2477817466cbSJens Wiklander mbedtls_mpi_uint r; 2478817466cbSJens Wiklander mbedtls_mpi Y; 2479817466cbSJens Wiklander 24803d3b0591SJens Wiklander MPI_VALIDATE_RET(X != NULL); 24813d3b0591SJens Wiklander MPI_VALIDATE_RET(f_rng != NULL); 24823d3b0591SJens Wiklander 2483*32b31808SJens Wiklander if (nbits < 3 || nbits > MBEDTLS_MPI_MAX_BITS) { 2484*32b31808SJens Wiklander return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; 2485*32b31808SJens Wiklander } 2486817466cbSJens Wiklander 248798bd5fe3SJens Wiklander mbedtls_mpi_init_mempool(&Y); 2488817466cbSJens Wiklander 2489817466cbSJens Wiklander n = BITS_TO_LIMBS(nbits); 2490817466cbSJens Wiklander 2491*32b31808SJens Wiklander if ((flags & MBEDTLS_MPI_GEN_PRIME_FLAG_LOW_ERR) == 0) { 24923d3b0591SJens Wiklander /* 24933d3b0591SJens Wiklander * 2^-80 error probability, number of rounds chosen per HAC, table 4.4 24943d3b0591SJens Wiklander */ 24953d3b0591SJens Wiklander rounds = ((nbits >= 1300) ? 2 : (nbits >= 850) ? 3 : 24963d3b0591SJens Wiklander (nbits >= 650) ? 4 : (nbits >= 350) ? 8 : 24973d3b0591SJens Wiklander (nbits >= 250) ? 12 : (nbits >= 150) ? 18 : 27); 2498*32b31808SJens Wiklander } else { 24993d3b0591SJens Wiklander /* 25003d3b0591SJens Wiklander * 2^-100 error probability, number of rounds computed based on HAC, 25013d3b0591SJens Wiklander * fact 4.48 25023d3b0591SJens Wiklander */ 25033d3b0591SJens Wiklander rounds = ((nbits >= 1450) ? 4 : (nbits >= 1150) ? 5 : 25043d3b0591SJens Wiklander (nbits >= 1000) ? 6 : (nbits >= 850) ? 7 : 25053d3b0591SJens Wiklander (nbits >= 750) ? 8 : (nbits >= 500) ? 13 : 25063d3b0591SJens Wiklander (nbits >= 250) ? 28 : (nbits >= 150) ? 40 : 51); 25073d3b0591SJens Wiklander } 25083d3b0591SJens Wiklander 2509*32b31808SJens Wiklander while (1) { 2510817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_fill_random(X, n * ciL, f_rng, p_rng)); 25113d3b0591SJens Wiklander /* make sure generated number is at least (nbits-1)+0.5 bits (FIPS 186-4 §B.3.3 steps 4.4, 5.5) */ 2512*32b31808SJens Wiklander if (X->p[n-1] < CEIL_MAXUINT_DIV_SQRT2) { 2513*32b31808SJens Wiklander continue; 2514*32b31808SJens Wiklander } 2515817466cbSJens Wiklander 25163d3b0591SJens Wiklander k = n * biL; 2517*32b31808SJens Wiklander if (k > nbits) { 2518*32b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(X, k - nbits)); 2519*32b31808SJens Wiklander } 2520817466cbSJens Wiklander X->p[0] |= 1; 2521817466cbSJens Wiklander 2522*32b31808SJens Wiklander if ((flags & MBEDTLS_MPI_GEN_PRIME_FLAG_DH) == 0) { 25233d3b0591SJens Wiklander ret = mbedtls_mpi_is_prime_ext(X, rounds, f_rng, p_rng); 25243d3b0591SJens Wiklander 2525*32b31808SJens Wiklander if (ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE) { 2526817466cbSJens Wiklander goto cleanup; 2527817466cbSJens Wiklander } 2528*32b31808SJens Wiklander } else { 2529817466cbSJens Wiklander /* 2530*32b31808SJens Wiklander * A necessary condition for Y and X = 2Y + 1 to be prime 2531817466cbSJens Wiklander * is X = 2 mod 3 (which is equivalent to Y = 2 mod 3). 2532817466cbSJens Wiklander * Make sure it is satisfied, while keeping X = 3 mod 4 2533817466cbSJens Wiklander */ 2534817466cbSJens Wiklander 2535817466cbSJens Wiklander X->p[0] |= 2; 2536817466cbSJens Wiklander 2537817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_mod_int(&r, X, 3)); 2538*32b31808SJens Wiklander if (r == 0) { 2539817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(X, X, 8)); 2540*32b31808SJens Wiklander } else if (r == 1) { 2541817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(X, X, 4)); 2542*32b31808SJens Wiklander } 2543817466cbSJens Wiklander 2544817466cbSJens Wiklander /* Set Y = (X-1) / 2, which is X / 2 because X is odd */ 2545817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&Y, X)); 2546817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&Y, 1)); 2547817466cbSJens Wiklander 2548*32b31808SJens Wiklander while (1) { 2549817466cbSJens Wiklander /* 2550817466cbSJens Wiklander * First, check small factors for X and Y 2551817466cbSJens Wiklander * before doing Miller-Rabin on any of them 2552817466cbSJens Wiklander */ 2553817466cbSJens Wiklander if ((ret = mpi_check_small_factors(X)) == 0 && 2554817466cbSJens Wiklander (ret = mpi_check_small_factors(&Y)) == 0 && 25553d3b0591SJens Wiklander (ret = mpi_miller_rabin(X, rounds, f_rng, p_rng)) 25563d3b0591SJens Wiklander == 0 && 25573d3b0591SJens Wiklander (ret = mpi_miller_rabin(&Y, rounds, f_rng, p_rng)) 2558*32b31808SJens Wiklander == 0) { 25593d3b0591SJens Wiklander goto cleanup; 2560*32b31808SJens Wiklander } 2561817466cbSJens Wiklander 2562*32b31808SJens Wiklander if (ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE) { 2563817466cbSJens Wiklander goto cleanup; 2564*32b31808SJens Wiklander } 2565817466cbSJens Wiklander 2566817466cbSJens Wiklander /* 2567817466cbSJens Wiklander * Next candidates. We want to preserve Y = (X-1) / 2 and 2568817466cbSJens Wiklander * Y = 1 mod 2 and Y = 2 mod 3 (eq X = 3 mod 4 and X = 2 mod 3) 2569817466cbSJens Wiklander * so up Y by 6 and X by 12. 2570817466cbSJens Wiklander */ 2571817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(X, X, 12)); 2572817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(&Y, &Y, 6)); 2573817466cbSJens Wiklander } 2574817466cbSJens Wiklander } 25753d3b0591SJens Wiklander } 2576817466cbSJens Wiklander 2577817466cbSJens Wiklander cleanup: 2578817466cbSJens Wiklander 2579817466cbSJens Wiklander mbedtls_mpi_free(&Y); 2580817466cbSJens Wiklander 2581*32b31808SJens Wiklander return ret; 2582817466cbSJens Wiklander } 2583817466cbSJens Wiklander 2584817466cbSJens Wiklander #endif /* MBEDTLS_GENPRIME */ 2585817466cbSJens Wiklander 2586817466cbSJens Wiklander #if defined(MBEDTLS_SELF_TEST) 2587817466cbSJens Wiklander 2588817466cbSJens Wiklander #define GCD_PAIR_COUNT 3 2589817466cbSJens Wiklander 2590817466cbSJens Wiklander static const int gcd_pairs[GCD_PAIR_COUNT][3] = 2591817466cbSJens Wiklander { 2592817466cbSJens Wiklander { 693, 609, 21 }, 2593817466cbSJens Wiklander { 1764, 868, 28 }, 2594817466cbSJens Wiklander { 768454923, 542167814, 1 } 2595817466cbSJens Wiklander }; 2596817466cbSJens Wiklander 2597817466cbSJens Wiklander /* 2598817466cbSJens Wiklander * Checkup routine 2599817466cbSJens Wiklander */ 2600817466cbSJens Wiklander int mbedtls_mpi_self_test(int verbose) 2601817466cbSJens Wiklander { 2602817466cbSJens Wiklander int ret, i; 2603817466cbSJens Wiklander mbedtls_mpi A, E, N, X, Y, U, V; 2604817466cbSJens Wiklander 260598bd5fe3SJens Wiklander mbedtls_mpi_init_mempool(&A); mbedtls_mpi_init_mempool(&E); 260698bd5fe3SJens Wiklander mbedtls_mpi_init_mempool(&N); mbedtls_mpi_init_mempool(&X); 260798bd5fe3SJens Wiklander mbedtls_mpi_init_mempool(&Y); mbedtls_mpi_init_mempool(&U); 260898bd5fe3SJens Wiklander mbedtls_mpi_init_mempool(&V); 2609817466cbSJens Wiklander 2610817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&A, 16, 2611817466cbSJens Wiklander "EFE021C2645FD1DC586E69184AF4A31E" \ 2612817466cbSJens Wiklander "D5F53E93B5F123FA41680867BA110131" \ 2613817466cbSJens Wiklander "944FE7952E2517337780CB0DB80E61AA" \ 2614817466cbSJens Wiklander "E7C8DDC6C5C6AADEB34EB38A2F40D5E6")); 2615817466cbSJens Wiklander 2616817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&E, 16, 2617817466cbSJens Wiklander "B2E7EFD37075B9F03FF989C7C5051C20" \ 2618817466cbSJens Wiklander "34D2A323810251127E7BF8625A4F49A5" \ 2619817466cbSJens Wiklander "F3E27F4DA8BD59C47D6DAABA4C8127BD" \ 2620817466cbSJens Wiklander "5B5C25763222FEFCCFC38B832366C29E")); 2621817466cbSJens Wiklander 2622817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&N, 16, 2623817466cbSJens Wiklander "0066A198186C18C10B2F5ED9B522752A" \ 2624817466cbSJens Wiklander "9830B69916E535C8F047518A889A43A5" \ 2625817466cbSJens Wiklander "94B6BED27A168D31D4A52F88925AA8F5")); 2626817466cbSJens Wiklander 2627817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&X, &A, &N)); 2628817466cbSJens Wiklander 2629817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&U, 16, 2630817466cbSJens Wiklander "602AB7ECA597A3D6B56FF9829A5E8B85" \ 2631817466cbSJens Wiklander "9E857EA95A03512E2BAE7391688D264A" \ 2632817466cbSJens Wiklander "A5663B0341DB9CCFD2C4C5F421FEC814" \ 2633817466cbSJens Wiklander "8001B72E848A38CAE1C65F78E56ABDEF" \ 2634817466cbSJens Wiklander "E12D3C039B8A02D6BE593F0BBBDA56F1" \ 2635817466cbSJens Wiklander "ECF677152EF804370C1A305CAF3B5BF1" \ 2636817466cbSJens Wiklander "30879B56C61DE584A0F53A2447A51E")); 2637817466cbSJens Wiklander 2638*32b31808SJens Wiklander if (verbose != 0) { 2639817466cbSJens Wiklander mbedtls_printf(" MPI test #1 (mul_mpi): "); 2640*32b31808SJens Wiklander } 2641817466cbSJens Wiklander 2642*32b31808SJens Wiklander if (mbedtls_mpi_cmp_mpi(&X, &U) != 0) { 2643*32b31808SJens Wiklander if (verbose != 0) { 2644817466cbSJens Wiklander mbedtls_printf("failed\n"); 2645*32b31808SJens Wiklander } 2646817466cbSJens Wiklander 2647817466cbSJens Wiklander ret = 1; 2648817466cbSJens Wiklander goto cleanup; 2649817466cbSJens Wiklander } 2650817466cbSJens Wiklander 2651*32b31808SJens Wiklander if (verbose != 0) { 2652817466cbSJens Wiklander mbedtls_printf("passed\n"); 2653*32b31808SJens Wiklander } 2654817466cbSJens Wiklander 2655817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_div_mpi(&X, &Y, &A, &N)); 2656817466cbSJens Wiklander 2657817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&U, 16, 2658817466cbSJens Wiklander "256567336059E52CAE22925474705F39A94")); 2659817466cbSJens Wiklander 2660817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&V, 16, 2661817466cbSJens Wiklander "6613F26162223DF488E9CD48CC132C7A" \ 2662817466cbSJens Wiklander "0AC93C701B001B092E4E5B9F73BCD27B" \ 2663817466cbSJens Wiklander "9EE50D0657C77F374E903CDFA4C642")); 2664817466cbSJens Wiklander 2665*32b31808SJens Wiklander if (verbose != 0) { 2666817466cbSJens Wiklander mbedtls_printf(" MPI test #2 (div_mpi): "); 2667*32b31808SJens Wiklander } 2668817466cbSJens Wiklander 2669817466cbSJens Wiklander if (mbedtls_mpi_cmp_mpi(&X, &U) != 0 || 2670*32b31808SJens Wiklander mbedtls_mpi_cmp_mpi(&Y, &V) != 0) { 2671*32b31808SJens Wiklander if (verbose != 0) { 2672817466cbSJens Wiklander mbedtls_printf("failed\n"); 2673*32b31808SJens Wiklander } 2674817466cbSJens Wiklander 2675817466cbSJens Wiklander ret = 1; 2676817466cbSJens Wiklander goto cleanup; 2677817466cbSJens Wiklander } 2678817466cbSJens Wiklander 2679*32b31808SJens Wiklander if (verbose != 0) { 2680817466cbSJens Wiklander mbedtls_printf("passed\n"); 2681*32b31808SJens Wiklander } 2682817466cbSJens Wiklander 2683817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&X, &A, &E, &N, NULL)); 2684817466cbSJens Wiklander 2685817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&U, 16, 2686817466cbSJens Wiklander "36E139AEA55215609D2816998ED020BB" \ 2687817466cbSJens Wiklander "BD96C37890F65171D948E9BC7CBAA4D9" \ 2688817466cbSJens Wiklander "325D24D6A3C12710F10A09FA08AB87")); 2689817466cbSJens Wiklander 2690*32b31808SJens Wiklander if (verbose != 0) { 2691817466cbSJens Wiklander mbedtls_printf(" MPI test #3 (exp_mod): "); 2692*32b31808SJens Wiklander } 2693817466cbSJens Wiklander 2694*32b31808SJens Wiklander if (mbedtls_mpi_cmp_mpi(&X, &U) != 0) { 2695*32b31808SJens Wiklander if (verbose != 0) { 2696817466cbSJens Wiklander mbedtls_printf("failed\n"); 2697*32b31808SJens Wiklander } 2698817466cbSJens Wiklander 2699817466cbSJens Wiklander ret = 1; 2700817466cbSJens Wiklander goto cleanup; 2701817466cbSJens Wiklander } 2702817466cbSJens Wiklander 2703*32b31808SJens Wiklander if (verbose != 0) { 2704817466cbSJens Wiklander mbedtls_printf("passed\n"); 2705*32b31808SJens Wiklander } 2706817466cbSJens Wiklander 2707817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_inv_mod(&X, &A, &N)); 2708817466cbSJens Wiklander 2709817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&U, 16, 2710817466cbSJens Wiklander "003A0AAEDD7E784FC07D8F9EC6E3BFD5" \ 2711817466cbSJens Wiklander "C3DBA76456363A10869622EAC2DD84EC" \ 2712817466cbSJens Wiklander "C5B8A74DAC4D09E03B5E0BE779F2DF61")); 2713817466cbSJens Wiklander 2714*32b31808SJens Wiklander if (verbose != 0) { 2715817466cbSJens Wiklander mbedtls_printf(" MPI test #4 (inv_mod): "); 2716*32b31808SJens Wiklander } 2717817466cbSJens Wiklander 2718*32b31808SJens Wiklander if (mbedtls_mpi_cmp_mpi(&X, &U) != 0) { 2719*32b31808SJens Wiklander if (verbose != 0) { 2720817466cbSJens Wiklander mbedtls_printf("failed\n"); 2721*32b31808SJens Wiklander } 2722817466cbSJens Wiklander 2723817466cbSJens Wiklander ret = 1; 2724817466cbSJens Wiklander goto cleanup; 2725817466cbSJens Wiklander } 2726817466cbSJens Wiklander 2727*32b31808SJens Wiklander if (verbose != 0) { 2728817466cbSJens Wiklander mbedtls_printf("passed\n"); 2729*32b31808SJens Wiklander } 2730817466cbSJens Wiklander 2731*32b31808SJens Wiklander if (verbose != 0) { 2732817466cbSJens Wiklander mbedtls_printf(" MPI test #5 (simple gcd): "); 2733*32b31808SJens Wiklander } 2734817466cbSJens Wiklander 2735*32b31808SJens Wiklander for (i = 0; i < GCD_PAIR_COUNT; i++) { 2736817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&X, gcd_pairs[i][0])); 2737817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&Y, gcd_pairs[i][1])); 2738817466cbSJens Wiklander 2739817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_gcd(&A, &X, &Y)); 2740817466cbSJens Wiklander 2741*32b31808SJens Wiklander if (mbedtls_mpi_cmp_int(&A, gcd_pairs[i][2]) != 0) { 2742*32b31808SJens Wiklander if (verbose != 0) { 2743817466cbSJens Wiklander mbedtls_printf("failed at %d\n", i); 2744*32b31808SJens Wiklander } 2745817466cbSJens Wiklander 2746817466cbSJens Wiklander ret = 1; 2747817466cbSJens Wiklander goto cleanup; 2748817466cbSJens Wiklander } 2749817466cbSJens Wiklander } 2750817466cbSJens Wiklander 2751*32b31808SJens Wiklander if (verbose != 0) { 2752817466cbSJens Wiklander mbedtls_printf("passed\n"); 2753*32b31808SJens Wiklander } 2754817466cbSJens Wiklander 2755817466cbSJens Wiklander cleanup: 2756817466cbSJens Wiklander 2757*32b31808SJens Wiklander if (ret != 0 && verbose != 0) { 27587901324dSJerome Forissier mbedtls_printf("Unexpected error, return code = %08X\n", (unsigned int) ret); 2759*32b31808SJens Wiklander } 2760817466cbSJens Wiklander 2761817466cbSJens Wiklander mbedtls_mpi_free(&A); mbedtls_mpi_free(&E); mbedtls_mpi_free(&N); mbedtls_mpi_free(&X); 2762817466cbSJens Wiklander mbedtls_mpi_free(&Y); mbedtls_mpi_free(&U); mbedtls_mpi_free(&V); 2763817466cbSJens Wiklander 2764*32b31808SJens Wiklander if (verbose != 0) { 2765817466cbSJens Wiklander mbedtls_printf("\n"); 2766*32b31808SJens Wiklander } 2767817466cbSJens Wiklander 2768*32b31808SJens Wiklander return ret; 2769817466cbSJens Wiklander } 2770817466cbSJens Wiklander 2771817466cbSJens Wiklander #endif /* MBEDTLS_SELF_TEST */ 2772817466cbSJens Wiklander 2773817466cbSJens Wiklander #endif /* MBEDTLS_BIGNUM_C */ 2774