Path: blob/master/libs/symcrypt/lib/ec_short_weierstrass.c
15010 views
//1// ec_short_weierstrass.c ECPOINT functions for short Weierstrass curves.2//3// Copyright (c) Microsoft Corporation. Licensed under the MIT license.4//5//67#include "precomp.h"89//10// Scratch space requirements for each ECPOINT function.11//12// A function's requirements in scratch space consist of requirements for its own arithmetic13// operations and temporaries ("self" scratch space) and scratch space requirements for other14// ECPOINT functions it might call ("callee" scratch space).15//16// If the outer function does not need the temporaries after calling the inner ECPOINT17// function, then the total scratch space can be the maximum of both. Otherwise the scratch18// space of the outer function should be the concatenation of the "self" scratch space and19// the "callee" scratch space.20//21// The following table shows the scratch space requirements of each function with appropriate22// abbreviations. The calling sequence implies a directed graph that starting from the "leaves"23// (functions that do no call others) allows to calculate the total scratch space requirements.24//25// #N Function Calls Function Self Temporaries Self Scratch26// 1 SetZero - 0 COM_MOD(FMod)27// 2 SetDistinguishedPoint - 0 028// 3 IsEqual - 4 ModEl COM_MOD(FMod)29// 4 IsZero - 1 ModEl COM_MOD(FMod)30// 5 OnCurve - 2 ModEl COM_MOD(FMod)31// 6 Double 1,4,9 2 Ecp 032// 7 Add 1,3,4,8,9 2 Ecp 033// 8 AddDiffNonZero - 8 ModEl COM_MOD(FMod)34// 9 Double - 6 ModEl COM_MOD(FMod)35//36// 10 SetRandom 11 0 COM_MOD(GOrd)37// 11 ScalarMul 4,5,7 1ModEl + (n+2)Ecp + 2Int COM_MOD(GOrd)38//39// Since only 4 functions call others and to keep things simple, we will have 240// types of scratch space: "ECURVE_COMMON" and "ECURVE_SCALAR"41//42// ---- All functions except 10 and 11 will use the "ECURVE_COMMON" scratch space. The size of it43// depends only on parameters of the curve. Schematically it will be:44// |----------COMMON------------------------------------------------------------------|45// |------8 ModEl + 2 Ecpoint----||------COM_MOD(FMod)--------------------------------|46//47// ---- The SetRandom and ScalarMul have requirements that depend on temporaries for the pre-computation.48// Also they depend on the "self" temporaries after calling the inner functions.49// Therefore, these will require the "ECURVE_SCALAR" scratch space which50// consists of two parts: The self space for the above two functions and the51// common scratch space. These parts SHOULD NOT overlap. Schematically:52//53// |--------------SCALAR---------------------------------------------------|54// |----1ModEl + (n+2)Ecp + 2Int--------||---max(COMMON, COM_MOD(GOrd)----|5556// The scratch space sizes are all calculated by the following function.57// *** Notice that almost all the curve parameters (exception is the distinguished point)58// must have been initialized before calling this function.59VOID60SYMCRYPT_CALL61SymCryptShortWeierstrassFillScratchSpaces( _In_ PSYMCRYPT_ECURVE pCurve )62{63UINT32 nDigits = SymCryptDigitsFromBits( pCurve->FModBitsize );6465//66// All the scratch space computations are upper bounded by the SizeofXXX bound (2^19) and67// the SCRATCH_BYTES_FOR_XXX bound (2^24) (see symcrypt_internal.h).68//69// One caveat is SymCryptSizeofEcpointFromCurve and SymCryptSizeofEcpointEx which calculate70// the size of EcPoint with 4 coordinates (each one a modelement of max size 2^17). Thus upper71// bounded by 2^20.72//73// Another is the precomp points computation where the nPrecompPoints are up to74// 2^SYMCRYPT_ECURVE_SW_DEF_WINDOW = 2^6 and the nRecodedDigits are equal to the75// GOrd bitsize < 2^20.76//77// Thus cbScratchScalarMulti is upper bounded by 2^6*2^20 + 2*2^20*2^4 ~ 2^26.78//7980// Common81pCurve->cbScratchCommon =828 * pCurve->cbModElement +832 * SymCryptSizeofEcpointFromCurve( pCurve ) +84SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( pCurve->FModDigits );8586// Scalar (Overhead)87pCurve->cbScratchScalar =88pCurve->cbModElement +892 * SymCryptSizeofEcpointFromCurve( pCurve ) +902 * SymCryptSizeofIntFromDigits( pCurve->GOrdDigits ) +91SYMCRYPT_MAX( pCurve->cbScratchCommon, SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( pCurve->GOrdDigits ));9293// Scalar dependent on precomp points (be careful to align the UINT32 arrays properly)94pCurve->cbScratchScalarMulti =95pCurve->info.sw.nPrecompPoints * SymCryptSizeofEcpointFromCurve( pCurve ) +96((2*pCurve->info.sw.nRecodedDigits * sizeof(UINT32) + SYMCRYPT_ASYM_ALIGN_VALUE - 1 )/SYMCRYPT_ASYM_ALIGN_VALUE) * SYMCRYPT_ASYM_ALIGN_VALUE;9798// GetSetValue99pCurve->cbScratchGetSetValue =100SymCryptSizeofEcpointEx( pCurve->cbModElement, SYMCRYPT_ECPOINT_FORMAT_MAX_LENGTH ) +1012 * pCurve->cbModElement +102SYMCRYPT_MAX( SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( pCurve->FModDigits ),103SYMCRYPT_SCRATCH_BYTES_FOR_MODINV( pCurve->FModDigits ) );104105pCurve->cbScratchGetSetValue = SYMCRYPT_MAX( pCurve->cbScratchGetSetValue, SymCryptSizeofIntFromDigits( nDigits ) );106107// Eckey108pCurve->cbScratchEckey =109SYMCRYPT_MAX( pCurve->cbModElement + SymCryptSizeofIntFromDigits(SymCryptEcurveDigitsofScalarMultiplier(pCurve)),110SymCryptSizeofEcpointFromCurve( pCurve ) ) +111SYMCRYPT_MAX( pCurve->cbScratchScalar + pCurve->cbScratchScalarMulti, pCurve->cbScratchGetSetValue );112}113114//115// The following function sets the point to (1:1:0) in Jacobian coordinates.116//117VOID118SYMCRYPT_CALL119SymCryptShortWeierstrassSetZero(120_In_ PCSYMCRYPT_ECURVE pCurve,121_Out_ PSYMCRYPT_ECPOINT poDst,122_Out_writes_bytes_( cbScratch )123PBYTE pbScratch,124SIZE_T cbScratch )125{126PCSYMCRYPT_MODULUS FMod = pCurve->FMod;127PSYMCRYPT_MODELEMENT peTmp = NULL;128129SYMCRYPT_ASSERT( SYMCRYPT_CURVE_IS_SHORT_WEIERSTRASS_TYPE(pCurve) );130SYMCRYPT_ASSERT( SymCryptEcurveIsSame(pCurve, poDst->pCurve) );131SYMCRYPT_ASSERT( cbScratch >= SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( pCurve->FModDigits ) );132133// Getting handle to X134peTmp = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 0, pCurve, poDst );135136// Setting the right value (always 1)137SymCryptModElementSetValueUint32( 1, FMod, peTmp, pbScratch, cbScratch );138139// Getting handle to Y140peTmp = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 1, pCurve, poDst );141142// Setting the right value (always 1)143SymCryptModElementSetValueUint32( 1, FMod, peTmp, pbScratch, cbScratch );144145// Getting handle to Z146peTmp = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 2, pCurve, poDst );147148// Setting the right value (always 0)149SymCryptModElementSetValueUint32( 0, pCurve->FMod, peTmp, pbScratch, cbScratch );150}151152VOID153SYMCRYPT_CALL154SymCryptShortWeierstrassSetDistinguished(155_In_ PCSYMCRYPT_ECURVE pCurve,156_Out_ PSYMCRYPT_ECPOINT poDst,157_Out_writes_bytes_( cbScratch )158PBYTE pbScratch,159SIZE_T cbScratch )160{161SYMCRYPT_ASSERT( SYMCRYPT_CURVE_IS_SHORT_WEIERSTRASS_TYPE(pCurve) );162SYMCRYPT_ASSERT( SymCryptEcurveIsSame(pCurve, poDst->pCurve) );163164UNREFERENCED_PARAMETER( pbScratch );165UNREFERENCED_PARAMETER( cbScratch );166167SymCryptEcpointCopy( pCurve, pCurve->G, poDst );168}169170//171// The following function checks if172// - X1*Z2^2 = X2*Z1^2 and Y1*Z2^3 = Y2*Z1^3 (Equal case)173// - X1*Z2^2 = X2*Z1^2 and Y1*Z2^3 = -Y2*Z1^3 (Negative case)174//175// Remark: The case where Z1 = Z2 = 0 is covered above (the zero point176// is equal to its negative).177//178UINT32179SYMCRYPT_CALL180SymCryptShortWeierstrassIsEqual(181_In_ PCSYMCRYPT_ECURVE pCurve,182_In_ PCSYMCRYPT_ECPOINT poSrc1,183_In_ PCSYMCRYPT_ECPOINT poSrc2,184UINT32 flags,185_Out_writes_bytes_( cbScratch )186PBYTE pbScratch,187SIZE_T cbScratch )188{189PCSYMCRYPT_MODULUS FMod = pCurve->FMod;190191PSYMCRYPT_MODELEMENT peX1 = NULL; // Pointer to X1192PSYMCRYPT_MODELEMENT peY1 = NULL; // Pointer to Y1193PSYMCRYPT_MODELEMENT peZ1 = NULL; // Pointer to Z1194PSYMCRYPT_MODELEMENT peX2 = NULL; // Pointer to X2195PSYMCRYPT_MODELEMENT peY2 = NULL; // Pointer to Y2196PSYMCRYPT_MODELEMENT peZ2 = NULL; // Pointer to Z2197198UINT32 dResX = 0;199UINT32 dResY = 0;200UINT32 dResYN = 0;201202PSYMCRYPT_MODELEMENT peT[4] = { 0 }; // Temporaries203204SYMCRYPT_ASSERT( SYMCRYPT_CURVE_IS_SHORT_WEIERSTRASS_TYPE(pCurve) );205SYMCRYPT_ASSERT( SymCryptEcurveIsSame(pCurve, poSrc1->pCurve) && SymCryptEcurveIsSame(pCurve, poSrc2->pCurve) );206SYMCRYPT_ASSERT( (flags & ~(SYMCRYPT_FLAG_ECPOINT_EQUAL|SYMCRYPT_FLAG_ECPOINT_NEG_EQUAL)) == 0 );207SYMCRYPT_ASSERT( cbScratch >= SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( pCurve->FModDigits ) + 4 * pCurve->cbModElement );208209// Creating temporaries210for (UINT32 i=0; i<4; i++)211{212peT[i] = SymCryptModElementCreate(213pbScratch,214pCurve->cbModElement,215FMod );216217SYMCRYPT_ASSERT( peT[i] != NULL);218219pbScratch += pCurve->cbModElement;220}221222// Fixing remaining scratch space size223cbScratch -= 4 * pCurve->cbModElement;224225// Getting pointers to x and y of the source point226peX1 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 0, pCurve, poSrc1 );227peY1 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 1, pCurve, poSrc1 );228peZ1 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 2, pCurve, poSrc1 );229peX2 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 0, pCurve, poSrc2 );230peY2 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 1, pCurve, poSrc2 );231peZ2 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 2, pCurve, poSrc2 );232233// Setting the default flag if flags == 0234flags |= ( SYMCRYPT_MASK32_ZERO( flags ) & SYMCRYPT_FLAG_ECPOINT_EQUAL );235236// Calculation237SymCryptModSquare( FMod, peZ1, peT[0], pbScratch, cbScratch ); // T0 := Z1 * Z1 = Z1^2238SymCryptModSquare( FMod, peZ2, peT[1], pbScratch, cbScratch ); // T1 := Z2 * Z2 = Z2^2239SymCryptModMul( FMod, peX1, peT[1], peT[2], pbScratch, cbScratch ); // T2 := X1 * T1 = X1*Z2^2240SymCryptModMul( FMod, peX2, peT[0], peT[3], pbScratch, cbScratch ); // T3 := X2 * T0 = X2*Z1^2241242dResX = SymCryptModElementIsEqual( FMod, peT[2], peT[3] );243244SymCryptModMul( FMod, peZ1, peT[0], peT[0], pbScratch, cbScratch ); // T0 := Z1 * T0 = Z1^3245SymCryptModMul( FMod, peZ2, peT[1], peT[1], pbScratch, cbScratch ); // T1 := Z2 * T1 = Z2^3246SymCryptModMul( FMod, peY1, peT[1], peT[2], pbScratch, cbScratch ); // T2 := Y1 * T1 = Y1*Z2^3247SymCryptModMul( FMod, peY2, peT[0], peT[3], pbScratch, cbScratch ); // T3 := Y2 * T0 = Y2*Z1^3248249dResY = SymCryptModElementIsEqual( FMod, peT[2], peT[3] );250251SymCryptModNeg( FMod, peT[3], peT[3], pbScratch, cbScratch ); // T3 := -T3 = -Y2*Z1^3252253dResYN = SymCryptModElementIsEqual( FMod, peT[2], peT[3] );254255return (SYMCRYPT_MASK32_NONZERO(flags & SYMCRYPT_FLAG_ECPOINT_EQUAL) & dResX & dResY) |256(SYMCRYPT_MASK32_NONZERO(flags & SYMCRYPT_FLAG_ECPOINT_NEG_EQUAL) & dResX & dResYN);257}258259UINT32260SYMCRYPT_CALL261SymCryptShortWeierstrassIsZero(262_In_ PCSYMCRYPT_ECURVE pCurve,263_In_ PCSYMCRYPT_ECPOINT poSrc,264_Out_writes_bytes_( cbScratch )265PBYTE pbScratch,266SIZE_T cbScratch )267{268PCSYMCRYPT_MODULUS FMod = pCurve->FMod;269PSYMCRYPT_MODELEMENT peZ = NULL; // Pointer to Z270271SYMCRYPT_ASSERT( SYMCRYPT_CURVE_IS_SHORT_WEIERSTRASS_TYPE(pCurve) );272SYMCRYPT_ASSERT( SymCryptEcurveIsSame(pCurve, poSrc->pCurve) );273274UNREFERENCED_PARAMETER( pbScratch );275UNREFERENCED_PARAMETER( cbScratch );276277// Getting pointer to Z of the source point278peZ = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 2, pCurve, poSrc );279280// Setting temporary to 0281return SymCryptModElementIsZero( FMod, peZ );282}283284//285// The following function verifies if the point (X:Y:Z) in Jacobian286// coordinates satisfies the equation Y^2 = X^3 + aXZ^4+bZ^6 .287//288UINT32289SYMCRYPT_CALL290SymCryptShortWeierstrassOnCurve(291_In_ PCSYMCRYPT_ECURVE pCurve,292_In_ PCSYMCRYPT_ECPOINT poSrc,293_Out_writes_bytes_( cbScratch )294PBYTE pbScratch,295SIZE_T cbScratch )296{297PCSYMCRYPT_MODULUS FMod = pCurve->FMod;298299PSYMCRYPT_MODELEMENT peX = NULL; // Pointer to X300PSYMCRYPT_MODELEMENT peY = NULL; // Pointer to Y301PSYMCRYPT_MODELEMENT peZ = NULL; // Pointer to Z302303PSYMCRYPT_MODELEMENT peT[2] = { 0 }; // Temporaries304305SYMCRYPT_ASSERT( SYMCRYPT_CURVE_IS_SHORT_WEIERSTRASS_TYPE(pCurve) );306SYMCRYPT_ASSERT( SymCryptEcurveIsSame(pCurve, poSrc->pCurve) );307SYMCRYPT_ASSERT( cbScratch >= SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( pCurve->FModDigits ) + 2 * pCurve->cbModElement );308309// Creating temporaries310for (UINT32 i=0; i<2; i++)311{312peT[i] = SymCryptModElementCreate(313pbScratch,314pCurve->cbModElement,315FMod );316317SYMCRYPT_ASSERT( peT[i] != NULL);318319pbScratch += pCurve->cbModElement;320}321322// Fixing remaining scratch space size323cbScratch -= 2*pCurve->cbModElement;324325// Getting pointers to coordinates of the source point326peX = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 0, pCurve, poSrc );327peY = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 1, pCurve, poSrc );328peZ = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 2, pCurve, poSrc );329330// Calculation331SymCryptModSquare( FMod, peZ, peT[0], pbScratch, cbScratch ); // T1 := Z * Z = Z^2332SymCryptModSquare( FMod, peT[0], peT[1], pbScratch, cbScratch ); // T2 := T1 * T1 = Z^4333SymCryptModMul( FMod, peT[0], peT[1], peT[0], pbScratch, cbScratch ); // T1 := T1 * T2 = Z^6334335SymCryptModMul( FMod, peT[0], pCurve->B, peT[0], pbScratch, cbScratch ); // T1 := T1 * b = bZ^6336337SymCryptModMul( FMod, peT[1], peX, peT[1], pbScratch, cbScratch ); // T2 := T2 * X = XZ^4338SymCryptModMul( FMod, peT[1], pCurve->A, peT[1], pbScratch, cbScratch ); // T2 := T2 * a = aXZ^4339340SymCryptModAdd( FMod, peT[0], peT[1], peT[1], pbScratch, cbScratch ); // T2 := T1 + T2 = aXZ^4 + bZ^6341342SymCryptModSquare( FMod, peX, peT[0], pbScratch, cbScratch ); // T1 := X * X = X^2343SymCryptModMul( FMod, peT[0], peX, peT[0], pbScratch, cbScratch ); // T1 := T1 * X = X^3344SymCryptModAdd( FMod, peT[0], peT[1], peT[1], pbScratch, cbScratch ); // T2 := T1 + T2 = X^3 + aXZ^4 + bZ^6345346SymCryptModSquare( FMod, peY, peT[0], pbScratch, cbScratch ); // T1 := Y * Y = Y^2347348return SymCryptModElementIsEqual( FMod, peT[0], peT[1] );349}350351//352// based on dbl-2007-bl formula353// but tweaked by saml to354// a) remove overeager conversions from modular multiplication to modular squaring which introduce355// more addition/subtraction. With current implementations (based on montgomery reduction),356// the cost of [a square and an add/sub] is greater than the cost of [a multiplication]357// b) share intermediate results of producing 8YYYY. [add/sub] is ~10% of cost of mul, so reducing358// count of these operation has a real impact359//360// 2Y = 2*Y1361// 2YY = 2Y*Y1362// 4YY = 2*2YY363// 8YYYY = 2YY*4YY364// S = X1*4YY365// XX = X1^2366// ZZ = Z1^2367// ZZZZ = ZZ^2368// M = 3*XX+a*ZZZZ369// T = M^2-2*S370// X3 = T371// Y3 = M*(S-T)-8YYYY372// Z3 = Z1*2Y373//374// Total cost:375// 6 Mul (1 by a)376// 4 Sqr377// 2 Add378// 4 Sub379// 3 Dbl380//381// Special Case:382// If the source point is equal to the identity383// point of the curve (i.e. Z1 = 0 in Jacobian384// coordinates) then the resulting point has385// Z3 = Z1*2Y1 = 0. Thus, this formula is386// complete (it works for all points).387//388VOID389SYMCRYPT_CALL390SymCryptShortWeierstrassDouble(391_In_ PCSYMCRYPT_ECURVE pCurve,392_In_ PCSYMCRYPT_ECPOINT poSrc,393_Out_ PSYMCRYPT_ECPOINT poDst,394UINT32 flags,395_Out_writes_bytes_( cbScratch )396PBYTE pbScratch,397SIZE_T cbScratch )398{399PCSYMCRYPT_MODULUS FMod = pCurve->FMod;400PSYMCRYPT_MODELEMENT peT[3] = { 0 }; // Temporaries401402PCSYMCRYPT_MODELEMENT peX1 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 0, pCurve, poSrc );403PCSYMCRYPT_MODELEMENT peY1 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 1, pCurve, poSrc );404PCSYMCRYPT_MODELEMENT peZ1 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 2, pCurve, poSrc );405406PSYMCRYPT_MODELEMENT peX3 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 0, pCurve, poDst );407PSYMCRYPT_MODELEMENT peY3 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 1, pCurve, poDst );408PSYMCRYPT_MODELEMENT peZ3 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 2, pCurve, poDst );409410SYMCRYPT_ASSERT( pCurve->type == SYMCRYPT_INTERNAL_ECURVE_TYPE_SHORT_WEIERSTRASS );411SYMCRYPT_ASSERT( SymCryptEcurveIsSame(pCurve, poSrc->pCurve) && SymCryptEcurveIsSame(pCurve, poDst->pCurve) );412SYMCRYPT_ASSERT( cbScratch >= SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( pCurve->FModDigits ) + 3 * pCurve->cbModElement );413414UNREFERENCED_PARAMETER( flags );415416// Creating temporaries417for (UINT32 i=0; i<3; i++)418{419peT[i] = SymCryptModElementCreate(420pbScratch,421pCurve->cbModElement,422FMod );423424SYMCRYPT_ASSERT( peT[i] != NULL);425426pbScratch += pCurve->cbModElement;427}428429// Fixing remaining scratch space size430cbScratch -= 3*pCurve->cbModElement;431432// Calculate the points433SymCryptModAdd( FMod, peY1, peY1, peT[0], pbScratch, cbScratch ); /* T0 := Y1 + Y1 = 2Y */434SymCryptModSquare( FMod, peZ1, peT[1], pbScratch, cbScratch ); /* T1 := Z1 * Z1 = ZZ */435SymCryptModMul( FMod, peT[0], peZ1, peZ3, pbScratch, cbScratch ); /* Z3 := 2Y * Z1 = 2YZ */436437SymCryptModMul( FMod, peY1, peT[0], peY3, pbScratch, cbScratch ); /* Y3 := 2Y * Y1 = 2YY */438SymCryptModAdd( FMod, peY3, peY3, peT[0], pbScratch, cbScratch ); /* T0 := 2YY + 2YY = 4YY */439SymCryptModMul( FMod, peT[0], peY3, peY3, pbScratch, cbScratch ); /* Y3 := 2YY * 4YY = 8YYYY */440441SymCryptModMul( FMod, peT[0], peX1, peT[0], pbScratch, cbScratch ); /* T0 := X1 * 4YY = 4XYY = S */442443SymCryptModSquare( FMod, peT[1], peT[1], pbScratch, cbScratch ); /* T1 := T1 * T1 = ZZZZ */444SymCryptModSquare( FMod, peX1, peT[2], pbScratch, cbScratch ); /* T2 := X1 * X1 = XX */445SymCryptModMul( FMod, peT[1], pCurve->A, peT[1], pbScratch, cbScratch ); /* T1 := T1 * a = a*ZZZZ */446SymCryptModAdd( FMod, peT[2], peT[1], peT[1], pbScratch, cbScratch ); /* T1 := T2 + T1 = XX + a*ZZZZ */447SymCryptModAdd( FMod, peT[2], peT[2], peT[2], pbScratch, cbScratch ); /* T2 := T2 + T2 = 2*XX */448SymCryptModAdd( FMod, peT[0], peT[0], peX3, pbScratch, cbScratch ); /* X3 := 2*S */449SymCryptModAdd( FMod, peT[2], peT[1], peT[1], pbScratch, cbScratch ); /* T1 := T2 + T1 = 3*XX + a*ZZZZ = M */450451SymCryptModSquare( FMod, peT[1], peT[2], pbScratch, cbScratch ); /* T2 := M^2 */452SymCryptModSub( FMod, peT[2], peX3, peX3, pbScratch, cbScratch ); /* X3 := M^2 - 2*S = T */453454SymCryptModSub( FMod, peT[0], peX3, peT[0], pbScratch, cbScratch ); /* T0 := S - T */455SymCryptModMul( FMod, peT[1], peT[0], peT[0], pbScratch, cbScratch ); /* T0 := M * (S - T) */456SymCryptModSub( FMod, peT[0], peY3, peY3, pbScratch, cbScratch ); /* Y3 := M * (S - T) - 8*YYYY */457}458459460//461// based on dbl-2007-bl / dbl-2001-b formulae462// but tweaked by saml to463// a) remove overeager conversions from modular multiplication to modular squaring which introduce464// more addition/subtraction. With current implementations (based on montgomery reduction),465// the cost of [a square and an add/sub] is greater than the cost of [a multiplication]466// b) share intermediate results of producing 8YYYY. [add/sub] is ~10% of cost of mul, so reducing467// count of these operation has a real impact468// c) make use of knowledge that curve has a == -3, so M can be calculated more efficiently469//470// 2Y = 2*Y1471// 2YY = 2Y*Y1472// 4YY = 2*2YY473// 8YYYY = 2YY*4YY474// ZZ = Z1^2475// S = X1*4YY476// M = 3*(X1+ZZ)*(X1-ZZ) = 3*(XX - ZZZZ)477// T = M^2-2*S478// X3 = T479// Y3 = M*(S-T)-8YYYY480// Z3 = 2Y*Z1481//482// Total cost:483// 6 Mul484// 2 Sqr485// 2 Add486// 4 Sub487// 4 Dbl488//489// Special Case:490// If the source point is equal to the identity491// point of the curve (i.e. Z1 = 0 in Jacobian492// coordinates) then the resulting point has493// Z3 = Z1*2Y1 = 0. Thus, this formula is494// complete (it works for all points).495//496VOID497SYMCRYPT_CALL498SymCryptShortWeierstrassDoubleSpecializedAm3(499_In_ PCSYMCRYPT_ECURVE pCurve,500_In_ PCSYMCRYPT_ECPOINT poSrc,501_Out_ PSYMCRYPT_ECPOINT poDst,502UINT32 flags,503_Out_writes_bytes_( cbScratch )504PBYTE pbScratch,505SIZE_T cbScratch )506{507PCSYMCRYPT_MODULUS FMod = pCurve->FMod;508PSYMCRYPT_MODELEMENT peT[3] = { 0 }; // Temporaries509510PCSYMCRYPT_MODELEMENT peX1 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 0, pCurve, poSrc );511PCSYMCRYPT_MODELEMENT peY1 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 1, pCurve, poSrc );512PCSYMCRYPT_MODELEMENT peZ1 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 2, pCurve, poSrc );513514PSYMCRYPT_MODELEMENT peX3 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 0, pCurve, poDst );515PSYMCRYPT_MODELEMENT peY3 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 1, pCurve, poDst );516PSYMCRYPT_MODELEMENT peZ3 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 2, pCurve, poDst );517518SYMCRYPT_ASSERT( pCurve->type == SYMCRYPT_INTERNAL_ECURVE_TYPE_SHORT_WEIERSTRASS_AM3 );519SYMCRYPT_ASSERT( SymCryptEcurveIsSame(pCurve, poSrc->pCurve) && SymCryptEcurveIsSame(pCurve, poDst->pCurve) );520SYMCRYPT_ASSERT( cbScratch >= SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( pCurve->FModDigits ) + 3 * pCurve->cbModElement );521522UNREFERENCED_PARAMETER( flags );523524// Creating temporaries525for (UINT32 i=0; i<3; i++)526{527peT[i] = SymCryptModElementCreate(528pbScratch,529pCurve->cbModElement,530FMod );531532SYMCRYPT_ASSERT( peT[i] != NULL);533534pbScratch += pCurve->cbModElement;535}536537// Fixing remaining scratch space size538cbScratch -= 3*pCurve->cbModElement;539540// Calculate the points541SymCryptModAdd( FMod, peY1, peY1, peT[0], pbScratch, cbScratch ); /* T0 := Y1 + Y1 = 2Y */542SymCryptModSquare( FMod, peZ1, peT[1], pbScratch, cbScratch ); /* T1 := Z1 * Z1 = ZZ */543SymCryptModMul( FMod, peY1, peT[0], peY3, pbScratch, cbScratch ); /* Y3 := 2Y * Y1 = 2YY */544545SymCryptModMul( FMod, peT[0], peZ1, peZ3, pbScratch, cbScratch ); /* Z3 := 2Y * Z1 = 2YZ */546547SymCryptModAdd( FMod, peY3, peY3, peT[0], pbScratch, cbScratch ); /* T0 := 2YY + 2YY = 4YY */548SymCryptModAdd( FMod, peX1, peT[1], peT[2], pbScratch, cbScratch ); /* T2 := X1 + ZZ */549SymCryptModMul( FMod, peT[0], peY3, peY3, pbScratch, cbScratch ); /* Y3 := 2YY * 4YY = 8YYYY */550551SymCryptModSub( FMod, peX1, peT[1], peT[1], pbScratch, cbScratch ); /* T1 := X1 - ZZ */552SymCryptModMul( FMod, peT[0], peX1, peT[0], pbScratch, cbScratch ); /* T0 := X1 * 4YY = 4XYY = S */553554SymCryptModMul( FMod, peT[2], peT[1], peT[2], pbScratch, cbScratch ); /* T2 := (X1 + ZZ)*(X1 - ZZ) = XX - ZZZZ */555SymCryptModAdd( FMod, peT[2], peT[2], peT[1], pbScratch, cbScratch ); /* T1 := 2*(XX - ZZZZ) */556SymCryptModAdd( FMod, peT[0], peT[0], peX3, pbScratch, cbScratch ); /* X3 := 2*S */557SymCryptModAdd( FMod, peT[1], peT[2], peT[1], pbScratch, cbScratch ); /* T1 := 3*(XX - ZZZZ) = M */558559SymCryptModSquare( FMod, peT[1], peT[2], pbScratch, cbScratch ); /* T2 := M^2 */560SymCryptModSub( FMod, peT[2], peX3, peX3, pbScratch, cbScratch ); /* X3 := M^2 - 2*S = T */561562SymCryptModSub( FMod, peT[0], peX3, peT[0], pbScratch, cbScratch ); /* T0 := S - T */563SymCryptModMul( FMod, peT[1], peT[0], peT[0], pbScratch, cbScratch ); /* T0 := M * (S - T) */564SymCryptModSub( FMod, peT[0], peY3, peY3, pbScratch, cbScratch ); /* Y3 := M * (S - T) - 8*YYYY */565}566567//568// based on add-2007-bl formula569// but tweaked by saml to570// remove overeager conversions from modular multiplication to modular squaring which introduce571// more addition/subtraction.572//573// Z1Z1 = Z1^2574// Z2Z2 = Z2^2575// U1 = X1*Z2Z2576// U2 = X2*Z1Z1577// S1 = Y1*Z2*Z2Z2578// S2 = Y2*Z1*Z1Z1579// H = U2-U1580// 2H = 2*H581// I = (2H)^2582// J = H*I583// r = 2*(S2-S1)584// V = U1*I585// X3 = r^2-J-2*V586// Y3 = r*(V-X3)-2*S1*J587// Z3 = (Z1*Z2)*2H588//589// Total cost:590// 12 Mul591// 4 Sqr592// 0 Add593// 7 Sub594// 3 Dbl595//596// Special Case:597// If the two source points are opposite (X1 / Z1^2 == X2 / Z2^2),598// then H = U2-U1 = 0. Thus Z3 = 0 and the result is correct.599//600VOID601SYMCRYPT_CALL602SymCryptShortWeierstrassAddDiffNonZero(603_In_ PCSYMCRYPT_ECURVE pCurve,604_In_ PCSYMCRYPT_ECPOINT poSrc1,605_In_ PCSYMCRYPT_ECPOINT poSrc2,606_Out_ PSYMCRYPT_ECPOINT poDst,607_Out_writes_bytes_( cbScratch )608PBYTE pbScratch,609SIZE_T cbScratch )610{611PCSYMCRYPT_MODULUS FMod = pCurve->FMod;612613PCSYMCRYPT_MODELEMENT peX1 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 0, pCurve, poSrc1 );614PCSYMCRYPT_MODELEMENT peY1 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 1, pCurve, poSrc1 );615PCSYMCRYPT_MODELEMENT peZ1 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 2, pCurve, poSrc1 );616617PCSYMCRYPT_MODELEMENT peX2 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 0, pCurve, poSrc2 );618PCSYMCRYPT_MODELEMENT peY2 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 1, pCurve, poSrc2 );619PCSYMCRYPT_MODELEMENT peZ2 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 2, pCurve, poSrc2 );620621PSYMCRYPT_MODELEMENT peX3 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 0, pCurve, poDst );622PSYMCRYPT_MODELEMENT peY3 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 1, pCurve, poDst );623PSYMCRYPT_MODELEMENT peZ3 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 2, pCurve, poDst );624625PSYMCRYPT_MODELEMENT peT[7] = { 0 }; // Temporaries626627SYMCRYPT_ASSERT( SYMCRYPT_CURVE_IS_SHORT_WEIERSTRASS_TYPE(pCurve) );628SYMCRYPT_ASSERT( SymCryptEcurveIsSame(pCurve, poSrc1->pCurve) && SymCryptEcurveIsSame(pCurve, poSrc2->pCurve) && SymCryptEcurveIsSame(pCurve, poDst->pCurve) );629SYMCRYPT_ASSERT( cbScratch >= SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( pCurve->FModDigits ) + 7 * pCurve->cbModElement );630631// Creating temporaries632for (UINT32 i=0; i<7; i++)633{634peT[i] = SymCryptModElementCreate(635pbScratch,636pCurve->cbModElement,637FMod );638639SYMCRYPT_ASSERT( peT[i] != NULL);640641pbScratch += pCurve->cbModElement;642}643644// Fixing remaining scratch space size645cbScratch -= 7*pCurve->cbModElement;646647// Calculation648649SymCryptModSquare( FMod, peZ1, peT[0], pbScratch, cbScratch ); /* T0 := Z1 * Z1 = Z1Z1 */650SymCryptModMul( FMod, peZ1, peT[0], peT[1], pbScratch, cbScratch ); /* T1 := Z1*Z1Z1 */651652SymCryptModSquare( FMod, peZ2, peT[6], pbScratch, cbScratch ); /* T6 := Z2 * Z2 = Z2Z2 */653SymCryptModMul( FMod, peX1, peT[6], peT[2], pbScratch, cbScratch ); /* T2 := X1 * T6 = X1*Z2Z2 = U1 */654SymCryptModMul( FMod, peX2, peT[0], peT[3], pbScratch, cbScratch ); /* T3 := X2 * Z1Z1 = U2 */655SymCryptModSub( FMod, peT[3], peT[2], peT[5], pbScratch, cbScratch ); /* T5 := T3 - T2 = U2 - U1 = H */656SymCryptModAdd( FMod, peT[5], peT[5], peT[3], pbScratch, cbScratch ); /* T3 := T5 + T5 = 2H */657658SymCryptModMul( FMod, peZ1, peZ2, peT[4], pbScratch, cbScratch ); /* T4 := Z1 * Z2 */659660SymCryptModMul( FMod, peZ2, peT[6], peT[6], pbScratch, cbScratch ); /* T6 := Z2 * T6 = Z2*Z2Z2 */661SymCryptModMul( FMod, peT[4], peT[3], peZ3, pbScratch, cbScratch ); /* Z3 := T4 * T3 = Z1*Z2*2H */662663SymCryptModMul( FMod, peY1, peT[6], peT[6], pbScratch, cbScratch ); /* T6 := Y1 * T6 = Y1*Z2*Z2Z2 = S1 */664SymCryptModMul( FMod, peY2, peT[1], peT[4], pbScratch, cbScratch ); /* T4 := Y2*Z1*Z1Z1 = S2 */665SymCryptModSub( FMod, peT[4], peT[6], peT[4], pbScratch, cbScratch ); /* T4 := T4 - T6 = S2-S1 */666SymCryptModAdd( FMod, peT[4], peT[4], peT[4], pbScratch, cbScratch ); /* T4 := T4 + T4 = 2*(S2-S1) = r */667668SymCryptModSquare( FMod, peT[3], peT[3], pbScratch, cbScratch ); /* T3 := T3 * T3 = (2*H)^2 = I */669SymCryptModMul( FMod, peT[3], peT[5], peT[5], pbScratch, cbScratch ); /* T5 := T3 * T5 = H*I = J */670SymCryptModMul( FMod, peT[2], peT[3], peT[3], pbScratch, cbScratch ); /* T3 := T2 * T3 = U1*I = V */671672SymCryptModSquare( FMod, peT[4], peT[2], pbScratch, cbScratch ); /* T2 := T4 * T4 = r^2 */673SymCryptModSub( FMod, peT[2], peT[5], peT[2], pbScratch, cbScratch ); /* T2 := T2 - T5 = r^2 - J */674SymCryptModSub( FMod, peT[2], peT[3], peT[2], pbScratch, cbScratch ); /* T2 := T2 - T3 = r^2 - J - V */675SymCryptModSub( FMod, peT[2], peT[3], peX3, pbScratch, cbScratch ); /* T2 := T2 - T3 = r^2 - J - 2*V = X3 */676677SymCryptModSub( FMod, peT[3], peX3, peT[3], pbScratch, cbScratch ); /* T3 := T3 - T2 = V - X3 */678SymCryptModMul( FMod, peT[3], peT[4], peT[3], pbScratch, cbScratch ); /* T3 := T3 * T4 = r*(V-X3) */679SymCryptModMul( FMod, peT[6], peT[5], peT[6], pbScratch, cbScratch ); /* T6 := T6 * T5 = S1*J */680SymCryptModAdd( FMod, peT[6], peT[6], peT[6], pbScratch, cbScratch ); /* T6 := T6 + T6 = 2*S1*J */681SymCryptModSub( FMod, peT[3], peT[6], peY3, pbScratch, cbScratch ); /* Y3 := T6 - T3 = r*(V-X3) - 2*S1*J */682}683684//685// The following function is a complete **SIDE-CHANNEL-UNSAFE**686// addition of points that detects as fast as possible the special cases687// and merges the two previous calls.688//689VOID690SYMCRYPT_CALL691SymCryptShortWeierstrassAddSideChannelUnsafe(692_In_ PCSYMCRYPT_ECURVE pCurve,693_In_ PCSYMCRYPT_ECPOINT poSrc1,694_In_ PCSYMCRYPT_ECPOINT poSrc2,695_Out_ PSYMCRYPT_ECPOINT poDst,696_Out_writes_bytes_( cbScratch )697PBYTE pbScratch,698SIZE_T cbScratch )699{700PCSYMCRYPT_MODULUS FMod = pCurve->FMod;701702PCSYMCRYPT_MODELEMENT peX1 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 0, pCurve, poSrc1 );703PCSYMCRYPT_MODELEMENT peY1 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 1, pCurve, poSrc1 );704PCSYMCRYPT_MODELEMENT peZ1 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 2, pCurve, poSrc1 );705706PCSYMCRYPT_MODELEMENT peX2 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 0, pCurve, poSrc2 );707PCSYMCRYPT_MODELEMENT peY2 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 1, pCurve, poSrc2 );708PCSYMCRYPT_MODELEMENT peZ2 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 2, pCurve, poSrc2 );709710PSYMCRYPT_MODELEMENT peT[8] = { 0 }; // Temporaries711712SYMCRYPT_ASSERT( SYMCRYPT_CURVE_IS_SHORT_WEIERSTRASS_TYPE(pCurve) );713SYMCRYPT_ASSERT( SymCryptEcurveIsSame(pCurve, poSrc1->pCurve) && SymCryptEcurveIsSame(pCurve, poSrc2->pCurve) && SymCryptEcurveIsSame(pCurve, poDst->pCurve) );714SYMCRYPT_ASSERT( cbScratch >= SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( pCurve->FModDigits ) + 8 * pCurve->cbModElement );715716// Check if one of the points is zero717if (SymCryptModElementIsZero( FMod, peZ1 ))718{719SymCryptEcpointCopy( pCurve, poSrc2, poDst);720return;721}722723if (SymCryptModElementIsZero( FMod, peZ2 ))724{725SymCryptEcpointCopy( pCurve, poSrc1, poDst);726return;727}728729// Creating temporaries730for (UINT32 i=0; i<8; i++)731{732peT[i] = SymCryptModElementCreate(733pbScratch,734pCurve->cbModElement,735FMod );736737SYMCRYPT_ASSERT( peT[i] != NULL);738739pbScratch += pCurve->cbModElement;740}741742// Fixing remaining scratch space size743cbScratch -= 8*pCurve->cbModElement;744745// Calculation746747SymCryptModSquare( FMod, peZ1, peT[0], pbScratch, cbScratch ); /* T0 := Z1 * Z1 = Z1Z1 */748SymCryptModMul( FMod, peZ1, peT[0], peT[1], pbScratch, cbScratch ); /* T1 := Z1*Z1Z1 */749750SymCryptModSquare( FMod, peZ2, peT[6], pbScratch, cbScratch ); /* T6 := Z2 * Z2 = Z2Z2 */751SymCryptModMul( FMod, peX1, peT[6], peT[2], pbScratch, cbScratch ); /* T2 := X1 * T6 = X1*Z2Z2 = U1 */752SymCryptModMul( FMod, peX2, peT[0], peT[3], pbScratch, cbScratch ); /* T3 := X2 * Z1Z1 = U2 */753SymCryptModSub( FMod, peT[3], peT[2], peT[5], pbScratch, cbScratch ); /* T5 := T3 - T2 = U2 - U1 = H */754755SymCryptModMul( FMod, peY2, peT[1], peT[7], pbScratch, cbScratch ); /* T7 := Y2 * T1 = Y2*Z1*Z1Z1 = S2 */756SymCryptModMul( FMod, peZ2, peT[6], peT[1], pbScratch, cbScratch ); /* T1 := Z2 * T6 = Z2*Z2Z2 */757SymCryptModMul( FMod, peY1, peT[1], peT[1], pbScratch, cbScratch ); /* T1 := Y1 * T1 = Y1*Z2*Z2Z2 = S1 */758SymCryptModSub( FMod, peT[7], peT[1], peT[7], pbScratch, cbScratch ); /* T7 := T7 - T1 = S2-S1 */759760if (SymCryptModElementIsZero( FMod, peT[5] ) & SymCryptModElementIsZero( FMod, peT[7] ))761{762// Points are equal - run double on poSrc1763764SymCryptModElementCopy( FMod, peT[0], peT[4] ); /* Move Z1Z1 for later */765766SymCryptModSquare( FMod, peX1, peT[0], pbScratch, cbScratch ); /* T0 := X1 * X1 = XX */767SymCryptModSquare( FMod, peY1, peT[3], pbScratch, cbScratch ); /* T3 := Y1 * Y1 = YY */768SymCryptModSquare( FMod, peT[3], peT[5], pbScratch, cbScratch ); /* T5 := T3 * T3 = YYYY */769770SymCryptModAdd( FMod, peX1, peT[3], peT[1], pbScratch, cbScratch ); /* T1 := X1 + T3 = X + YY */771SymCryptModSquare( FMod, peT[1], peT[1], pbScratch, cbScratch ); /* T1 := T1 * T1 = (X + YY)^2 */772SymCryptModSub( FMod, peT[1], peT[0], peT[1], pbScratch, cbScratch ); /* T1 := T1 - T0 = (X + YY)^2 - XX */773SymCryptModSub( FMod, peT[1], peT[5], peT[1], pbScratch, cbScratch ); /* T1 := T1 - T5 = (X + YY)^2 - XX - YYYY */774SymCryptModAdd( FMod, peT[1], peT[1], peT[1], pbScratch, cbScratch ); /* T1 := T1 + T1 = 2*((X + YY)^2 - XX - YYYY) = S */775776//SymCryptModSquare( FMod, peZ1, peT[4], pbScratch, cbScratch ); /* T4 := Z1 * Z1 = ZZ */777778SymCryptModSquare( FMod, peT[4], peT[2], pbScratch, cbScratch ); /* T2 := T4 * T4 = ZZ^2 */779SymCryptModMul( FMod, peT[2], pCurve->A, peT[2], pbScratch, cbScratch ); /* T2 := T2 * a = a*ZZ^2 */780SymCryptModAdd( FMod, peT[2], peT[0], peT[2], pbScratch, cbScratch ); /* T2 := T2 + T0 = XX + a*ZZ^2 */781SymCryptModAdd( FMod, peT[0], peT[0], peT[0], pbScratch, cbScratch ); /* T0 := T0 + T0 = 2*XX */782SymCryptModAdd( FMod, peT[2], peT[0], peT[2], pbScratch, cbScratch ); /* T2 := T2 + T0 = 3*XX + a*ZZ^2 = M */783784SymCryptModSquare( FMod, peT[2], peT[0], pbScratch, cbScratch ); /* T0 := T2 * T2 = M^2 */785SymCryptModSub( FMod, peT[0], peT[1], peT[0], pbScratch, cbScratch ); /* T0 := T0 - T1 = M^2 - S */786SymCryptModSub( FMod, peT[0], peT[1], peT[0], pbScratch, cbScratch ); /* T0 := T0 - T1 = M^2 - 2*S = T = X3 */787788SymCryptModSub( FMod, peT[1], peT[0], peT[1], pbScratch, cbScratch ); /* T1 := T1 - T0 = S - T */789SymCryptModMul( FMod, peT[2], peT[1], peT[1], pbScratch, cbScratch ); /* T1 := T2 * T1 = M * (S - T) */790SymCryptModAdd( FMod, peT[5], peT[5], peT[5], pbScratch, cbScratch ); /* T5 := T5 + T5 = 2*YYYY */791SymCryptModAdd( FMod, peT[5], peT[5], peT[5], pbScratch, cbScratch ); /* T5 := T5 + T5 = 4*YYYY */792SymCryptModAdd( FMod, peT[5], peT[5], peT[5], pbScratch, cbScratch ); /* T5 := T5 + T5 = 8*YYYY */793SymCryptModSub( FMod, peT[1], peT[5], peT[1], pbScratch, cbScratch ); /* T1 := T1 - T5 = M * (S - T) - 8*YYYY = Y3 */794795SymCryptModAdd( FMod, peY1, peZ1, peT[2], pbScratch, cbScratch ); /* T2 := Y1 + Z1 */796SymCryptModSquare( FMod, peT[2], peT[2], pbScratch, cbScratch ); /* T2 := T2 * T2 = (Y + Z )^2 */797SymCryptModSub( FMod, peT[2], peT[3], peT[2], pbScratch, cbScratch ); /* T2 := T2 - T3 = (Y + Z )^2 - YY */798SymCryptModSub( FMod, peT[2], peT[4], peT[2], pbScratch, cbScratch ); /* T2 := T2 - T4 = (Y + Z )^2 - YY - ZZ = Z3 */799800// Setting the result801SymCryptModElementCopy( FMod, peT[0], SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 0, pCurve, poDst ) );802SymCryptModElementCopy( FMod, peT[1], SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 1, pCurve, poDst ) );803SymCryptModElementCopy( FMod, peT[2], SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 2, pCurve, poDst ) );804}805else806{807// Continue the addition808809SymCryptModAdd( FMod, peZ1, peZ2, peT[4], pbScratch, cbScratch ); /* T4 := Z1 + Z2 */810SymCryptModSquare( FMod, peT[4], peT[4], pbScratch, cbScratch ); /* T4 := T4 * T4 = (Z1 + Z2)^2 */811SymCryptModSub( FMod, peT[4], peT[0], peT[4], pbScratch, cbScratch ); /* T4 := T4 - Z1Z1 = (Z1 + Z2)^2 - Z1Z1 */812SymCryptModSub( FMod, peT[4], peT[6], peT[4], pbScratch, cbScratch ); /* T4 := T4 - T6 = (Z1 + Z2)^2 - Z1Z1 - Z2Z2 */813SymCryptModMul( FMod, peT[4], peT[5], peT[4], pbScratch, cbScratch ); /* T4 := T4 * T5 = ((Z1 + Z2)^2 - Z1Z1 - Z2Z2)*H = Z3 */814815SymCryptModAdd( FMod, peT[7], peT[7], peT[7], pbScratch, cbScratch ); /* T7 := T7 + T7 = 2*(S2-S1) = r */816817SymCryptModAdd( FMod, peT[5], peT[5], peT[3], pbScratch, cbScratch ); /* T3 := T5 + T5 = 2*H */818SymCryptModSquare( FMod, peT[3], peT[3], pbScratch, cbScratch ); /* T3 := T3 * T3 = (2*H)^2 = I */819SymCryptModMul( FMod, peT[3], peT[5], peT[5], pbScratch, cbScratch ); /* T5 := T3 * T5 = H*I = J */820SymCryptModMul( FMod, peT[2], peT[3], peT[3], pbScratch, cbScratch ); /* T3 := T2 * T3 = U1*I = V */821822SymCryptModSquare( FMod, peT[7], peT[2], pbScratch, cbScratch ); /* T2 := T7 * T7 = r^2 */823SymCryptModSub( FMod, peT[2], peT[5], peT[2], pbScratch, cbScratch ); /* T2 := T2 - T5 = r^2 - J */824SymCryptModSub( FMod, peT[2], peT[3], peT[2], pbScratch, cbScratch ); /* T2 := T2 - T3 = r^2 - J - V */825SymCryptModSub( FMod, peT[2], peT[3], peT[2], pbScratch, cbScratch ); /* T2 := T2 - T3 = r^2 - J - 2*V = X3 */826827SymCryptModSub( FMod, peT[3], peT[2], peT[3], pbScratch, cbScratch ); /* T3 := T3 - T2 = V - X3 */828SymCryptModMul( FMod, peT[3], peT[7], peT[3], pbScratch, cbScratch ); /* T3 := T3 * T7 = r*(V-X3) */829SymCryptModMul( FMod, peT[1], peT[5], peT[6], pbScratch, cbScratch ); /* T6 := T1 * T5 = S1*J */830SymCryptModAdd( FMod, peT[6], peT[6], peT[6], pbScratch, cbScratch ); /* T6 := T6 + T6 = 2*S1*J */831SymCryptModSub( FMod, peT[3], peT[6], peT[3], pbScratch, cbScratch ); /* T3 := T6 - T3 = r*(V-X3) - 2*S1*J = Y3 */832833// Setting the result834SymCryptModElementCopy( FMod, peT[2], SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 0, pCurve, poDst ) );835SymCryptModElementCopy( FMod, peT[3], SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 1, pCurve, poDst ) );836SymCryptModElementCopy( FMod, peT[4], SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 2, pCurve, poDst ) );837}838}839840VOID841SYMCRYPT_CALL842SymCryptShortWeierstrassAdd(843_In_ PCSYMCRYPT_ECURVE pCurve,844_In_ PCSYMCRYPT_ECPOINT poSrc1,845_In_ PCSYMCRYPT_ECPOINT poSrc2,846_Out_ PSYMCRYPT_ECPOINT poDst,847UINT32 flags,848_Out_writes_bytes_( cbScratch )849PBYTE pbScratch,850SIZE_T cbScratch )851{852UINT32 dSrc1Zero = 0;853UINT32 dSrc2Zero = 0;854UINT32 dSrcEqual = 0;855856// Temporary points857PSYMCRYPT_ECPOINT poQ0 = NULL;858PSYMCRYPT_ECPOINT poQ1 = NULL;859860SIZE_T cbEcpoint = SymCryptSizeofEcpointFromCurve( pCurve );861862SYMCRYPT_ASSERT( SYMCRYPT_CURVE_IS_SHORT_WEIERSTRASS_TYPE(pCurve) );863SYMCRYPT_ASSERT( SymCryptEcurveIsSame(pCurve, poSrc1->pCurve) && SymCryptEcurveIsSame(pCurve, poSrc2->pCurve) && SymCryptEcurveIsSame(pCurve, poDst->pCurve) );864SYMCRYPT_ASSERT( cbScratch >= SYMCRYPT_INTERNAL_SCRATCH_BYTES_FOR_COMMON_ECURVE_OPERATIONS( pCurve ) ); // We will need the entire scratch space865866SYMCRYPT_ASSERT( cbScratch > 2*cbEcpoint );867868if ((flags & SYMCRYPT_FLAG_DATA_PUBLIC) != 0)869{870SymCryptShortWeierstrassAddSideChannelUnsafe( pCurve, poSrc1, poSrc2, poDst, pbScratch, cbScratch );871}872else873{874// Creating temporary points875poQ0 = SymCryptEcpointCreate( pbScratch, cbEcpoint, pCurve );876SYMCRYPT_ASSERT( poQ0 != NULL);877pbScratch += cbEcpoint;878879poQ1 = SymCryptEcpointCreate( pbScratch, cbEcpoint, pCurve );880SYMCRYPT_ASSERT( poQ1 != NULL);881pbScratch += cbEcpoint;882883// Fixing remaining scratch space size884cbScratch -= 2*cbEcpoint;885886// Calculate the masks887dSrc1Zero = SymCryptShortWeierstrassIsZero( pCurve, poSrc1, pbScratch, cbScratch );888dSrc2Zero = SymCryptShortWeierstrassIsZero( pCurve, poSrc2, pbScratch, cbScratch );889dSrcEqual = SymCryptShortWeierstrassIsEqual( pCurve, poSrc1, poSrc2, SYMCRYPT_FLAG_ECPOINT_EQUAL, pbScratch, cbScratch );890891// Side-channel safe computations892SymCryptShortWeierstrassAddDiffNonZero( pCurve, poSrc1, poSrc2, poQ0, pbScratch, cbScratch ); // This covers the cases where Src1 != Src2 or Src1 = -Src2893894SymCryptEcpointDouble( pCurve, poSrc1, poQ1, 0, pbScratch, cbScratch ); // Dispatch to Double function; enables type assertion on SymCryptShortWeierstrassDouble to be specific895SymCryptEcpointMaskedCopy( pCurve, poQ1, poQ0, dSrcEqual ); // (Masked) copy if the points are equal896897SymCryptEcpointMaskedCopy( pCurve, poSrc1, poQ0, dSrc2Zero ); // (Masked) copy if Src2 = 0898SymCryptEcpointMaskedCopy( pCurve, poSrc2, poQ0, dSrc1Zero ); // (Masked) copy if Src1 = 0899900SymCryptEcpointCopy( pCurve, poQ0, poDst ); // Copy the final result to destination901}902}903904VOID905SYMCRYPT_CALL906SymCryptShortWeierstrassNegate(907_In_ PCSYMCRYPT_ECURVE pCurve,908_Inout_ PSYMCRYPT_ECPOINT poSrc,909UINT32 mask,910_Out_writes_bytes_( cbScratch )911PBYTE pbScratch,912SIZE_T cbScratch )913{914PCSYMCRYPT_MODULUS FMod = pCurve->FMod;915PSYMCRYPT_MODELEMENT peY = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 1, pCurve, poSrc);916917PSYMCRYPT_MODELEMENT peTmp = NULL;918919SYMCRYPT_ASSERT( SYMCRYPT_CURVE_IS_SHORT_WEIERSTRASS_TYPE(pCurve) );920SYMCRYPT_ASSERT( SymCryptEcurveIsSame(pCurve, poSrc->pCurve) );921SYMCRYPT_ASSERT( cbScratch >= SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( pCurve->FModDigits ) + pCurve->cbModElement);922923peTmp = SymCryptModElementCreate(924pbScratch,925pCurve->cbModElement,926FMod );927SYMCRYPT_ASSERT( peTmp != NULL);928929pbScratch += pCurve->cbModElement;930cbScratch -= pCurve->cbModElement;931932SymCryptModNeg( FMod, peY, peTmp, pbScratch, cbScratch );933SymCryptModElementMaskedCopy( FMod, peTmp, peY, mask );934}935936937