Coverage Report

Created: 2024-11-21 07:03

/src/SymCrypt/lib/ec_short_weierstrass.c
Line
Count
Source (jump to first uncovered line)
1
//
2
// ec_short_weierstrass.c   ECPOINT functions for short Weierstrass curves.
3
//
4
// Copyright (c) Microsoft Corporation. Licensed under the MIT license.
5
//
6
//
7
8
#include "precomp.h"
9
10
//
11
// Scratch space requirements for each ECPOINT function.
12
//
13
// A function's requirements in scratch space consist of requirements for its own arithmetic
14
// operations and temporaries ("self" scratch space) and scratch space requirements for other
15
// ECPOINT functions it might call ("callee" scratch space).
16
//
17
// If the outer function does not need the temporaries after calling the inner ECPOINT
18
// function, then the total scratch space can be the maximum of both. Otherwise the scratch
19
// space of the outer function should be the concatenation of the "self" scratch space and
20
// the "callee" scratch space.
21
//
22
// The following table shows the scratch space requirements of each function with appropriate
23
// abbreviations. The calling sequence implies a directed graph that starting from the "leaves"
24
// (functions that do no call others) allows to calculate the total scratch space requirements.
25
//
26
//  #N Function                     Calls Function  Self Temporaries            Self Scratch
27
//   1 SetZero                      -               0                           COM_MOD(FMod)
28
//   2 SetDistinguishedPoint        -               0                           0
29
//   3 IsEqual                      -               4 ModEl                     COM_MOD(FMod)
30
//   4 IsZero                       -               1 ModEl                     COM_MOD(FMod)
31
//   5 OnCurve                      -               2 ModEl                     COM_MOD(FMod)
32
//   6 Double                       1,4,9           2 Ecp                       0
33
//   7 Add                          1,3,4,8,9       2 Ecp                       0
34
//   8 AddDiffNonZero               -               8 ModEl                     COM_MOD(FMod)
35
//   9 Double                       -               6 ModEl                     COM_MOD(FMod)
36
//
37
//  10 SetRandom                    11              0                           COM_MOD(GOrd)
38
//  11 ScalarMul                    4,5,7           1ModEl + (n+2)Ecp + 2Int    COM_MOD(GOrd)
39
//
40
// Since only 4 functions call others and to keep things simple, we will have 2
41
// types of scratch space: "ECURVE_COMMON" and "ECURVE_SCALAR"
42
//
43
// ---- All functions except 10 and 11 will use the "ECURVE_COMMON" scratch space. The size of it
44
//      depends only on parameters of the curve. Schematically it will be:
45
//          |----------COMMON------------------------------------------------------------------|
46
//          |------8 ModEl + 2 Ecpoint----||------COM_MOD(FMod)--------------------------------|
47
//
48
// ---- The SetRandom and ScalarMul have requirements that depend on temporaries for the pre-computation.
49
//      Also they depend on the "self" temporaries after calling the inner functions.
50
//      Therefore, these will require the "ECURVE_SCALAR" scratch space which
51
//      consists of two parts: The self space for the above two functions and the
52
//      common scratch space. These parts SHOULD NOT overlap. Schematically:
53
//
54
//          |--------------SCALAR---------------------------------------------------|
55
//          |----1ModEl + (n+2)Ecp + 2Int--------||---max(COMMON, COM_MOD(GOrd)----|
56
57
// The scratch space sizes are all calculated by the following function.
58
// *** Notice that almost all the curve parameters (exception is the distinguished point)
59
//     must have been initialized before calling this function.
60
VOID
61
SYMCRYPT_CALL
62
SymCryptShortWeierstrassFillScratchSpaces( _In_ PSYMCRYPT_ECURVE pCurve )
63
852
{
64
852
    UINT32 nDigits = SymCryptDigitsFromBits( pCurve->FModBitsize );
65
66
    //
67
    // All the scratch space computations are upper bounded by the SizeofXXX bound (2^19) and
68
    // the SCRATCH_BYTES_FOR_XXX bound (2^24) (see symcrypt_internal.h).
69
    //
70
    // One caveat is SymCryptSizeofEcpointFromCurve and SymCryptSizeofEcpointEx which calculate
71
    // the size of EcPoint with 4 coordinates (each one a modelement of max size 2^17). Thus upper
72
    // bounded by 2^20.
73
    //
74
    // Another is the precomp points computation where the nPrecompPoints are up to
75
    // 2^SYMCRYPT_ECURVE_SW_DEF_WINDOW = 2^6 and the nRecodedDigits are equal to the
76
    // GOrd bitsize < 2^20.
77
    //
78
    // Thus cbScratchScalarMulti is upper bounded by 2^6*2^20 + 2*2^20*2^4 ~ 2^26.
79
    //
80
81
    // Common
82
852
    pCurve->cbScratchCommon =
83
852
            8 * pCurve->cbModElement +
84
852
            2 * SymCryptSizeofEcpointFromCurve( pCurve ) +
85
852
            SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( pCurve->FModDigits );
86
87
    // Scalar (Overhead)
88
852
    pCurve->cbScratchScalar =
89
852
            pCurve->cbModElement +
90
852
            2 * SymCryptSizeofEcpointFromCurve( pCurve ) +
91
852
            2 * SymCryptSizeofIntFromDigits( pCurve->GOrdDigits ) +
92
852
            SYMCRYPT_MAX( pCurve->cbScratchCommon, SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( pCurve->GOrdDigits ));
93
94
    // Scalar dependent on precomp points (be careful to align the UINT32 arrays properly)
95
852
    pCurve->cbScratchScalarMulti =
96
852
            pCurve->info.sw.nPrecompPoints * SymCryptSizeofEcpointFromCurve( pCurve ) +
97
852
            ((2*pCurve->info.sw.nRecodedDigits * sizeof(UINT32) + SYMCRYPT_ASYM_ALIGN_VALUE - 1 )/SYMCRYPT_ASYM_ALIGN_VALUE) * SYMCRYPT_ASYM_ALIGN_VALUE;
98
99
    // GetSetValue
100
852
    pCurve->cbScratchGetSetValue =
101
852
            SymCryptSizeofEcpointEx( pCurve->cbModElement, SYMCRYPT_ECPOINT_FORMAT_MAX_LENGTH ) +
102
852
            2 * pCurve->cbModElement +
103
852
            SYMCRYPT_MAX(    SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( pCurve->FModDigits ),
104
852
                    SYMCRYPT_SCRATCH_BYTES_FOR_MODINV( pCurve->FModDigits ) );
105
106
852
    pCurve->cbScratchGetSetValue = SYMCRYPT_MAX( pCurve->cbScratchGetSetValue, SymCryptSizeofIntFromDigits( nDigits ) );
107
108
    // Eckey
109
852
    pCurve->cbScratchEckey =
110
852
            SYMCRYPT_MAX( pCurve->cbModElement + SymCryptSizeofIntFromDigits(SymCryptEcurveDigitsofScalarMultiplier(pCurve)),
111
852
                SymCryptSizeofEcpointFromCurve( pCurve ) ) +
112
852
            SYMCRYPT_MAX( pCurve->cbScratchScalar + pCurve->cbScratchScalarMulti, pCurve->cbScratchGetSetValue );
113
852
}
114
115
//
116
// The following function sets the point to (1:1:0) in Jacobian coordinates.
117
//
118
VOID
119
SYMCRYPT_CALL
120
SymCryptShortWeierstrassSetZero(
121
    _In_    PCSYMCRYPT_ECURVE   pCurve,
122
    _Out_   PSYMCRYPT_ECPOINT   poDst,
123
    _Out_writes_bytes_( cbScratch )
124
            PBYTE               pbScratch,
125
            SIZE_T              cbScratch )
126
829
{
127
829
    PCSYMCRYPT_MODULUS FMod = pCurve->FMod;
128
829
    PSYMCRYPT_MODELEMENT peTmp = NULL;
129
130
829
    SYMCRYPT_ASSERT( SYMCRYPT_CURVE_IS_SHORT_WEIERSTRASS_TYPE(pCurve) );
131
829
    SYMCRYPT_ASSERT( SymCryptEcurveIsSame(pCurve, poDst->pCurve) );
132
829
    SYMCRYPT_ASSERT( cbScratch >= SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( pCurve->FModDigits ) );
133
134
    // Getting handle to X
135
829
    peTmp = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 0, pCurve, poDst );
136
137
    // Setting the right value (always 1)
138
829
    SymCryptModElementSetValueUint32( 1, FMod, peTmp, pbScratch, cbScratch );
139
140
    // Getting handle to Y
141
829
    peTmp = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 1, pCurve, poDst );
142
143
    // Setting the right value (always 1)
144
829
    SymCryptModElementSetValueUint32( 1, FMod, peTmp, pbScratch, cbScratch );
145
146
    // Getting handle to Z
147
829
    peTmp = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 2, pCurve, poDst );
148
149
    // Setting the right value (always 0)
150
829
    SymCryptModElementSetValueUint32( 0, pCurve->FMod, peTmp, pbScratch, cbScratch );
151
829
}
152
153
VOID
154
SYMCRYPT_CALL
155
SymCryptShortWeierstrassSetDistinguished(
156
    _In_    PCSYMCRYPT_ECURVE   pCurve,
157
    _Out_   PSYMCRYPT_ECPOINT   poDst,
158
    _Out_writes_bytes_( cbScratch )
159
            PBYTE               pbScratch,
160
            SIZE_T              cbScratch )
161
0
{
162
0
    SYMCRYPT_ASSERT( SYMCRYPT_CURVE_IS_SHORT_WEIERSTRASS_TYPE(pCurve) );
163
0
    SYMCRYPT_ASSERT( SymCryptEcurveIsSame(pCurve, poDst->pCurve) );
164
165
0
    UNREFERENCED_PARAMETER( pbScratch );
166
0
    UNREFERENCED_PARAMETER( cbScratch );
167
168
0
    SymCryptEcpointCopy( pCurve, pCurve->G, poDst );
169
0
}
170
171
//
172
// The following function checks if
173
//      - X1*Z2^2 = X2*Z1^2 and Y1*Z2^3 = Y2*Z1^3 (Equal case)
174
//      - X1*Z2^2 = X2*Z1^2 and Y1*Z2^3 = -Y2*Z1^3 (Negative case)
175
//
176
// Remark: The case where Z1 = Z2 = 0 is covered above (the zero point
177
//         is equal to its negative).
178
//
179
UINT32
180
SYMCRYPT_CALL
181
SymCryptShortWeierstrassIsEqual(
182
    _In_    PCSYMCRYPT_ECURVE   pCurve,
183
    _In_    PCSYMCRYPT_ECPOINT  poSrc1,
184
    _In_    PCSYMCRYPT_ECPOINT  poSrc2,
185
            UINT32              flags,
186
    _Out_writes_bytes_( cbScratch )
187
            PBYTE               pbScratch,
188
            SIZE_T              cbScratch )
189
660
{
190
660
    PCSYMCRYPT_MODULUS FMod = pCurve->FMod;
191
192
660
    PSYMCRYPT_MODELEMENT peX1 = NULL;    // Pointer to X1
193
660
    PSYMCRYPT_MODELEMENT peY1 = NULL;    // Pointer to Y1
194
660
    PSYMCRYPT_MODELEMENT peZ1 = NULL;    // Pointer to Z1
195
660
    PSYMCRYPT_MODELEMENT peX2 = NULL;    // Pointer to X2
196
660
    PSYMCRYPT_MODELEMENT peY2 = NULL;    // Pointer to Y2
197
660
    PSYMCRYPT_MODELEMENT peZ2 = NULL;    // Pointer to Z2
198
199
660
    UINT32  dResX = 0;
200
660
    UINT32  dResY = 0;
201
660
    UINT32  dResYN = 0;
202
203
660
    PSYMCRYPT_MODELEMENT peT[4] = { 0 };  // Temporaries
204
205
660
    SYMCRYPT_ASSERT( SYMCRYPT_CURVE_IS_SHORT_WEIERSTRASS_TYPE(pCurve) );
206
660
    SYMCRYPT_ASSERT( SymCryptEcurveIsSame(pCurve, poSrc1->pCurve) && SymCryptEcurveIsSame(pCurve, poSrc2->pCurve) );
207
660
    SYMCRYPT_ASSERT( (flags & ~(SYMCRYPT_FLAG_ECPOINT_EQUAL|SYMCRYPT_FLAG_ECPOINT_NEG_EQUAL)) == 0 );
208
660
    SYMCRYPT_ASSERT( cbScratch >= SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( pCurve->FModDigits ) + 4 * pCurve->cbModElement );
209
210
    // Creating temporaries
211
3.30k
    for (UINT32 i=0; i<4; i++)
212
2.64k
    {
213
2.64k
        peT[i] = SymCryptModElementCreate(
214
2.64k
                pbScratch,
215
2.64k
                pCurve->cbModElement,
216
2.64k
                FMod );
217
218
2.64k
        SYMCRYPT_ASSERT( peT[i] != NULL);
219
220
2.64k
        pbScratch += pCurve->cbModElement;
221
2.64k
    }
222
223
    // Fixing remaining scratch space size
224
660
    cbScratch -= 4 * pCurve->cbModElement;
225
226
    // Getting pointers to x and y of the source point
227
660
    peX1 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 0, pCurve, poSrc1 );
228
660
    peY1 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 1, pCurve, poSrc1 );
229
660
    peZ1 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 2, pCurve, poSrc1 );
230
660
    peX2 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 0, pCurve, poSrc2 );
231
660
    peY2 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 1, pCurve, poSrc2 );
232
660
    peZ2 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 2, pCurve, poSrc2 );
233
234
    // Setting the default flag if flags == 0
235
660
    flags |= ( SYMCRYPT_MASK32_ZERO( flags ) & SYMCRYPT_FLAG_ECPOINT_EQUAL );
236
237
    // Calculation
238
660
    SymCryptModSquare( FMod, peZ1, peT[0], pbScratch, cbScratch );            // T0 := Z1 * Z1 = Z1^2
239
660
    SymCryptModSquare( FMod, peZ2, peT[1], pbScratch, cbScratch );            // T1 := Z2 * Z2 = Z2^2
240
660
    SymCryptModMul( FMod, peX1, peT[1], peT[2], pbScratch, cbScratch );       // T2 := X1 * T1 = X1*Z2^2
241
660
    SymCryptModMul( FMod, peX2, peT[0], peT[3], pbScratch, cbScratch );       // T3 := X2 * T0 = X2*Z1^2
242
243
660
    dResX = SymCryptModElementIsEqual( FMod, peT[2], peT[3] );
244
245
660
    SymCryptModMul( FMod, peZ1, peT[0], peT[0], pbScratch, cbScratch );       // T0 := Z1 * T0 = Z1^3
246
660
    SymCryptModMul( FMod, peZ2, peT[1], peT[1], pbScratch, cbScratch );       // T1 := Z2 * T1 = Z2^3
247
660
    SymCryptModMul( FMod, peY1, peT[1], peT[2], pbScratch, cbScratch );       // T2 := Y1 * T1 = Y1*Z2^3
248
660
    SymCryptModMul( FMod, peY2, peT[0], peT[3], pbScratch, cbScratch );       // T3 := Y2 * T0 = Y2*Z1^3
249
250
660
    dResY = SymCryptModElementIsEqual( FMod, peT[2], peT[3] );
251
252
660
    SymCryptModNeg( FMod, peT[3], peT[3], pbScratch, cbScratch );             // T3 := -T3 = -Y2*Z1^3
253
254
660
    dResYN = SymCryptModElementIsEqual( FMod, peT[2], peT[3] );
255
256
660
    return (SYMCRYPT_MASK32_NONZERO(flags & SYMCRYPT_FLAG_ECPOINT_EQUAL) & dResX & dResY) |
257
660
           (SYMCRYPT_MASK32_NONZERO(flags & SYMCRYPT_FLAG_ECPOINT_NEG_EQUAL) & dResX & dResYN);
258
660
}
259
260
UINT32
261
SYMCRYPT_CALL
262
SymCryptShortWeierstrassIsZero(
263
    _In_    PCSYMCRYPT_ECURVE   pCurve,
264
    _In_    PCSYMCRYPT_ECPOINT  poSrc,
265
    _Out_writes_bytes_( cbScratch )
266
            PBYTE               pbScratch,
267
            SIZE_T              cbScratch )
268
4.05k
{
269
4.05k
    PCSYMCRYPT_MODULUS FMod = pCurve->FMod;
270
4.05k
    PSYMCRYPT_MODELEMENT peZ = NULL;    // Pointer to Z
271
272
4.05k
    SYMCRYPT_ASSERT( SYMCRYPT_CURVE_IS_SHORT_WEIERSTRASS_TYPE(pCurve) );
273
4.05k
    SYMCRYPT_ASSERT( SymCryptEcurveIsSame(pCurve, poSrc->pCurve) );
274
275
4.05k
    UNREFERENCED_PARAMETER( pbScratch );
276
4.05k
    UNREFERENCED_PARAMETER( cbScratch );
277
278
    // Getting pointer to Z of the source point
279
4.05k
    peZ = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 2, pCurve, poSrc );
280
281
    // Setting temporary to 0
282
4.05k
    return SymCryptModElementIsZero( FMod, peZ );
283
4.05k
}
284
285
//
286
// The following function verifies if the point (X:Y:Z) in Jacobian
287
// coordinates satisfies the equation Y^2 = X^3 + aXZ^4+bZ^6 .
288
//
289
UINT32
290
SYMCRYPT_CALL
291
SymCryptShortWeierstrassOnCurve(
292
    _In_    PCSYMCRYPT_ECURVE   pCurve,
293
    _In_    PCSYMCRYPT_ECPOINT  poSrc,
294
    _Out_writes_bytes_( cbScratch )
295
            PBYTE               pbScratch,
296
            SIZE_T              cbScratch )
297
738
{
298
738
    PCSYMCRYPT_MODULUS FMod = pCurve->FMod;
299
300
738
    PSYMCRYPT_MODELEMENT peX = NULL;    // Pointer to X
301
738
    PSYMCRYPT_MODELEMENT peY = NULL;    // Pointer to Y
302
738
    PSYMCRYPT_MODELEMENT peZ = NULL;    // Pointer to Z
303
304
738
    PSYMCRYPT_MODELEMENT peT[2] = { 0 }; // Temporaries
305
306
738
    SYMCRYPT_ASSERT( SYMCRYPT_CURVE_IS_SHORT_WEIERSTRASS_TYPE(pCurve) );
307
738
    SYMCRYPT_ASSERT( SymCryptEcurveIsSame(pCurve, poSrc->pCurve) );
308
738
    SYMCRYPT_ASSERT( cbScratch >= SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( pCurve->FModDigits ) + 2 * pCurve->cbModElement );
309
310
    // Creating temporaries
311
2.21k
    for (UINT32 i=0; i<2; i++)
312
1.47k
    {
313
1.47k
        peT[i] = SymCryptModElementCreate(
314
1.47k
                pbScratch,
315
1.47k
                pCurve->cbModElement,
316
1.47k
                FMod );
317
318
1.47k
        SYMCRYPT_ASSERT( peT[i] != NULL);
319
320
1.47k
        pbScratch += pCurve->cbModElement;
321
1.47k
    }
322
323
    // Fixing remaining scratch space size
324
738
    cbScratch -= 2*pCurve->cbModElement;
325
326
    // Getting pointers to coordinates of the source point
327
738
    peX = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 0, pCurve, poSrc );
328
738
    peY = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 1, pCurve, poSrc );
329
738
    peZ = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 2, pCurve, poSrc );
330
331
    // Calculation
332
738
    SymCryptModSquare( FMod, peZ, peT[0], pbScratch, cbScratch );               // T1 := Z  * Z  = Z^2
333
738
    SymCryptModSquare( FMod, peT[0], peT[1], pbScratch, cbScratch );            // T2 := T1 * T1 = Z^4
334
738
    SymCryptModMul( FMod, peT[0], peT[1], peT[0], pbScratch, cbScratch );       // T1 := T1 * T2 = Z^6
335
336
738
    SymCryptModMul( FMod, peT[0], pCurve->B, peT[0], pbScratch, cbScratch );    // T1 := T1 * b  = bZ^6
337
338
738
    SymCryptModMul( FMod, peT[1], peX, peT[1], pbScratch, cbScratch );          // T2 := T2 * X  = XZ^4
339
738
    SymCryptModMul( FMod, peT[1], pCurve->A, peT[1], pbScratch, cbScratch );    // T2 := T2 * a  = aXZ^4
340
341
738
    SymCryptModAdd( FMod, peT[0], peT[1], peT[1], pbScratch, cbScratch );       // T2 := T1 + T2 = aXZ^4 + bZ^6
342
343
738
    SymCryptModSquare( FMod, peX, peT[0], pbScratch, cbScratch );               // T1 := X  * X  = X^2
344
738
    SymCryptModMul( FMod, peT[0], peX, peT[0], pbScratch, cbScratch );          // T1 := T1 * X  = X^3
345
738
    SymCryptModAdd( FMod, peT[0], peT[1], peT[1], pbScratch, cbScratch );       // T2 := T1 + T2 = X^3 + aXZ^4 + bZ^6
346
347
738
    SymCryptModSquare( FMod, peY, peT[0], pbScratch, cbScratch );               // T1 := Y  * Y  = Y^2
348
349
738
    return SymCryptModElementIsEqual( FMod, peT[0], peT[1] );
350
738
}
351
352
//
353
// based on dbl-2007-bl formula
354
// but tweaked by saml to
355
//   a) remove overeager conversions from modular multiplication to modular squaring which introduce 
356
//      more addition/subtraction. With current implementations (based on montgomery reduction),
357
//      the cost of [a square and an add/sub] is greater than the cost of [a multiplication]
358
//   b) share intermediate results of producing 8YYYY. [add/sub] is ~10% of cost of mul, so reducing
359
//      count of these operation has a real impact
360
//
361
//      2Y = 2*Y1
362
//      2YY = 2Y*Y1
363
//      4YY = 2*2YY
364
//      8YYYY = 2YY*4YY
365
//      S = X1*4YY
366
//      XX = X1^2
367
//      ZZ = Z1^2
368
//      ZZZZ = ZZ^2
369
//      M = 3*XX+a*ZZZZ
370
//      T = M^2-2*S
371
//      X3 = T
372
//      Y3 = M*(S-T)-8YYYY
373
//      Z3 = Z1*2Y
374
//
375
// Total cost:
376
//      6 Mul (1 by a)
377
//      4 Sqr
378
//      2 Add
379
//      4 Sub
380
//      3 Dbl
381
//
382
// Special Case:
383
//      If the source point is equal to the identity
384
//      point of the curve (i.e. Z1 = 0 in Jacobian
385
//      coordinates) then the resulting point has
386
//      Z3 = Z1*2Y1 = 0. Thus, this formula is
387
//      complete (it works for all points).
388
//
389
VOID
390
SYMCRYPT_CALL
391
SymCryptShortWeierstrassDouble(
392
    _In_    PCSYMCRYPT_ECURVE   pCurve,
393
    _In_    PCSYMCRYPT_ECPOINT  poSrc,
394
    _Out_   PSYMCRYPT_ECPOINT   poDst,
395
            UINT32              flags,
396
    _Out_writes_bytes_( cbScratch )
397
            PBYTE               pbScratch,
398
            SIZE_T              cbScratch )
399
0
{
400
0
    PCSYMCRYPT_MODULUS FMod = pCurve->FMod;
401
0
    PSYMCRYPT_MODELEMENT peT[3] = { 0 };    // Temporaries
402
403
0
    PCSYMCRYPT_MODELEMENT peX1 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 0, pCurve, poSrc );
404
0
    PCSYMCRYPT_MODELEMENT peY1 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 1, pCurve, poSrc );
405
0
    PCSYMCRYPT_MODELEMENT peZ1 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 2, pCurve, poSrc );
406
407
0
    PSYMCRYPT_MODELEMENT  peX3 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 0, pCurve, poDst );
408
0
    PSYMCRYPT_MODELEMENT  peY3 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 1, pCurve, poDst );
409
0
    PSYMCRYPT_MODELEMENT  peZ3 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 2, pCurve, poDst );
410
411
0
    SYMCRYPT_ASSERT( pCurve->type == SYMCRYPT_INTERNAL_ECURVE_TYPE_SHORT_WEIERSTRASS );
412
0
    SYMCRYPT_ASSERT( SymCryptEcurveIsSame(pCurve, poSrc->pCurve) && SymCryptEcurveIsSame(pCurve, poDst->pCurve) );
413
0
    SYMCRYPT_ASSERT( cbScratch >= SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( pCurve->FModDigits ) + 3 * pCurve->cbModElement );
414
415
0
    UNREFERENCED_PARAMETER( flags );
416
417
    // Creating temporaries
418
0
    for (UINT32 i=0; i<3; i++)
419
0
    {
420
0
        peT[i] = SymCryptModElementCreate(
421
0
                pbScratch,
422
0
                pCurve->cbModElement,
423
0
                FMod );
424
425
0
        SYMCRYPT_ASSERT( peT[i] != NULL);
426
427
0
        pbScratch += pCurve->cbModElement;
428
0
    }
429
430
    // Fixing remaining scratch space size
431
0
    cbScratch -= 3*pCurve->cbModElement;
432
433
    // Calculate the points
434
0
    SymCryptModAdd( FMod, peY1, peY1, peT[0], pbScratch, cbScratch );           /* T0 := Y1 + Y1 = 2Y */
435
0
    SymCryptModSquare( FMod, peZ1, peT[1], pbScratch, cbScratch );              /* T1 := Z1 * Z1 = ZZ */
436
0
    SymCryptModMul( FMod, peT[0], peZ1, peZ3, pbScratch, cbScratch );           /* Z3 := 2Y * Z1 = 2YZ */
437
438
0
    SymCryptModMul( FMod, peY1, peT[0], peY3, pbScratch, cbScratch );           /* Y3 := 2Y * Y1 = 2YY */
439
0
    SymCryptModAdd( FMod, peY3, peY3, peT[0], pbScratch, cbScratch );           /* T0 := 2YY + 2YY = 4YY */
440
0
    SymCryptModMul( FMod, peT[0], peY3, peY3, pbScratch, cbScratch );           /* Y3 := 2YY * 4YY = 8YYYY */
441
442
0
    SymCryptModMul( FMod, peT[0], peX1, peT[0], pbScratch, cbScratch );         /* T0 := X1 * 4YY = 4XYY = S */
443
444
0
    SymCryptModSquare( FMod, peT[1], peT[1], pbScratch, cbScratch );            /* T1 := T1 * T1 = ZZZZ */
445
0
    SymCryptModSquare( FMod, peX1, peT[2], pbScratch, cbScratch );              /* T2 := X1 * X1 = XX */
446
0
    SymCryptModMul( FMod, peT[1], pCurve->A, peT[1], pbScratch, cbScratch );    /* T1 := T1 * a  = a*ZZZZ */
447
0
    SymCryptModAdd( FMod, peT[2], peT[1], peT[1], pbScratch, cbScratch );       /* T1 := T2 + T1 = XX + a*ZZZZ */
448
0
    SymCryptModAdd( FMod, peT[2], peT[2], peT[2], pbScratch, cbScratch );       /* T2 := T2 + T2 = 2*XX */
449
0
    SymCryptModAdd( FMod, peT[0], peT[0], peX3, pbScratch, cbScratch );         /* X3 := 2*S */
450
0
    SymCryptModAdd( FMod, peT[2], peT[1], peT[1], pbScratch, cbScratch );       /* T1 := T2 + T1 = 3*XX + a*ZZZZ = M */
451
452
0
    SymCryptModSquare( FMod, peT[1], peT[2], pbScratch, cbScratch );            /* T2 := M^2 */
453
0
    SymCryptModSub( FMod, peT[2], peX3, peX3, pbScratch, cbScratch );           /* X3 := M^2 - 2*S = T */
454
455
0
    SymCryptModSub( FMod, peT[0], peX3, peT[0], pbScratch, cbScratch );         /* T0 := S - T */
456
0
    SymCryptModMul( FMod, peT[1], peT[0], peT[0], pbScratch, cbScratch );       /* T0 := M * (S - T) */
457
0
    SymCryptModSub( FMod, peT[0], peY3, peY3, pbScratch, cbScratch );           /* Y3 := M * (S - T) - 8*YYYY */
458
0
}
459
460
461
//
462
// based on dbl-2007-bl / dbl-2001-b formulae
463
// but tweaked by saml to
464
//   a) remove overeager conversions from modular multiplication to modular squaring which introduce 
465
//      more addition/subtraction. With current implementations (based on montgomery reduction),
466
//      the cost of [a square and an add/sub] is greater than the cost of [a multiplication]
467
//   b) share intermediate results of producing 8YYYY. [add/sub] is ~10% of cost of mul, so reducing
468
//      count of these operation has a real impact
469
//   c) make use of knowledge that curve has a == -3, so M can be calculated more efficiently
470
//
471
//      2Y = 2*Y1
472
//      2YY = 2Y*Y1
473
//      4YY = 2*2YY
474
//      8YYYY = 2YY*4YY
475
//      ZZ = Z1^2
476
//      S = X1*4YY
477
//      M = 3*(X1+ZZ)*(X1-ZZ) = 3*(XX - ZZZZ)
478
//      T = M^2-2*S
479
//      X3 = T
480
//      Y3 = M*(S-T)-8YYYY
481
//      Z3 = 2Y*Z1
482
//
483
// Total cost:
484
//      6 Mul
485
//      2 Sqr
486
//      2 Add
487
//      4 Sub
488
//      4 Dbl
489
//
490
// Special Case:
491
//      If the source point is equal to the identity
492
//      point of the curve (i.e. Z1 = 0 in Jacobian
493
//      coordinates) then the resulting point has
494
//      Z3 = Z1*2Y1 = 0. Thus, this formula is
495
//      complete (it works for all points).
496
//
497
VOID
498
SYMCRYPT_CALL
499
SymCryptShortWeierstrassDoubleSpecializedAm3(
500
    _In_    PCSYMCRYPT_ECURVE   pCurve,
501
    _In_    PCSYMCRYPT_ECPOINT  poSrc,
502
    _Out_   PSYMCRYPT_ECPOINT   poDst,
503
            UINT32              flags,
504
    _Out_writes_bytes_( cbScratch )
505
            PBYTE               pbScratch,
506
            SIZE_T              cbScratch )
507
315k
{
508
315k
    PCSYMCRYPT_MODULUS FMod = pCurve->FMod;
509
315k
    PSYMCRYPT_MODELEMENT peT[3] = { 0 };    // Temporaries
510
511
315k
    PCSYMCRYPT_MODELEMENT peX1 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 0, pCurve, poSrc );
512
315k
    PCSYMCRYPT_MODELEMENT peY1 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 1, pCurve, poSrc );
513
315k
    PCSYMCRYPT_MODELEMENT peZ1 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 2, pCurve, poSrc );
514
515
315k
    PSYMCRYPT_MODELEMENT  peX3 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 0, pCurve, poDst );
516
315k
    PSYMCRYPT_MODELEMENT  peY3 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 1, pCurve, poDst );
517
315k
    PSYMCRYPT_MODELEMENT  peZ3 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 2, pCurve, poDst );
518
519
315k
    SYMCRYPT_ASSERT( pCurve->type == SYMCRYPT_INTERNAL_ECURVE_TYPE_SHORT_WEIERSTRASS_AM3 );
520
315k
    SYMCRYPT_ASSERT( SymCryptEcurveIsSame(pCurve, poSrc->pCurve) && SymCryptEcurveIsSame(pCurve, poDst->pCurve) );
521
315k
    SYMCRYPT_ASSERT( cbScratch >= SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( pCurve->FModDigits ) + 3 * pCurve->cbModElement );
522
523
315k
    UNREFERENCED_PARAMETER( flags );
524
525
    // Creating temporaries
526
1.26M
    for (UINT32 i=0; i<3; i++)
527
945k
    {
528
945k
        peT[i] = SymCryptModElementCreate(
529
945k
                pbScratch,
530
945k
                pCurve->cbModElement,
531
945k
                FMod );
532
533
945k
        SYMCRYPT_ASSERT( peT[i] != NULL);
534
535
945k
        pbScratch += pCurve->cbModElement;
536
945k
    }
537
538
    // Fixing remaining scratch space size
539
315k
    cbScratch -= 3*pCurve->cbModElement;
540
 
541
    // Calculate the points
542
315k
    SymCryptModAdd( FMod, peY1, peY1, peT[0], pbScratch, cbScratch );       /* T0 := Y1 + Y1 = 2Y */
543
315k
    SymCryptModSquare( FMod, peZ1, peT[1], pbScratch, cbScratch );          /* T1 := Z1 * Z1 = ZZ */
544
315k
    SymCryptModMul( FMod, peY1, peT[0], peY3, pbScratch, cbScratch );       /* Y3 := 2Y * Y1 = 2YY */
545
546
315k
    SymCryptModMul( FMod, peT[0], peZ1, peZ3, pbScratch, cbScratch );       /* Z3 := 2Y * Z1 = 2YZ */
547
548
315k
    SymCryptModAdd( FMod, peY3, peY3, peT[0], pbScratch, cbScratch );       /* T0 := 2YY + 2YY = 4YY */
549
315k
    SymCryptModAdd( FMod, peX1, peT[1], peT[2], pbScratch, cbScratch );     /* T2 := X1 + ZZ */
550
315k
    SymCryptModMul( FMod, peT[0], peY3, peY3, pbScratch, cbScratch );       /* Y3 := 2YY * 4YY = 8YYYY */
551
552
315k
    SymCryptModSub( FMod, peX1, peT[1], peT[1], pbScratch, cbScratch );     /* T1 := X1 - ZZ */
553
315k
    SymCryptModMul( FMod, peT[0], peX1, peT[0], pbScratch, cbScratch );     /* T0 := X1 * 4YY = 4XYY = S */
554
555
315k
    SymCryptModMul( FMod, peT[2], peT[1], peT[2], pbScratch, cbScratch );   /* T2 := (X1 + ZZ)*(X1 - ZZ) = XX - ZZZZ */
556
315k
    SymCryptModAdd( FMod, peT[2], peT[2], peT[1], pbScratch, cbScratch );   /* T1 := 2*(XX - ZZZZ) */
557
315k
    SymCryptModAdd( FMod, peT[0], peT[0], peX3, pbScratch, cbScratch );     /* X3 := 2*S */
558
315k
    SymCryptModAdd( FMod, peT[1], peT[2], peT[1], pbScratch, cbScratch );   /* T1 := 3*(XX - ZZZZ) = M */
559
560
315k
    SymCryptModSquare( FMod, peT[1], peT[2], pbScratch, cbScratch );        /* T2 := M^2 */
561
315k
    SymCryptModSub( FMod, peT[2], peX3, peX3, pbScratch, cbScratch );       /* X3 := M^2 - 2*S = T */
562
563
315k
    SymCryptModSub( FMod, peT[0], peX3, peT[0], pbScratch, cbScratch );     /* T0 := S - T */
564
315k
    SymCryptModMul( FMod, peT[1], peT[0], peT[0], pbScratch, cbScratch );   /* T0 := M * (S - T) */
565
315k
    SymCryptModSub( FMod, peT[0], peY3, peY3, pbScratch, cbScratch );       /* Y3 := M * (S - T) - 8*YYYY */
566
315k
}
567
568
//
569
// based on add-2007-bl formula
570
// but tweaked by saml to
571
//      remove overeager conversions from modular multiplication to modular squaring which introduce 
572
//      more addition/subtraction.
573
//
574
//      Z1Z1 = Z1^2
575
//      Z2Z2 = Z2^2
576
//      U1 = X1*Z2Z2
577
//      U2 = X2*Z1Z1
578
//      S1 = Y1*Z2*Z2Z2
579
//      S2 = Y2*Z1*Z1Z1
580
//      H = U2-U1
581
//      2H = 2*H
582
//      I = (2H)^2
583
//      J = H*I
584
//      r = 2*(S2-S1)
585
//      V = U1*I
586
//      X3 = r^2-J-2*V
587
//      Y3 = r*(V-X3)-2*S1*J
588
//      Z3 = (Z1*Z2)*2H
589
//
590
// Total cost:
591
//     12 Mul
592
//      4 Sqr
593
//      0 Add
594
//      7 Sub
595
//      3 Dbl
596
//
597
// Special Case:
598
//      If the two source points are opposite (X1 / Z1^2 == X2 / Z2^2),
599
//      then H = U2-U1 = 0. Thus Z3 = 0 and the result is correct.
600
//
601
VOID
602
SYMCRYPT_CALL
603
SymCryptShortWeierstrassAddDiffNonZero(
604
    _In_    PCSYMCRYPT_ECURVE   pCurve,
605
    _In_    PCSYMCRYPT_ECPOINT  poSrc1,
606
    _In_    PCSYMCRYPT_ECPOINT  poSrc2,
607
    _Out_   PSYMCRYPT_ECPOINT   poDst,
608
    _Out_writes_bytes_( cbScratch )
609
            PBYTE               pbScratch,
610
            SIZE_T              cbScratch )
611
64.1k
{
612
64.1k
    PCSYMCRYPT_MODULUS FMod = pCurve->FMod;
613
614
64.1k
    PCSYMCRYPT_MODELEMENT peX1 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 0, pCurve, poSrc1 );
615
64.1k
    PCSYMCRYPT_MODELEMENT peY1 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 1, pCurve, poSrc1 );
616
64.1k
    PCSYMCRYPT_MODELEMENT peZ1 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 2, pCurve, poSrc1 );
617
618
64.1k
    PCSYMCRYPT_MODELEMENT peX2 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 0, pCurve, poSrc2 );
619
64.1k
    PCSYMCRYPT_MODELEMENT peY2 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 1, pCurve, poSrc2 );
620
64.1k
    PCSYMCRYPT_MODELEMENT peZ2 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 2, pCurve, poSrc2 );
621
622
64.1k
    PSYMCRYPT_MODELEMENT  peX3 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 0, pCurve, poDst );
623
64.1k
    PSYMCRYPT_MODELEMENT  peY3 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 1, pCurve, poDst );
624
64.1k
    PSYMCRYPT_MODELEMENT  peZ3 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 2, pCurve, poDst );
625
626
64.1k
    PSYMCRYPT_MODELEMENT peT[7] = { 0 };  // Temporaries
627
628
64.1k
    SYMCRYPT_ASSERT( SYMCRYPT_CURVE_IS_SHORT_WEIERSTRASS_TYPE(pCurve) );
629
64.1k
    SYMCRYPT_ASSERT( SymCryptEcurveIsSame(pCurve, poSrc1->pCurve) && SymCryptEcurveIsSame(pCurve, poSrc2->pCurve) && SymCryptEcurveIsSame(pCurve, poDst->pCurve) );
630
64.1k
    SYMCRYPT_ASSERT( cbScratch >= SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( pCurve->FModDigits ) + 7 * pCurve->cbModElement );
631
632
    // Creating temporaries
633
512k
    for (UINT32 i=0; i<7; i++)
634
448k
    {
635
448k
        peT[i] = SymCryptModElementCreate(
636
448k
                pbScratch,
637
448k
                pCurve->cbModElement,
638
448k
                FMod );
639
640
448k
        SYMCRYPT_ASSERT( peT[i] != NULL);
641
642
448k
        pbScratch += pCurve->cbModElement;
643
448k
    }
644
645
    // Fixing remaining scratch space size
646
64.1k
    cbScratch -= 7*pCurve->cbModElement;
647
648
    // Calculation
649
650
64.1k
    SymCryptModSquare( FMod, peZ1, peT[0], pbScratch, cbScratch );          /* T0 := Z1 * Z1 = Z1Z1 */
651
64.1k
    SymCryptModMul( FMod, peZ1, peT[0], peT[1], pbScratch, cbScratch );     /* T1 := Z1*Z1Z1 */
652
653
64.1k
    SymCryptModSquare( FMod, peZ2, peT[6], pbScratch, cbScratch );          /* T6 := Z2 * Z2 = Z2Z2 */
654
64.1k
    SymCryptModMul( FMod, peX1, peT[6], peT[2], pbScratch, cbScratch );     /* T2 := X1 * T6 = X1*Z2Z2 = U1 */
655
64.1k
    SymCryptModMul( FMod, peX2, peT[0], peT[3], pbScratch, cbScratch );     /* T3 := X2 * Z1Z1 = U2 */
656
64.1k
    SymCryptModSub( FMod, peT[3], peT[2], peT[5], pbScratch, cbScratch );   /* T5 := T3 - T2 = U2 - U1 = H */
657
64.1k
    SymCryptModAdd( FMod, peT[5], peT[5], peT[3], pbScratch, cbScratch );   /* T3 := T5 + T5 = 2H */
658
659
64.1k
    SymCryptModMul( FMod, peZ1, peZ2, peT[4], pbScratch, cbScratch );       /* T4 := Z1 * Z2 */
660
661
64.1k
    SymCryptModMul( FMod, peZ2, peT[6], peT[6], pbScratch, cbScratch );     /* T6 := Z2 * T6 = Z2*Z2Z2 */
662
64.1k
    SymCryptModMul( FMod, peT[4], peT[3], peZ3, pbScratch, cbScratch );     /* Z3 := T4 * T3 = Z1*Z2*2H */
663
664
64.1k
    SymCryptModMul( FMod, peY1, peT[6], peT[6], pbScratch, cbScratch );     /* T6 := Y1 * T6 = Y1*Z2*Z2Z2 = S1 */
665
64.1k
    SymCryptModMul( FMod, peY2, peT[1], peT[4], pbScratch, cbScratch );     /* T4 := Y2*Z1*Z1Z1 = S2 */
666
64.1k
    SymCryptModSub( FMod, peT[4], peT[6], peT[4], pbScratch, cbScratch );   /* T4 := T4 - T6 = S2-S1 */
667
64.1k
    SymCryptModAdd( FMod, peT[4], peT[4], peT[4], pbScratch, cbScratch );   /* T4 := T4 + T4 = 2*(S2-S1) = r */
668
669
64.1k
    SymCryptModSquare( FMod, peT[3], peT[3], pbScratch, cbScratch );        /* T3 := T3 * T3 = (2*H)^2 = I */
670
64.1k
    SymCryptModMul( FMod, peT[3], peT[5], peT[5], pbScratch, cbScratch );   /* T5 := T3 * T5 = H*I = J */
671
64.1k
    SymCryptModMul( FMod, peT[2], peT[3], peT[3], pbScratch, cbScratch );   /* T3 := T2 * T3 = U1*I = V */
672
673
64.1k
    SymCryptModSquare( FMod, peT[4], peT[2], pbScratch, cbScratch );        /* T2 := T4 * T4 = r^2 */
674
64.1k
    SymCryptModSub( FMod, peT[2], peT[5], peT[2], pbScratch, cbScratch );   /* T2 := T2 - T5 = r^2 - J */
675
64.1k
    SymCryptModSub( FMod, peT[2], peT[3], peT[2], pbScratch, cbScratch );   /* T2 := T2 - T3 = r^2 - J - V */
676
64.1k
    SymCryptModSub( FMod, peT[2], peT[3], peX3, pbScratch, cbScratch );     /* T2 := T2 - T3 = r^2 - J - 2*V = X3 */
677
678
64.1k
    SymCryptModSub( FMod, peT[3], peX3, peT[3], pbScratch, cbScratch );     /* T3 := T3 - T2 = V - X3 */
679
64.1k
    SymCryptModMul( FMod, peT[3], peT[4], peT[3], pbScratch, cbScratch );   /* T3 := T3 * T4 = r*(V-X3) */
680
64.1k
    SymCryptModMul( FMod, peT[6], peT[5], peT[6], pbScratch, cbScratch );   /* T6 := T6 * T5 = S1*J */
681
64.1k
    SymCryptModAdd( FMod, peT[6], peT[6], peT[6], pbScratch, cbScratch );   /* T6 := T6 + T6 = 2*S1*J */
682
64.1k
    SymCryptModSub( FMod, peT[3], peT[6], peY3, pbScratch, cbScratch );     /* Y3 := T6 - T3 = r*(V-X3) - 2*S1*J */
683
64.1k
}
684
685
//
686
// The following function is a complete **SIDE-CHANNEL-UNSAFE**
687
// addition of points that detects as fast as possible the special cases
688
// and merges the two previous calls.
689
//
690
VOID
691
SYMCRYPT_CALL
692
SymCryptShortWeierstrassAddSideChannelUnsafe(
693
    _In_    PCSYMCRYPT_ECURVE   pCurve,
694
    _In_    PCSYMCRYPT_ECPOINT  poSrc1,
695
    _In_    PCSYMCRYPT_ECPOINT  poSrc2,
696
    _Out_   PSYMCRYPT_ECPOINT   poDst,
697
    _Out_writes_bytes_( cbScratch )
698
            PBYTE               pbScratch,
699
            SIZE_T              cbScratch )
700
18.0k
{
701
18.0k
    PCSYMCRYPT_MODULUS FMod = pCurve->FMod;
702
703
18.0k
    PCSYMCRYPT_MODELEMENT peX1 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 0, pCurve, poSrc1 );
704
18.0k
    PCSYMCRYPT_MODELEMENT peY1 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 1, pCurve, poSrc1 );
705
18.0k
    PCSYMCRYPT_MODELEMENT peZ1 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 2, pCurve, poSrc1 );
706
707
18.0k
    PCSYMCRYPT_MODELEMENT peX2 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 0, pCurve, poSrc2 );
708
18.0k
    PCSYMCRYPT_MODELEMENT peY2 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 1, pCurve, poSrc2 );
709
18.0k
    PCSYMCRYPT_MODELEMENT peZ2 = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 2, pCurve, poSrc2 );
710
711
18.0k
    PSYMCRYPT_MODELEMENT peT[8] = { 0 };  // Temporaries
712
713
18.0k
    SYMCRYPT_ASSERT( SYMCRYPT_CURVE_IS_SHORT_WEIERSTRASS_TYPE(pCurve) );
714
18.0k
    SYMCRYPT_ASSERT( SymCryptEcurveIsSame(pCurve, poSrc1->pCurve) && SymCryptEcurveIsSame(pCurve, poSrc2->pCurve) && SymCryptEcurveIsSame(pCurve, poDst->pCurve) );
715
18.0k
    SYMCRYPT_ASSERT( cbScratch >= SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( pCurve->FModDigits ) + 8 * pCurve->cbModElement );
716
717
    // Check if one of the points is zero
718
18.0k
    if (SymCryptModElementIsZero( FMod, peZ1 ))
719
263
    {
720
263
        SymCryptEcpointCopy( pCurve, poSrc2, poDst);
721
263
        return;
722
263
    }
723
724
17.7k
    if (SymCryptModElementIsZero( FMod, peZ2 ))
725
0
    {
726
0
        SymCryptEcpointCopy( pCurve, poSrc1, poDst);
727
0
        return;
728
0
    }
729
730
    // Creating temporaries
731
159k
    for (UINT32 i=0; i<8; i++)
732
141k
    {
733
141k
        peT[i] = SymCryptModElementCreate(
734
141k
                pbScratch,
735
141k
                pCurve->cbModElement,
736
141k
                FMod );
737
738
141k
        SYMCRYPT_ASSERT( peT[i] != NULL);
739
740
141k
        pbScratch += pCurve->cbModElement;
741
141k
    }
742
743
    // Fixing remaining scratch space size
744
17.7k
    cbScratch -= 8*pCurve->cbModElement;
745
746
    // Calculation
747
748
17.7k
    SymCryptModSquare( FMod, peZ1, peT[0], pbScratch, cbScratch );          /* T0 := Z1 * Z1 = Z1Z1 */
749
17.7k
    SymCryptModMul( FMod, peZ1, peT[0], peT[1], pbScratch, cbScratch );     /* T1 := Z1*Z1Z1 */
750
751
17.7k
    SymCryptModSquare( FMod, peZ2, peT[6], pbScratch, cbScratch );          /* T6 := Z2 * Z2 = Z2Z2 */
752
17.7k
    SymCryptModMul( FMod, peX1, peT[6], peT[2], pbScratch, cbScratch );     /* T2 := X1 * T6 = X1*Z2Z2 = U1 */
753
17.7k
    SymCryptModMul( FMod, peX2, peT[0], peT[3], pbScratch, cbScratch );     /* T3 := X2 * Z1Z1 = U2 */
754
17.7k
    SymCryptModSub( FMod, peT[3], peT[2], peT[5], pbScratch, cbScratch );   /* T5 := T3 - T2 = U2 - U1 = H */
755
756
17.7k
    SymCryptModMul( FMod, peY2, peT[1], peT[7], pbScratch, cbScratch );     /* T7 := Y2 * T1 = Y2*Z1*Z1Z1 = S2 */
757
17.7k
    SymCryptModMul( FMod, peZ2, peT[6], peT[1], pbScratch, cbScratch );     /* T1 := Z2 * T6 = Z2*Z2Z2 */
758
17.7k
    SymCryptModMul( FMod, peY1, peT[1], peT[1], pbScratch, cbScratch );     /* T1 := Y1 * T1 = Y1*Z2*Z2Z2 = S1 */
759
17.7k
    SymCryptModSub( FMod, peT[7], peT[1], peT[7], pbScratch, cbScratch );   /* T7 := T7 - T1 = S2-S1 */
760
761
17.7k
    if (SymCryptModElementIsZero( FMod, peT[5] ) & SymCryptModElementIsZero( FMod, peT[7] ))
762
0
    {
763
        // Points are equal - run double on poSrc1
764
765
0
        SymCryptModElementCopy( FMod, peT[0], peT[4] );                             /* Move Z1Z1 for later */
766
767
0
        SymCryptModSquare( FMod, peX1, peT[0], pbScratch, cbScratch );              /* T0 := X1 * X1 = XX */
768
0
        SymCryptModSquare( FMod, peY1, peT[3], pbScratch, cbScratch );              /* T3 := Y1 * Y1 = YY */
769
0
        SymCryptModSquare( FMod, peT[3], peT[5], pbScratch, cbScratch );            /* T5 := T3 * T3 = YYYY */
770
771
0
        SymCryptModAdd( FMod, peX1, peT[3], peT[1], pbScratch, cbScratch );         /* T1 := X1 + T3 = X + YY */
772
0
        SymCryptModSquare( FMod, peT[1], peT[1], pbScratch, cbScratch );            /* T1 := T1 * T1 = (X + YY)^2 */
773
0
        SymCryptModSub( FMod, peT[1], peT[0], peT[1], pbScratch, cbScratch );       /* T1 := T1 - T0 = (X + YY)^2 - XX */
774
0
        SymCryptModSub( FMod, peT[1], peT[5], peT[1], pbScratch, cbScratch );       /* T1 := T1 - T5 = (X + YY)^2 - XX - YYYY */
775
0
        SymCryptModAdd( FMod, peT[1], peT[1], peT[1], pbScratch, cbScratch );       /* T1 := T1 + T1 = 2*((X + YY)^2 - XX - YYYY) = S */
776
777
        //SymCryptModSquare( FMod, peZ1, peT[4], pbScratch, cbScratch );              /* T4 := Z1 * Z1 = ZZ */
778
779
0
        SymCryptModSquare( FMod, peT[4], peT[2], pbScratch, cbScratch );            /* T2 := T4 * T4 = ZZ^2 */
780
0
        SymCryptModMul( FMod, peT[2], pCurve->A, peT[2], pbScratch, cbScratch );    /* T2 := T2 * a  = a*ZZ^2 */
781
0
        SymCryptModAdd( FMod, peT[2], peT[0], peT[2], pbScratch, cbScratch );       /* T2 := T2 + T0 = XX + a*ZZ^2 */
782
0
        SymCryptModAdd( FMod, peT[0], peT[0], peT[0], pbScratch, cbScratch );       /* T0 := T0 + T0 = 2*XX */
783
0
        SymCryptModAdd( FMod, peT[2], peT[0], peT[2], pbScratch, cbScratch );       /* T2 := T2 + T0 = 3*XX + a*ZZ^2 = M */
784
785
0
        SymCryptModSquare( FMod, peT[2], peT[0], pbScratch, cbScratch );            /* T0 := T2 * T2 = M^2 */
786
0
        SymCryptModSub( FMod, peT[0], peT[1], peT[0], pbScratch, cbScratch );       /* T0 := T0 - T1 = M^2 - S */
787
0
        SymCryptModSub( FMod, peT[0], peT[1], peT[0], pbScratch, cbScratch );       /* T0 := T0 - T1 = M^2 - 2*S = T = X3 */
788
789
0
        SymCryptModSub( FMod, peT[1], peT[0], peT[1], pbScratch, cbScratch );       /* T1 := T1 - T0 = S - T */
790
0
        SymCryptModMul( FMod, peT[2], peT[1], peT[1], pbScratch, cbScratch );       /* T1 := T2 * T1 = M * (S - T) */
791
0
        SymCryptModAdd( FMod, peT[5], peT[5], peT[5], pbScratch, cbScratch );       /* T5 := T5 + T5 = 2*YYYY */
792
0
        SymCryptModAdd( FMod, peT[5], peT[5], peT[5], pbScratch, cbScratch );       /* T5 := T5 + T5 = 4*YYYY */
793
0
        SymCryptModAdd( FMod, peT[5], peT[5], peT[5], pbScratch, cbScratch );       /* T5 := T5 + T5 = 8*YYYY */
794
0
        SymCryptModSub( FMod, peT[1], peT[5], peT[1], pbScratch, cbScratch );       /* T1 := T1 - T5 = M * (S - T) - 8*YYYY = Y3 */
795
796
0
        SymCryptModAdd( FMod, peY1, peZ1, peT[2], pbScratch, cbScratch );           /* T2 := Y1 + Z1 */
797
0
        SymCryptModSquare( FMod, peT[2], peT[2], pbScratch, cbScratch );            /* T2 := T2 * T2 = (Y + Z )^2 */
798
0
        SymCryptModSub( FMod, peT[2], peT[3], peT[2], pbScratch, cbScratch );       /* T2 := T2 - T3 = (Y + Z )^2 - YY */
799
0
        SymCryptModSub( FMod, peT[2], peT[4], peT[2], pbScratch, cbScratch );       /* T2 := T2 - T4 = (Y + Z )^2 - YY - ZZ = Z3 */
800
801
        // Setting the result
802
0
        SymCryptModElementCopy( FMod, peT[0], SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 0, pCurve, poDst ) );
803
0
        SymCryptModElementCopy( FMod, peT[1], SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 1, pCurve, poDst ) );
804
0
        SymCryptModElementCopy( FMod, peT[2], SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 2, pCurve, poDst ) );
805
0
    }
806
17.7k
    else
807
17.7k
    {
808
        // Continue the addition
809
810
17.7k
        SymCryptModAdd( FMod, peZ1, peZ2, peT[4], pbScratch, cbScratch );       /* T4 := Z1 + Z2 */
811
17.7k
        SymCryptModSquare( FMod, peT[4], peT[4], pbScratch, cbScratch );        /* T4 := T4 * T4 = (Z1 + Z2)^2 */
812
17.7k
        SymCryptModSub( FMod, peT[4], peT[0], peT[4], pbScratch, cbScratch );   /* T4 := T4 - Z1Z1 = (Z1 + Z2)^2 - Z1Z1 */
813
17.7k
        SymCryptModSub( FMod, peT[4], peT[6], peT[4], pbScratch, cbScratch );   /* T4 := T4 - T6 = (Z1 + Z2)^2 - Z1Z1 - Z2Z2 */
814
17.7k
        SymCryptModMul( FMod, peT[4], peT[5], peT[4], pbScratch, cbScratch );   /* T4 := T4 * T5 = ((Z1 + Z2)^2 - Z1Z1 - Z2Z2)*H = Z3 */
815
816
17.7k
        SymCryptModAdd( FMod, peT[7], peT[7], peT[7], pbScratch, cbScratch );   /* T7 := T7 + T7 = 2*(S2-S1) = r */
817
818
17.7k
        SymCryptModAdd( FMod, peT[5], peT[5], peT[3], pbScratch, cbScratch );   /* T3 := T5 + T5 = 2*H */
819
17.7k
        SymCryptModSquare( FMod, peT[3], peT[3], pbScratch, cbScratch );        /* T3 := T3 * T3 = (2*H)^2 = I */
820
17.7k
        SymCryptModMul( FMod, peT[3], peT[5], peT[5], pbScratch, cbScratch );   /* T5 := T3 * T5 = H*I = J */
821
17.7k
        SymCryptModMul( FMod, peT[2], peT[3], peT[3], pbScratch, cbScratch );   /* T3 := T2 * T3 = U1*I = V */
822
823
17.7k
        SymCryptModSquare( FMod, peT[7], peT[2], pbScratch, cbScratch );        /* T2 := T7 * T7 = r^2 */
824
17.7k
        SymCryptModSub( FMod, peT[2], peT[5], peT[2], pbScratch, cbScratch );   /* T2 := T2 - T5 = r^2 - J */
825
17.7k
        SymCryptModSub( FMod, peT[2], peT[3], peT[2], pbScratch, cbScratch );   /* T2 := T2 - T3 = r^2 - J - V */
826
17.7k
        SymCryptModSub( FMod, peT[2], peT[3], peT[2], pbScratch, cbScratch );   /* T2 := T2 - T3 = r^2 - J - 2*V = X3 */
827
828
17.7k
        SymCryptModSub( FMod, peT[3], peT[2], peT[3], pbScratch, cbScratch );   /* T3 := T3 - T2 = V - X3 */
829
17.7k
        SymCryptModMul( FMod, peT[3], peT[7], peT[3], pbScratch, cbScratch );   /* T3 := T3 * T7 = r*(V-X3) */
830
17.7k
        SymCryptModMul( FMod, peT[1], peT[5], peT[6], pbScratch, cbScratch );   /* T6 := T1 * T5 = S1*J */
831
17.7k
        SymCryptModAdd( FMod, peT[6], peT[6], peT[6], pbScratch, cbScratch );   /* T6 := T6 + T6 = 2*S1*J */
832
17.7k
        SymCryptModSub( FMod, peT[3], peT[6], peT[3], pbScratch, cbScratch );   /* T3 := T6 - T3 = r*(V-X3) - 2*S1*J = Y3 */
833
834
        // Setting the result
835
17.7k
        SymCryptModElementCopy( FMod, peT[2], SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 0, pCurve, poDst ) );
836
17.7k
        SymCryptModElementCopy( FMod, peT[3], SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 1, pCurve, poDst ) );
837
17.7k
        SymCryptModElementCopy( FMod, peT[4], SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 2, pCurve, poDst ) );
838
17.7k
    }
839
17.7k
}
840
841
VOID
842
SYMCRYPT_CALL
843
SymCryptShortWeierstrassAdd(
844
    _In_    PCSYMCRYPT_ECURVE   pCurve,
845
    _In_    PCSYMCRYPT_ECPOINT  poSrc1,
846
    _In_    PCSYMCRYPT_ECPOINT  poSrc2,
847
    _Out_   PSYMCRYPT_ECPOINT   poDst,
848
            UINT32              flags,
849
    _Out_writes_bytes_( cbScratch )
850
            PBYTE               pbScratch,
851
            SIZE_T              cbScratch )
852
18.6k
{
853
18.6k
    UINT32 dSrc1Zero = 0;
854
18.6k
    UINT32 dSrc2Zero = 0;
855
18.6k
    UINT32 dSrcEqual = 0;
856
857
    // Temporary points
858
18.6k
    PSYMCRYPT_ECPOINT   poQ0 = NULL;
859
18.6k
    PSYMCRYPT_ECPOINT   poQ1 = NULL;
860
861
18.6k
    SIZE_T cbEcpoint = SymCryptSizeofEcpointFromCurve( pCurve );
862
863
18.6k
    SYMCRYPT_ASSERT( SYMCRYPT_CURVE_IS_SHORT_WEIERSTRASS_TYPE(pCurve) );
864
18.6k
    SYMCRYPT_ASSERT( SymCryptEcurveIsSame(pCurve, poSrc1->pCurve) && SymCryptEcurveIsSame(pCurve, poSrc2->pCurve) && SymCryptEcurveIsSame(pCurve, poDst->pCurve) );
865
18.6k
    SYMCRYPT_ASSERT( cbScratch >= SYMCRYPT_INTERNAL_SCRATCH_BYTES_FOR_COMMON_ECURVE_OPERATIONS( pCurve ) );     // We will need the entire scratch space
866
867
18.6k
    SYMCRYPT_ASSERT( cbScratch > 2*cbEcpoint );
868
869
18.6k
    if ((flags & SYMCRYPT_FLAG_DATA_PUBLIC) != 0)
870
18.0k
    {
871
18.0k
        SymCryptShortWeierstrassAddSideChannelUnsafe( pCurve, poSrc1, poSrc2, poDst, pbScratch, cbScratch );
872
18.0k
    }
873
660
    else
874
660
    {
875
        // Creating temporary points
876
660
        poQ0 = SymCryptEcpointCreate( pbScratch, cbEcpoint, pCurve );
877
660
        SYMCRYPT_ASSERT( poQ0 != NULL);
878
660
        pbScratch += cbEcpoint;
879
880
660
        poQ1 = SymCryptEcpointCreate( pbScratch, cbEcpoint, pCurve );
881
660
        SYMCRYPT_ASSERT( poQ1 != NULL);
882
660
        pbScratch += cbEcpoint;
883
884
        // Fixing remaining scratch space size
885
660
        cbScratch -= 2*cbEcpoint;
886
887
        // Calculate the masks
888
660
        dSrc1Zero = SymCryptShortWeierstrassIsZero( pCurve, poSrc1, pbScratch, cbScratch );
889
660
        dSrc2Zero = SymCryptShortWeierstrassIsZero( pCurve, poSrc2, pbScratch, cbScratch );
890
660
        dSrcEqual = SymCryptShortWeierstrassIsEqual( pCurve, poSrc1, poSrc2, SYMCRYPT_FLAG_ECPOINT_EQUAL, pbScratch, cbScratch );
891
892
        // Side-channel safe computations
893
660
        SymCryptShortWeierstrassAddDiffNonZero( pCurve, poSrc1, poSrc2, poQ0, pbScratch, cbScratch );   // This covers the cases where Src1 != Src2 or Src1 = -Src2
894
895
660
        SymCryptEcpointDouble( pCurve, poSrc1, poQ1, 0, pbScratch, cbScratch );     // Dispatch to Double function; enables type assertion on SymCryptShortWeierstrassDouble to be specific
896
660
        SymCryptEcpointMaskedCopy( pCurve, poQ1, poQ0, dSrcEqual );                                     // (Masked) copy if the points are equal
897
898
660
        SymCryptEcpointMaskedCopy( pCurve, poSrc1, poQ0, dSrc2Zero );                                   // (Masked) copy if Src2 = 0
899
660
        SymCryptEcpointMaskedCopy( pCurve, poSrc2, poQ0, dSrc1Zero );                                   // (Masked) copy if Src1 = 0
900
901
660
        SymCryptEcpointCopy( pCurve, poQ0, poDst );                                 // Copy the final result to destination
902
660
    }
903
18.6k
}
904
905
VOID
906
SYMCRYPT_CALL
907
SymCryptShortWeierstrassNegate(
908
    _In_    PCSYMCRYPT_ECURVE   pCurve,
909
    _Inout_ PSYMCRYPT_ECPOINT   poSrc,
910
            UINT32              mask,
911
    _Out_writes_bytes_( cbScratch )
912
            PBYTE               pbScratch,
913
            SIZE_T              cbScratch )
914
58.2k
{
915
58.2k
    PCSYMCRYPT_MODULUS FMod = pCurve->FMod;
916
58.2k
    PSYMCRYPT_MODELEMENT peY = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 1, pCurve, poSrc);
917
918
58.2k
    PSYMCRYPT_MODELEMENT peTmp = NULL;
919
920
58.2k
    SYMCRYPT_ASSERT( SYMCRYPT_CURVE_IS_SHORT_WEIERSTRASS_TYPE(pCurve) );
921
58.2k
    SYMCRYPT_ASSERT( SymCryptEcurveIsSame(pCurve, poSrc->pCurve) );
922
58.2k
    SYMCRYPT_ASSERT( cbScratch >= SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( pCurve->FModDigits ) + pCurve->cbModElement);
923
924
58.2k
    peTmp = SymCryptModElementCreate(
925
58.2k
                pbScratch,
926
58.2k
                pCurve->cbModElement,
927
58.2k
                FMod );
928
58.2k
    SYMCRYPT_ASSERT( peTmp != NULL);
929
930
58.2k
    pbScratch += pCurve->cbModElement;
931
58.2k
    cbScratch -= pCurve->cbModElement;
932
933
58.2k
    SymCryptModNeg( FMod, peY, peTmp, pbScratch, cbScratch );
934
58.2k
    SymCryptModElementMaskedCopy( FMod, peTmp, peY, mask );
935
58.2k
}