Merge pull request #6747 from gilles-peskine-arm/bignum-mod-random
Bignum mod random
This commit is contained in:
commit
2fcb4c1d06
15 changed files with 909 additions and 175 deletions
|
@ -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 );
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
118
tests/include/test/bignum_helpers.h
Normal file
118
tests/include/test/bignum_helpers.h
Normal 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 */
|
|
@ -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 */
|
||||
|
|
|
@ -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
142
tests/src/bignum_helpers.c
Normal 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 */
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 )
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue