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