in unittest/lib/testArithmetic.cpp [3672:3757]
VOID testCompositeModInv()
{
// We just check that ModInv works properly with weird inputs
PSYMCRYPT_MODULUS pMod = SymCryptModulusAllocate( 1 );
PSYMCRYPT_MODELEMENT pEl = SymCryptModElementAllocate( pMod );
PSYMCRYPT_MODELEMENT pInv = SymCryptModElementAllocate( pMod );
SIZE_T cbScratch = 1 << 20;
PBYTE pbScratch = (PBYTE) SymCryptCallbackAlloc( cbScratch ); // this allocator provides the necessary alignment
SYMCRYPT_ERROR scError;
CHECK( pMod != NULL && pEl != NULL && pbScratch != NULL, "Out of memory" );
for( int cnt = 0; cnt < 1000; cnt++ )
{
UINT32 mod = (UINT32) g_rng.sizet( 2, (1<<16) );
// Must be 2 or odd to even pass the sanity checks for prime moduli
if( mod != 2 )
{
mod |= 1;
}
UINT32 x = (UINT32) g_rng.sizet( mod );
CHECK( x < mod, "?" );
SymCryptIntSetValueUint32( mod, SymCryptIntFromModulus( pMod ) );
// Our current code requires the PRIME and DATA_PUBLIC flags.
UINT32 modFlags = 0;
BYTE b = g_rng.byte();
/* Code to generat random flags (for when we support them)
if( b & 1 )
{
if( b & 2 )
{
modFlags |= SYMCRYPT_FLAG_DATA_PUBLIC;
} else {
modFlags |= SYMCRYPT_FLAG_MODULUS_PARITY_PUBLIC;
}
}
if( (b & 4) != 0 && (mod == 2 || (mod & 1) != 0 ) )
{
// We deliberately limit ourselves to only checking for oddness in primes
// as our RSA/DSA code doesn't check for primality when receiving parameters from
// outside parties.
modFlags |= SYMCRYPT_FLAG_MODULUS_PRIME;
}
*/
modFlags = SYMCRYPT_FLAG_DATA_PUBLIC | SYMCRYPT_FLAG_MODULUS_PRIME;
SymCryptIntToModulus( SymCryptIntFromModulus( pMod ), pMod, g_rng.byte(), modFlags, pbScratch, cbScratch );
SymCryptModElementSetValueUint32( x, pMod, pEl, pbScratch, cbScratch );
// We must use DATA_PUBLIC, otherwise the modinv routine blinds the input which
// can introduce errors when the modulus isn't prime, and that makes our test
// less sensitive.
UINT32 opFlags = SYMCRYPT_FLAG_DATA_PUBLIC;
scError = SymCryptModInv( pMod, pEl, pInv, opFlags, pbScratch, cbScratch );
// Check that the result is correct when we get no error
if( scError == SYMCRYPT_NO_ERROR )
{
SymCryptModMul( pMod, pEl, pInv, pInv, pbScratch, cbScratch );
SYMCRYPT_ERROR scError2 = SymCryptModElementGetValue( pMod, pInv, &b, 1, SYMCRYPT_NUMBER_FORMAT_LSB_FIRST, pbScratch, cbScratch );
CHECK( scError2 == SYMCRYPT_NO_ERROR && b == 1, "ModInv * input is not 1" );
}
BOOL coPrime = GcdUint32( x, mod ) == 1;
CHECK( coPrime || scError != SYMCRYPT_NO_ERROR, "No error for modinv that does not exist" );
CHECK( (modFlags & SYMCRYPT_FLAG_DATA_PUBLIC) == 0 ||
(modFlags & SYMCRYPT_FLAG_MODULUS_PRIME) == 0 ||
!coPrime ||
scError == SYMCRYPT_NO_ERROR, "Unexpected error for modinverse" );
}
SymCryptWipe(pbScratch,cbScratch);
SymCryptCallbackFree(pbScratch);
SymCryptModElementFree( pMod, pEl );
SymCryptModElementFree( pMod, pInv );
SymCryptModulusFree( pMod );
}