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