1a8e1175bSopenharmony_ci/* 2a8e1175bSopenharmony_ci * Low-level modular bignum functions 3a8e1175bSopenharmony_ci * 4a8e1175bSopenharmony_ci * Copyright The Mbed TLS Contributors 5a8e1175bSopenharmony_ci * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later 6a8e1175bSopenharmony_ci */ 7a8e1175bSopenharmony_ci 8a8e1175bSopenharmony_ci#include "common.h" 9a8e1175bSopenharmony_ci 10a8e1175bSopenharmony_ci#if defined(MBEDTLS_BIGNUM_C) && defined(MBEDTLS_ECP_WITH_MPI_UINT) 11a8e1175bSopenharmony_ci 12a8e1175bSopenharmony_ci#include <string.h> 13a8e1175bSopenharmony_ci 14a8e1175bSopenharmony_ci#include "mbedtls/error.h" 15a8e1175bSopenharmony_ci#include "mbedtls/platform_util.h" 16a8e1175bSopenharmony_ci 17a8e1175bSopenharmony_ci#include "mbedtls/platform.h" 18a8e1175bSopenharmony_ci 19a8e1175bSopenharmony_ci#include "bignum_core.h" 20a8e1175bSopenharmony_ci#include "bignum_mod_raw.h" 21a8e1175bSopenharmony_ci#include "bignum_mod.h" 22a8e1175bSopenharmony_ci#include "constant_time_internal.h" 23a8e1175bSopenharmony_ci 24a8e1175bSopenharmony_ci#include "bignum_mod_raw_invasive.h" 25a8e1175bSopenharmony_ci 26a8e1175bSopenharmony_civoid mbedtls_mpi_mod_raw_cond_assign(mbedtls_mpi_uint *X, 27a8e1175bSopenharmony_ci const mbedtls_mpi_uint *A, 28a8e1175bSopenharmony_ci const mbedtls_mpi_mod_modulus *N, 29a8e1175bSopenharmony_ci unsigned char assign) 30a8e1175bSopenharmony_ci{ 31a8e1175bSopenharmony_ci mbedtls_mpi_core_cond_assign(X, A, N->limbs, mbedtls_ct_bool(assign)); 32a8e1175bSopenharmony_ci} 33a8e1175bSopenharmony_ci 34a8e1175bSopenharmony_civoid mbedtls_mpi_mod_raw_cond_swap(mbedtls_mpi_uint *X, 35a8e1175bSopenharmony_ci mbedtls_mpi_uint *Y, 36a8e1175bSopenharmony_ci const mbedtls_mpi_mod_modulus *N, 37a8e1175bSopenharmony_ci unsigned char swap) 38a8e1175bSopenharmony_ci{ 39a8e1175bSopenharmony_ci mbedtls_mpi_core_cond_swap(X, Y, N->limbs, mbedtls_ct_bool(swap)); 40a8e1175bSopenharmony_ci} 41a8e1175bSopenharmony_ci 42a8e1175bSopenharmony_ciint mbedtls_mpi_mod_raw_read(mbedtls_mpi_uint *X, 43a8e1175bSopenharmony_ci const mbedtls_mpi_mod_modulus *N, 44a8e1175bSopenharmony_ci const unsigned char *input, 45a8e1175bSopenharmony_ci size_t input_length, 46a8e1175bSopenharmony_ci mbedtls_mpi_mod_ext_rep ext_rep) 47a8e1175bSopenharmony_ci{ 48a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 49a8e1175bSopenharmony_ci 50a8e1175bSopenharmony_ci switch (ext_rep) { 51a8e1175bSopenharmony_ci case MBEDTLS_MPI_MOD_EXT_REP_LE: 52a8e1175bSopenharmony_ci ret = mbedtls_mpi_core_read_le(X, N->limbs, 53a8e1175bSopenharmony_ci input, input_length); 54a8e1175bSopenharmony_ci break; 55a8e1175bSopenharmony_ci case MBEDTLS_MPI_MOD_EXT_REP_BE: 56a8e1175bSopenharmony_ci ret = mbedtls_mpi_core_read_be(X, N->limbs, 57a8e1175bSopenharmony_ci input, input_length); 58a8e1175bSopenharmony_ci break; 59a8e1175bSopenharmony_ci default: 60a8e1175bSopenharmony_ci return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; 61a8e1175bSopenharmony_ci } 62a8e1175bSopenharmony_ci 63a8e1175bSopenharmony_ci if (ret != 0) { 64a8e1175bSopenharmony_ci goto cleanup; 65a8e1175bSopenharmony_ci } 66a8e1175bSopenharmony_ci 67a8e1175bSopenharmony_ci if (!mbedtls_mpi_core_lt_ct(X, N->p, N->limbs)) { 68a8e1175bSopenharmony_ci ret = MBEDTLS_ERR_MPI_BAD_INPUT_DATA; 69a8e1175bSopenharmony_ci goto cleanup; 70a8e1175bSopenharmony_ci } 71a8e1175bSopenharmony_ci 72a8e1175bSopenharmony_cicleanup: 73a8e1175bSopenharmony_ci 74a8e1175bSopenharmony_ci return ret; 75a8e1175bSopenharmony_ci} 76a8e1175bSopenharmony_ci 77a8e1175bSopenharmony_ciint mbedtls_mpi_mod_raw_write(const mbedtls_mpi_uint *A, 78a8e1175bSopenharmony_ci const mbedtls_mpi_mod_modulus *N, 79a8e1175bSopenharmony_ci unsigned char *output, 80a8e1175bSopenharmony_ci size_t output_length, 81a8e1175bSopenharmony_ci mbedtls_mpi_mod_ext_rep ext_rep) 82a8e1175bSopenharmony_ci{ 83a8e1175bSopenharmony_ci switch (ext_rep) { 84a8e1175bSopenharmony_ci case MBEDTLS_MPI_MOD_EXT_REP_LE: 85a8e1175bSopenharmony_ci return mbedtls_mpi_core_write_le(A, N->limbs, 86a8e1175bSopenharmony_ci output, output_length); 87a8e1175bSopenharmony_ci case MBEDTLS_MPI_MOD_EXT_REP_BE: 88a8e1175bSopenharmony_ci return mbedtls_mpi_core_write_be(A, N->limbs, 89a8e1175bSopenharmony_ci output, output_length); 90a8e1175bSopenharmony_ci default: 91a8e1175bSopenharmony_ci return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; 92a8e1175bSopenharmony_ci } 93a8e1175bSopenharmony_ci} 94a8e1175bSopenharmony_ci 95a8e1175bSopenharmony_civoid mbedtls_mpi_mod_raw_sub(mbedtls_mpi_uint *X, 96a8e1175bSopenharmony_ci const mbedtls_mpi_uint *A, 97a8e1175bSopenharmony_ci const mbedtls_mpi_uint *B, 98a8e1175bSopenharmony_ci const mbedtls_mpi_mod_modulus *N) 99a8e1175bSopenharmony_ci{ 100a8e1175bSopenharmony_ci mbedtls_mpi_uint c = mbedtls_mpi_core_sub(X, A, B, N->limbs); 101a8e1175bSopenharmony_ci 102a8e1175bSopenharmony_ci (void) mbedtls_mpi_core_add_if(X, N->p, N->limbs, (unsigned) c); 103a8e1175bSopenharmony_ci} 104a8e1175bSopenharmony_ci 105a8e1175bSopenharmony_ciMBEDTLS_STATIC_TESTABLE 106a8e1175bSopenharmony_civoid mbedtls_mpi_mod_raw_fix_quasi_reduction(mbedtls_mpi_uint *X, 107a8e1175bSopenharmony_ci const mbedtls_mpi_mod_modulus *N) 108a8e1175bSopenharmony_ci{ 109a8e1175bSopenharmony_ci mbedtls_mpi_uint c = mbedtls_mpi_core_sub(X, X, N->p, N->limbs); 110a8e1175bSopenharmony_ci 111a8e1175bSopenharmony_ci (void) mbedtls_mpi_core_add_if(X, N->p, N->limbs, (unsigned) c); 112a8e1175bSopenharmony_ci} 113a8e1175bSopenharmony_ci 114a8e1175bSopenharmony_ci 115a8e1175bSopenharmony_civoid mbedtls_mpi_mod_raw_mul(mbedtls_mpi_uint *X, 116a8e1175bSopenharmony_ci const mbedtls_mpi_uint *A, 117a8e1175bSopenharmony_ci const mbedtls_mpi_uint *B, 118a8e1175bSopenharmony_ci const mbedtls_mpi_mod_modulus *N, 119a8e1175bSopenharmony_ci mbedtls_mpi_uint *T) 120a8e1175bSopenharmony_ci{ 121a8e1175bSopenharmony_ci /* Standard (A * B) multiplication stored into pre-allocated T 122a8e1175bSopenharmony_ci * buffer of fixed limb size of (2N + 1). 123a8e1175bSopenharmony_ci * 124a8e1175bSopenharmony_ci * The space may not not fully filled by when 125a8e1175bSopenharmony_ci * MBEDTLS_MPI_MOD_REP_OPT_RED is used. */ 126a8e1175bSopenharmony_ci const size_t T_limbs = BITS_TO_LIMBS(N->bits) * 2; 127a8e1175bSopenharmony_ci switch (N->int_rep) { 128a8e1175bSopenharmony_ci case MBEDTLS_MPI_MOD_REP_MONTGOMERY: 129a8e1175bSopenharmony_ci mbedtls_mpi_core_montmul(X, A, B, N->limbs, N->p, N->limbs, 130a8e1175bSopenharmony_ci N->rep.mont.mm, T); 131a8e1175bSopenharmony_ci break; 132a8e1175bSopenharmony_ci case MBEDTLS_MPI_MOD_REP_OPT_RED: 133a8e1175bSopenharmony_ci mbedtls_mpi_core_mul(T, A, N->limbs, B, N->limbs); 134a8e1175bSopenharmony_ci 135a8e1175bSopenharmony_ci /* Optimised Reduction */ 136a8e1175bSopenharmony_ci (*N->rep.ored.modp)(T, T_limbs); 137a8e1175bSopenharmony_ci 138a8e1175bSopenharmony_ci /* Convert back to canonical representation */ 139a8e1175bSopenharmony_ci mbedtls_mpi_mod_raw_fix_quasi_reduction(T, N); 140a8e1175bSopenharmony_ci memcpy(X, T, N->limbs * sizeof(mbedtls_mpi_uint)); 141a8e1175bSopenharmony_ci break; 142a8e1175bSopenharmony_ci default: 143a8e1175bSopenharmony_ci break; 144a8e1175bSopenharmony_ci } 145a8e1175bSopenharmony_ci 146a8e1175bSopenharmony_ci} 147a8e1175bSopenharmony_ci 148a8e1175bSopenharmony_cisize_t mbedtls_mpi_mod_raw_inv_prime_working_limbs(size_t AN_limbs) 149a8e1175bSopenharmony_ci{ 150a8e1175bSopenharmony_ci /* mbedtls_mpi_mod_raw_inv_prime() needs a temporary for the exponent, 151a8e1175bSopenharmony_ci * which will be the same size as the modulus and input (AN_limbs), 152a8e1175bSopenharmony_ci * and additional space to pass to mbedtls_mpi_core_exp_mod(). */ 153a8e1175bSopenharmony_ci return AN_limbs + 154a8e1175bSopenharmony_ci mbedtls_mpi_core_exp_mod_working_limbs(AN_limbs, AN_limbs); 155a8e1175bSopenharmony_ci} 156a8e1175bSopenharmony_ci 157a8e1175bSopenharmony_civoid mbedtls_mpi_mod_raw_inv_prime(mbedtls_mpi_uint *X, 158a8e1175bSopenharmony_ci const mbedtls_mpi_uint *A, 159a8e1175bSopenharmony_ci const mbedtls_mpi_uint *N, 160a8e1175bSopenharmony_ci size_t AN_limbs, 161a8e1175bSopenharmony_ci const mbedtls_mpi_uint *RR, 162a8e1175bSopenharmony_ci mbedtls_mpi_uint *T) 163a8e1175bSopenharmony_ci{ 164a8e1175bSopenharmony_ci /* Inversion by power: g^|G| = 1 => g^(-1) = g^(|G|-1), and 165a8e1175bSopenharmony_ci * |G| = N - 1, so we want 166a8e1175bSopenharmony_ci * g^(|G|-1) = g^(N - 2) 167a8e1175bSopenharmony_ci */ 168a8e1175bSopenharmony_ci 169a8e1175bSopenharmony_ci /* Use the first AN_limbs of T to hold N - 2 */ 170a8e1175bSopenharmony_ci mbedtls_mpi_uint *Nminus2 = T; 171a8e1175bSopenharmony_ci (void) mbedtls_mpi_core_sub_int(Nminus2, N, 2, AN_limbs); 172a8e1175bSopenharmony_ci 173a8e1175bSopenharmony_ci /* Rest of T is given to exp_mod for its working space */ 174a8e1175bSopenharmony_ci mbedtls_mpi_core_exp_mod(X, 175a8e1175bSopenharmony_ci A, N, AN_limbs, Nminus2, AN_limbs, 176a8e1175bSopenharmony_ci RR, T + AN_limbs); 177a8e1175bSopenharmony_ci} 178a8e1175bSopenharmony_ci 179a8e1175bSopenharmony_civoid mbedtls_mpi_mod_raw_add(mbedtls_mpi_uint *X, 180a8e1175bSopenharmony_ci const mbedtls_mpi_uint *A, 181a8e1175bSopenharmony_ci const mbedtls_mpi_uint *B, 182a8e1175bSopenharmony_ci const mbedtls_mpi_mod_modulus *N) 183a8e1175bSopenharmony_ci{ 184a8e1175bSopenharmony_ci mbedtls_mpi_uint carry, borrow; 185a8e1175bSopenharmony_ci carry = mbedtls_mpi_core_add(X, A, B, N->limbs); 186a8e1175bSopenharmony_ci borrow = mbedtls_mpi_core_sub(X, X, N->p, N->limbs); 187a8e1175bSopenharmony_ci (void) mbedtls_mpi_core_add_if(X, N->p, N->limbs, (unsigned) (carry ^ borrow)); 188a8e1175bSopenharmony_ci} 189a8e1175bSopenharmony_ci 190a8e1175bSopenharmony_ciint mbedtls_mpi_mod_raw_canonical_to_modulus_rep( 191a8e1175bSopenharmony_ci mbedtls_mpi_uint *X, 192a8e1175bSopenharmony_ci const mbedtls_mpi_mod_modulus *N) 193a8e1175bSopenharmony_ci{ 194a8e1175bSopenharmony_ci switch (N->int_rep) { 195a8e1175bSopenharmony_ci case MBEDTLS_MPI_MOD_REP_MONTGOMERY: 196a8e1175bSopenharmony_ci return mbedtls_mpi_mod_raw_to_mont_rep(X, N); 197a8e1175bSopenharmony_ci case MBEDTLS_MPI_MOD_REP_OPT_RED: 198a8e1175bSopenharmony_ci return 0; 199a8e1175bSopenharmony_ci default: 200a8e1175bSopenharmony_ci return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; 201a8e1175bSopenharmony_ci } 202a8e1175bSopenharmony_ci} 203a8e1175bSopenharmony_ci 204a8e1175bSopenharmony_ciint mbedtls_mpi_mod_raw_modulus_to_canonical_rep( 205a8e1175bSopenharmony_ci mbedtls_mpi_uint *X, 206a8e1175bSopenharmony_ci const mbedtls_mpi_mod_modulus *N) 207a8e1175bSopenharmony_ci{ 208a8e1175bSopenharmony_ci switch (N->int_rep) { 209a8e1175bSopenharmony_ci case MBEDTLS_MPI_MOD_REP_MONTGOMERY: 210a8e1175bSopenharmony_ci return mbedtls_mpi_mod_raw_from_mont_rep(X, N); 211a8e1175bSopenharmony_ci case MBEDTLS_MPI_MOD_REP_OPT_RED: 212a8e1175bSopenharmony_ci return 0; 213a8e1175bSopenharmony_ci default: 214a8e1175bSopenharmony_ci return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; 215a8e1175bSopenharmony_ci } 216a8e1175bSopenharmony_ci} 217a8e1175bSopenharmony_ci 218a8e1175bSopenharmony_ciint mbedtls_mpi_mod_raw_random(mbedtls_mpi_uint *X, 219a8e1175bSopenharmony_ci mbedtls_mpi_uint min, 220a8e1175bSopenharmony_ci const mbedtls_mpi_mod_modulus *N, 221a8e1175bSopenharmony_ci int (*f_rng)(void *, unsigned char *, size_t), 222a8e1175bSopenharmony_ci void *p_rng) 223a8e1175bSopenharmony_ci{ 224a8e1175bSopenharmony_ci int ret = mbedtls_mpi_core_random(X, min, N->p, N->limbs, f_rng, p_rng); 225a8e1175bSopenharmony_ci if (ret != 0) { 226a8e1175bSopenharmony_ci return ret; 227a8e1175bSopenharmony_ci } 228a8e1175bSopenharmony_ci return mbedtls_mpi_mod_raw_canonical_to_modulus_rep(X, N); 229a8e1175bSopenharmony_ci} 230a8e1175bSopenharmony_ci 231a8e1175bSopenharmony_ciint mbedtls_mpi_mod_raw_to_mont_rep(mbedtls_mpi_uint *X, 232a8e1175bSopenharmony_ci const mbedtls_mpi_mod_modulus *N) 233a8e1175bSopenharmony_ci{ 234a8e1175bSopenharmony_ci mbedtls_mpi_uint *T; 235a8e1175bSopenharmony_ci const size_t t_limbs = mbedtls_mpi_core_montmul_working_limbs(N->limbs); 236a8e1175bSopenharmony_ci 237a8e1175bSopenharmony_ci if ((T = (mbedtls_mpi_uint *) mbedtls_calloc(t_limbs, ciL)) == NULL) { 238a8e1175bSopenharmony_ci return MBEDTLS_ERR_MPI_ALLOC_FAILED; 239a8e1175bSopenharmony_ci } 240a8e1175bSopenharmony_ci 241a8e1175bSopenharmony_ci mbedtls_mpi_core_to_mont_rep(X, X, N->p, N->limbs, 242a8e1175bSopenharmony_ci N->rep.mont.mm, N->rep.mont.rr, T); 243a8e1175bSopenharmony_ci 244a8e1175bSopenharmony_ci mbedtls_zeroize_and_free(T, t_limbs * ciL); 245a8e1175bSopenharmony_ci return 0; 246a8e1175bSopenharmony_ci} 247a8e1175bSopenharmony_ci 248a8e1175bSopenharmony_ciint mbedtls_mpi_mod_raw_from_mont_rep(mbedtls_mpi_uint *X, 249a8e1175bSopenharmony_ci const mbedtls_mpi_mod_modulus *N) 250a8e1175bSopenharmony_ci{ 251a8e1175bSopenharmony_ci const size_t t_limbs = mbedtls_mpi_core_montmul_working_limbs(N->limbs); 252a8e1175bSopenharmony_ci mbedtls_mpi_uint *T; 253a8e1175bSopenharmony_ci 254a8e1175bSopenharmony_ci if ((T = (mbedtls_mpi_uint *) mbedtls_calloc(t_limbs, ciL)) == NULL) { 255a8e1175bSopenharmony_ci return MBEDTLS_ERR_MPI_ALLOC_FAILED; 256a8e1175bSopenharmony_ci } 257a8e1175bSopenharmony_ci 258a8e1175bSopenharmony_ci mbedtls_mpi_core_from_mont_rep(X, X, N->p, N->limbs, N->rep.mont.mm, T); 259a8e1175bSopenharmony_ci 260a8e1175bSopenharmony_ci mbedtls_zeroize_and_free(T, t_limbs * ciL); 261a8e1175bSopenharmony_ci return 0; 262a8e1175bSopenharmony_ci} 263a8e1175bSopenharmony_ci 264a8e1175bSopenharmony_civoid mbedtls_mpi_mod_raw_neg(mbedtls_mpi_uint *X, 265a8e1175bSopenharmony_ci const mbedtls_mpi_uint *A, 266a8e1175bSopenharmony_ci const mbedtls_mpi_mod_modulus *N) 267a8e1175bSopenharmony_ci{ 268a8e1175bSopenharmony_ci mbedtls_mpi_core_sub(X, N->p, A, N->limbs); 269a8e1175bSopenharmony_ci 270a8e1175bSopenharmony_ci /* If A=0 initially, then X=N now. Detect this by 271a8e1175bSopenharmony_ci * subtracting N and catching the carry. */ 272a8e1175bSopenharmony_ci mbedtls_mpi_uint borrow = mbedtls_mpi_core_sub(X, X, N->p, N->limbs); 273a8e1175bSopenharmony_ci (void) mbedtls_mpi_core_add_if(X, N->p, N->limbs, (unsigned) borrow); 274a8e1175bSopenharmony_ci} 275a8e1175bSopenharmony_ci 276a8e1175bSopenharmony_ci#endif /* MBEDTLS_BIGNUM_C && MBEDTLS_ECP_WITH_MPI_UINT */ 277