Coverage Report

Created: 2024-11-21 07:03

/src/SymCrypt/lib/ec_mul.c
Line
Count
Source (jump to first uncovered line)
1
//
2
// ec_mul.c   Generic multiplication algorithms for elliptic curves
3
//
4
// Copyright (c) Microsoft Corporation. Licensed under the MIT license.
5
//
6
//
7
8
#include "precomp.h"
9
10
//
11
// Most of the following algorithms were presented in the paper
12
// "Selecting Elliptic Curves for Cryptography: An Efficiency and
13
//  Security Analysis" by Bos, Costello, Longa, and Naehrig
14
//
15
16
//
17
// The following is an adaptation of algorithm 4: "Precomputation
18
// scheme for Weierstrass curves"
19
//
20
// Input:   Point P and number of precomputed points nPoints (=2^(w-2))
21
//
22
// Output:  P[i] = (2*i+1)P for 0<=i<2^(w-2)
23
//
24
// Remarks:
25
//          1. We store each point in an array of 4*2^(w-2) = 2^w modelements where
26
//             each point is represented with X,Y,Z Jacobian coordinates and the W=-Y
27
//             negated Y coordinate (so that we can get the negative of a point easily)
28
//          2. The source point P is already in the 0'th position of the array.
29
//
30
VOID
31
SYMCRYPT_CALL
32
SymCryptPrecomputation(
33
    _In_    PCSYMCRYPT_ECURVE       pCurve,
34
            UINT32                  nPoints,
35
    _In_reads_( SYMCRYPT_ECURVE_SW_MAX_NPRECOMP_POINTS )
36
            PSYMCRYPT_ECPOINT *     poPIs,
37
    _Out_   PSYMCRYPT_ECPOINT       poQ,
38
    _Out_writes_bytes_( cbScratch )
39
            PBYTE               pbScratch,
40
            SIZE_T              cbScratch )
41
1.20k
{
42
1.20k
    SYMCRYPT_ASSERT( SymCryptEcurveIsSame(pCurve, poQ->pCurve) );
43
    // Calculation for Q = 2*P
44
1.20k
    SymCryptEcpointDouble( pCurve, poPIs[0], poQ, 0, pbScratch, cbScratch );
45
46
19.2k
    for (UINT32 i=1; i<nPoints; i++)
47
18.0k
    {
48
        // Calculation for (2i+1)*P = i*Q + P
49
18.0k
        SymCryptEcpointAddDiffNonZero( pCurve, poQ, poPIs[i-1], poPIs[i], pbScratch, cbScratch );
50
18.0k
    }
51
1.20k
}
52
53
VOID
54
SYMCRYPT_CALL
55
SymCryptOfflinePrecomputation(
56
    _In_    PSYMCRYPT_ECURVE pCurve,
57
    _Out_writes_bytes_( cbScratch )
58
            PBYTE         pbScratch,
59
            SIZE_T        cbScratch )
60
946
{
61
946
    PSYMCRYPT_ECPOINT poQ = NULL;
62
63
946
    UINT32 cbEcpoint = SymCryptSizeofEcpointFromCurve( pCurve );
64
65
946
    SYMCRYPT_ASSERT( cbScratch >= cbEcpoint + SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( pCurve->FModDigits ) );
66
67
946
    poQ = SymCryptEcpointCreate( pbScratch, cbEcpoint, pCurve );
68
946
    SYMCRYPT_ASSERT( poQ != NULL );
69
946
    pbScratch += cbEcpoint;
70
946
    cbScratch -= cbEcpoint;
71
72
946
    SymCryptPrecomputation(
73
946
                pCurve,
74
946
                pCurve->info.sw.nPrecompPoints,
75
946
                pCurve->info.sw.poPrecompPoints,
76
946
                poQ,
77
946
                pbScratch,
78
946
                cbScratch );
79
946
}
80
81
// Mask which is 0xffffffff only when _index == _target
82
968k
#define DELTA_MASK( _index, _target)    SYMCRYPT_MASK32_ZERO( (_index) ^ (_target) )
83
84
//
85
// The following is an adaptation of algorithm 1: "Variable-base scalar multiplication
86
// using the fixed-window method"
87
//
88
SYMCRYPT_ERROR
89
SYMCRYPT_CALL
90
SymCryptEcpointScalarMulFixedWindow(
91
    _In_    PCSYMCRYPT_ECURVE       pCurve,
92
    _In_    PCSYMCRYPT_INT          piScalar,
93
    _In_opt_
94
            PCSYMCRYPT_ECPOINT      poSrc,
95
            UINT32                  flags,
96
    _Out_   PSYMCRYPT_ECPOINT       poDst,
97
    _Out_writes_bytes_( cbScratch )
98
            PBYTE               pbScratch,
99
            SIZE_T              cbScratch )
100
795
{
101
795
    SYMCRYPT_ERROR  scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;
102
103
795
    PCSYMCRYPT_MODULUS FMod = pCurve->FMod;
104
105
795
    UINT32  i, j;
106
107
795
    UINT32  w = pCurve->info.sw.window;
108
795
    UINT32  nPrecompPoints = pCurve->info.sw.nPrecompPoints;
109
  // dcl - assuming that nRecodedDigits has some reasonably small range - please document
110
  // so that we can know usage of this variable will not cause problems
111
  // Also, documentation of inputs, notes, etc at the function definition would be quite helpful
112
795
    UINT32  nRecodedDigits = ((pCurve->GOrdBitsize + w - 2) / (w-1)) + 1;
113
114
    // Masks
115
795
    UINT32  fZero = 0;
116
795
    UINT32  fEven = 0;
117
795
    UINT32  indexMask = 0;
118
119
795
    BOOLEAN bPrecompOffline = FALSE;
120
121
    // ====================================================
122
    // Temporaries
123
795
    PSYMCRYPT_MODELEMENT    peT = NULL;
124
795
    PSYMCRYPT_ECPOINT       poPIs[SYMCRYPT_ECURVE_SW_MAX_NPRECOMP_POINTS] = { 0 };
125
795
    PSYMCRYPT_ECPOINT       poQ = NULL;
126
795
    PSYMCRYPT_ECPOINT       poTmp = NULL;
127
795
    PSYMCRYPT_INT           piRem = NULL;
128
795
    PSYMCRYPT_INT           piTmp = NULL;
129
795
    PUINT32                 absofKIs = NULL;
130
795
    PUINT32                 sigofKIs = NULL;
131
    // ===================================================
132
133
795
    PSYMCRYPT_MODELEMENT    peQX = NULL;
134
795
    PSYMCRYPT_MODELEMENT    peQY = NULL;
135
795
    PSYMCRYPT_MODELEMENT    peQZ = NULL;
136
137
795
    SIZE_T cbEcpoint = SymCryptSizeofEcpointFromCurve( pCurve );
138
795
    SIZE_T cbScalar = SymCryptSizeofIntFromDigits( pCurve->GOrdDigits );
139
140
    // Make sure we only specify the correct flags
141
795
    if ((flags & ~SYMCRYPT_FLAG_ECC_LL_COFACTOR_MUL) != 0)
142
0
    {
143
0
        scError = SYMCRYPT_INVALID_ARGUMENT;
144
0
        goto exit;
145
0
    }
146
147
    // Check if poSrc is NULL and if yes set it to G
148
795
    if (poSrc == NULL)
149
726
    {
150
726
        poSrc = pCurve->G;
151
726
        bPrecompOffline = TRUE;
152
726
    }
153
154
795
    SYMCRYPT_ASSERT( SYMCRYPT_CURVE_IS_SHORT_WEIERSTRASS_TYPE(pCurve) ||
155
795
                     SYMCRYPT_CURVE_IS_TWISTED_EDWARDS_TYPE(pCurve) );
156
795
    SYMCRYPT_ASSERT( SymCryptEcurveIsSame(pCurve, poSrc->pCurve) && SymCryptEcurveIsSame(pCurve, poDst->pCurve) );
157
795
    SYMCRYPT_ASSERT( cbScratch >= SYMCRYPT_INTERNAL_SCRATCH_BYTES_FOR_SCALAR_ECURVE_OPERATIONS(pCurve, 1) );
158
159
795
    SYMCRYPT_ASSERT( cbScratch >=
160
795
                        pCurve->cbModElement +
161
795
                        (nPrecompPoints+2)*cbEcpoint +
162
795
                        2*cbScalar +
163
795
                        ((2*nRecodedDigits*sizeof(UINT32) + SYMCRYPT_ASYM_ALIGN_VALUE - 1)/SYMCRYPT_ASYM_ALIGN_VALUE )*SYMCRYPT_ASYM_ALIGN_VALUE +
164
795
                        SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_ECURVE_OPERATIONS( pCurve ) );
165
166
    // Creating temporary modelement
167
795
    peT = SymCryptModElementCreate( pbScratch, pCurve->cbModElement, FMod );
168
795
    SYMCRYPT_ASSERT( peT != NULL );
169
795
    pbScratch += pCurve->cbModElement;
170
171
    // Creating temporary precomputed points (if needed)
172
795
    SYMCRYPT_ASSERT( nPrecompPoints <= SYMCRYPT_ECURVE_SW_MAX_NPRECOMP_POINTS );
173
13.5k
    for (i=0; i<nPrecompPoints; i++)
174
12.7k
    {
175
12.7k
        if (bPrecompOffline)
176
11.6k
        {
177
11.6k
            poPIs[i] = pCurve->info.sw.poPrecompPoints[i];
178
11.6k
        }
179
1.10k
        else
180
1.10k
        {
181
1.10k
            poPIs[i] = SymCryptEcpointCreate( pbScratch, cbEcpoint, pCurve );
182
1.10k
            SYMCRYPT_ASSERT( poPIs[i] != NULL );
183
1.10k
            pbScratch += cbEcpoint;
184
1.10k
        }
185
12.7k
    }
186
187
    // Creating temporary points
188
795
    poQ = SymCryptEcpointCreate( pbScratch, cbEcpoint, pCurve );
189
795
    SYMCRYPT_ASSERT( poQ != NULL );
190
795
    pbScratch += cbEcpoint;
191
192
795
    poTmp = SymCryptEcpointCreate( pbScratch, cbEcpoint, pCurve );
193
795
    SYMCRYPT_ASSERT( poTmp != NULL );
194
795
    pbScratch += cbEcpoint;
195
196
    // Creating temporary scalar for the remainder
197
795
    piRem = SymCryptIntCreate( pbScratch, cbScalar, pCurve->GOrdDigits );
198
795
    SYMCRYPT_ASSERT( piRem != NULL);
199
795
    pbScratch += cbScalar;
200
201
795
    piTmp = SymCryptIntCreate( pbScratch, cbScalar, pCurve->GOrdDigits );
202
795
    SYMCRYPT_ASSERT( piTmp != NULL);
203
795
    pbScratch += cbScalar;
204
205
    // Fixing pointers to recoded digits (be careful that the remaining space is SYMCRYPT_ASYM_ALIGNed)
206
795
    absofKIs = (PUINT32) pbScratch;
207
795
    pbScratch += nRecodedDigits * sizeof(UINT32);
208
795
    sigofKIs = (PUINT32) pbScratch;
209
795
    pbScratch += nRecodedDigits * sizeof(UINT32);
210
795
    pbScratch = (PBYTE) ( ((ULONG_PTR)pbScratch + SYMCRYPT_ASYM_ALIGN_VALUE - 1) & ~(SYMCRYPT_ASYM_ALIGN_VALUE - 1) );
211
212
    // Fixing remaining scratch space size
213
795
    cbScratch -= ( pCurve->cbModElement + (nPrecompPoints+2)*cbEcpoint + 2*cbScalar );
214
795
    cbScratch -= (((2*nRecodedDigits*sizeof(UINT32) + SYMCRYPT_ASYM_ALIGN_VALUE - 1)/SYMCRYPT_ASYM_ALIGN_VALUE )*SYMCRYPT_ASYM_ALIGN_VALUE);
215
216
    //
217
    // Main algorithm
218
    //
219
220
    // It is the caller's responsibility to ensure that the provided piScalar <= GOrd, double check this in debug mode
221
795
    SYMCRYPT_ASSERT( !SymCryptIntIsLessThan( SymCryptIntFromModulus( pCurve->GOrd ), piScalar ) );
222
223
    // Store k into an int
224
795
    SymCryptIntCopy( piScalar, piRem );
225
226
    // Check if k is 0
227
795
    fZero = SymCryptIntIsEqualUint32( piRem, 0 );
228
229
    // Or if the src point is zero
230
795
    fZero |= SymCryptEcpointIsZero( pCurve, poSrc, pbScratch, cbScratch );
231
232
    // Check if k is even and convert it to r-k if true
233
795
    fEven = SYMCRYPT_MASK32_ZERO(SymCryptIntGetBit( piRem, 0 ));
234
795
    SymCryptIntSubSameSize( SymCryptIntFromModulus(pCurve->GOrd), piRem, piTmp);
235
795
    SymCryptIntMaskedCopy( piTmp, piRem, fEven );
236
237
    // Recoding stage
238
795
    SymCryptFixedWindowRecoding( w, piRem, piTmp, absofKIs, sigofKIs, nRecodedDigits );
239
240
    // Precomputation stage
241
795
    if (!bPrecompOffline)
242
69
    {
243
        // Copy the first point in the start of the poPIs array
244
69
        SymCryptEcpointCopy( pCurve, poSrc, poPIs[0] );
245
246
69
        SymCryptPrecomputation( pCurve, nPrecompPoints, poPIs, poQ, pbScratch, cbScratch );
247
69
    }
248
249
250
    // Get the pointers to Q
251
795
    peQX = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 0, pCurve, poQ );
252
795
    peQY = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 1, pCurve, poQ );
253
795
    peQZ = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 2, pCurve, poQ );
254
255
    // Q = P[ (|k_t|-1)/2 ] in memory access side-channel safe way
256
    // That is, we touch all the precomputed points. The access pattern of KIs is fixed.
257
13.5k
    for (j=0; j<nPrecompPoints; j++)
258
12.7k
    {
259
12.7k
        indexMask = DELTA_MASK( j, absofKIs[nRecodedDigits-1] );
260
12.7k
        SymCryptEcpointMaskedCopy( pCurve, poPIs[j], poQ, indexMask);
261
12.7k
    }
262
263
59.7k
    for (i=nRecodedDigits - 2; i>0; i--)
264
58.9k
    {
265
        // Q = 2^(w-1) * Q
266
353k
        for (j=0; j<w-1; j++)
267
294k
        {
268
294k
            SymCryptEcpointDouble( pCurve, poQ, poQ, 0, pbScratch, cbScratch );
269
294k
        }
270
271
        // Copy the required precomputed point into poTmp (touch all points)
272
1.00M
        for (j=0; j<nPrecompPoints; j++)
273
942k
        {
274
942k
            indexMask = DELTA_MASK( j, absofKIs[i] );
275
942k
            SymCryptEcpointMaskedCopy( pCurve, poPIs[j], poTmp, indexMask);
276
942k
        }
277
278
        // Negate if needed
279
58.9k
        SymCryptEcpointNegate( pCurve, poTmp, sigofKIs[i], pbScratch, cbScratch );
280
281
        // Do the addition Q + s_i P[k_i]
282
58.9k
        SymCryptEcpointAddDiffNonZero( pCurve, poQ, poTmp, poQ, pbScratch, cbScratch );
283
58.9k
    }
284
285
    // Q = 2^(w-1) * Q
286
4.77k
    for (j=0; j<w-1; j++)
287
3.97k
    {
288
3.97k
        SymCryptEcpointDouble( pCurve, poQ, poQ, 0, pbScratch, cbScratch );
289
3.97k
    }
290
291
    // Copy the point s_0 P[k_0] into poTmp
292
13.5k
    for (j=0; j<nPrecompPoints; j++)
293
12.7k
    {
294
12.7k
        indexMask = DELTA_MASK( j, absofKIs[0] );
295
12.7k
        SymCryptEcpointMaskedCopy( pCurve, poPIs[j], poTmp, indexMask);
296
12.7k
    }
297
298
    // Negate if needed
299
795
    SymCryptEcpointNegate( pCurve, poTmp, sigofKIs[0], pbScratch, cbScratch );
300
301
    // Complete addition routine
302
795
    SymCryptEcpointAdd( pCurve, poQ, poTmp, poQ, 0, pbScratch, cbScratch );
303
304
    // If even invert
305
795
    SymCryptEcpointNegate( pCurve, poQ, fEven, pbScratch, cbScratch );
306
307
    // Multiply by the cofactor (if needed) by continuing the doubling
308
795
    if ((pCurve->coFactorPower!=0) && ((flags & SYMCRYPT_FLAG_ECC_LL_COFACTOR_MUL) != 0))
309
47
    {
310
141
        for (j=0; j<pCurve->coFactorPower; j++)
311
94
        {
312
94
            SymCryptEcpointDouble( pCurve, poQ, poQ, 0, pbScratch, cbScratch );
313
94
        }
314
47
    }
315
316
    // If the resultant point is zero, ensure it will be set to the canonical zero point
317
795
    fZero |= SymCryptEcpointIsZero( pCurve, poQ, pbScratch, cbScratch );
318
319
    // Set the zero point
320
795
    SymCryptEcpointSetZero( pCurve, poTmp, pbScratch, cbScratch );
321
795
    SymCryptEcpointMaskedCopy( pCurve, poTmp, poQ, fZero );
322
323
    // Output the result (normalized flag == FALSE)
324
795
    SymCryptEcpointCopy( pCurve, poQ, poDst );
325
326
795
    scError = SYMCRYPT_NO_ERROR;
327
328
795
exit:
329
330
795
    return scError;
331
795
}
332
333
//
334
// The following is an adaptation of algorithm 9: "Double-scalar multiplication using the
335
// width-w NAF with interleaving"
336
//
337
SYMCRYPT_ERROR
338
SYMCRYPT_CALL
339
SymCryptEcpointMultiScalarMulWnafWithInterleaving(
340
    _In_                            PCSYMCRYPT_ECURVE       pCurve,
341
    _In_reads_( nPoints )           PCSYMCRYPT_INT *        piSrcScalarArray,
342
    _In_reads_( nPoints )           PCSYMCRYPT_ECPOINT *    poSrcEcpointArray,
343
    _In_                            UINT32                  nPoints,
344
    _In_                            UINT32                  flags,
345
    _Out_                           PSYMCRYPT_ECPOINT       poDst,
346
    _Out_writes_bytes_( cbScratch ) PBYTE                   pbScratch,
347
                                    SIZE_T                  cbScratch )
348
191
{
349
191
    SYMCRYPT_ERROR  scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;
350
351
191
    UINT32  i, j;
352
353
191
    UINT32  w = pCurve->info.sw.window;
354
191
    UINT32  nPrecompPoints = pCurve->info.sw.nPrecompPoints;            // One table for each base
355
191
    UINT32  nRecodedDigits = pCurve->GOrdBitsize + 1;                   // Notice the difference with the fixed window
356
357
    // Masks
358
191
    UINT32  fZero[SYMCRYPT_ECURVE_MULTI_SCALAR_MUL_MAX_NPOINTS] = { 0 };
359
191
    UINT32  fZeroTot = 0xffffffff;
360
361
191
    BOOLEAN bPrecompOffline = FALSE;
362
363
    // ====================================================
364
    // Temporaries
365
191
    PSYMCRYPT_ECPOINT       poPIs[SYMCRYPT_ECURVE_SW_MAX_NPRECOMP_POINTS] = { 0 };
366
191
    PSYMCRYPT_ECPOINT       poQ = NULL;
367
191
    PSYMCRYPT_ECPOINT       poTmp = NULL;
368
191
    PSYMCRYPT_INT           piRem = NULL;
369
191
    PSYMCRYPT_INT           piTmp = NULL;
370
371
191
    PUINT32                 absofKIs = NULL;
372
191
    PUINT32                 sigofKIs = NULL;
373
    // ===================================================
374
375
191
    SIZE_T cbEcpoint = SymCryptSizeofEcpointFromCurve( pCurve );
376
191
    SIZE_T cbScalar = SymCryptSizeofIntFromDigits( pCurve->GOrdDigits );
377
378
191
    PBYTE pbScratchEnd = pbScratch + cbScratch;
379
191
    UNREFERENCED_PARAMETER( pbScratchEnd ); // Used in asserts
380
381
    // Make sure we only specify the correct flags
382
191
    if ((flags & ~(SYMCRYPT_FLAG_DATA_PUBLIC | SYMCRYPT_FLAG_ECC_LL_COFACTOR_MUL)) != 0)
383
0
    {
384
0
        scError = SYMCRYPT_INVALID_ARGUMENT;
385
0
        goto exit;
386
0
    }
387
388
    // Check the maximum number of points
389
191
    if (nPoints > SYMCRYPT_ECURVE_MULTI_SCALAR_MUL_MAX_NPOINTS)
390
0
    {
391
0
        scError = SYMCRYPT_NOT_IMPLEMENTED;
392
0
        goto exit;
393
0
    }
394
395
    // Check if the first point is NULL
396
191
    if (poSrcEcpointArray[0] == NULL)
397
191
    {
398
191
        poSrcEcpointArray[0] = pCurve->G;
399
191
        bPrecompOffline = TRUE;
400
191
    }
401
402
    // Make sure that the non side-channel flag is specified
403
191
    if ((flags & SYMCRYPT_FLAG_DATA_PUBLIC) == 0 )
404
0
    {
405
0
        scError = SYMCRYPT_NOT_IMPLEMENTED;
406
0
        goto exit;
407
0
    }
408
409
191
    SYMCRYPT_ASSERT( SYMCRYPT_CURVE_IS_SHORT_WEIERSTRASS_TYPE(pCurve) ||
410
191
                     SYMCRYPT_CURVE_IS_TWISTED_EDWARDS_TYPE(pCurve) );
411
191
    SYMCRYPT_ASSERT( SymCryptEcurveIsSame(pCurve, poDst->pCurve) );
412
191
    SYMCRYPT_ASSERT( cbScratch >= SYMCRYPT_INTERNAL_SCRATCH_BYTES_FOR_SCALAR_ECURVE_OPERATIONS(pCurve, nPoints) );
413
414
    // Creating temporary precomputed points (if needed for the first point)
415
6.30k
    for (i=0; i<nPoints*nPrecompPoints; i++)
416
6.11k
    {
417
6.11k
        if ((i<nPrecompPoints) && bPrecompOffline)
418
3.05k
        {
419
3.05k
            poPIs[i] = pCurve->info.sw.poPrecompPoints[i];
420
3.05k
        }
421
3.05k
        else
422
3.05k
        {
423
3.05k
            SYMCRYPT_ASSERT( pbScratch + cbEcpoint <= pbScratchEnd );
424
3.05k
            poPIs[i] = SymCryptEcpointCreate( pbScratch, cbEcpoint, pCurve );
425
3.05k
            SYMCRYPT_ASSERT( poPIs[i] != NULL );
426
3.05k
            pbScratch += cbEcpoint;
427
3.05k
        }
428
6.11k
    }
429
430
191
    SYMCRYPT_ASSERT( pbScratch + 2*cbEcpoint + 2*cbScalar + 2*nPoints*nRecodedDigits*sizeof(UINT32) <= pbScratchEnd );
431
    // Creating temporary points
432
191
    poQ = SymCryptEcpointCreate( pbScratch, cbEcpoint, pCurve );
433
191
    SYMCRYPT_ASSERT( poQ != NULL );
434
191
    pbScratch += cbEcpoint;
435
436
191
    poTmp = SymCryptEcpointCreate( pbScratch, cbEcpoint, pCurve );
437
191
    SYMCRYPT_ASSERT( poTmp != NULL );
438
191
    pbScratch += cbEcpoint;
439
440
    // Creating temporary scalar for the remainder
441
191
    piRem = SymCryptIntCreate( pbScratch, cbScalar, pCurve->GOrdDigits );
442
191
    SYMCRYPT_ASSERT( piRem != NULL);
443
191
    pbScratch += cbScalar;
444
445
191
    piTmp = SymCryptIntCreate( pbScratch, cbScalar, pCurve->GOrdDigits );
446
191
    SYMCRYPT_ASSERT( piTmp != NULL);
447
191
    pbScratch += cbScalar;
448
449
    // Fixing pointers to recoded digits (be careful that the remaining space is SYMCRYPT_ASYM_ALIGNed)
450
191
    absofKIs = (PUINT32) pbScratch;
451
191
    pbScratch += nPoints * nRecodedDigits * sizeof(UINT32);
452
191
    sigofKIs = (PUINT32) pbScratch;
453
191
    pbScratch += nPoints * nRecodedDigits * sizeof(UINT32);
454
191
    pbScratch = (PBYTE) ( ((ULONG_PTR)pbScratch + SYMCRYPT_ASYM_ALIGN_VALUE - 1) & ~(SYMCRYPT_ASYM_ALIGN_VALUE - 1) );
455
456
    // Fixing remaining scratch space size
457
  // dcl - my guess is that the values here are small enough that there should not be a problem, but
458
  // would be better if that were documented.
459
191
    cbScratch -= ( (nPoints*nPrecompPoints+2)*cbEcpoint + 2*cbScalar );
460
191
    cbScratch -= (((2*nPoints*nRecodedDigits*sizeof(UINT32) + SYMCRYPT_ASYM_ALIGN_VALUE - 1)/SYMCRYPT_ASYM_ALIGN_VALUE )*SYMCRYPT_ASYM_ALIGN_VALUE);
461
462
    //
463
    // Main algorithm
464
    //
465
573
    for (j = 0; j<nPoints; j++)
466
382
    {
467
382
        SYMCRYPT_ASSERT( SymCryptEcurveIsSame(pCurve, poSrcEcpointArray[j]->pCurve) );
468
469
        // Check if k is 0 or if the src point is zero
470
382
        fZero[j] = ( SymCryptIntIsEqualUint32( piSrcScalarArray[j], 0 ) | SymCryptEcpointIsZero( pCurve, poSrcEcpointArray[j], pbScratch, cbScratch ) );
471
382
        fZeroTot &= fZero[j];
472
473
        // Skip the recoding stage (and all remaining steps) if this point will give result zero
474
382
        if (!fZero[j])
475
351
        {
476
351
            SymCryptIntCopy( piSrcScalarArray[j], piRem );
477
478
            // Recoding stage
479
351
            SymCryptWidthNafRecoding( w, piRem, &absofKIs[j*nRecodedDigits], &sigofKIs[j*nRecodedDigits], nRecodedDigits );
480
481
            // Precomputation stage
482
351
            if ((j>0) || !bPrecompOffline)
483
191
            {
484
                // Copy the first point in the start of the poPIs array
485
191
                SymCryptEcpointCopy( pCurve, poSrcEcpointArray[j], poPIs[j*nPrecompPoints] );
486
487
191
                SymCryptPrecomputation( pCurve, nPrecompPoints, &poPIs[j*nPrecompPoints], poQ, pbScratch, cbScratch );
488
191
            }
489
351
        }
490
382
    }
491
492
    // Set poQ to zero point
493
191
    SymCryptEcpointSetZero( pCurve, poQ, pbScratch, cbScratch );
494
495
191
    if (!fZeroTot)
496
191
    {
497
        // Main loop
498
78.5k
        for (INT32 i = nRecodedDigits-1; i>-1; i--)
499
78.3k
        {
500
78.3k
            SymCryptEcpointDouble( pCurve, poQ, poQ, 0, pbScratch, cbScratch );
501
502
235k
            for (j = 0; j<nPoints; j++)
503
156k
            {
504
156k
                if (!fZero[j] && sigofKIs[j*nRecodedDigits + i] != 0)
505
20.3k
                {
506
20.3k
                    SymCryptEcpointCopy( pCurve, poPIs[j*nPrecompPoints + absofKIs[j*nRecodedDigits + i]/2], poTmp );
507
508
20.3k
                    if (sigofKIs[j*nRecodedDigits + i] == 0xffffffff)
509
9.94k
                    {
510
9.94k
                        SymCryptEcpointNegate( pCurve, poTmp, 0xffffffff, pbScratch, cbScratch );
511
9.94k
                    }
512
513
20.3k
                    SymCryptEcpointAdd( pCurve, poQ, poTmp, poQ, SYMCRYPT_FLAG_DATA_PUBLIC, pbScratch, cbScratch );
514
20.3k
                }
515
156k
            }
516
78.3k
        }
517
191
    }
518
519
    // Multiply by the cofactor (if needed) by continuing the doubling
520
191
    if ((pCurve->coFactorPower!=0) && ((flags & SYMCRYPT_FLAG_ECC_LL_COFACTOR_MUL) != 0))
521
0
    {
522
0
        for (j=0; j<pCurve->coFactorPower; j++)
523
0
        {
524
0
            SymCryptEcpointDouble( pCurve, poQ, poQ, 0, pbScratch, cbScratch );
525
0
        }
526
0
    }
527
528
    // If the resultant point is zero, ensure it will be set to the canonical zero point
529
191
    if ( SymCryptEcpointIsZero( pCurve, poQ, pbScratch, cbScratch ) )
530
0
    {
531
        // Set poQ to zero point
532
0
        SymCryptEcpointSetZero( pCurve, poQ, pbScratch, cbScratch );
533
0
    }
534
535
    // Copy the result to the destination (normalized flag == FALSE)
536
191
    SymCryptEcpointCopy( pCurve, poQ, poDst );
537
538
191
    scError = SYMCRYPT_NO_ERROR;
539
540
191
exit:
541
191
    return scError;
542
191
}
543
544
VOID
545
SYMCRYPT_CALL
546
SymCryptEcpointGenericSetRandom(
547
    _In_    PCSYMCRYPT_ECURVE       pCurve,
548
    _Out_   PSYMCRYPT_INT           piScalar,
549
    _Out_   PSYMCRYPT_ECPOINT       poDst,
550
    _Out_writes_bytes_( cbScratch )
551
            PBYTE                   pbScratch,
552
            SIZE_T                  cbScratch )
553
0
{
554
0
    PSYMCRYPT_MODELEMENT peScalar = NULL;
555
0
    SYMCRYPT_ASSERT( SymCryptEcurveIsSame(pCurve, poDst->pCurve) );
556
0
    SYMCRYPT_ASSERT( cbScratch >= SYMCRYPT_INTERNAL_SCRATCH_BYTES_FOR_SCALAR_ECURVE_OPERATIONS(pCurve, 1) );
557
0
    SYMCRYPT_ASSERT( cbScratch >= pCurve->cbModElement );
558
559
0
    peScalar = SymCryptModElementCreate( pbScratch, pCurve->cbModElement, pCurve->GOrd );
560
0
    SYMCRYPT_ASSERT( peScalar != NULL );
561
562
    // Setting a random mod element in the [1, SubgroupOrder-1] set
563
0
    SymCryptModSetRandom( pCurve->GOrd, peScalar, (SYMCRYPT_FLAG_MODRANDOM_ALLOW_ONE|SYMCRYPT_FLAG_MODRANDOM_ALLOW_MINUSONE), pbScratch + pCurve->cbModElement, cbScratch - pCurve->cbModElement );
564
565
    // Setting the integer
566
0
    SymCryptModElementToInt( pCurve->GOrd, peScalar, piScalar, pbScratch + pCurve->cbModElement, cbScratch - pCurve->cbModElement );
567
568
    // Do the multiplication (pass over the entire scratch space as it is not needed anymore)
569
    // !! Explicitly not checking the error return here as the only error is from specifying invalid flags !!
570
0
    SymCryptEcpointScalarMul( pCurve, piScalar, NULL, 0, poDst, pbScratch, cbScratch );
571
0
}