#include "precomp.h"
VOID
SYMCRYPT_CALL
SymCryptMontgomeryFillScratchSpaces(_In_ PSYMCRYPT_ECURVE pCurve)
{
UINT32 nDigits = SymCryptDigitsFromBits( pCurve->FModBitsize );
UINT32 nBytes = SymCryptSizeofModElementFromModulus( pCurve->FMod );
UINT32 nCommon = SYMCRYPT_MAX( SymCryptSizeofIntFromDigits( nDigits ), SYMCRYPT_MAX( SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( nDigits ), SYMCRYPT_SCRATCH_BYTES_FOR_MODINV( nDigits ) ) );
UINT32 cbModElement = pCurve->cbModElement;
UINT32 nDigitsFieldLength = pCurve->FModDigits;
pCurve->cbScratchCommon = nCommon;
pCurve->cbScratchScalar =
SymCryptSizeofIntFromDigits(nDigits) +
6 * nBytes +
nCommon;
pCurve->cbScratchScalarMulti = 0;
pCurve->cbScratchGetSetValue =
SymCryptSizeofEcpointEx( cbModElement, SYMCRYPT_ECPOINT_FORMAT_MAX_LENGTH ) +
2 * cbModElement +
SYMCRYPT_MAX( SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( nDigitsFieldLength ),
SYMCRYPT_SCRATCH_BYTES_FOR_MODINV( nDigitsFieldLength ) );
pCurve->cbScratchGetSetValue = SYMCRYPT_MAX( pCurve->cbScratchGetSetValue, SymCryptSizeofIntFromDigits( nDigits ) );
pCurve->cbScratchEckey =
SYMCRYPT_MAX( cbModElement + SymCryptSizeofIntFromDigits(SymCryptEcurveDigitsofScalarMultiplier(pCurve)),
SymCryptSizeofEcpointFromCurve( pCurve ) ) +
SYMCRYPT_MAX( pCurve->cbScratchScalar, pCurve->cbScratchGetSetValue );
}
VOID
SYMCRYPT_CALL
SymCryptMontgomerySetDistinguished(
_In_ PCSYMCRYPT_ECURVE pCurve,
_Out_ PSYMCRYPT_ECPOINT poDst,
_Out_writes_bytes_( cbScratch )
PBYTE pbScratch,
SIZE_T cbScratch )
{
SYMCRYPT_ASSERT( SYMCRYPT_CURVE_IS_MONTGOMERY_TYPE(pCurve) );
SYMCRYPT_ASSERT( SymCryptEcurveIsSame(pCurve, poDst->pCurve) );
UNREFERENCED_PARAMETER( pbScratch );
UNREFERENCED_PARAMETER( cbScratch );
SymCryptEcpointCopy( pCurve, pCurve->G, poDst );
}
UINT32
SYMCRYPT_CALL
SymCryptMontgomeryIsEqual(
_In_ PCSYMCRYPT_ECURVE pCurve,
_In_ PCSYMCRYPT_ECPOINT poSrc1,
_In_ PCSYMCRYPT_ECPOINT poSrc2,
UINT32 flags,
_Out_writes_bytes_( cbScratch )
PBYTE pbScratch,
SIZE_T cbScratch)
{
PSYMCRYPT_MODELEMENT peTemp[2];
PSYMCRYPT_MODELEMENT peSrc1X, peSrc1Z;
PSYMCRYPT_MODELEMENT peSrc2X, peSrc2Z;
PSYMCRYPT_MODULUS pmMod = pCurve->FMod;
SIZE_T nBytes;
SYMCRYPT_ASSERT( (flags & ~(SYMCRYPT_FLAG_ECPOINT_EQUAL|SYMCRYPT_FLAG_ECPOINT_NEG_EQUAL)) == 0 );
SYMCRYPT_ASSERT( SYMCRYPT_CURVE_IS_MONTGOMERY_TYPE(pCurve) );
SYMCRYPT_ASSERT( SymCryptEcurveIsSame(pCurve, poSrc1->pCurve) && SymCryptEcurveIsSame(pCurve, poSrc2->pCurve) );
SYMCRYPT_ASSERT( cbScratch >= SYMCRYPT_INTERNAL_SCRATCH_BYTES_FOR_COMMON_ECURVE_OPERATIONS( pCurve ) );
UNREFERENCED_PARAMETER( flags );
nBytes = SymCryptSizeofModElementFromModulus( pmMod );
SYMCRYPT_ASSERT( cbScratch >= 2 * nBytes );
for (UINT32 i = 0; i < 2; ++i)
{
peTemp[i] = SymCryptModElementCreate( pbScratch, nBytes, pmMod );
pbScratch += nBytes;
cbScratch -= nBytes;
}
peSrc1X = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 0, pCurve, poSrc1 );
peSrc1Z = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 1, pCurve, poSrc1 );
peSrc2X = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 0, pCurve, poSrc2 );
peSrc2Z = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 1, pCurve, poSrc2 );
SymCryptModMul( pmMod, peSrc1X, peSrc2Z, peTemp[0], pbScratch, cbScratch );
SymCryptModMul( pmMod, peSrc2X, peSrc1Z, peTemp[1], pbScratch, cbScratch );
return SymCryptModElementIsEqual( pmMod, peTemp[0], peTemp[1] );
}
UINT32
SYMCRYPT_CALL
SymCryptMontgomeryIsZero(
_In_ PCSYMCRYPT_ECURVE pCurve,
_In_ PCSYMCRYPT_ECPOINT poSrc,
_Out_writes_bytes_( cbScratch )
PBYTE pbScratch,
SIZE_T cbScratch )
{
PCSYMCRYPT_MODULUS FMod = pCurve->FMod;
PSYMCRYPT_MODELEMENT peZ = NULL;
SYMCRYPT_ASSERT( SYMCRYPT_CURVE_IS_MONTGOMERY_TYPE(pCurve) );
SYMCRYPT_ASSERT( SymCryptEcurveIsSame(pCurve, poSrc->pCurve) );
UNREFERENCED_PARAMETER( pbScratch );
UNREFERENCED_PARAMETER( cbScratch );
peZ = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 1, pCurve, poSrc );
return SymCryptModElementIsZero( FMod, peZ );
}
VOID
SymCryptMontgomeryDoubleAndAdd(
_In_ PCSYMCRYPT_MODULUS pmMod,
_In_ PCSYMCRYPT_MODELEMENT peX1,
_In_opt_ PCSYMCRYPT_MODELEMENT peZ1,
_In_ PCSYMCRYPT_MODELEMENT peA24,
_Inout_ PSYMCRYPT_MODELEMENT peX2,
_Inout_ PSYMCRYPT_MODELEMENT peZ2,
_Inout_ PSYMCRYPT_MODELEMENT peX3,
_Inout_ PSYMCRYPT_MODELEMENT peZ3,
_Inout_ PSYMCRYPT_MODELEMENT peTemp1,
_Inout_ PSYMCRYPT_MODELEMENT peTemp2,
_Out_writes_bytes_( cbScratch ) PBYTE pbScratch,
SIZE_T cbScratch)
{
SymCryptModAdd( pmMod, peX2, peZ2, peTemp1, pbScratch, cbScratch );
SymCryptModSub( pmMod, peX2, peZ2, peZ2, pbScratch, cbScratch );
SymCryptModAdd( pmMod, peX3, peZ3, peTemp2, pbScratch, cbScratch );
SymCryptModSub( pmMod, peX3, peZ3, peZ3, pbScratch, cbScratch );
SymCryptModMul( pmMod, peTemp2, peZ2, peX3, pbScratch, cbScratch );
SymCryptModMul( pmMod, peZ3, peTemp1, peZ3, pbScratch, cbScratch );
SymCryptModSquare( pmMod, peTemp1, peX2, pbScratch, cbScratch );
SymCryptModSquare( pmMod, peZ2, peTemp1, pbScratch, cbScratch );
SymCryptModSub( pmMod, peX2, peTemp1, peTemp2, pbScratch, cbScratch );
SymCryptModMul( pmMod, peX2, peTemp1, peX2, pbScratch, cbScratch );
SymCryptModMul( pmMod, peA24, peTemp2, peZ2, pbScratch, cbScratch );
SymCryptModAdd( pmMod, peTemp1, peZ2, peZ2, pbScratch, cbScratch );
SymCryptModMul( pmMod, peTemp2, peZ2, peZ2, pbScratch, cbScratch );
SymCryptModAdd( pmMod, peZ3, peX3, peTemp1, pbScratch, cbScratch );
SymCryptModSub( pmMod, peZ3, peX3, peZ3, pbScratch, cbScratch );
SymCryptModSquare( pmMod, peTemp1, peX3, pbScratch, cbScratch );
if (peZ1 != NULL)
{
SymCryptModMul( pmMod, peZ1, peX3, peX3, pbScratch, cbScratch );
}
SymCryptModSquare( pmMod, peZ3, peZ3, pbScratch, cbScratch );
SymCryptModMul( pmMod, peX1, peZ3, peZ3, pbScratch, cbScratch );
}
SYMCRYPT_ERROR
SYMCRYPT_CALL
SymCryptMontgomeryPointScalarMul(
_In_ PCSYMCRYPT_ECURVE pCurve,
_In_ PCSYMCRYPT_INT piScalar,
_In_opt_
PCSYMCRYPT_ECPOINT poSrc,
UINT32 flags,
_Out_ PSYMCRYPT_ECPOINT poDst,
_Out_writes_bytes_( cbScratch )
PBYTE pbScratch,
SIZE_T cbScratch)
{
SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
PSYMCRYPT_MODULUS pmMod;
PSYMCRYPT_MODELEMENT peX1, peZ1, peA24, peX2, peZ2, peX3, peZ3, peTemp1, peTemp2, peResult;
UINT32 i, nBytes, nDigits, cond, newcond, nCommon;
PBYTE pBegin;
SIZE_T cbAllScratch;
SYMCRYPT_ASSERT( SYMCRYPT_CURVE_IS_MONTGOMERY_TYPE(pCurve) );
SYMCRYPT_ASSERT( (poSrc == NULL || SymCryptEcurveIsSame(pCurve, poSrc->pCurve)) && SymCryptEcurveIsSame(pCurve, poDst->pCurve) );
if ((flags & ~SYMCRYPT_FLAG_ECC_LL_COFACTOR_MUL) != 0)
{
scError = SYMCRYPT_INVALID_ARGUMENT;
goto cleanup;
}
if (poSrc == NULL)
{
poSrc = pCurve->G;
}
pmMod = pCurve->FMod;
nDigits = SymCryptDigitsFromBits( pCurve->FModBitsize );
nBytes = SymCryptSizeofModElementFromModulus( pmMod );
nCommon = SYMCRYPT_MAX( SymCryptSizeofIntFromDigits(nDigits), SYMCRYPT_MAX(SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS(nDigits), SYMCRYPT_SCRATCH_BYTES_FOR_MODINV(nDigits)));
SYMCRYPT_ASSERT( cbScratch >= 6 * nBytes + nCommon );
cbAllScratch = cbScratch;
pBegin = pbScratch;
peX2 = SymCryptModElementCreate( pbScratch, nBytes, pmMod );
pbScratch += nBytes;
peZ2 = SymCryptModElementCreate( pbScratch, nBytes, pmMod );
pbScratch += nBytes;
peX3 = SymCryptModElementCreate( pbScratch, nBytes, pmMod );
pbScratch += nBytes;
peZ3 = SymCryptModElementCreate( pbScratch, nBytes, pmMod );
pbScratch += nBytes;
peTemp1 = SymCryptModElementCreate( pbScratch, nBytes, pmMod );
pbScratch += nBytes;
peTemp2 = SymCryptModElementCreate( pbScratch, nBytes, pmMod );
pbScratch += nBytes;
cbScratch = nCommon;
peA24 = pCurve->A;
peX1 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 0, pCurve, poSrc);
peZ1 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 1, pCurve, poSrc);
SymCryptModElementSetValueUint32( 1, pmMod, peX2, pbScratch, cbScratch );
SymCryptModElementSetValueUint32( 0, pmMod, peZ2, pbScratch, cbScratch );
SymCryptModElementCopy( pmMod, peX1, peX3 );
SymCryptModElementCopy( pmMod, peZ1, peZ3 );
if ( poSrc->normalized )
{
peZ1 = NULL;
}
i = (pCurve->GOrdBitsize + pCurve->coFactorPower);
cond = 0;
while ( i != 0 )
{
i--;
newcond = SymCryptIntGetBit( piScalar, i );
cond ^= newcond;
SymCryptModElementConditionalSwap( pmMod, peX2, peX3, cond);
SymCryptModElementConditionalSwap( pmMod, peZ2, peZ3, cond);
cond = newcond;
SymCryptMontgomeryDoubleAndAdd( pmMod, peX1, peZ1, peA24, peX2, peZ2, peX3, peZ3, peTemp1, peTemp2, pbScratch, cbScratch );
}
SymCryptModElementConditionalSwap( pmMod, peX2, peX3, cond);
SymCryptModElementConditionalSwap( pmMod, peZ2, peZ3, cond);
if ((flags & SYMCRYPT_FLAG_ECC_LL_COFACTOR_MUL) != 0)
{
i = pCurve->coFactorPower;
while (i!=0)
{
i--;
SymCryptMontgomeryDoubleAndAdd( pmMod, peX1, NULL, peA24, peX2, peZ2, peX3, peZ3, peTemp1, peTemp2, pbScratch, cbScratch );
}
}
peResult = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 0, pCurve, poDst);
SymCryptModElementCopy( pCurve->FMod, peX2, peResult );
peResult = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 1, pCurve, poDst);
SymCryptModElementCopy( pCurve->FMod, peZ2, peResult );
poDst->normalized = FALSE;
scError = SYMCRYPT_NO_ERROR;
cleanup:
return scError;
}