Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pr7051 suggestions #9

Open
wants to merge 13 commits into
base: development
Choose a base branch
from
96 changes: 64 additions & 32 deletions library/ecp_curves.c
Original file line number Diff line number Diff line change
Expand Up @@ -4582,6 +4582,8 @@ static int ecp_mod_p384(mbedtls_mpi *);
#endif
#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED)
static int ecp_mod_p521(mbedtls_mpi *);
MBEDTLS_STATIC_TESTABLE
int mbedtls_ecp_mod_p521_raw(mbedtls_mpi_uint *N_p, size_t N_n);
#endif

#define NIST_MODP(P) grp->modp = ecp_mod_ ## P;
Expand Down Expand Up @@ -5162,60 +5164,90 @@ static int ecp_mod_p384(mbedtls_mpi *N)
MBEDTLS_ECP_DP_SECP384R1_ENABLED */

#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED)
/*
* Here we have an actual Mersenne prime, so things are more straightforward.
* However, chunks are aligned on a 'weird' boundary (521 bits).
*/

/* Size of p521 in terms of mbedtls_mpi_uint */
#define P521_WIDTH (521 / 8 / sizeof(mbedtls_mpi_uint) + 1)

/* Bits to keep in the most significant mbedtls_mpi_uint */
#define P521_MASK 0x01FF

/*
* Fast quasi-reduction modulo p521 (FIPS 186-3 D.2.5)
* Write N as A1 + 2^521 A0, return A0 + A1
* Fast quasi-reduction modulo p521 = 2^521 - 1 (FIPS 186-3 D.2.5)
*/
static int ecp_mod_p521(mbedtls_mpi *N)
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t i;
mbedtls_mpi M;
mbedtls_mpi_uint Mp[P521_WIDTH + 1];
/* Worst case for the size of M is when mbedtls_mpi_uint is 16 bits:
* we need to hold bits 513 to 1056, which is 34 limbs, that is
* P521_WIDTH + 1. Otherwise P521_WIDTH is enough. */
size_t expected_width = 2 * ((521 + biL - 1) / biL);
MBEDTLS_MPI_CHK(mbedtls_mpi_grow(N, expected_width));
ret = mbedtls_ecp_mod_p521_raw(N->p, expected_width);
cleanup:
return ret;
}

if (N->n < P521_WIDTH) {
return 0;
}
MBEDTLS_STATIC_TESTABLE
int mbedtls_ecp_mod_p521_raw(mbedtls_mpi_uint *X, size_t X_limbs)
{
mbedtls_mpi_uint carry = 0;

/* M = A1 */
M.s = 1;
M.n = N->n - (P521_WIDTH - 1);
if (M.n > P521_WIDTH + 1) {
M.n = P521_WIDTH + 1;
if (X_limbs > 2 * P521_WIDTH - 1) {
X_limbs = 2 * P521_WIDTH - 1;
}
if (X_limbs < P521_WIDTH) {
return 0;
}
M.p = Mp;
memcpy(Mp, N->p + P521_WIDTH - 1, M.n * sizeof(mbedtls_mpi_uint));
MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&M, 521 % (8 * sizeof(mbedtls_mpi_uint))));

/* N = A0 */
N->p[P521_WIDTH - 1] &= P521_MASK;
for (i = P521_WIDTH; i < N->n; i++) {
N->p[i] = 0;
/* Step 1: Reduction to P521_WIDTH limbs */
if (X_limbs > P521_WIDTH) {
/* Helper references for bottom part of X */
mbedtls_mpi_uint *X0 = X;
size_t X0_limbs = P521_WIDTH;
/* Helper references for top part of X */
mbedtls_mpi_uint *X1 = X + X0_limbs;
size_t X1_limbs = X_limbs - X0_limbs;

/* Split X as X0 + 2^P521_WIDTH X1 and compute X0 + 2^(biL - 9) X1.
* (We are using that 2^P521_WIDTH = 2^(512 + biL) and that
* 2^(512 + biL) X1 = 2^(biL - 9) X1 mod P521.)
* The high order limb of the result will be held in carry and the rest
* in X0 (that is the result will be represented as
* 2^P521_WIDTH carry + X0).
*
* Also, note that the resulting carry is either 0 or 1:
* X0 < 2^P521_WIDTH = 2^(512 + biL) and X1 < 2^(P521_WIDTH-biL) = 2^512
* therefore
* X0 + 2^(biL - 9) X1 < 2^(512 + biL) + 2^(512 + biL - 9)
* which in turn is less than 2 * 2^(512 + biL).
*/
mbedtls_mpi_uint shift = ((mbedtls_mpi_uint) 1u) << (biL - 9);
carry = mbedtls_mpi_core_mla(X0, X0_limbs, X1, X1_limbs, shift);

/* Set X to X0 (by clearing the top part). */
memset(X1, 0, X1_limbs * sizeof(mbedtls_mpi_uint));
}

/* N = A0 + A1 */
MBEDTLS_MPI_CHK(mbedtls_mpi_add_abs(N, N, &M));
/* Step 2: Reduction modulo P521
*
* At this point X is reduced to P521_WIDTH limbs. What remains is to add
* the carry (that is 2^P521_WIDTH carry) and to reduce mod P521. */

/* 2^P521_WIDTH carry = 2^(512 + biL) carry = 2^(biL - 9) carry mod P521.
* Also, recall that carry is either 0 or 1. */
mbedtls_mpi_uint addend = carry << (biL - 9);
/* Keep the top 9 bits and reduce the rest, using 2^521 = 1 mod P521. */
addend += (X[P521_WIDTH-1] >> 9);
X[P521_WIDTH-1] &= P521_MASK;
/* Declare a helper array for carrying out the addition. */
mbedtls_mpi_uint addend_arr[P521_WIDTH] = { 0 };
addend_arr[0] = addend;
(void) mbedtls_mpi_core_add(X, X, addend_arr, P521_WIDTH);
/* Both addends were less than P521 therefore X < 2 P521. (This also means
* that the result fit in P521_WIDTH limbs and there won't be any carry.) */

cleanup:
return ret;
return 0;
}

#undef P521_WIDTH
#undef P521_MASK

#endif /* MBEDTLS_ECP_DP_SECP521R1_ENABLED */

#endif /* MBEDTLS_ECP_NIST_OPTIM */
Expand Down
13 changes: 13 additions & 0 deletions library/ecp_invasive.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,19 @@ int mbedtls_ecp_gen_privkey_mx(size_t n_bits,

#endif /* MBEDTLS_ECP_MONTGOMERY_ENABLED */

#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED)

/** Fast quasi-reduction modulo p521 = 2^521 - 1 (FIPS 186-3 D.2.5)
*
* \param[in,out] N_p The address of the MPI to be converted.
* Must have 2 * N - 1 limbs, where N is the modulus.
* \param[in] N_n The length of \p N_p in limbs.
*/
MBEDTLS_STATIC_TESTABLE
int mbedtls_ecp_mod_p521_raw(mbedtls_mpi_uint *N_p, size_t N_n);

#endif /* MBEDTLS_ECP_DP_SECP521R1_ENABLED */

#endif /* MBEDTLS_TEST_HOOKS && MBEDTLS_ECP_C */

#endif /* MBEDTLS_ECP_INVASIVE_H */
1 change: 1 addition & 0 deletions scripts/make_generated_files.bat
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ python scripts\generate_ssl_debug_helpers.py || exit /b 1
perl scripts\generate_visualc_files.pl || exit /b 1
python scripts\generate_psa_constants.py || exit /b 1
python tests\scripts\generate_bignum_tests.py || exit /b 1
python tests\scripts\generate_ecp_tests.py || exit /b 1
python tests\scripts\generate_psa_tests.py || exit /b 1
6 changes: 5 additions & 1 deletion scripts/mbedtls_dev/bignum_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,10 @@ def combination_pairs(values: List[T]) -> List[Tuple[T, T]]:
"""Return all pair combinations from input values."""
return [(x, y) for x in values for y in values]

def hex_digits_for_limb(limbs: int, bits_in_limb: int) -> int:
""" Retrun the hex digits need for a number of limbs. """
return 2 * (limbs * bits_in_limb // 8)

class OperationCommon(test_data_generation.BaseTest):
"""Common features for bignum binary operations.

Expand Down Expand Up @@ -138,7 +142,7 @@ def limbs(self) -> int:

@property
def hex_digits(self) -> int:
return 2 * (self.limbs * self.bits_in_limb // 8)
return hex_digits_for_limb(self.limbs, self.bits_in_limb)

def format_arg(self, val: str) -> str:
if self.input_style not in self.input_styles:
Expand Down
117 changes: 117 additions & 0 deletions scripts/mbedtls_dev/ecp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
"""Framework classes for generation of ecp test cases."""
# Copyright The Mbed TLS Contributors
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from typing import List

from . import test_data_generation
from . import bignum_common

class EcpTarget(test_data_generation.BaseTarget):
#pylint: disable=abstract-method, too-few-public-methods
"""Target for ecp test case generation."""
target_basename = 'test_suite_ecp.generated'

class EcpP521R1Raw(bignum_common.ModOperationCommon,
EcpTarget):
"""Test cases for ecp quasi_reduction()."""
test_function = "ecp_mod_p521_raw"
test_name = "ecp_mod_p521_raw"
input_style = "fixed"
arity = 1

moduli = [("01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")
] # type: List[str]

input_values = [
"0", "1",

# Corner case: maximum canonical P521 multiplication result
("3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
"ff80000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"00004"),

# Test case for overflow during addition
("0001efffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
"000001ef"
"0000000000000000000000000000000000000000000000000000000000000000"
"000000000000000000000000000000000000000000000000000000000f000000"),

# First 8 number generated by random.getrandbits(1042) - seed(2,2)
("0003cc2e82523e86feac7eb7dc38f519b91751dacdbd47d364be8049a372db8f"
"6e405d93ffed9235288bc781ae66267594c9c9500925e4749b575bd13653f8dd"
"9b1f282e"
"4067c3584ee207f8da94e3e8ab73738fcf1822ffbc6887782b491044d5e34124"
"5c6e433715ba2bdd177219d30e7a269fd95bafc8f2a4d27bdcf4bb99f4bea973"),
("00017052829e07b0829a48d422fe99a22c70501e533c91352d3d854e061b9030"
"3b08c6e33c7295782d6c797f8f7d9b782a1be9cd8697bbd0e2520e33e44c5055"
"6c71c4a6"
"6148a86fe8624fab5186ee32ee8d7ee9770348a05d300cb90706a045defc044a"
"09325626e6b58de744ab6cce80877b6f71e1f6d2ef8acd128b4f2fc15f3f57eb"),
("00021f15a7a83ee0761ebfd2bd143fa9b714210c665d7435c1066932f4767f26"
"294365b2721dea3bf63f23d0dbe53fcafb2147df5ca495fa5a91c89b97eeab64"
"ca2ce6bc"
"5d3fd983c34c769fe89204e2e8168561867e5e15bc01bfce6a27e0dfcbf87544"
"72154e76e4c11ab2fec3f6b32e8d4b8a8f54f8ceacaab39e83844b40ffa9b9f1"),
("000381bc2a838af8d5c44a4eb3172062d08f1bb2531d6460f0caeef038c89b38"
"a8acb5137c9260dc74e088a9b9492f258ebdbfe3eb9ac688b9d39cca91551e82"
"59cc60b1"
"7604e4b4e73695c3e652c71a74667bffe202849da9643a295a9ac6decbd4d3e2"
"d4dec9ef83f0be4e80371eb97f81375eecc1cb6347733e847d718d733ff98ff3"),
("00034816c8c69069134bccd3e1cf4f589f8e4ce0af29d115ef24bd625dd961e6"
"830b54fa7d28f93435339774bb1e386c4fd5079e681b8f5896838b769da59b74"
"a6c3181c"
"81e220df848b1df78feb994a81167346d4c0dca8b4c9e755cc9c3adcf515a823"
"4da4daeb4f3f87777ad1f45ae9500ec9c5e2486c44a4a8f69dc8db48e86ec9c6"),
("000397846c4454b90f756132e16dce72f18e859835e1f291d322a7353ead4efe"
"440e2b4fda9c025a22f1a83185b98f5fc11e60de1b343f52ea748db9e020307a"
"aeb6db2c"
"3a038a709779ac1f45e9dd320c855fdfa7251af0930cdbd30f0ad2a81b2d19a2"
"beaa14a7ff3fe32a30ffc4eed0a7bd04e85bfcdd0227eeb7b9d7d01f5769da05"),
("00002c3296e6bc4d62b47204007ee4fab105d83e85e951862f0981aebc1b00d9"
"2838e766ef9b6bf2d037fe2e20b6a8464174e75a5f834da70569c018eb2b5693"
"babb7fbb"
"0a76c196067cfdcb11457d9cf45e2fa01d7f4275153924800600571fac3a5b26"
"3fdf57cd2c0064975c3747465cc36c270e8a35b10828d569c268a20eb78ac332"),
("00009d23b4917fc09f20dbb0dcc93f0e66dfe717c17313394391b6e2e6eacb0f"
"0bb7be72bd6d25009aeb7fa0c4169b148d2f527e72daf0a54ef25c0707e33868"
"7d1f7157"
"5653a45c49390aa51cf5192bbf67da14be11d56ba0b4a2969d8055a9f03f2d71"
"581d8e830112ff0f0948eccaf8877acf26c377c13f719726fd70bddacb4deeec"),

# Next 2 number generated by random.getrandbits(521)
("12b84ae65e920a63ac1f2b64df6dff07870c9d531ae72a47403063238da1a1fe"
"3f9d6a179fa50f96cd4aff9261aa92c0e6f17ec940639bc2ccdf572df00790813e3"),
("166049dd332a73fa0b26b75196cf87eb8a09b27ec714307c68c425424a1574f1"
"eedf5b0f16cdfdb839424d201e653f53d6883ca1c107ca6e706649889c0c7f38608")
]

@property
def arg_a(self) -> str:
# Number of limbs: 2 * N - 1
hex_digits = bignum_common.hex_digits_for_limb(2 * self.limbs - 1, self.bits_in_limb)
return super().format_arg('{:x}'.format(self.int_a)).zfill(hex_digits)

def result(self) -> List[str]:
result = self.int_a % self.int_n
return [self.format_result(result)]

@property
def is_valid(self) -> bool:
return True
Loading