mirror of
				https://github.com/Mbed-TLS/mbedtls.git
				synced 2025-10-27 12:15:33 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			395 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			395 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /**
 | |
|  *  Modular bignum functions
 | |
|  *
 | |
|  *  Copyright The Mbed TLS Contributors
 | |
|  *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
 | |
|  */
 | |
| 
 | |
| #include "common.h"
 | |
| 
 | |
| #if defined(MBEDTLS_BIGNUM_C) && defined(MBEDTLS_ECP_WITH_MPI_UINT)
 | |
| 
 | |
| #include <string.h>
 | |
| 
 | |
| #include "mbedtls/platform_util.h"
 | |
| #include "mbedtls/error.h"
 | |
| #include "mbedtls/bignum.h"
 | |
| 
 | |
| #include "mbedtls/platform.h"
 | |
| 
 | |
| #include "bignum_core.h"
 | |
| #include "bignum_mod.h"
 | |
| #include "bignum_mod_raw.h"
 | |
| #include "constant_time_internal.h"
 | |
| 
 | |
| int mbedtls_mpi_mod_residue_setup(mbedtls_mpi_mod_residue *r,
 | |
|                                   const mbedtls_mpi_mod_modulus *N,
 | |
|                                   mbedtls_mpi_uint *p,
 | |
|                                   size_t p_limbs)
 | |
| {
 | |
|     if (p_limbs != N->limbs || !mbedtls_mpi_core_lt_ct(p, N->p, N->limbs)) {
 | |
|         return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
 | |
|     }
 | |
| 
 | |
|     r->limbs = N->limbs;
 | |
|     r->p = p;
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| void mbedtls_mpi_mod_residue_release(mbedtls_mpi_mod_residue *r)
 | |
| {
 | |
|     if (r == NULL) {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     r->limbs = 0;
 | |
|     r->p = NULL;
 | |
| }
 | |
| 
 | |
| void mbedtls_mpi_mod_modulus_init(mbedtls_mpi_mod_modulus *N)
 | |
| {
 | |
|     if (N == NULL) {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     N->p = NULL;
 | |
|     N->limbs = 0;
 | |
|     N->bits = 0;
 | |
|     N->int_rep = MBEDTLS_MPI_MOD_REP_INVALID;
 | |
| }
 | |
| 
 | |
| void mbedtls_mpi_mod_modulus_free(mbedtls_mpi_mod_modulus *N)
 | |
| {
 | |
|     if (N == NULL) {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     switch (N->int_rep) {
 | |
|         case MBEDTLS_MPI_MOD_REP_MONTGOMERY:
 | |
|             if (N->rep.mont.rr != NULL) {
 | |
|                 mbedtls_zeroize_and_free((mbedtls_mpi_uint *) N->rep.mont.rr,
 | |
|                                          N->limbs * sizeof(mbedtls_mpi_uint));
 | |
|                 N->rep.mont.rr = NULL;
 | |
|             }
 | |
|             N->rep.mont.mm = 0;
 | |
|             break;
 | |
|         case MBEDTLS_MPI_MOD_REP_OPT_RED:
 | |
|             N->rep.ored.modp = NULL;
 | |
|             break;
 | |
|         case MBEDTLS_MPI_MOD_REP_INVALID:
 | |
|             break;
 | |
|     }
 | |
| 
 | |
|     N->p = NULL;
 | |
|     N->limbs = 0;
 | |
|     N->bits = 0;
 | |
|     N->int_rep = MBEDTLS_MPI_MOD_REP_INVALID;
 | |
| }
 | |
| 
 | |
| static int set_mont_const_square(const mbedtls_mpi_uint **X,
 | |
|                                  const mbedtls_mpi_uint *A,
 | |
|                                  size_t limbs)
 | |
| {
 | |
|     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
 | |
|     mbedtls_mpi N;
 | |
|     mbedtls_mpi RR;
 | |
|     *X = NULL;
 | |
| 
 | |
|     mbedtls_mpi_init(&N);
 | |
|     mbedtls_mpi_init(&RR);
 | |
| 
 | |
|     if (A == NULL || limbs == 0 || limbs >= (MBEDTLS_MPI_MAX_LIMBS / 2) - 2) {
 | |
|         goto cleanup;
 | |
|     }
 | |
| 
 | |
|     if (mbedtls_mpi_grow(&N, limbs)) {
 | |
|         goto cleanup;
 | |
|     }
 | |
| 
 | |
|     memcpy(N.p, A, sizeof(mbedtls_mpi_uint) * limbs);
 | |
| 
 | |
|     ret = mbedtls_mpi_core_get_mont_r2_unsafe(&RR, &N);
 | |
| 
 | |
|     if (ret == 0) {
 | |
|         *X = RR.p;
 | |
|         RR.p = NULL;
 | |
|     }
 | |
| 
 | |
| cleanup:
 | |
|     mbedtls_mpi_free(&N);
 | |
|     mbedtls_mpi_free(&RR);
 | |
|     ret = (ret != 0) ? MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED : 0;
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| static inline void standard_modulus_setup(mbedtls_mpi_mod_modulus *N,
 | |
|                                           const mbedtls_mpi_uint *p,
 | |
|                                           size_t p_limbs,
 | |
|                                           mbedtls_mpi_mod_rep_selector int_rep)
 | |
| {
 | |
|     N->p = p;
 | |
|     N->limbs = p_limbs;
 | |
|     N->bits = mbedtls_mpi_core_bitlen(p, p_limbs);
 | |
|     N->int_rep = int_rep;
 | |
| }
 | |
| 
 | |
| int mbedtls_mpi_mod_modulus_setup(mbedtls_mpi_mod_modulus *N,
 | |
|                                   const mbedtls_mpi_uint *p,
 | |
|                                   size_t p_limbs)
 | |
| {
 | |
|     int ret = 0;
 | |
|     standard_modulus_setup(N, p, p_limbs, MBEDTLS_MPI_MOD_REP_MONTGOMERY);
 | |
|     N->rep.mont.mm = mbedtls_mpi_core_montmul_init(N->p);
 | |
|     ret = set_mont_const_square(&N->rep.mont.rr, N->p, N->limbs);
 | |
| 
 | |
|     if (ret != 0) {
 | |
|         mbedtls_mpi_mod_modulus_free(N);
 | |
|     }
 | |
| 
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| int mbedtls_mpi_mod_optred_modulus_setup(mbedtls_mpi_mod_modulus *N,
 | |
|                                          const mbedtls_mpi_uint *p,
 | |
|                                          size_t p_limbs,
 | |
|                                          mbedtls_mpi_modp_fn modp)
 | |
| {
 | |
|     standard_modulus_setup(N, p, p_limbs, MBEDTLS_MPI_MOD_REP_OPT_RED);
 | |
|     N->rep.ored.modp = modp;
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| int mbedtls_mpi_mod_mul(mbedtls_mpi_mod_residue *X,
 | |
|                         const mbedtls_mpi_mod_residue *A,
 | |
|                         const mbedtls_mpi_mod_residue *B,
 | |
|                         const mbedtls_mpi_mod_modulus *N)
 | |
| {
 | |
|     if (N->limbs == 0) {
 | |
|         return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
 | |
|     }
 | |
| 
 | |
|     if (X->limbs != N->limbs || A->limbs != N->limbs || B->limbs != N->limbs) {
 | |
|         return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
 | |
|     }
 | |
| 
 | |
|     mbedtls_mpi_uint *T = mbedtls_calloc(N->limbs * 2 + 1, ciL);
 | |
|     if (T == NULL) {
 | |
|         return MBEDTLS_ERR_MPI_ALLOC_FAILED;
 | |
|     }
 | |
| 
 | |
|     mbedtls_mpi_mod_raw_mul(X->p, A->p, B->p, N, T);
 | |
| 
 | |
|     mbedtls_free(T);
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| int mbedtls_mpi_mod_sub(mbedtls_mpi_mod_residue *X,
 | |
|                         const mbedtls_mpi_mod_residue *A,
 | |
|                         const mbedtls_mpi_mod_residue *B,
 | |
|                         const mbedtls_mpi_mod_modulus *N)
 | |
| {
 | |
|     if (X->limbs != N->limbs || A->limbs != N->limbs || B->limbs != N->limbs) {
 | |
|         return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
 | |
|     }
 | |
| 
 | |
|     mbedtls_mpi_mod_raw_sub(X->p, A->p, B->p, N);
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| static int mbedtls_mpi_mod_inv_mont(mbedtls_mpi_mod_residue *X,
 | |
|                                     const mbedtls_mpi_mod_residue *A,
 | |
|                                     const mbedtls_mpi_mod_modulus *N,
 | |
|                                     mbedtls_mpi_uint *working_memory)
 | |
| {
 | |
|     /* Input already in Montgomery form, so there's little to do */
 | |
|     mbedtls_mpi_mod_raw_inv_prime(X->p, A->p,
 | |
|                                   N->p, N->limbs,
 | |
|                                   N->rep.mont.rr,
 | |
|                                   working_memory);
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| static int mbedtls_mpi_mod_inv_non_mont(mbedtls_mpi_mod_residue *X,
 | |
|                                         const mbedtls_mpi_mod_residue *A,
 | |
|                                         const mbedtls_mpi_mod_modulus *N,
 | |
|                                         mbedtls_mpi_uint *working_memory)
 | |
| {
 | |
|     /* Need to convert input into Montgomery form */
 | |
| 
 | |
|     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
 | |
| 
 | |
|     mbedtls_mpi_mod_modulus Nmont;
 | |
|     mbedtls_mpi_mod_modulus_init(&Nmont);
 | |
| 
 | |
|     MBEDTLS_MPI_CHK(mbedtls_mpi_mod_modulus_setup(&Nmont, N->p, N->limbs));
 | |
| 
 | |
|     /* We'll use X->p to hold the Montgomery form of the input A->p */
 | |
|     mbedtls_mpi_core_to_mont_rep(X->p, A->p, Nmont.p, Nmont.limbs,
 | |
|                                  Nmont.rep.mont.mm, Nmont.rep.mont.rr,
 | |
|                                  working_memory);
 | |
| 
 | |
|     mbedtls_mpi_mod_raw_inv_prime(X->p, X->p,
 | |
|                                   Nmont.p, Nmont.limbs,
 | |
|                                   Nmont.rep.mont.rr,
 | |
|                                   working_memory);
 | |
| 
 | |
|     /* And convert back from Montgomery form */
 | |
| 
 | |
|     mbedtls_mpi_core_from_mont_rep(X->p, X->p, Nmont.p, Nmont.limbs,
 | |
|                                    Nmont.rep.mont.mm, working_memory);
 | |
| 
 | |
| cleanup:
 | |
|     mbedtls_mpi_mod_modulus_free(&Nmont);
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| int mbedtls_mpi_mod_inv(mbedtls_mpi_mod_residue *X,
 | |
|                         const mbedtls_mpi_mod_residue *A,
 | |
|                         const mbedtls_mpi_mod_modulus *N)
 | |
| {
 | |
|     if (X->limbs != N->limbs || A->limbs != N->limbs) {
 | |
|         return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
 | |
|     }
 | |
| 
 | |
|     /* Zero has the same value regardless of Montgomery form or not */
 | |
|     if (mbedtls_mpi_core_check_zero_ct(A->p, A->limbs) == 0) {
 | |
|         return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
 | |
|     }
 | |
| 
 | |
|     size_t working_limbs =
 | |
|         mbedtls_mpi_mod_raw_inv_prime_working_limbs(N->limbs);
 | |
| 
 | |
|     mbedtls_mpi_uint *working_memory = mbedtls_calloc(working_limbs,
 | |
|                                                       sizeof(mbedtls_mpi_uint));
 | |
|     if (working_memory == NULL) {
 | |
|         return MBEDTLS_ERR_MPI_ALLOC_FAILED;
 | |
|     }
 | |
| 
 | |
|     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
 | |
| 
 | |
|     switch (N->int_rep) {
 | |
|         case MBEDTLS_MPI_MOD_REP_MONTGOMERY:
 | |
|             ret = mbedtls_mpi_mod_inv_mont(X, A, N, working_memory);
 | |
|             break;
 | |
|         case MBEDTLS_MPI_MOD_REP_OPT_RED:
 | |
|             ret = mbedtls_mpi_mod_inv_non_mont(X, A, N, working_memory);
 | |
|             break;
 | |
|         default:
 | |
|             ret = MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
 | |
|             break;
 | |
|     }
 | |
| 
 | |
|     mbedtls_zeroize_and_free(working_memory,
 | |
|                              working_limbs * sizeof(mbedtls_mpi_uint));
 | |
| 
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| int mbedtls_mpi_mod_add(mbedtls_mpi_mod_residue *X,
 | |
|                         const mbedtls_mpi_mod_residue *A,
 | |
|                         const mbedtls_mpi_mod_residue *B,
 | |
|                         const mbedtls_mpi_mod_modulus *N)
 | |
| {
 | |
|     if (X->limbs != N->limbs || A->limbs != N->limbs || B->limbs != N->limbs) {
 | |
|         return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
 | |
|     }
 | |
| 
 | |
|     mbedtls_mpi_mod_raw_add(X->p, A->p, B->p, N);
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| int mbedtls_mpi_mod_random(mbedtls_mpi_mod_residue *X,
 | |
|                            mbedtls_mpi_uint min,
 | |
|                            const mbedtls_mpi_mod_modulus *N,
 | |
|                            int (*f_rng)(void *, unsigned char *, size_t),
 | |
|                            void *p_rng)
 | |
| {
 | |
|     if (X->limbs != N->limbs) {
 | |
|         return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
 | |
|     }
 | |
|     return mbedtls_mpi_mod_raw_random(X->p, min, N, f_rng, p_rng);
 | |
| }
 | |
| 
 | |
| int mbedtls_mpi_mod_read(mbedtls_mpi_mod_residue *r,
 | |
|                          const mbedtls_mpi_mod_modulus *N,
 | |
|                          const unsigned char *buf,
 | |
|                          size_t buflen,
 | |
|                          mbedtls_mpi_mod_ext_rep ext_rep)
 | |
| {
 | |
|     int ret = MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
 | |
| 
 | |
|     /* Do our best to check if r and m have been set up */
 | |
|     if (r->limbs == 0 || N->limbs == 0) {
 | |
|         goto cleanup;
 | |
|     }
 | |
|     if (r->limbs != N->limbs) {
 | |
|         goto cleanup;
 | |
|     }
 | |
| 
 | |
|     ret = mbedtls_mpi_mod_raw_read(r->p, N, buf, buflen, ext_rep);
 | |
|     if (ret != 0) {
 | |
|         goto cleanup;
 | |
|     }
 | |
| 
 | |
|     r->limbs = N->limbs;
 | |
| 
 | |
|     ret = mbedtls_mpi_mod_raw_canonical_to_modulus_rep(r->p, N);
 | |
| 
 | |
| cleanup:
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| int mbedtls_mpi_mod_write(const mbedtls_mpi_mod_residue *r,
 | |
|                           const mbedtls_mpi_mod_modulus *N,
 | |
|                           unsigned char *buf,
 | |
|                           size_t buflen,
 | |
|                           mbedtls_mpi_mod_ext_rep ext_rep)
 | |
| {
 | |
|     /* Do our best to check if r and m have been set up */
 | |
|     if (r->limbs == 0 || N->limbs == 0) {
 | |
|         return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
 | |
|     }
 | |
|     if (r->limbs != N->limbs) {
 | |
|         return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
 | |
|     }
 | |
| 
 | |
|     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
 | |
|     mbedtls_mpi_uint *working_memory = r->p;
 | |
|     size_t working_memory_len = sizeof(mbedtls_mpi_uint) * r->limbs;
 | |
| 
 | |
|     if (N->int_rep == MBEDTLS_MPI_MOD_REP_MONTGOMERY) {
 | |
| 
 | |
|         working_memory = mbedtls_calloc(r->limbs, sizeof(mbedtls_mpi_uint));
 | |
| 
 | |
|         if (working_memory == NULL) {
 | |
|             ret = MBEDTLS_ERR_MPI_ALLOC_FAILED;
 | |
|             goto cleanup;
 | |
|         }
 | |
| 
 | |
|         memcpy(working_memory, r->p, working_memory_len);
 | |
| 
 | |
|         ret = mbedtls_mpi_mod_raw_from_mont_rep(working_memory, N);
 | |
|         if (ret != 0) {
 | |
|             goto cleanup;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     ret = mbedtls_mpi_mod_raw_write(working_memory, N, buf, buflen, ext_rep);
 | |
| 
 | |
| cleanup:
 | |
| 
 | |
|     if (N->int_rep == MBEDTLS_MPI_MOD_REP_MONTGOMERY &&
 | |
|         working_memory != NULL) {
 | |
| 
 | |
|         mbedtls_zeroize_and_free(working_memory, working_memory_len);
 | |
|     }
 | |
| 
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| #endif /* MBEDTLS_BIGNUM_C && MBEDTLS_ECP_WITH_MPI_UINT */
 |