/* * Initializes a MPI. * * A temporary MPI is allocated and if a bigInt is supplied the MPI is * initialized with the value of the bigInt. */ static void get_mpi(mbedtls_mpi *mpi, const TEE_BigInt *bigInt) { /* * The way the GP spec is defining the bignums it's * difficult/tricky to do it using 64-bit arithmetics given that * we'd need 64-bit alignment of the data as well. */ COMPILE_TIME_ASSERT(sizeof(mbedtls_mpi_uint) == sizeof(uint32_t)); /* * The struct bigint_hdr is the overhead added to the bigint and * is required to take exactly 2 uint32_t. */ COMPILE_TIME_ASSERT(sizeof(struct bigint_hdr) == sizeof(uint32_t) * BIGINT_HDR_SIZE_IN_U32); mbedtls_mpi_init_mempool(mpi); if (bigInt) { const struct bigint_hdr *hdr = (struct bigint_hdr *)bigInt; const mbedtls_mpi_uint *p = (const mbedtls_mpi_uint *)(hdr + 1); size_t n = hdr->nblimbs; /* Trim of eventual insignificant zeroes */ while (n && !p[n - 1]) n--; MPI_CHECK(mbedtls_mpi_grow(mpi, n)); mpi->s = hdr->sign; memcpy(mpi->p, p, n * sizeof(mbedtls_mpi_uint)); } }
/* reduce */ static int montgomery_reduce(void *a, void *b, void *c) { mbedtls_mpi A; mbedtls_mpi *N = b; mbedtls_mpi_uint *mm = c; mbedtls_mpi T; int ret = CRYPT_MEM; mbedtls_mpi_init_mempool(&T); mbedtls_mpi_init_mempool(&A); if (mbedtls_mpi_grow(&T, (N->n + 1) * 2)) goto out; if (mbedtls_mpi_cmp_mpi(a, N) > 0) { if (mbedtls_mpi_mod_mpi(&A, a, N)) goto out; } else { if (mbedtls_mpi_copy(&A, a)) goto out; } if (mbedtls_mpi_grow(&A, N->n + 1)) goto out; if (mbedtls_mpi_montred(&A, N, *mm, &T)) goto out; if (mbedtls_mpi_copy(a, &A)) goto out; ret = CRYPT_OK; out: mbedtls_mpi_free(&A); mbedtls_mpi_free(&T); return ret; }
/* Read mbedTLS MPI bignum back from hardware memory block. Reads num_words words from block. Can return a failure result if fails to grow the MPI result. */ static inline int mem_block_to_mpi(mbedtls_mpi *x, uint32_t mem_base, int num_words) { int ret = 0; MBEDTLS_MPI_CHK( mbedtls_mpi_grow(x, num_words) ); /* Copy data from memory block registers */ memcpy(x->p, (uint32_t *)mem_base, num_words * 4); /* Zero any remaining limbs in the bignum, if the buffer is bigger than num_words */ for(size_t i = num_words; i < x->n; i++) { x->p[i] = 0; } asm volatile ("memw"); cleanup: return ret; }
/* Deal with the case when X & Y are too long for the hardware unit, by splitting one operand into two halves. Y must be the longer operand Slice Y into Yp, Ypp such that: Yp = lower 'b' bits of Y Ypp = upper 'b' bits of Y (right shifted) Such that Z = X * Y Z = X * (Yp + Ypp<<b) Z = (X * Yp) + (X * Ypp<<b) Note that this function may recurse multiple times, if both X & Y are too long for the hardware multiplication unit. */ static int mpi_mult_mpi_overlong(mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, size_t bits_y, size_t words_result) { int ret; mbedtls_mpi Ztemp; const size_t limbs_y = (bits_y + biL - 1) / biL; /* Rather than slicing in two on bits we slice on limbs (32 bit words) */ const size_t limbs_slice = limbs_y / 2; /* Yp holds lower bits of Y (declared to reuse Y's array contents to save on copying) */ const mbedtls_mpi Yp = { .p = Y->p, .n = limbs_slice, .s = Y->s }; /* Ypp holds upper bits of Y, right shifted (also reuses Y's array contents) */ const mbedtls_mpi Ypp = { .p = Y->p + limbs_slice, .n = limbs_y - limbs_slice, .s = Y->s }; mbedtls_mpi_init(&Ztemp); /* Grow Z to result size early, avoid interim allocations */ mbedtls_mpi_grow(Z, words_result); /* Get result Ztemp = Yp * X (need temporary variable Ztemp) */ MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi(&Ztemp, X, &Yp) ); /* Z = Ypp * Y */ MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi(Z, X, &Ypp) ); /* Z = Z << b */ MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l(Z, limbs_slice * biL) ); /* Z += Ztemp */ MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi(Z, Z, &Ztemp) ); cleanup: mbedtls_mpi_free(&Ztemp); return ret; }