#include "precomp.h"
VOID
SYMCRYPT_CALL
SymCryptPrecomputation(
_In_ PCSYMCRYPT_ECURVE pCurve,
UINT32 nPoints,
_In_reads_( SYMCRYPT_ECURVE_SW_MAX_NPRECOMP_POINTS )
PSYMCRYPT_ECPOINT * poPIs,
_Out_ PSYMCRYPT_ECPOINT poQ,
_Out_writes_bytes_( cbScratch )
PBYTE pbScratch,
SIZE_T cbScratch )
{
SYMCRYPT_ASSERT( SymCryptEcurveIsSame(pCurve, poQ->pCurve) );
SymCryptEcpointDouble( pCurve, poPIs[0], poQ, 0, pbScratch, cbScratch );
for (UINT32 i=1; i<nPoints; i++)
{
SymCryptEcpointAddDiffNonZero( pCurve, poQ, poPIs[i-1], poPIs[i], pbScratch, cbScratch );
}
}
VOID
SYMCRYPT_CALL
SymCryptOfflinePrecomputation(
_In_ PSYMCRYPT_ECURVE pCurve,
_Out_writes_bytes_( cbScratch )
PBYTE pbScratch,
SIZE_T cbScratch )
{
PSYMCRYPT_ECPOINT poQ = NULL;
UINT32 cbEcpoint = SymCryptSizeofEcpointFromCurve( pCurve );
SYMCRYPT_ASSERT( cbScratch >= cbEcpoint + SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( pCurve->FModDigits ) );
poQ = SymCryptEcpointCreate( pbScratch, cbEcpoint, pCurve );
SYMCRYPT_ASSERT( poQ != NULL );
pbScratch += cbEcpoint;
cbScratch -= cbEcpoint;
SymCryptPrecomputation(
pCurve,
pCurve->info.sw.nPrecompPoints,
pCurve->info.sw.poPrecompPoints,
poQ,
pbScratch,
cbScratch );
}
#define DELTA_MASK( _index, _target) SYMCRYPT_MASK32_ZERO( (_index) ^ (_target) )
SYMCRYPT_ERROR
SYMCRYPT_CALL
SymCryptEcpointScalarMulFixedWindow(
_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_MEMORY_ALLOCATION_FAILURE;
PCSYMCRYPT_MODULUS FMod = pCurve->FMod;
UINT32 i, j;
UINT32 w = pCurve->info.sw.window;
UINT32 nPrecompPoints = pCurve->info.sw.nPrecompPoints;
UINT32 nRecodedDigits = ((pCurve->GOrdBitsize + w - 2) / (w-1)) + 1;
UINT32 fZero = 0;
UINT32 fEven = 0;
UINT32 indexMask = 0;
BOOLEAN bPrecompOffline = FALSE;
PSYMCRYPT_MODELEMENT peT = NULL;
PSYMCRYPT_ECPOINT poPIs[SYMCRYPT_ECURVE_SW_MAX_NPRECOMP_POINTS] = { 0 };
PSYMCRYPT_ECPOINT poQ = NULL;
PSYMCRYPT_ECPOINT poTmp = NULL;
PSYMCRYPT_INT piRem = NULL;
PSYMCRYPT_INT piTmp = NULL;
PUINT32 absofKIs = NULL;
PUINT32 sigofKIs = NULL;
PSYMCRYPT_MODELEMENT peQX = NULL;
PSYMCRYPT_MODELEMENT peQY = NULL;
PSYMCRYPT_MODELEMENT peQZ = NULL;
SIZE_T cbEcpoint = SymCryptSizeofEcpointFromCurve( pCurve );
SIZE_T cbScalar = SymCryptSizeofIntFromDigits( pCurve->GOrdDigits );
if ((flags & ~SYMCRYPT_FLAG_ECC_LL_COFACTOR_MUL) != 0)
{
scError = SYMCRYPT_INVALID_ARGUMENT;
goto exit;
}
if (poSrc == NULL)
{
poSrc = pCurve->G;
bPrecompOffline = TRUE;
}
SYMCRYPT_ASSERT( SYMCRYPT_CURVE_IS_SHORT_WEIERSTRASS_TYPE(pCurve) ||
SYMCRYPT_CURVE_IS_TWISTED_EDWARDS_TYPE(pCurve) );
SYMCRYPT_ASSERT( SymCryptEcurveIsSame(pCurve, poSrc->pCurve) && SymCryptEcurveIsSame(pCurve, poDst->pCurve) );
SYMCRYPT_ASSERT( cbScratch >= SYMCRYPT_INTERNAL_SCRATCH_BYTES_FOR_SCALAR_ECURVE_OPERATIONS(pCurve, 1) );
SYMCRYPT_ASSERT( cbScratch >=
pCurve->cbModElement +
(nPrecompPoints+2)*cbEcpoint +
2*cbScalar +
((2*nRecodedDigits*sizeof(UINT32) + SYMCRYPT_ASYM_ALIGN_VALUE - 1)/SYMCRYPT_ASYM_ALIGN_VALUE )*SYMCRYPT_ASYM_ALIGN_VALUE +
SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_ECURVE_OPERATIONS( pCurve ) );
peT = SymCryptModElementCreate( pbScratch, pCurve->cbModElement, FMod );
SYMCRYPT_ASSERT( peT != NULL );
pbScratch += pCurve->cbModElement;
SYMCRYPT_ASSERT( nPrecompPoints <= SYMCRYPT_ECURVE_SW_MAX_NPRECOMP_POINTS );
for (i=0; i<nPrecompPoints; i++)
{
if (bPrecompOffline)
{
poPIs[i] = pCurve->info.sw.poPrecompPoints[i];
}
else
{
poPIs[i] = SymCryptEcpointCreate( pbScratch, cbEcpoint, pCurve );
SYMCRYPT_ASSERT( poPIs[i] != NULL );
pbScratch += cbEcpoint;
}
}
poQ = SymCryptEcpointCreate( pbScratch, cbEcpoint, pCurve );
SYMCRYPT_ASSERT( poQ != NULL );
pbScratch += cbEcpoint;
poTmp = SymCryptEcpointCreate( pbScratch, cbEcpoint, pCurve );
SYMCRYPT_ASSERT( poTmp != NULL );
pbScratch += cbEcpoint;
piRem = SymCryptIntCreate( pbScratch, cbScalar, pCurve->GOrdDigits );
SYMCRYPT_ASSERT( piRem != NULL);
pbScratch += cbScalar;
piTmp = SymCryptIntCreate( pbScratch, cbScalar, pCurve->GOrdDigits );
SYMCRYPT_ASSERT( piTmp != NULL);
pbScratch += cbScalar;
absofKIs = (PUINT32) pbScratch;
pbScratch += nRecodedDigits * sizeof(UINT32);
sigofKIs = (PUINT32) pbScratch;
pbScratch += nRecodedDigits * sizeof(UINT32);
pbScratch = (PBYTE) ( ((SIZE_T)pbScratch + SYMCRYPT_ASYM_ALIGN_VALUE - 1) & ~(SYMCRYPT_ASYM_ALIGN_VALUE - 1) );
cbScratch -= ( pCurve->cbModElement + (nPrecompPoints+2)*cbEcpoint + 2*cbScalar );
cbScratch -= (((2*nRecodedDigits*sizeof(UINT32) + SYMCRYPT_ASYM_ALIGN_VALUE - 1)/SYMCRYPT_ASYM_ALIGN_VALUE )*SYMCRYPT_ASYM_ALIGN_VALUE);
SYMCRYPT_ASSERT( !SymCryptIntIsLessThan( SymCryptIntFromModulus( pCurve->GOrd ), piScalar ) );
SymCryptIntCopy( piScalar, piRem );
fZero = SymCryptIntIsEqualUint32( piRem, 0 );
fZero |= SymCryptEcpointIsZero( pCurve, poSrc, pbScratch, cbScratch );
fEven = SYMCRYPT_MASK32_ZERO(SymCryptIntGetBit( piRem, 0 ));
SymCryptIntSubSameSize( SymCryptIntFromModulus(pCurve->GOrd), piRem, piTmp);
SymCryptIntMaskedCopy( piTmp, piRem, fEven );
SymCryptFixedWindowRecoding( w, piRem, piTmp, absofKIs, sigofKIs, nRecodedDigits );
if (!bPrecompOffline)
{
SymCryptEcpointCopy( pCurve, poSrc, poPIs[0] );
SymCryptPrecomputation( pCurve, nPrecompPoints, poPIs, poQ, pbScratch, cbScratch );
}
peQX = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 0, pCurve, poQ );
peQY = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 1, pCurve, poQ );
peQZ = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 2, pCurve, poQ );
for (j=0; j<nPrecompPoints; j++)
{
indexMask = DELTA_MASK( j, absofKIs[nRecodedDigits-1] );
SymCryptEcpointMaskedCopy( pCurve, poPIs[j], poQ, indexMask);
}
for (i=nRecodedDigits - 2; i>0; i--)
{
for (j=0; j<w-1; j++)
{
SymCryptEcpointDouble( pCurve, poQ, poQ, 0, pbScratch, cbScratch );
}
for (j=0; j<nPrecompPoints; j++)
{
indexMask = DELTA_MASK( j, absofKIs[i] );
SymCryptEcpointMaskedCopy( pCurve, poPIs[j], poTmp, indexMask);
}
SymCryptEcpointNegate( pCurve, poTmp, sigofKIs[i], pbScratch, cbScratch );
SymCryptEcpointAddDiffNonZero( pCurve, poQ, poTmp, poQ, pbScratch, cbScratch );
}
for (j=0; j<w-1; j++)
{
SymCryptEcpointDouble( pCurve, poQ, poQ, 0, pbScratch, cbScratch );
}
for (j=0; j<nPrecompPoints; j++)
{
indexMask = DELTA_MASK( j, absofKIs[0] );
SymCryptEcpointMaskedCopy( pCurve, poPIs[j], poTmp, indexMask);
}
SymCryptEcpointNegate( pCurve, poTmp, sigofKIs[0], pbScratch, cbScratch );
SymCryptEcpointAdd( pCurve, poQ, poTmp, poQ, 0, pbScratch, cbScratch );
SymCryptEcpointNegate( pCurve, poQ, fEven, pbScratch, cbScratch );
if ((pCurve->coFactorPower!=0) && ((flags & SYMCRYPT_FLAG_ECC_LL_COFACTOR_MUL) != 0))
{
for (j=0; j<pCurve->coFactorPower; j++)
{
SymCryptEcpointDouble( pCurve, poQ, poQ, 0, pbScratch, cbScratch );
}
}
fZero |= SymCryptEcpointIsZero( pCurve, poQ, pbScratch, cbScratch );
SymCryptEcpointSetZero( pCurve, poTmp, pbScratch, cbScratch );
SymCryptEcpointMaskedCopy( pCurve, poTmp, poQ, fZero );
SymCryptEcpointCopy( pCurve, poQ, poDst );
scError = SYMCRYPT_NO_ERROR;
exit:
return scError;
}
SYMCRYPT_ERROR
SYMCRYPT_CALL
SymCryptEcpointMultiScalarMulWnafWithInterleaving(
_In_ PCSYMCRYPT_ECURVE pCurve,
_In_reads_( nPoints ) PCSYMCRYPT_INT * piSrcScalarArray,
_In_reads_( nPoints ) PCSYMCRYPT_ECPOINT * poSrcEcpointArray,
_In_ UINT32 nPoints,
_In_ UINT32 flags,
_Out_ PSYMCRYPT_ECPOINT poDst,
_Out_writes_bytes_( cbScratch ) PBYTE pbScratch,
SIZE_T cbScratch )
{
SYMCRYPT_ERROR scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;
UINT32 i, j;
UINT32 w = pCurve->info.sw.window;
UINT32 nPrecompPoints = pCurve->info.sw.nPrecompPoints;
UINT32 nRecodedDigits = pCurve->GOrdBitsize + 1;
UINT32 fZero[SYMCRYPT_ECURVE_MULTI_SCALAR_MUL_MAX_NPOINTS] = { 0 };
UINT32 fZeroTot = 0xffffffff;
BOOLEAN bPrecompOffline = FALSE;
PSYMCRYPT_ECPOINT poPIs[SYMCRYPT_ECURVE_SW_MAX_NPRECOMP_POINTS] = { 0 };
PSYMCRYPT_ECPOINT poQ = NULL;
PSYMCRYPT_ECPOINT poTmp = NULL;
PSYMCRYPT_INT piRem = NULL;
PSYMCRYPT_INT piTmp = NULL;
PUINT32 absofKIs = NULL;
PUINT32 sigofKIs = NULL;
SIZE_T cbEcpoint = SymCryptSizeofEcpointFromCurve( pCurve );
SIZE_T cbScalar = SymCryptSizeofIntFromDigits( pCurve->GOrdDigits );
PBYTE pbScratchEnd = pbScratch + cbScratch;
UNREFERENCED_PARAMETER( pbScratchEnd );
if ((flags & ~(SYMCRYPT_FLAG_DATA_PUBLIC | SYMCRYPT_FLAG_ECC_LL_COFACTOR_MUL)) != 0)
{
scError = SYMCRYPT_INVALID_ARGUMENT;
goto exit;
}
if (nPoints > SYMCRYPT_ECURVE_MULTI_SCALAR_MUL_MAX_NPOINTS)
{
scError = SYMCRYPT_NOT_IMPLEMENTED;
goto exit;
}
if (poSrcEcpointArray[0] == NULL)
{
poSrcEcpointArray[0] = pCurve->G;
bPrecompOffline = TRUE;
}
if ((flags & SYMCRYPT_FLAG_DATA_PUBLIC) == 0 )
{
scError = SYMCRYPT_NOT_IMPLEMENTED;
goto exit;
}
SYMCRYPT_ASSERT( SYMCRYPT_CURVE_IS_SHORT_WEIERSTRASS_TYPE(pCurve) ||
SYMCRYPT_CURVE_IS_TWISTED_EDWARDS_TYPE(pCurve) );
SYMCRYPT_ASSERT( SymCryptEcurveIsSame(pCurve, poDst->pCurve) );
SYMCRYPT_ASSERT( cbScratch >= SYMCRYPT_INTERNAL_SCRATCH_BYTES_FOR_SCALAR_ECURVE_OPERATIONS(pCurve, nPoints) );
for (i=0; i<nPoints*nPrecompPoints; i++)
{
if ((i<nPrecompPoints) && bPrecompOffline)
{
poPIs[i] = pCurve->info.sw.poPrecompPoints[i];
}
else
{
SYMCRYPT_ASSERT( pbScratch + cbEcpoint <= pbScratchEnd );
poPIs[i] = SymCryptEcpointCreate( pbScratch, cbEcpoint, pCurve );
SYMCRYPT_ASSERT( poPIs[i] != NULL );
pbScratch += cbEcpoint;
}
}
SYMCRYPT_ASSERT( pbScratch + 2*cbEcpoint + 2*cbScalar + 2*nPoints*nRecodedDigits*sizeof(UINT32) <= pbScratchEnd );
poQ = SymCryptEcpointCreate( pbScratch, cbEcpoint, pCurve );
SYMCRYPT_ASSERT( poQ != NULL );
pbScratch += cbEcpoint;
poTmp = SymCryptEcpointCreate( pbScratch, cbEcpoint, pCurve );
SYMCRYPT_ASSERT( poTmp != NULL );
pbScratch += cbEcpoint;
piRem = SymCryptIntCreate( pbScratch, cbScalar, pCurve->GOrdDigits );
SYMCRYPT_ASSERT( piRem != NULL);
pbScratch += cbScalar;
piTmp = SymCryptIntCreate( pbScratch, cbScalar, pCurve->GOrdDigits );
SYMCRYPT_ASSERT( piTmp != NULL);
pbScratch += cbScalar;
absofKIs = (PUINT32) pbScratch;
pbScratch += nPoints * nRecodedDigits * sizeof(UINT32);
sigofKIs = (PUINT32) pbScratch;
pbScratch += nPoints * nRecodedDigits * sizeof(UINT32);
pbScratch = (PBYTE) ( ((SIZE_T)pbScratch + SYMCRYPT_ASYM_ALIGN_VALUE - 1) & ~(SYMCRYPT_ASYM_ALIGN_VALUE - 1) );
cbScratch -= ( (nPoints*nPrecompPoints+2)*cbEcpoint + 2*cbScalar );
cbScratch -= (((2*nPoints*nRecodedDigits*sizeof(UINT32) + SYMCRYPT_ASYM_ALIGN_VALUE - 1)/SYMCRYPT_ASYM_ALIGN_VALUE )*SYMCRYPT_ASYM_ALIGN_VALUE);
for (j = 0; j<nPoints; j++)
{
SYMCRYPT_ASSERT( SymCryptEcurveIsSame(pCurve, poSrcEcpointArray[j]->pCurve) );
fZero[j] = ( SymCryptIntIsEqualUint32( piSrcScalarArray[j], 0 ) | SymCryptEcpointIsZero( pCurve, poSrcEcpointArray[j], pbScratch, cbScratch ) );
fZeroTot &= fZero[j];
if (!fZero[j])
{
SymCryptIntCopy( piSrcScalarArray[j], piRem );
SymCryptWidthNafRecoding( w, piRem, &absofKIs[j*nRecodedDigits], &sigofKIs[j*nRecodedDigits], nRecodedDigits );
if ((j>0) || !bPrecompOffline)
{
SymCryptEcpointCopy( pCurve, poSrcEcpointArray[j], poPIs[j*nPrecompPoints] );
SymCryptPrecomputation( pCurve, nPrecompPoints, &poPIs[j*nPrecompPoints], poQ, pbScratch, cbScratch );
}
}
}
SymCryptEcpointSetZero( pCurve, poQ, pbScratch, cbScratch );
if (!fZeroTot)
{
for (INT32 i = nRecodedDigits-1; i>-1; i--)
{
SymCryptEcpointDouble( pCurve, poQ, poQ, 0, pbScratch, cbScratch );
for (j = 0; j<nPoints; j++)
{
if (!fZero[j] && sigofKIs[j*nRecodedDigits + i] != 0)
{
SymCryptEcpointCopy( pCurve, poPIs[j*nPrecompPoints + absofKIs[j*nRecodedDigits + i]/2], poTmp );
if (sigofKIs[j*nRecodedDigits + i] == 0xffffffff)
{
SymCryptEcpointNegate( pCurve, poTmp, 0xffffffff, pbScratch, cbScratch );
}
SymCryptEcpointAdd( pCurve, poQ, poTmp, poQ, SYMCRYPT_FLAG_DATA_PUBLIC, pbScratch, cbScratch );
}
}
}
}
if ((pCurve->coFactorPower!=0) && ((flags & SYMCRYPT_FLAG_ECC_LL_COFACTOR_MUL) != 0))
{
for (j=0; j<pCurve->coFactorPower; j++)
{
SymCryptEcpointDouble( pCurve, poQ, poQ, 0, pbScratch, cbScratch );
}
}
if ( SymCryptEcpointIsZero( pCurve, poQ, pbScratch, cbScratch ) )
{
SymCryptEcpointSetZero( pCurve, poQ, pbScratch, cbScratch );
}
SymCryptEcpointCopy( pCurve, poQ, poDst );
scError = SYMCRYPT_NO_ERROR;
exit:
return scError;
}
VOID
SYMCRYPT_CALL
SymCryptEcpointGenericSetRandom(
_In_ PCSYMCRYPT_ECURVE pCurve,
_Out_ PSYMCRYPT_INT piScalar,
_Out_ PSYMCRYPT_ECPOINT poDst,
_Out_writes_bytes_( cbScratch )
PBYTE pbScratch,
SIZE_T cbScratch )
{
PSYMCRYPT_MODELEMENT peScalar = NULL;
SYMCRYPT_ASSERT( SymCryptEcurveIsSame(pCurve, poDst->pCurve) );
SYMCRYPT_ASSERT( cbScratch >= SYMCRYPT_INTERNAL_SCRATCH_BYTES_FOR_SCALAR_ECURVE_OPERATIONS(pCurve, 1) );
SYMCRYPT_ASSERT( cbScratch >= pCurve->cbModElement );
peScalar = SymCryptModElementCreate( pbScratch, pCurve->cbModElement, pCurve->GOrd );
SYMCRYPT_ASSERT( peScalar != NULL );
SymCryptModSetRandom( pCurve->GOrd, peScalar, (SYMCRYPT_FLAG_MODRANDOM_ALLOW_ONE|SYMCRYPT_FLAG_MODRANDOM_ALLOW_MINUSONE), pbScratch + pCurve->cbModElement, cbScratch - pCurve->cbModElement );
SymCryptModElementToInt( pCurve->GOrd, peScalar, piScalar, pbScratch + pCurve->cbModElement, cbScratch - pCurve->cbModElement );
SymCryptEcpointScalarMul( pCurve, piScalar, NULL, 0, poDst, pbScratch, cbScratch );
}