Merge pull request #6747 from gilles-peskine-arm/bignum-mod-random

Bignum mod random
This commit is contained in:
Manuel Pégourié-Gonnard 2022-12-23 10:36:22 +01:00 committed by GitHub
commit 2fcb4c1d06
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 909 additions and 175 deletions

View file

@ -303,6 +303,17 @@ int mbedtls_mpi_mod_add( mbedtls_mpi_mod_residue *X,
/* BEGIN MERGE SLOT 6 */
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 ) );
}
/* END MERGE SLOT 6 */
/* BEGIN MERGE SLOT 7 */
@ -326,8 +337,7 @@ int mbedtls_mpi_mod_read( mbedtls_mpi_mod_residue *r,
r->limbs = m->limbs;
if( m->int_rep == MBEDTLS_MPI_MOD_REP_MONTGOMERY )
ret = mbedtls_mpi_mod_raw_to_mont_rep( r->p, m );
ret = mbedtls_mpi_mod_raw_canonical_to_modulus_rep( r->p, m );
cleanup:
return ( ret );

View file

@ -87,12 +87,23 @@
#include "mbedtls/bignum.h"
#endif
/* Skip 1 as it is slightly easier to accidentally pass to functions. */
/** How residues associated with a modulus are represented.
*
* This also determines which fields of the modulus structure are valid and
* what their contents are (see #mbedtls_mpi_mod_modulus).
*/
typedef enum
{
/** Representation not chosen (makes the modulus structure invalid). */
MBEDTLS_MPI_MOD_REP_INVALID = 0,
/* Skip 1 as it is slightly easier to accidentally pass to functions. */
/** Montgomery representation. */
MBEDTLS_MPI_MOD_REP_MONTGOMERY = 2,
MBEDTLS_MPI_MOD_REP_OPT_RED
/** TODO: document this.
*
* Residues are in canonical representation.
*/
MBEDTLS_MPI_MOD_REP_OPT_RED,
} mbedtls_mpi_mod_rep_selector;
/* Make mbedtls_mpi_mod_rep_selector and mbedtls_mpi_mod_ext_rep disjoint to
@ -124,7 +135,9 @@ typedef struct {
mbedtls_mpi_mod_rep_selector int_rep; // selector to signal the active member of the union
union rep
{
/* if int_rep == #MBEDTLS_MPI_MOD_REP_MONTGOMERY */
mbedtls_mpi_mont_struct mont;
/* if int_rep == #MBEDTLS_MPI_MOD_REP_OPT_RED */
mbedtls_mpi_opt_red_struct ored;
} rep;
} mbedtls_mpi_mod_modulus;
@ -319,6 +332,39 @@ int mbedtls_mpi_mod_add( mbedtls_mpi_mod_residue *X,
/* BEGIN MERGE SLOT 6 */
/** Generate a random number uniformly in a range.
*
* This function generates a random number between \p min inclusive and
* \p N exclusive.
*
* The procedure complies with RFC 6979 §3.3 (deterministic ECDSA)
* when the RNG is a suitably parametrized instance of HMAC_DRBG
* and \p min is \c 1.
*
* \note There are `N - min` possible outputs. The lower bound
* \p min can be reached, but the upper bound \p N cannot.
*
* \param X The destination residue.
* \param min The minimum value to return. It must be strictly smaller
* than \b N.
* \param N The modulus.
* This is the upper bound of the output range, exclusive.
* \param f_rng The RNG function to use. This must not be \c NULL.
* \param p_rng The RNG parameter to be passed to \p f_rng.
*
* \return \c 0 if successful.
* \return #MBEDTLS_ERR_MPI_NOT_ACCEPTABLE if the implementation was
* unable to find a suitable value within a limited number
* of attempts. This has a negligible probability if \p N
* is significantly larger than \p min, which is the case
* for all usual cryptographic applications.
*/
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 );
/* END MERGE SLOT 6 */
/* BEGIN MERGE SLOT 7 */

View file

@ -186,6 +186,48 @@ void mbedtls_mpi_mod_raw_add( mbedtls_mpi_uint *X,
/* BEGIN MERGE SLOT 6 */
int mbedtls_mpi_mod_raw_canonical_to_modulus_rep(
mbedtls_mpi_uint *X,
const mbedtls_mpi_mod_modulus *N )
{
switch( N->int_rep )
{
case MBEDTLS_MPI_MOD_REP_MONTGOMERY:
return( mbedtls_mpi_mod_raw_to_mont_rep( X, N ) );
case MBEDTLS_MPI_MOD_REP_OPT_RED:
return( 0 );
default:
return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
}
}
int mbedtls_mpi_mod_raw_modulus_to_canonical_rep(
mbedtls_mpi_uint *X,
const mbedtls_mpi_mod_modulus *N )
{
switch( N->int_rep )
{
case MBEDTLS_MPI_MOD_REP_MONTGOMERY:
return( mbedtls_mpi_mod_raw_from_mont_rep( X, N ) );
case MBEDTLS_MPI_MOD_REP_OPT_RED:
return( 0 );
default:
return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
}
}
int 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 )
{
int ret = mbedtls_mpi_core_random( X, min, N->p, N->limbs, f_rng, p_rng );
if( ret != 0 )
return( ret );
return( mbedtls_mpi_mod_raw_canonical_to_modulus_rep( X, N ) );
}
/* END MERGE SLOT 6 */
/* BEGIN MERGE SLOT 7 */

View file

@ -336,6 +336,74 @@ void mbedtls_mpi_mod_raw_add( mbedtls_mpi_uint *X,
/* BEGIN MERGE SLOT 6 */
/** Convert an MPI from canonical representation (little-endian limb array)
* to the representation associated with the modulus.
*
* \param[in,out] X The limb array to convert.
* It must have as many limbs as \p N.
* It is converted in place.
* If this function returns an error, the content of \p X
* is unspecified.
* \param[in] N The modulus structure.
*
*\ return \c 0 if successful.
* Otherwise an \c MBEDTLS_ERR_MPI_xxx error code.
*/
int mbedtls_mpi_mod_raw_canonical_to_modulus_rep(
mbedtls_mpi_uint *X,
const mbedtls_mpi_mod_modulus *N );
/** Convert an MPI from the representation associated with the modulus
* to canonical representation (little-endian limb array).
*
* \param[in,out] X The limb array to convert.
* It must have as many limbs as \p N.
* It is converted in place.
* If this function returns an error, the content of \p X
* is unspecified.
* \param[in] N The modulus structure.
*
*\ return \c 0 if successful.
* Otherwise an \c MBEDTLS_ERR_MPI_xxx error code.
*/
int mbedtls_mpi_mod_raw_modulus_to_canonical_rep(
mbedtls_mpi_uint *X,
const mbedtls_mpi_mod_modulus *N );
/** Generate a random number uniformly in a range.
*
* This function generates a random number between \p min inclusive and
* \p N exclusive.
*
* The procedure complies with RFC 6979 §3.3 (deterministic ECDSA)
* when the RNG is a suitably parametrized instance of HMAC_DRBG
* and \p min is \c 1.
*
* \note There are `N - min` possible outputs. The lower bound
* \p min can be reached, but the upper bound \p N cannot.
*
* \param X The destination MPI, in canonical representation modulo \p N.
* It must not be aliased with \p N or otherwise overlap it.
* \param min The minimum value to return. It must be strictly smaller
* than \b N.
* \param N The modulus.
* This is the upper bound of the output range, exclusive.
* \param f_rng The RNG function to use. This must not be \c NULL.
* \param p_rng The RNG parameter to be passed to \p f_rng.
*
* \return \c 0 if successful.
* \return #MBEDTLS_ERR_MPI_NOT_ACCEPTABLE if the implementation was
* unable to find a suitable value within a limited number
* of attempts. This has a negligible probability if \p N
* is significantly larger than \p min, which is the case
* for all usual cryptographic applications.
*/
int 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 );
/* END MERGE SLOT 6 */
/* BEGIN MERGE SLOT 7 */

View file

@ -15,6 +15,7 @@
# limitations under the License.
from abc import abstractmethod
import enum
from typing import Iterator, List, Tuple, TypeVar, Any
from itertools import chain
@ -53,7 +54,7 @@ def hex_to_int(val: str) -> int:
return 0
return int(val, 16)
def quote_str(val) -> str:
def quote_str(val: str) -> str:
return "\"{}\"".format(val)
def bound_mpi(val: int, bits_in_limb: int) -> int:
@ -139,7 +140,7 @@ class OperationCommon(test_data_generation.BaseTest):
def hex_digits(self) -> int:
return 2 * (self.limbs * self.bits_in_limb // 8)
def format_arg(self, val) -> str:
def format_arg(self, val: str) -> str:
if self.input_style not in self.input_styles:
raise ValueError("Unknown input style!")
if self.input_style == "variable":
@ -147,7 +148,7 @@ class OperationCommon(test_data_generation.BaseTest):
else:
return val.zfill(self.hex_digits)
def format_result(self, res) -> str:
def format_result(self, res: int) -> str:
res_str = '{:x}'.format(res)
return quote_str(self.format_arg(res_str))
@ -245,6 +246,23 @@ class OperationCommon(test_data_generation.BaseTest):
)
class ModulusRepresentation(enum.Enum):
"""Representation selector of a modulus."""
# Numerical values aligned with the type mbedtls_mpi_mod_rep_selector
INVALID = 0
MONTGOMERY = 2
OPT_RED = 3
def symbol(self) -> str:
"""The C symbol for this representation selector."""
return 'MBEDTLS_MPI_MOD_REP_' + self.name
@classmethod
def supported_representations(cls) -> List['ModulusRepresentation']:
"""Return all representations that are supported in positive test cases."""
return [cls.MONTGOMERY, cls.OPT_RED]
class ModOperationCommon(OperationCommon):
#pylint: disable=abstract-method
"""Target for bignum mod_raw test case generation."""
@ -266,6 +284,17 @@ class ModOperationCommon(OperationCommon):
def from_montgomery(self, val: int) -> int:
return (val * self.r_inv) % self.int_n
def convert_from_canonical(self, canonical: int,
rep: ModulusRepresentation) -> int:
"""Convert values from canonical representation to the given representation."""
if rep is ModulusRepresentation.MONTGOMERY:
return self.to_montgomery(canonical)
elif rep is ModulusRepresentation.OPT_RED:
return canonical
else:
raise ValueError('Modulus representation not supported: {}'
.format(rep.name))
@property
def boundary(self) -> int:
return self.int_n
@ -282,6 +311,9 @@ class ModOperationCommon(OperationCommon):
def arg_n(self) -> str:
return self.format_arg(self.val_n)
def format_arg(self, val: str) -> str:
return super().format_arg(val).zfill(self.hex_digits)
def arguments(self) -> List[str]:
return [quote_str(self.arg_n)] + super().arguments()

View file

@ -14,8 +14,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from typing import Dict, List
from typing import Iterator, List
from . import test_case
from . import test_data_generation
from . import bignum_common
from .bignum_data import ONLY_PRIME_MODULI
@ -116,6 +117,88 @@ class BignumModRawAdd(bignum_common.ModOperationCommon,
# BEGIN MERGE SLOT 6
class BignumModRawConvertRep(bignum_common.ModOperationCommon,
BignumModRawTarget):
# This is an abstract class, it's ok to have unimplemented methods.
#pylint: disable=abstract-method
"""Test cases for representation conversion."""
symbol = ""
input_style = "arch_split"
arity = 1
rep = bignum_common.ModulusRepresentation.INVALID
def set_representation(self, r: bignum_common.ModulusRepresentation) -> None:
self.rep = r
def arguments(self) -> List[str]:
return ([bignum_common.quote_str(self.arg_n), self.rep.symbol(),
bignum_common.quote_str(self.arg_a)] +
self.result())
def description(self) -> str:
base = super().description()
mod_with_rep = 'mod({})'.format(self.rep.name)
return base.replace('mod', mod_with_rep, 1)
@classmethod
def test_cases_for_values(cls, rep: bignum_common.ModulusRepresentation,
n: str, a: str) -> Iterator[test_case.TestCase]:
"""Emit test cases for the given values (if any).
This may emit no test cases if a isn't valid for the modulus n,
or multiple test cases if rep requires different data depending
on the limb size.
"""
for bil in cls.limb_sizes:
test_object = cls(n, a, bits_in_limb=bil)
test_object.set_representation(rep)
# The class is set to having separate test cases for each limb
# size, because the Montgomery representation requires it.
# But other representations don't require it. So for other
# representations, emit a single test case with no dependency
# on the limb size.
if rep is not bignum_common.ModulusRepresentation.MONTGOMERY:
test_object.dependencies = \
[dep for dep in test_object.dependencies
if not dep.startswith('MBEDTLS_HAVE_INT')]
if test_object.is_valid:
yield test_object.create_test_case()
if rep is not bignum_common.ModulusRepresentation.MONTGOMERY:
# A single test case (emitted, or skipped due to invalidity)
# is enough, since this test case doesn't depend on the
# limb size.
break
# The parent class doesn't support non-bignum parameters. So we override
# test generation, in order to have the representation as a parameter.
@classmethod
def generate_function_tests(cls) -> Iterator[test_case.TestCase]:
for rep in bignum_common.ModulusRepresentation.supported_representations():
for n in cls.moduli:
for a in cls.input_values:
yield from cls.test_cases_for_values(rep, n, a)
class BignumModRawCanonicalToModulusRep(BignumModRawConvertRep):
"""Test cases for mpi_mod_raw_canonical_to_modulus_rep."""
test_function = "mpi_mod_raw_canonical_to_modulus_rep"
test_name = "Rep canon->mod"
def result(self) -> List[str]:
return [self.format_result(self.convert_from_canonical(self.int_a, self.rep))]
class BignumModRawModulusToCanonicalRep(BignumModRawConvertRep):
"""Test cases for mpi_mod_raw_modulus_to_canonical_rep."""
test_function = "mpi_mod_raw_modulus_to_canonical_rep"
test_name = "Rep mod->canon"
@property
def arg_a(self) -> str:
return self.format_arg("{:x}".format(self.convert_from_canonical(self.int_a, self.rep)))
def result(self) -> List[str]:
return [self.format_result(self.int_a)]
# END MERGE SLOT 6
# BEGIN MERGE SLOT 7

View file

@ -0,0 +1,118 @@
/**
* \file bignum_helpers.h
*
* \brief This file contains the prototypes of helper functions for
* bignum-related testing.
*/
/*
* 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.
*/
#ifndef TEST_BIGNUM_HELPERS_H
#define TEST_BIGNUM_HELPERS_H
#include <mbedtls/build_info.h>
#if defined(MBEDTLS_BIGNUM_C)
#include <mbedtls/bignum.h>
#include <bignum_mod.h>
/** Allocate and populate a core MPI from a test case argument.
*
* This function allocates exactly as many limbs as necessary to fit
* the length of the input. In other words, it preserves leading zeros.
*
* The limb array is allocated with mbedtls_calloc() and must later be
* freed with mbedtls_free().
*
* \param[in,out] pX The address where a pointer to the allocated limb
* array will be stored.
* \c *pX must be null on entry.
* On exit, \c *pX is null on error or if the number
* of limbs is 0.
* \param[out] plimbs The address where the number of limbs will be stored.
* \param[in] input The test argument to read.
* It is interpreted as a hexadecimal representation
* of a non-negative integer.
*
* \return \c 0 on success, an \c MBEDTLS_ERR_MPI_xxx error code otherwise.
*/
int mbedtls_test_read_mpi_core( mbedtls_mpi_uint **pX, size_t *plimbs,
const char *input );
/** Read a modulus from a hexadecimal string.
*
* This function allocates exactly as many limbs as necessary to fit
* the length of the input. In other words, it preserves leading zeros.
*
* The limb array is allocated with mbedtls_calloc() and must later be
* freed with mbedtls_free(). You can do that by calling
* mbedtls_test_mpi_mod_modulus_free_with_limbs().
*
* \param[in,out] N A modulus structure. It must be initialized, but
* not set up.
* \param[in] s The null-terminated hexadecimal string to read from.
* \param int_rep The desired representation of residues.
*
* \return \c 0 on success, an \c MBEDTLS_ERR_MPI_xxx error code otherwise.
*/
int mbedtls_test_read_mpi_modulus( mbedtls_mpi_mod_modulus *N,
const char *s,
mbedtls_mpi_mod_rep_selector int_rep );
/** Free a modulus and its limbs.
*
* \param[in] N A modulus structure such that there is no other
* reference to `N->p`.
*/
void mbedtls_test_mpi_mod_modulus_free_with_limbs( mbedtls_mpi_mod_modulus *N );
/** Read an MPI from a hexadecimal string.
*
* Like mbedtls_mpi_read_string(), but with tighter guarantees around
* edge cases.
*
* - This function guarantees that if \p s begins with '-' then the sign
* bit of the result will be negative, even if the value is 0.
* When this function encounters such a "negative 0", it
* increments #mbedtls_test_case_uses_negative_0.
* - The size of the result is exactly the minimum number of limbs needed
* to fit the digits in the input. In particular, this function constructs
* a bignum with 0 limbs for an empty string, and a bignum with leading 0
* limbs if the string has sufficiently many leading 0 digits.
* This is important so that the "0 (null)" and "0 (1 limb)" and
* "leading zeros" test cases do what they claim.
*
* \param[out] X The MPI object to populate. It must be initialized.
* \param[in] s The null-terminated hexadecimal string to read from.
*
* \return \c 0 on success, an \c MBEDTLS_ERR_MPI_xxx error code otherwise.
*/
int mbedtls_test_read_mpi( mbedtls_mpi *X, const char *s );
/** Nonzero if the current test case had an input parsed with
* mbedtls_test_read_mpi() that is a negative 0 (`"-"`, `"-0"`, `"-00"`, etc.,
* constructing a result with the sign bit set to -1 and the value being
* all-limbs-0, which is not a valid representation in #mbedtls_mpi but is
* tested for robustness).
*/
extern unsigned mbedtls_test_case_uses_negative_0;
#endif /* MBEDTLS_BIGNUM_C */
#endif /* TEST_BIGNUM_HELPERS_H */

View file

@ -215,6 +215,17 @@ void mbedtls_test_hexify( unsigned char *obuf,
const unsigned char *ibuf,
int len );
/**
* \brief Convert hexadecimal digit to an integer.
*
* \param c The digit to convert (`'0'` to `'9'`, `'A'` to `'F'` or
* `'a'` to `'f'`).
* \param[out] uc On success, the value of the digit (0 to 15).
*
* \return 0 on success, -1 if \p c is not a hexadecimal digit.
*/
int mbedtls_test_ascii2uc(const char c, unsigned char *uc);
/**
* Allocate and zeroize a buffer.
*
@ -269,60 +280,4 @@ void mbedtls_test_err_add_check( int high, int low,
const char *file, int line);
#endif
#if defined(MBEDTLS_BIGNUM_C)
/** Allocate and populate a core MPI from a test case argument.
*
* This function allocates exactly as many limbs as necessary to fit
* the length of the input. In other words, it preserves leading zeros.
*
* The limb array is allocated with mbedtls_calloc() and must later be
* freed with mbedtls_free().
*
* \param[in,out] pX The address where a pointer to the allocated limb
* array will be stored.
* \c *pX must be null on entry.
* On exit, \c *pX is null on error or if the number
* of limbs is 0.
* \param[out] plimbs The address where the number of limbs will be stored.
* \param[in] input The test argument to read.
* It is interpreted as a hexadecimal representation
* of a non-negative integer.
*
* \return \c 0 on success, an \c MBEDTLS_ERR_MPI_xxx error code otherwise.
*/
int mbedtls_test_read_mpi_core( mbedtls_mpi_uint **pX, size_t *plimbs,
const char *input );
/** Read an MPI from a hexadecimal string.
*
* Like mbedtls_mpi_read_string(), but with tighter guarantees around
* edge cases.
*
* - This function guarantees that if \p s begins with '-' then the sign
* bit of the result will be negative, even if the value is 0.
* When this function encounters such a "negative 0", it
* increments #mbedtls_test_case_uses_negative_0.
* - The size of the result is exactly the minimum number of limbs needed
* to fit the digits in the input. In particular, this function constructs
* a bignum with 0 limbs for an empty string, and a bignum with leading 0
* limbs if the string has sufficiently many leading 0 digits.
* This is important so that the "0 (null)" and "0 (1 limb)" and
* "leading zeros" test cases do what they claim.
*
* \param[out] X The MPI object to populate. It must be initialized.
* \param[in] s The null-terminated hexadecimal string to read from.
*
* \return \c 0 on success, an \c MBEDTLS_ERR_MPI_xxx error code otherwise.
*/
int mbedtls_test_read_mpi( mbedtls_mpi *X, const char *s );
/** Nonzero if the current test case had an input parsed with
* mbedtls_test_read_mpi() that is a negative 0 (`"-"`, `"-0"`, `"-00"`, etc.,
* constructing a result with the sign bit set to -1 and the value being
* all-limbs-0, which is not a valid representation in #mbedtls_mpi but is
* tested for robustness).
*/
extern unsigned mbedtls_test_case_uses_negative_0;
#endif /* MBEDTLS_BIGNUM_C */
#endif /* TEST_HELPERS_H */

View file

@ -60,7 +60,6 @@ from abc import ABCMeta
from typing import List
import scripts_path # pylint: disable=unused-import
from mbedtls_dev import test_case
from mbedtls_dev import test_data_generation
from mbedtls_dev import bignum_common
# Import modules containing additional test classes

142
tests/src/bignum_helpers.c Normal file
View file

@ -0,0 +1,142 @@
/**
* \file bignum_helpers.c
*
* \brief This file contains the prototypes of helper functions for
* bignum-related testing.
*/
/*
* 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.
*/
#define MBEDTLS_ALLOW_PRIVATE_ACCESS
#include <test/bignum_helpers.h>
#if defined(MBEDTLS_BIGNUM_C)
#include <stdlib.h>
#include <string.h>
#include <mbedtls/bignum.h>
#include <bignum_core.h>
#include <bignum_mod.h>
#include <bignum_mod_raw.h>
#include <test/helpers.h>
#include <test/macros.h>
int mbedtls_test_read_mpi_core( mbedtls_mpi_uint **pX, size_t *plimbs,
const char *input )
{
/* Sanity check */
if( *pX != NULL )
return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
size_t hex_len = strlen( input );
size_t byte_len = ( hex_len + 1 ) / 2;
*plimbs = CHARS_TO_LIMBS( byte_len );
/* A core bignum is not allowed to be empty. Forbid it as test data,
* this way static analyzers have a chance of knowing we don't expect
* the bignum functions to support empty inputs. */
if( *plimbs == 0 )
return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
*pX = mbedtls_calloc( *plimbs, sizeof( **pX ) );
if( *pX == NULL )
return( MBEDTLS_ERR_MPI_ALLOC_FAILED );
unsigned char *byte_start = ( unsigned char * ) *pX;
if( byte_len % sizeof( mbedtls_mpi_uint ) != 0 )
{
byte_start += sizeof( mbedtls_mpi_uint ) - byte_len % sizeof( mbedtls_mpi_uint );
}
if( ( hex_len & 1 ) != 0 )
{
/* mbedtls_test_unhexify wants an even number of hex digits */
TEST_ASSERT( mbedtls_test_ascii2uc( *input, byte_start ) == 0 );
++byte_start;
++input;
--byte_len;
}
TEST_ASSERT( mbedtls_test_unhexify( byte_start,
byte_len,
input,
&byte_len ) == 0 );
mbedtls_mpi_core_bigendian_to_host( *pX, *plimbs );
return( 0 );
exit:
mbedtls_free( *pX );
return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
}
int mbedtls_test_read_mpi_modulus( mbedtls_mpi_mod_modulus *N,
const char *s,
mbedtls_mpi_mod_rep_selector int_rep )
{
mbedtls_mpi_uint *p = NULL;
size_t limbs = 0;
if( N->limbs != 0 )
return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
int ret = mbedtls_test_read_mpi_core( &p, &limbs, s );
if( ret != 0 )
return( ret );
ret = mbedtls_mpi_mod_modulus_setup( N, p, limbs, int_rep );
if( ret != 0 )
mbedtls_free( p );
return( ret );
}
void mbedtls_test_mpi_mod_modulus_free_with_limbs( mbedtls_mpi_mod_modulus *N )
{
mbedtls_free( (mbedtls_mpi_uint*) N->p );
mbedtls_mpi_mod_modulus_free( N );
}
int mbedtls_test_read_mpi( mbedtls_mpi *X, const char *s )
{
int negative = 0;
/* Always set the sign bit to -1 if the input has a minus sign, even for 0.
* This creates an invalid representation, which mbedtls_mpi_read_string()
* avoids but we want to be able to create that in test data. */
if( s[0] == '-' )
{
++s;
negative = 1;
}
/* mbedtls_mpi_read_string() currently retains leading zeros.
* It always allocates at least one limb for the value 0. */
if( s[0] == 0 )
{
mbedtls_mpi_free( X );
return( 0 );
}
int ret = mbedtls_mpi_read_string( X, 16, s );
if( ret != 0 )
return( ret );
if( negative )
{
if( mbedtls_mpi_cmp_int( X, 0 ) == 0 )
++mbedtls_test_case_uses_negative_0;
X->s = -1;
}
return( 0 );
}
#endif /* MBEDTLS_BIGNUM_C */

View file

@ -48,7 +48,7 @@ void mbedtls_test_platform_teardown( void )
#endif /* MBEDTLS_PLATFORM_C */
}
static int ascii2uc(const char c, unsigned char *uc)
int mbedtls_test_ascii2uc(const char c, unsigned char *uc)
{
if( ( c >= '0' ) && ( c <= '9' ) )
*uc = c - '0';
@ -207,10 +207,10 @@ int mbedtls_test_unhexify( unsigned char *obuf,
while( *ibuf != 0 )
{
if ( ascii2uc( *(ibuf++), &uc ) != 0 )
if ( mbedtls_test_ascii2uc( *(ibuf++), &uc ) != 0 )
return( -1 );
if ( ascii2uc( *(ibuf++), &uc2 ) != 0 )
if ( mbedtls_test_ascii2uc( *(ibuf++), &uc2 ) != 0 )
return( -1 );
*(obuf++) = ( uc << 4 ) | uc2;
@ -350,84 +350,3 @@ void mbedtls_test_err_add_check( int high, int low,
}
}
#endif /* MBEDTLS_TEST_HOOKS */
#if defined(MBEDTLS_BIGNUM_C)
#include "bignum_core.h"
int mbedtls_test_read_mpi_core( mbedtls_mpi_uint **pX, size_t *plimbs,
const char *input )
{
/* Sanity check */
if( *pX != NULL )
return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
size_t hex_len = strlen( input );
size_t byte_len = ( hex_len + 1 ) / 2;
*plimbs = CHARS_TO_LIMBS( byte_len );
/* A core bignum is not allowed to be empty. Forbid it as test data,
* this way static analyzers have a chance of knowing we don't expect
* the bignum functions to support empty inputs. */
if( *plimbs == 0 )
return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
*pX = mbedtls_calloc( *plimbs, sizeof( **pX ) );
if( *pX == NULL )
return( MBEDTLS_ERR_MPI_ALLOC_FAILED );
unsigned char *byte_start = ( unsigned char * ) *pX;
if( byte_len % sizeof( mbedtls_mpi_uint ) != 0 )
{
byte_start += sizeof( mbedtls_mpi_uint ) - byte_len % sizeof( mbedtls_mpi_uint );
}
if( ( hex_len & 1 ) != 0 )
{
/* mbedtls_test_unhexify wants an even number of hex digits */
TEST_ASSERT( ascii2uc( *input, byte_start ) == 0 );
++byte_start;
++input;
--byte_len;
}
TEST_ASSERT( mbedtls_test_unhexify( byte_start,
byte_len,
input,
&byte_len ) == 0 );
mbedtls_mpi_core_bigendian_to_host( *pX, *plimbs );
return( 0 );
exit:
mbedtls_free( *pX );
return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
}
int mbedtls_test_read_mpi( mbedtls_mpi *X, const char *s )
{
int negative = 0;
/* Always set the sign bit to -1 if the input has a minus sign, even for 0.
* This creates an invalid representation, which mbedtls_mpi_read_string()
* avoids but we want to be able to create that in test data. */
if( s[0] == '-' )
{
++s;
negative = 1;
}
/* mbedtls_mpi_read_string() currently retains leading zeros.
* It always allocates at least one limb for the value 0. */
if( s[0] == 0 )
{
mbedtls_mpi_free( X );
return( 0 );
}
int ret = mbedtls_mpi_read_string( X, 16, s );
if( ret != 0 )
return( ret );
if( negative )
{
if( mbedtls_mpi_cmp_int( X, 0 ) == 0 )
++mbedtls_test_case_uses_negative_0;
X->s = -1;
}
return( 0 );
}
#endif

View file

@ -5,6 +5,7 @@
#include <test/helpers.h>
#include <test/macros.h>
#include <test/random.h>
#include <test/bignum_helpers.h>
#include <test/psa_crypto_helpers.h>
#include <stdlib.h>

View file

@ -619,7 +619,59 @@ exit:
/* END MERGE SLOT 5 */
/* BEGIN MERGE SLOT 6 */
/* BEGIN_CASE */
void mpi_mod_raw_canonical_to_modulus_rep( const char *input_N, int rep,
const char *input_A,
const char *input_X )
{
mbedtls_mpi_mod_modulus N;
mbedtls_mpi_mod_modulus_init( &N );
mbedtls_mpi_uint *A = NULL;
size_t A_limbs = 0;;
mbedtls_mpi_uint *X = NULL;
size_t X_limbs = 0;
TEST_EQUAL( 0, mbedtls_test_read_mpi_modulus( &N, input_N, rep ) );
TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &A, &A_limbs, input_A ) );
TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &X, &X_limbs, input_X ) );
TEST_EQUAL( 0, mbedtls_mpi_mod_raw_canonical_to_modulus_rep( A, &N ) );
ASSERT_COMPARE( A, A_limbs * sizeof( mbedtls_mpi_uint ),
X, X_limbs * sizeof( mbedtls_mpi_uint ) );
exit:
mbedtls_test_mpi_mod_modulus_free_with_limbs( &N );
mbedtls_free( A );
mbedtls_free( X );
}
/* END_CASE */
/* BEGIN_CASE */
void mpi_mod_raw_modulus_to_canonical_rep( const char *input_N, int rep,
const char *input_A,
const char *input_X )
{
mbedtls_mpi_mod_modulus N;
mbedtls_mpi_mod_modulus_init( &N );
mbedtls_mpi_uint *A = NULL;
size_t A_limbs = 0;
mbedtls_mpi_uint *X = NULL;
size_t X_limbs = 0;
TEST_EQUAL( 0, mbedtls_test_read_mpi_modulus( &N, input_N, rep ) );
TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &A, &A_limbs, input_A ) );
TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &X, &X_limbs, input_X ) );
TEST_EQUAL( 0, mbedtls_mpi_mod_raw_modulus_to_canonical_rep( A, &N ) );
ASSERT_COMPARE( A, A_limbs * sizeof( mbedtls_mpi_uint ),
X, X_limbs * sizeof( mbedtls_mpi_uint ) );
exit:
mbedtls_test_mpi_mod_modulus_free_with_limbs( &N );
mbedtls_free( A );
mbedtls_free( X );
}
/* END_CASE */
/* END MERGE SLOT 6 */
/* BEGIN MERGE SLOT 7 */

View file

@ -17,31 +17,55 @@ MPI core random basic: 2^30..2^129
mpi_core_random_basic:0x40000000:"0200000000000000000000000000000000":0
# Use the same data values for mpi_core_random_basic->NOT_ACCEPTABLE
# and for mpi_random_values where we want to return NOT_ACCEPTABLE but
# this isn't checked at runtime.
MPI core random basic: 2^28-1..2^28 (NOT_ACCEPTABLE)
mpi_core_random_basic:0x0fffffff:"10000000":MBEDTLS_ERR_MPI_NOT_ACCEPTABLE
# and for mpi_XXX_random_values where we want to return NOT_ACCEPTABLE
# but this isn't checked at runtime.
MPI core random basic: 2^28-1..2^28+1 (NOT_ACCEPTABLE)
mpi_core_random_basic:0x0fffffff:"10000001":MBEDTLS_ERR_MPI_NOT_ACCEPTABLE
MPI random legacy=core: 2^28-1..2^28 (NOT_ACCEPTABLE)
mpi_random_values:0x0fffffff:"10000000"
MPI random legacy=core: 2^28-1..2^28+1 (NOT_ACCEPTABLE)
mpi_legacy_random_values:0x0fffffff:"10000001"
MPI core random basic: 2^29-1..2^29 (NOT_ACCEPTABLE)
mpi_core_random_basic:0x1fffffff:"20000000":MBEDTLS_ERR_MPI_NOT_ACCEPTABLE
MPI random mod=core: 2^28-1..2^28+1 (NOT_ACCEPTABLE) (Mont)
mpi_mod_random_values:0x0fffffff:"10000001":MBEDTLS_MPI_MOD_REP_MONTGOMERY
MPI random legacy=core: 2^29-1..2^29 (NOT_ACCEPTABLE)
mpi_random_values:0x1fffffff:"20000000"
MPI random mod=core: 2^28-1..2^28+1 (NOT_ACCEPTABLE) (canon)
mpi_mod_random_values:0x0fffffff:"10000001":MBEDTLS_MPI_MOD_REP_OPT_RED
MPI core random basic: 2^30-1..2^30 (NOT_ACCEPTABLE)
mpi_core_random_basic:0x3fffffff:"40000000":MBEDTLS_ERR_MPI_NOT_ACCEPTABLE
MPI core random basic: 2^29-1..2^29+1 (NOT_ACCEPTABLE)
mpi_core_random_basic:0x1fffffff:"20000001":MBEDTLS_ERR_MPI_NOT_ACCEPTABLE
MPI random legacy=core: 2^30-1..2^30 (NOT_ACCEPTABLE)
mpi_random_values:0x3fffffff:"40000000"
MPI random legacy=core: 2^29-1..2^29+1 (NOT_ACCEPTABLE)
mpi_legacy_random_values:0x1fffffff:"20000001"
MPI core random basic: 2^31-1..2^31 (NOT_ACCEPTABLE)
mpi_core_random_basic:0x7fffffff:"80000000":MBEDTLS_ERR_MPI_NOT_ACCEPTABLE
MPI random mod=core: 2^29-1..2^29+1 (NOT_ACCEPTABLE) (Mont)
mpi_mod_random_values:0x1fffffff:"20000001":MBEDTLS_MPI_MOD_REP_MONTGOMERY
MPI random legacy=core: 2^31-1..2^31 (NOT_ACCEPTABLE)
mpi_random_values:0x7fffffff:"80000000"
MPI random mod=core: 2^29-1..2^29+1 (NOT_ACCEPTABLE) (canon)
mpi_mod_random_values:0x1fffffff:"20000001":MBEDTLS_MPI_MOD_REP_OPT_RED
MPI core random basic: 2^30-1..2^30+1 (NOT_ACCEPTABLE)
mpi_core_random_basic:0x3fffffff:"40000001":MBEDTLS_ERR_MPI_NOT_ACCEPTABLE
MPI random legacy=core: 2^30-1..2^30+1 (NOT_ACCEPTABLE)
mpi_legacy_random_values:0x3fffffff:"40000001"
MPI random mod=core: 2^30-1..2^30+1 (NOT_ACCEPTABLE) (Mont)
mpi_mod_random_values:0x3fffffff:"40000001":MBEDTLS_MPI_MOD_REP_MONTGOMERY
MPI random mod=core: 2^30-1..2^30+1 (NOT_ACCEPTABLE) (canon)
mpi_mod_random_values:0x3fffffff:"40000001":MBEDTLS_MPI_MOD_REP_OPT_RED
MPI core random basic: 2^31-1..2^31+1 (NOT_ACCEPTABLE)
mpi_core_random_basic:0x7fffffff:"80000001":MBEDTLS_ERR_MPI_NOT_ACCEPTABLE
MPI random legacy=core: 2^31-1..2^31+1 (NOT_ACCEPTABLE)
mpi_legacy_random_values:0x7fffffff:"80000001"
MPI random mod=core: 2^31-1..2^31+1 (NOT_ACCEPTABLE) (Mont)
mpi_mod_random_values:0x7fffffff:"80000001":MBEDTLS_MPI_MOD_REP_MONTGOMERY
MPI random mod=core: 2^31-1..2^31+1 (NOT_ACCEPTABLE) (canon)
mpi_mod_random_values:0x7fffffff:"80000001":MBEDTLS_MPI_MOD_REP_OPT_RED
MPI random in range: 1..2
mpi_random_many:1:"02":1000
@ -214,22 +238,103 @@ MPI random bad arguments: min > N = 1, 0 limb in upper bound
mpi_random_fail:2:"000000000000000001":MBEDTLS_ERR_MPI_BAD_INPUT_DATA
MPI random legacy=core: 0..1
mpi_random_values:0:"01"
mpi_legacy_random_values:0:"01"
MPI random legacy=core: 0..2
mpi_random_values:0:"02"
mpi_legacy_random_values:0:"02"
MPI random legacy=core: 1..2
mpi_random_values:1:"02"
mpi_legacy_random_values:1:"02"
MPI random legacy=core: 2^30..2^31
mpi_random_values:0x40000000:"80000000"
mpi_legacy_random_values:0x40000000:"80000000"
MPI random legacy=core: 2^31-1..2^32-1
mpi_random_values:0x7fffffff:"ffffffff"
mpi_legacy_random_values:0x7fffffff:"ffffffff"
MPI random legacy=core: 0..2^256
mpi_random_values:0:"010000000000000000000000000000000000000000000000000000000000000000"
mpi_legacy_random_values:0:"010000000000000000000000000000000000000000000000000000000000000000"
MPI random legacy=core: 0..2^256+1
mpi_random_values:0:"010000000000000000000000000000000000000000000000000000000000000001"
mpi_legacy_random_values:0:"010000000000000000000000000000000000000000000000000000000000000001"
MPI random mod=core: 0..1 (Mont)
mpi_mod_random_values:0:"01":MBEDTLS_MPI_MOD_REP_MONTGOMERY
MPI random mod=core: 0..1 (canon)
mpi_mod_random_values:0:"01":MBEDTLS_MPI_MOD_REP_OPT_RED
MPI random mod=core: 0..3 (Mont)
mpi_mod_random_values:0:"03":MBEDTLS_MPI_MOD_REP_MONTGOMERY
MPI random mod=core: 0..3 (canon)
mpi_mod_random_values:0:"03":MBEDTLS_MPI_MOD_REP_OPT_RED
MPI random mod=core: 1..3 (Mont)
mpi_mod_random_values:1:"03":MBEDTLS_MPI_MOD_REP_MONTGOMERY
MPI random mod=core: 1..3 (canon)
mpi_mod_random_values:1:"03":MBEDTLS_MPI_MOD_REP_OPT_RED
MPI random mod=core: 2^30..2^31-1 (Mont)
mpi_mod_random_values:0x40000000:"7fffffff":MBEDTLS_MPI_MOD_REP_MONTGOMERY
MPI random mod=core: 2^30..2^31-1 (canon)
mpi_mod_random_values:0x40000000:"7fffffff":MBEDTLS_MPI_MOD_REP_OPT_RED
MPI random mod=core: 2^31-1..2^32-1 (Mont)
mpi_mod_random_values:0x7fffffff:"ffffffff":MBEDTLS_MPI_MOD_REP_MONTGOMERY
MPI random mod=core: 2^31-1..2^32-1 (canon)
mpi_mod_random_values:0x7fffffff:"ffffffff":MBEDTLS_MPI_MOD_REP_OPT_RED
MPI random mod=core: 0..2^256+1 (Mont)
mpi_mod_random_values:0:"010000000000000000000000000000000000000000000000000000000000000001":MBEDTLS_MPI_MOD_REP_MONTGOMERY
MPI random mod=core: 0..2^256+1 (canon)
mpi_mod_random_values:0:"010000000000000000000000000000000000000000000000000000000000000001":MBEDTLS_MPI_MOD_REP_OPT_RED
MPI random mod validation: 1 limb, good, 0..1
mpi_mod_random_validation:0:"1":0:0
MPI random mod validation: 1 limb, good, 1..3
mpi_mod_random_validation:1:"3":0:0
MPI random mod validation: 1 limb, good, 2..3
mpi_mod_random_validation:2:"3":0:0
MPI random mod validation: 1 limb, good, 3..5
mpi_mod_random_validation:3:"5":0:0
MPI random mod validation: 1 limb, good, 4..5
mpi_mod_random_validation:4:"5":0:0
MPI random mod validation: 1 limb, good, 5..7
mpi_mod_random_validation:5:"7":0:0
MPI random mod validation: 1 limb, good, 6..7
mpi_mod_random_validation:6:"7":0:0
MPI random mod validation: 1 limb, good, 0..0x123
mpi_mod_random_validation:0:"123":0:0
MPI random mod validation: 2+ limbs, good
mpi_mod_random_validation:0:"01234567890123456789":0:0
MPI random mod validation: 1 limb, output null
mpi_mod_random_validation:0:"123":-1:MBEDTLS_ERR_MPI_BAD_INPUT_DATA
MPI random mod validation: 1 limb, output too large
mpi_mod_random_validation:0:"123":1:MBEDTLS_ERR_MPI_BAD_INPUT_DATA
MPI random mod validation: 2+ limbs, output too small
mpi_mod_random_validation:0:"01234567890123456789":-1:MBEDTLS_ERR_MPI_BAD_INPUT_DATA
MPI random mod validation: 2+ limbs, output too large
mpi_mod_random_validation:0:"01234567890123456789":1:MBEDTLS_ERR_MPI_BAD_INPUT_DATA
MPI random mod validation: min == upper bound
mpi_mod_random_validation:0x123:"123":-1:MBEDTLS_ERR_MPI_BAD_INPUT_DATA
MPI random mod validation: min > upper bound
mpi_mod_random_validation:0x124:"123":-1:MBEDTLS_ERR_MPI_BAD_INPUT_DATA

View file

@ -3,11 +3,44 @@
* functions. Due to the complexity of how these functions are tested,
* we test all the layers in a single test suite, unlike the way other
* functions are tested with each layer in its own test suite.
*
* Test strategy
* =============
*
* There are three main goals for testing random() functions:
* - Parameter validation.
* - Correctness of outputs (well-formed, in range).
* - Distribution of outputs.
*
* We test parameter validation in a standard way, with unit tests with
* positive and negative cases:
* - mbedtls_mpi_core_random(): negative cases for mpi_core_random_basic.
* - mbedtls_mpi_mod_raw_random(), mbedtls_mpi_mod_random(): negative
* cases for mpi_mod_random_validation.
* - mbedtls_mpi_random(): mpi_random_fail.
*
* We test the correctness of outputs in positive tests:
* - mbedtls_mpi_core_random(): positive cases for mpi_core_random_basic,
* and mpi_random_many.
* - mbedtls_mpi_mod_raw_random(), mbedtls_mpi_mod_random(): tested indirectly
* via mpi_mod_random_values.
* - mbedtls_mpi_random(): mpi_random_sizes, plus indirectly via
* mpi_random_values.
*
* We test the distribution of outputs only for mbedtls_mpi_core_random(),
* in mpi_random_many, which runs the function multiple times. This also
* helps in validating the output range, through test cases with a small
* range where any output out of range would be very likely to lead to a
* test failure. For the other functions, we validate the distribution
* indirectly by testing that these functions consume the random generator
* in the same way as mbedtls_mpi_core_random(). This is done in
* mpi_mod_random_values and mpi_legacy_random_values.
*/
#include "mbedtls/bignum.h"
#include "mbedtls/entropy.h"
#include "bignum_core.h"
#include "bignum_mod_raw.h"
#include "constant_time_internal.h"
/* This test suite only manipulates non-negative bignums. */
@ -110,7 +143,7 @@ exit:
/* END_CASE */
/* BEGIN_CASE */
void mpi_random_values( int min, char *max_hex )
void mpi_legacy_random_values( int min, char *max_hex )
{
/* Same RNG as in mpi_core_random_basic */
mbedtls_test_rnd_pseudo_info rnd_core = rnd_pseudo_seed;
@ -158,6 +191,77 @@ exit:
}
/* END_CASE */
/* BEGIN_CASE */
void mpi_mod_random_values( int min, char *max_hex, int rep )
{
/* Same RNG as in mpi_core_random_basic */
mbedtls_test_rnd_pseudo_info rnd_core = rnd_pseudo_seed;
mbedtls_test_rnd_pseudo_info rnd_mod_raw;
memcpy( &rnd_mod_raw, &rnd_core, sizeof( rnd_core ) );
mbedtls_test_rnd_pseudo_info rnd_mod;
memcpy( &rnd_mod, &rnd_core, sizeof( rnd_core ) );
mbedtls_mpi_uint *R_core = NULL;
mbedtls_mpi_uint *R_mod_raw = NULL;
mbedtls_mpi_uint *R_mod_digits = NULL;
mbedtls_mpi_mod_residue R_mod;
mbedtls_mpi_mod_modulus N;
mbedtls_mpi_mod_modulus_init( &N );
TEST_EQUAL( mbedtls_test_read_mpi_modulus( &N, max_hex, rep ), 0 );
ASSERT_ALLOC( R_core, N.limbs );
ASSERT_ALLOC( R_mod_raw, N.limbs );
ASSERT_ALLOC( R_mod_digits, N.limbs );
TEST_EQUAL( mbedtls_mpi_mod_residue_setup( &R_mod, &N,
R_mod_digits, N.limbs ),
0 );
/* Call the core and mod random() functions with the same random stream. */
int core_ret = mbedtls_mpi_core_random( R_core,
min, N.p, N.limbs,
mbedtls_test_rnd_pseudo_rand,
&rnd_core );
int mod_raw_ret = mbedtls_mpi_mod_raw_random( R_mod_raw,
min, &N,
mbedtls_test_rnd_pseudo_rand,
&rnd_mod_raw );
int mod_ret = mbedtls_mpi_mod_random( &R_mod,
min, &N,
mbedtls_test_rnd_pseudo_rand,
&rnd_mod );
/* They must return the same status, and, on success, output the
* same number, with the same limb count. */
TEST_EQUAL( core_ret, mod_raw_ret );
TEST_EQUAL( core_ret, mod_ret );
if( core_ret == 0 )
{
TEST_EQUAL( mbedtls_mpi_mod_raw_modulus_to_canonical_rep( R_mod_raw, &N ),
0 );
ASSERT_COMPARE( R_core, N.limbs * ciL,
R_mod_raw, N.limbs * ciL );
TEST_EQUAL( mbedtls_mpi_mod_raw_modulus_to_canonical_rep( R_mod_digits, &N ),
0 );
ASSERT_COMPARE( R_core, N.limbs * ciL,
R_mod_digits, N.limbs * ciL );
}
/* Also check that they have consumed the RNG in the same way. */
/* This may theoretically fail on rare platforms with padding in
* the structure! If this is a problem in practice, change to a
* field-by-field comparison. */
ASSERT_COMPARE( &rnd_core, sizeof( rnd_core ),
&rnd_mod_raw, sizeof( rnd_mod_raw ) );
ASSERT_COMPARE( &rnd_core, sizeof( rnd_core ),
&rnd_mod, sizeof( rnd_mod ) );
exit:
mbedtls_test_mpi_mod_modulus_free_with_limbs( &N );
mbedtls_free( R_core );
mbedtls_free( R_mod_raw );
mbedtls_free( R_mod_digits );
}
/* END_CASE */
/* BEGIN_CASE */
void mpi_random_many( int min, char *bound_hex, int iterations )
{
@ -311,6 +415,64 @@ exit:
}
/* END_CASE */
/* BEGIN_CASE */
void mpi_mod_random_validation( int min, char *bound_hex,
int result_limbs_delta,
int expected_ret )
{
mbedtls_mpi_uint *result_digits = NULL;
mbedtls_mpi_mod_modulus N;
mbedtls_mpi_mod_modulus_init( &N );
TEST_EQUAL( mbedtls_test_read_mpi_modulus( &N, bound_hex,
MBEDTLS_MPI_MOD_REP_OPT_RED ),
0 );
size_t result_limbs = N.limbs + result_limbs_delta;
ASSERT_ALLOC( result_digits, result_limbs );
/* Build a reside that might not match the modulus, to test that
* the library function rejects that as expected. */
mbedtls_mpi_mod_residue result = {result_digits, result_limbs};
TEST_EQUAL( mbedtls_mpi_mod_random( &result, min, &N,
mbedtls_test_rnd_std_rand, NULL ),
expected_ret );
if( expected_ret == 0 )
{
/* Success should only be expected when the result has the same
* size as the modulus, otherwise it's a mistake in the test data. */
TEST_EQUAL( result_limbs, N.limbs );
/* Sanity check: check that the result is in range */
TEST_EQUAL( mbedtls_mpi_core_lt_ct( result_digits, N.p, N.limbs ),
1 );
/* Check result >= min (changes result) */
TEST_EQUAL( mbedtls_mpi_core_sub_int( result_digits, result_digits, min,
result_limbs ),
0 );
}
/* When the result has the right number of limbs, also test mod_raw
* (for which this is an unchecked precondition). */
if( result_limbs_delta == 0 )
{
TEST_EQUAL( mbedtls_mpi_mod_raw_random( result_digits, min, &N,
mbedtls_test_rnd_std_rand, NULL ),
expected_ret );
if( expected_ret == 0 )
{
TEST_EQUAL( mbedtls_mpi_core_lt_ct( result_digits, N.p, N.limbs ),
1 );
TEST_EQUAL( mbedtls_mpi_core_sub_int( result_digits, result.p, min,
result_limbs ),
0 );
}
}
exit:
mbedtls_test_mpi_mod_modulus_free_with_limbs( &N );
mbedtls_free( result_digits );
}
/* END_CASE */
/* BEGIN_CASE */
void mpi_random_fail( int min, data_t *bound_bytes, int expected_ret )
{