Coverage Report

Created: 2024-11-21 07:03

/src/SymCrypt/lib/ecpoint.c
Line
Count
Source (jump to first uncovered line)
1
//
2
// ecpoint.c   Ecpoint functions
3
//
4
// Copyright (c) Microsoft Corporation. Licensed under the MIT license.
5
//
6
//
7
8
#include "precomp.h"
9
10
// Table with the number of field elements for each point format
11
const UINT32 SymCryptEcpointFormatNumberofElements[] = {
12
    0,
13
    1,      // SYMCRYPT_ECPOINT_FORMAT_X
14
    2,      // SYMCRYPT_ECPOINT_FORMAT_XY
15
};
16
17
UINT32
18
SYMCRYPT_CALL
19
SymCryptSizeofEcpointEx(
20
    UINT32 cbModElement,
21
    UINT32 numOfCoordinates )
22
62.2k
{
23
62.2k
    SYMCRYPT_ASSERT(numOfCoordinates > 0);
24
62.2k
    SYMCRYPT_ASSERT(numOfCoordinates <= SYMCRYPT_ECPOINT_FORMAT_MAX_LENGTH);
25
26
    // Callers should never specify numOfCoordinates equal to 0 or greater than
27
    // SYMCRYPT_ECPOINT_FORMAT_MAX_LENGTH
28
    // Return 0 to indicate failure if a caller does specify invalid numOfCoordinates
29
62.2k
    if( (numOfCoordinates == 0) || (numOfCoordinates > SYMCRYPT_ECPOINT_FORMAT_MAX_LENGTH) )
30
0
    {
31
0
        return 0;
32
0
    }
33
34
    // Since the maximum number of coordinates is 4 this result is bounded
35
    // by 4*2^17 + overhead ~ 2^20
36
62.2k
    return sizeof(SYMCRYPT_ECPOINT) + numOfCoordinates * cbModElement;
37
62.2k
}
38
39
UINT32
40
SYMCRYPT_CALL
41
SymCryptSizeofEcpointFromCurve( PCSYMCRYPT_ECURVE pCurve )
42
30.1k
{
43
    // Same bound as SymCryptSizeofEcpointEx
44
30.1k
    return SymCryptSizeofEcpointEx( pCurve->cbModElement, SYMCRYPT_INTERNAL_NUMOF_COORDINATES(pCurve->eCoordinates) );
45
30.1k
}
46
47
PSYMCRYPT_ECPOINT
48
SYMCRYPT_CALL
49
SymCryptEcpointAllocate( _In_ PCSYMCRYPT_ECURVE pCurve )
50
0
{
51
0
    PVOID               p = NULL;
52
0
    SIZE_T              cb;
53
0
    PSYMCRYPT_ECPOINT   res = NULL;
54
55
0
    cb = SymCryptSizeofEcpointFromCurve( pCurve );
56
57
0
    if ( cb != 0 )
58
0
    {
59
0
        p = SymCryptCallbackAlloc( cb );
60
0
    }
61
62
0
    if ( p==NULL )
63
0
    {
64
0
        goto cleanup;
65
0
    }
66
67
0
    res = SymCryptEcpointCreate( p, cb, pCurve );
68
69
0
cleanup:
70
0
    return res;
71
0
}
72
73
VOID
74
SYMCRYPT_CALL
75
SymCryptEcpointFree(
76
     _In_ PCSYMCRYPT_ECURVE pCurve,
77
     _Out_ PSYMCRYPT_ECPOINT poDst )
78
0
{
79
0
    SYMCRYPT_CHECK_MAGIC( poDst );
80
0
    SymCryptEcpointWipe( pCurve, poDst );
81
0
    SymCryptCallbackFree( poDst );
82
0
}
83
84
PSYMCRYPT_ECPOINT
85
SYMCRYPT_CALL
86
SymCryptEcpointCreateEx(
87
    _Out_writes_bytes_( cbBuffer )  PBYTE               pbBuffer,
88
                                    SIZE_T              cbBuffer,
89
                                    PCSYMCRYPT_ECURVE   pCurve,
90
                                    UINT32              numOfCoordinates )
91
27.1k
{
92
27.1k
    PSYMCRYPT_ECPOINT       poPoint = NULL;
93
94
27.1k
    PSYMCRYPT_MODELEMENT    pmTmp = NULL;
95
27.1k
    UINT32                  cbModElement = pCurve->cbModElement;
96
97
27.1k
    PBYTE pbBufferEnd = pbBuffer + cbBuffer;
98
27.1k
    UNREFERENCED_PARAMETER( pbBufferEnd );     // only referenced in an ASSERT...
99
100
27.1k
    SYMCRYPT_ASSERT( pCurve->FMod != 0 );
101
27.1k
    SYMCRYPT_ASSERT( pCurve->cbModElement != 0 );
102
27.1k
    SYMCRYPT_ASSERT( cbBuffer >= SymCryptSizeofEcpointEx( pCurve->cbModElement, numOfCoordinates ) );
103
27.1k
    if ( cbBuffer == 0 || numOfCoordinates == 0 )
104
0
    {
105
0
        goto cleanup;
106
0
    }
107
108
27.1k
    SYMCRYPT_ASSERT_ASYM_ALIGNED( pbBuffer );
109
110
27.1k
    poPoint = (PSYMCRYPT_ECPOINT) pbBuffer;
111
112
27.1k
    pbBuffer += sizeof(SYMCRYPT_ECPOINT);
113
114
    // Setting the point coordinates
115
114k
    for (UINT32 i=0; i<numOfCoordinates; i++)
116
87.1k
    {
117
87.1k
        SYMCRYPT_ASSERT( pbBuffer + cbModElement <= pbBufferEnd );
118
87.1k
        pmTmp = SymCryptModElementCreate( pbBuffer, cbModElement, pCurve->FMod );
119
87.1k
        if ( pmTmp == NULL )
120
0
        {
121
0
            poPoint = NULL;
122
0
            goto cleanup;
123
0
        }
124
87.1k
        pbBuffer += cbModElement;
125
87.1k
    }
126
127
    // Setting the normalized flag
128
27.1k
    poPoint->normalized = FALSE;
129
130
    // Setting the curve
131
27.1k
    poPoint->pCurve     = pCurve;
132
133
    // Setting the magic
134
27.1k
    SYMCRYPT_SET_MAGIC( poPoint );
135
136
27.1k
cleanup:
137
27.1k
    return poPoint;
138
27.1k
}
139
140
PSYMCRYPT_ECPOINT
141
SYMCRYPT_CALL
142
SymCryptEcpointCreate(
143
    _Out_writes_bytes_( cbBuffer )  PBYTE               pbBuffer,
144
                                    SIZE_T              cbBuffer,
145
    _In_                            PCSYMCRYPT_ECURVE   pCurve )
146
25.0k
{
147
148
25.0k
    SYMCRYPT_ASSERT( pCurve->eCoordinates != 0 );
149
150
25.0k
    return SymCryptEcpointCreateEx( pbBuffer, cbBuffer, pCurve, SYMCRYPT_INTERNAL_NUMOF_COORDINATES(pCurve->eCoordinates) );
151
25.0k
}
152
153
PSYMCRYPT_ECPOINT
154
SYMCRYPT_CALL
155
SymCryptEcpointRetrieveHandle( _In_  PBYTE   pbBuffer )
156
0
{
157
0
    SYMCRYPT_ASSERT_ASYM_ALIGNED( pbBuffer );
158
159
0
    return (PSYMCRYPT_ECPOINT) pbBuffer;
160
0
}
161
162
VOID
163
SYMCRYPT_CALL
164
SymCryptEcpointWipe( _In_ PCSYMCRYPT_ECURVE pCurve, _Out_ PSYMCRYPT_ECPOINT poDst )
165
0
{
166
0
    SYMCRYPT_ASSERT( SymCryptEcurveIsSame(pCurve, poDst->pCurve) );
167
168
    // Wipe the whole structure in one go.
169
0
    SymCryptWipe( poDst, SymCryptSizeofEcpointFromCurve( pCurve ) );
170
0
}
171
172
VOID
173
SymCryptEcpointCopy(
174
    _In_    PCSYMCRYPT_ECURVE   pCurve,
175
    _In_    PCSYMCRYPT_ECPOINT  poSrc,
176
    _Out_   PSYMCRYPT_ECPOINT   poDst )
177
22.5k
{
178
22.5k
    SYMCRYPT_ASSERT( SymCryptEcurveIsSame(pCurve, poSrc->pCurve) && SymCryptEcurveIsSame(pCurve, poDst->pCurve) );
179
180
22.5k
    if( poSrc != poDst )
181
22.5k
    {
182
        // Unconditionally set the normalization state of destination to source
183
22.5k
        poDst->normalized = poSrc->normalized;
184
185
22.5k
        memcpy(poDst + 1, poSrc + 1, SYMCRYPT_INTERNAL_NUMOF_COORDINATES(pCurve->eCoordinates) * pCurve->FModDigits * SYMCRYPT_FDEF_DIGIT_SIZE);
186
22.5k
    }
187
22.5k
}
188
189
VOID
190
SymCryptEcpointMaskedCopy(
191
    _In_    PCSYMCRYPT_ECURVE   pCurve,
192
    _In_    PCSYMCRYPT_ECPOINT  poSrc,
193
    _Out_   PSYMCRYPT_ECPOINT   poDst,
194
            UINT32              mask )
195
971k
{
196
971k
    SYMCRYPT_ASSERT( (mask == 0) || (mask == 0xffffffff) );
197
971k
    SYMCRYPT_ASSERT( SymCryptEcurveIsSame(pCurve, poSrc->pCurve) && SymCryptEcurveIsSame(pCurve, poDst->pCurve) );
198
199
    // Unconditionally combine the normalization state of source and destination to avoid potential for
200
    // leak of mask. Normalized is a non-secret value and is permitted to be leaked by side-channels
201
971k
    poDst->normalized &= poSrc->normalized;
202
203
  // dcl - this looks like the equivalent of memcpy
204
  // should be proven that arguments cannot be the result of an integer overflow
205
971k
    SymCryptFdefMaskedCopy((PCBYTE)poSrc + sizeof(SYMCRYPT_ECPOINT), (PBYTE)poDst + sizeof(SYMCRYPT_ECPOINT), SYMCRYPT_INTERNAL_NUMOF_COORDINATES(pCurve->eCoordinates) * pCurve->FModDigits, mask );
206
971k
}
207
208
//
209
// SymCryptEcpointTransform: Internal function to transform an ECPOINT
210
// from one coordinate representation to another. One point has the default
211
// format of the curve. The other point has a format large enough for the external
212
// SYMCRYPT_ECPOINT_FORMAT.
213
//
214
// When the boolean setValue is set to TRUE, the source point is the one with
215
// the external format eformat, and the destination point has the default
216
// format of the curve. If setValue = FALSE the roles are reversed.
217
// This function is only called by the Get / Set Value functions.
218
//
219
SYMCRYPT_ERROR
220
SYMCRYPT_CALL
221
SymCryptEcpointTransform(
222
    _In_    PCSYMCRYPT_ECURVE               pCurve,
223
    _In_    PCSYMCRYPT_ECPOINT              poSrc,
224
    _Out_   PSYMCRYPT_ECPOINT               poDst,
225
            SYMCRYPT_ECPOINT_FORMAT         eformat,
226
            BOOLEAN                         setValue,
227
            UINT32                          flags,
228
    _Out_writes_bytes_( cbScratch )
229
            PBYTE                           pbScratch,
230
            SIZE_T                          cbScratch )
231
2.08k
{
232
2.08k
    SYMCRYPT_ERROR          scError = SYMCRYPT_NO_ERROR;
233
234
2.08k
    PSYMCRYPT_MODELEMENT    peSrc = NULL;
235
2.08k
    PSYMCRYPT_MODELEMENT    peDst = NULL;
236
2.08k
    PSYMCRYPT_MODELEMENT    peX = NULL;
237
2.08k
    PSYMCRYPT_MODELEMENT    peY = NULL;
238
239
2.08k
    SYMCRYPT_ECPOINT_COORDINATES    coFrom = SYMCRYPT_ECPOINT_COORDINATES_INVALID;
240
2.08k
    SYMCRYPT_ECPOINT_COORDINATES    coTo = SYMCRYPT_ECPOINT_COORDINATES_INVALID;
241
242
2.08k
    PSYMCRYPT_MODELEMENT peT[2] = { 0 };    // Temporaries
243
244
2.08k
    SYMCRYPT_ASSERT( (flags & ~SYMCRYPT_FLAG_DATA_PUBLIC) == 0 );
245
2.08k
    SYMCRYPT_ASSERT( SymCryptEcurveIsSame(pCurve, poSrc->pCurve) && SymCryptEcurveIsSame(pCurve, poDst->pCurve) );
246
2.08k
    SYMCRYPT_ASSERT( cbScratch >= SYMCRYPT_MAX(  SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( pCurve->FModDigits ),
247
2.08k
                                        SYMCRYPT_SCRATCH_BYTES_FOR_MODINV( pCurve->FModDigits )) +
248
2.08k
                                  2 * pCurve->cbModElement );
249
250
    // Get the assumed representation from the external format
251
2.08k
    switch (eformat)
252
2.08k
    {
253
325
    case (SYMCRYPT_ECPOINT_FORMAT_X):
254
325
        coFrom = SYMCRYPT_ECPOINT_COORDINATES_SINGLE;
255
325
        break;
256
1.75k
    case (SYMCRYPT_ECPOINT_FORMAT_XY):
257
1.75k
        coFrom = SYMCRYPT_ECPOINT_COORDINATES_AFFINE;
258
1.75k
        break;
259
0
    default:
260
0
        scError = SYMCRYPT_INVALID_ARGUMENT;
261
0
        goto cleanup;
262
2.08k
    }
263
264
    // Find out whether we are setting or getting the value of the ECPOINT
265
2.08k
    if (setValue)
266
1.17k
    {
267
1.17k
        coTo = pCurve->eCoordinates;
268
1.17k
    }
269
912
    else
270
912
    {
271
912
        coTo = coFrom;
272
912
        coFrom = pCurve->eCoordinates;
273
912
    }
274
275
    // Take all the possible supported transformations:
276
    //      - From SYMCRYPT_ECPOINT_COORDINATES_SINGLE to
277
    //          * SYMCRYPT_ECPOINT_COORDINATES_SINGLE (identity transformation)
278
    //          * SYMCRYPT_ECPOINT_COORDINATES_AFFINE (** Set all zeros to the Y coordinate **)
279
    //          * SYMCRYPT_ECPOINT_COORDINATES_SINGLE_PROJECTIVE
280
    //      - From SYMCRYPT_ECPOINT_COORDINATES_AFFINE to
281
    //          * SYMCRYPT_ECPOINT_COORDINATES_SINGLE (** Ignore Y coordinate **)
282
    //          * SYMCRYPT_ECPOINT_COORDINATES_AFFINE (identity transformation)
283
    //          * SYMCRYPT_ECPOINT_COORDINATES_JACOBIAN
284
    //          * SYMCRYPT_ECPOINT_COORDINATES_EXTENDED_PROJECTIVE
285
    //          * SYMCRYPT_ECPOINT_COORDINATES_SINGLE_PROJECTIVE (** Ignore Y coordinate **)
286
    //      - From SYMCRYPT_ECPOINT_COORDINATES_JACOBIAN to
287
    //          * SYMCRYPT_ECPOINT_COORDINATES_SINGLE
288
    //          * SYMCRYPT_ECPOINT_COORDINATES_AFFINE
289
    //          * SYMCRYPT_ECPOINT_COORDINATES_JACOBIAN (identity transformation)
290
    //      - From SYMCRYPT_ECPOINT_COORDINATES_EXTENDED_PROJECTIVE to
291
    //          * SYMCRYPT_ECPOINT_COORDINATES_SINGLE
292
    //          * SYMCRYPT_ECPOINT_COORDINATES_AFFINE
293
    //          * SYMCRYPT_ECPOINT_COORDINATES_EXTENDED_PROJECTIVE (identity transformation)
294
    //      - From SYMCRYPT_ECPOINT_COORDINATES_SINGLE_PROJECTIVE
295
    //          * SYMCRYPT_ECPOINT_COORDINATES_SINGLE
296
    //          * SYMCRYPT_ECPOINT_COORDINATES_AFFINE (** Set all zeros to the Y coordinate **)
297
    //          * SYMCRYPT_ECPOINT_COORDINATES_SINGLE_PROJECTIVE (identity transformation)
298
299
  // dcl - this appears that it might be a candidate for refactoring. Lots of code that looks
300
  // duplicated across sections. Maybe some number of small functions would make it less fragile?
301
2.08k
    if ( coFrom == coTo )
302
0
    {
303
0
        SymCryptEcpointCopy( pCurve, poSrc, poDst );    // All the identity transformations.
304
0
    }
305
2.08k
    else if (coFrom == SYMCRYPT_ECPOINT_COORDINATES_SINGLE)
306
0
    {
307
0
        if (coTo == SYMCRYPT_ECPOINT_COORDINATES_AFFINE)
308
0
        {
309
            // Copy X
310
0
            peX = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 0, pCurve, poSrc );
311
0
            SYMCRYPT_ASSERT( peX != NULL );
312
313
0
            peDst = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 0, pCurve, poDst );
314
0
            SYMCRYPT_ASSERT( peDst != NULL );
315
316
0
            SymCryptModElementCopy( pCurve->FMod, peX, peDst );
317
318
            // Set Y to 0
319
0
            peDst = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 1, pCurve, poDst );
320
0
            SYMCRYPT_ASSERT( peDst != NULL );
321
322
0
            SymCryptModElementSetValueUint32( 0, pCurve->FMod, peDst, pbScratch, cbScratch );
323
0
        }
324
0
        else if (coTo == SYMCRYPT_ECPOINT_COORDINATES_SINGLE_PROJECTIVE)
325
0
        {
326
            // Copy X
327
0
            peX = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 0, pCurve, poSrc );
328
0
            SYMCRYPT_ASSERT( peX != NULL );
329
330
0
            peDst = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 0, pCurve, poDst );
331
0
            SYMCRYPT_ASSERT( peDst != NULL );
332
333
0
            SymCryptModElementCopy( pCurve->FMod, peX, peDst );
334
335
            // Set Y to 1
336
0
            peDst = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 1, pCurve, poDst );
337
0
            SYMCRYPT_ASSERT( peDst != NULL );
338
339
0
            SymCryptModElementSetValueUint32( 1, pCurve->FMod, peDst, pbScratch, cbScratch );
340
341
            // Setting the normalized flag
342
0
            poDst->normalized = TRUE;
343
0
        }
344
0
        else
345
0
        {
346
0
            scError = SYMCRYPT_NOT_IMPLEMENTED;
347
0
            goto cleanup;
348
0
        }
349
0
    }
350
2.08k
    else if (coFrom == SYMCRYPT_ECPOINT_COORDINATES_AFFINE)
351
1.17k
    {
352
1.17k
        if ( (coTo == SYMCRYPT_ECPOINT_COORDINATES_SINGLE) ||
353
1.17k
             (coTo == SYMCRYPT_ECPOINT_COORDINATES_JACOBIAN) ||
354
1.17k
             (coTo == SYMCRYPT_ECPOINT_COORDINATES_EXTENDED_PROJECTIVE) ||
355
1.17k
             (coTo == SYMCRYPT_ECPOINT_COORDINATES_SINGLE_PROJECTIVE)
356
1.17k
           )
357
1.17k
        {
358
            // Copy X
359
1.17k
            peX = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 0, pCurve, poSrc );
360
1.17k
            SYMCRYPT_ASSERT( peX != NULL );
361
362
1.17k
            peDst = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 0, pCurve, poDst );
363
1.17k
            SYMCRYPT_ASSERT( peDst != NULL );
364
365
1.17k
            SymCryptModElementCopy( pCurve->FMod, peX, peDst );
366
367
1.17k
            if ( (coTo == SYMCRYPT_ECPOINT_COORDINATES_JACOBIAN) ||
368
1.17k
                 (coTo == SYMCRYPT_ECPOINT_COORDINATES_EXTENDED_PROJECTIVE) )
369
1.17k
            {
370
                // Copy Y
371
1.17k
                peY = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 1, pCurve, poSrc );
372
1.17k
                SYMCRYPT_ASSERT( peY != NULL );
373
374
1.17k
                peDst = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 1, pCurve, poDst );
375
1.17k
                SYMCRYPT_ASSERT( peDst != NULL );
376
377
1.17k
                SymCryptModElementCopy( pCurve->FMod, peY, peDst );
378
379
                // Set Z to 1
380
1.17k
                peDst = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 2, pCurve, poDst );
381
1.17k
                SYMCRYPT_ASSERT( peDst != NULL );
382
383
1.17k
                SymCryptModElementSetValueUint32( 1, pCurve->FMod, peDst, pbScratch, cbScratch );
384
385
1.17k
                if (coTo == SYMCRYPT_ECPOINT_COORDINATES_EXTENDED_PROJECTIVE)
386
125
                {
387
                    // T = x * y * z
388
125
                    peDst = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 3, pCurve, poDst );
389
125
                    SYMCRYPT_ASSERT( peDst != NULL );
390
391
125
                    SymCryptModMul( pCurve->FMod, peX, peY, peDst, pbScratch, cbScratch );
392
125
                }
393
394
                // Setting the normalized flag
395
1.17k
                poDst->normalized = TRUE;
396
1.17k
            }
397
0
            else if (coTo == SYMCRYPT_ECPOINT_COORDINATES_SINGLE_PROJECTIVE)
398
0
            {
399
                // Set Y to 1 (Ignore the second coordinate of the source point)
400
0
                peDst = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 1, pCurve, poDst );
401
0
                SYMCRYPT_ASSERT( peDst != NULL );
402
403
0
                SymCryptModElementSetValueUint32( 1, pCurve->FMod, peDst, pbScratch, cbScratch );
404
405
                // Setting the normalized flag
406
0
                poDst->normalized = TRUE;
407
0
            }
408
1.17k
        }
409
0
        else
410
0
        {
411
0
            scError = SYMCRYPT_NOT_IMPLEMENTED;
412
0
            goto cleanup;
413
0
        }
414
1.17k
    }
415
912
    else if (coFrom == SYMCRYPT_ECPOINT_COORDINATES_JACOBIAN)
416
825
    {
417
825
        if ( (coTo == SYMCRYPT_ECPOINT_COORDINATES_SINGLE) ||
418
825
             (coTo == SYMCRYPT_ECPOINT_COORDINATES_AFFINE) )
419
825
        {
420
            // Creating temporaries
421
2.47k
            for (UINT32 i=0; i<2; i++)
422
1.65k
            {
423
1.65k
                peT[i] = SymCryptModElementCreate( pbScratch, pCurve->cbModElement, pCurve->FMod );
424
1.65k
                SYMCRYPT_ASSERT( peT[i] != NULL);
425
426
1.65k
                pbScratch += pCurve->cbModElement;
427
1.65k
            }
428
429
825
            cbScratch -= 2*pCurve->cbModElement;
430
431
            // Get the Z coordinate of the source point
432
825
            peSrc = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 2, pCurve, poSrc );
433
825
            SYMCRYPT_ASSERT( peSrc != NULL );
434
435
            // Check if Z is equal to 0 (i.e. the point is the point at infinity)
436
825
            if (SymCryptModElementIsZero(pCurve->FMod, peSrc))
437
0
            {
438
0
                scError = SYMCRYPT_INCOMPATIBLE_FORMAT;
439
0
                goto cleanup;
440
0
            }
441
442
            // Calculation
443
            // T0 := 1  / Z
444
825
            scError = SymCryptModInv( pCurve->FMod, peSrc, peT[0], flags, pbScratch, cbScratch );
445
825
            if( scError != SYMCRYPT_NO_ERROR )
446
0
            {
447
0
                goto cleanup;
448
0
            }
449
450
825
            SymCryptModMul( pCurve->FMod, peT[0], peT[0], peT[1], pbScratch, cbScratch );           // T1 := T0 * T0 = 1/Z^2
451
452
            // Get the X coordinates
453
825
            peSrc = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 0, pCurve, poSrc );
454
825
            SYMCRYPT_ASSERT( peSrc != NULL );
455
456
825
            peDst = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 0, pCurve, poDst );
457
825
            SYMCRYPT_ASSERT( peDst != NULL );
458
459
            // Set the new X
460
825
            SymCryptModMul( pCurve->FMod, peSrc, peT[1], peDst, pbScratch, cbScratch );       // X2 := X * T1 = X/Z^2
461
462
825
            if (coTo == SYMCRYPT_ECPOINT_COORDINATES_AFFINE)
463
541
            {
464
541
                SymCryptModMul( pCurve->FMod, peT[0], peT[1], peT[1], pbScratch, cbScratch );     // T1 := T0 * T1 = 1/Z^3
465
466
                // Get the Y coordinates
467
541
                peSrc = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 1, pCurve, poSrc );
468
541
                SYMCRYPT_ASSERT( peSrc != NULL );
469
470
541
                peDst = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 1, pCurve, poDst );
471
541
                SYMCRYPT_ASSERT( peDst != NULL );
472
473
                // Set the new Y
474
541
                SymCryptModMul( pCurve->FMod, peSrc, peT[1], peDst, pbScratch, cbScratch );       // Y2 := Y * T1 = Y/Z^3
475
541
            }
476
825
        }
477
0
        else
478
0
        {
479
0
            scError = SYMCRYPT_NOT_IMPLEMENTED;
480
0
            goto cleanup;
481
0
        }
482
825
    }
483
87
    else if ( coFrom == SYMCRYPT_ECPOINT_COORDINATES_EXTENDED_PROJECTIVE )
484
87
    {
485
486
87
        if ( (coTo == SYMCRYPT_ECPOINT_COORDINATES_SINGLE) ||
487
87
             (coTo == SYMCRYPT_ECPOINT_COORDINATES_AFFINE) )
488
87
        {
489
            // Creating temporary
490
87
            peT[0] = SymCryptModElementCreate( pbScratch, pCurve->cbModElement, pCurve->FMod );
491
87
            SYMCRYPT_ASSERT( peT[0] != NULL);
492
87
            pbScratch += pCurve->cbModElement;
493
87
            cbScratch -= 2*pCurve->cbModElement;
494
495
            // Get the Z coordinate of the source point
496
87
            peSrc = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 2, pCurve, poSrc );
497
87
            SYMCRYPT_ASSERT( peSrc != NULL );
498
499
            // Check if Z is equal to 0 (i.e. the point is the point at infinity)
500
87
            if (SymCryptModElementIsZero(pCurve->FMod, peSrc))
501
0
            {
502
0
                scError = SYMCRYPT_INCOMPATIBLE_FORMAT;
503
0
                goto cleanup;
504
0
            }
505
506
            // peT[0] = 1 / Z
507
87
            scError = SymCryptModInv( pCurve->FMod, peSrc, peT[0], flags, pbScratch, cbScratch );
508
87
            if( scError != SYMCRYPT_NO_ERROR )
509
0
            {
510
0
                goto cleanup;
511
0
            }
512
513
            // Get the X coordinates
514
87
            peSrc = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 0, pCurve, poSrc );
515
87
            SYMCRYPT_ASSERT( peSrc != NULL );
516
517
87
            peDst = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 0, pCurve, poDst );
518
87
            SYMCRYPT_ASSERT( peDst != NULL );
519
520
            // x = X * (1 / Z)
521
87
            SymCryptModMul( pCurve->FMod, peSrc, peT[0], peDst, pbScratch, cbScratch );
522
523
87
            if (coTo == SYMCRYPT_ECPOINT_COORDINATES_AFFINE)
524
46
            {
525
                // Get the Y coordinates
526
46
                peSrc = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 1, pCurve, poSrc );
527
46
                SYMCRYPT_ASSERT( peSrc != NULL );
528
529
46
                peDst = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 1, pCurve, poDst );
530
46
                SYMCRYPT_ASSERT( peDst != NULL );
531
532
                // y = Y * (1 / Z)
533
46
                SymCryptModMul( pCurve->FMod, peSrc, peT[0], peDst, pbScratch, cbScratch );
534
46
            }
535
87
        }
536
0
        else
537
0
        {
538
0
            scError = SYMCRYPT_NOT_IMPLEMENTED;
539
0
            goto cleanup;
540
0
        }
541
87
    }
542
0
    else if (coFrom == SYMCRYPT_ECPOINT_COORDINATES_SINGLE_PROJECTIVE)
543
0
    {
544
0
        if ( (coTo == SYMCRYPT_ECPOINT_COORDINATES_SINGLE) ||
545
0
             (coTo == SYMCRYPT_ECPOINT_COORDINATES_AFFINE) )
546
0
        {
547
            // Creating temporary
548
0
            peT[0] = SymCryptModElementCreate( pbScratch, pCurve->cbModElement, pCurve->FMod );
549
0
            SYMCRYPT_ASSERT( peT[0] != NULL);
550
551
0
            pbScratch += pCurve->cbModElement;
552
0
            cbScratch -= pCurve->cbModElement;
553
554
            // Get the Y coordinate of the source point
555
0
            peSrc = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 1, pCurve, poSrc );
556
0
            SYMCRYPT_ASSERT( peSrc != NULL );
557
558
            // Check if Y is equal to 0 (i.e. the point is the point at infinity)
559
0
            if (SymCryptModElementIsZero(pCurve->FMod, peSrc))
560
0
            {
561
0
                scError = SYMCRYPT_INCOMPATIBLE_FORMAT;
562
0
                goto cleanup;
563
0
            }
564
565
            // Calculation
566
0
            scError = SymCryptModInv( pCurve->FMod, peSrc, peT[0], flags, pbScratch, cbScratch );              // T0 := 1 / Y
567
0
            if( scError != SYMCRYPT_NO_ERROR )
568
0
            {
569
0
                goto cleanup;
570
0
            }
571
572
            // Get the X coordinates
573
0
            peSrc = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 0, pCurve, poSrc );
574
0
            SYMCRYPT_ASSERT( peSrc != NULL );
575
576
0
            peDst = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 0, pCurve, poDst );
577
0
            SYMCRYPT_ASSERT( peDst != NULL );
578
579
            // Set the new X
580
0
            SymCryptModMul( pCurve->FMod, peSrc, peT[0], peDst, pbScratch, cbScratch );       // X2 := X * T0 = X/Y
581
582
0
            if (coTo == SYMCRYPT_ECPOINT_COORDINATES_AFFINE)
583
0
            {
584
                // Set Y to 0
585
0
                peDst = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 1, pCurve, poDst );
586
0
                SYMCRYPT_ASSERT( peDst != NULL );
587
588
0
                SymCryptModElementSetValueUint32( 0, pCurve->FMod, peDst, pbScratch, cbScratch );
589
0
            }
590
0
        }
591
0
    }
592
0
    else
593
0
    {
594
0
        scError = SYMCRYPT_NOT_IMPLEMENTED;
595
0
        goto cleanup;
596
0
    }
597
598
2.08k
cleanup:
599
600
2.08k
    return scError;
601
2.08k
}
602
603
SYMCRYPT_ERROR
604
SYMCRYPT_CALL
605
SymCryptEcpointSetValue(
606
    _In_                            PCSYMCRYPT_ECURVE       pCurve,
607
    _In_reads_bytes_(cbSrc)         PCBYTE                  pbSrc,
608
                                    SIZE_T                  cbSrc,
609
                                    SYMCRYPT_NUMBER_FORMAT  nformat,
610
                                    SYMCRYPT_ECPOINT_FORMAT eformat,
611
    _Out_                           PSYMCRYPT_ECPOINT       poDst,
612
                                    UINT32                  flags,
613
    _Out_writes_bytes_( cbScratch ) PBYTE                   pbScratch,
614
                                    SIZE_T                  cbScratch )
615
1.17k
{
616
1.17k
    SYMCRYPT_ERROR          scError = SYMCRYPT_NOT_IMPLEMENTED;
617
1.17k
    PSYMCRYPT_MODELEMENT    peTmp = NULL;       // Temporary MODELEMENT handle
618
1.17k
    PSYMCRYPT_ECPOINT       poLarge = NULL;     // ECPOINT with the largest format available
619
1.17k
    UINT32                  cbLarge = 0;
620
1.17k
    PSYMCRYPT_INT           piTemp = NULL;
621
1.17k
    UINT32                  cbTemp = 0;
622
1.17k
    UINT32                  publicKeyDigits = SymCryptEcurveDigitsofFieldElement( pCurve );
623
624
1.17k
    SYMCRYPT_ASSERT( (flags & ~SYMCRYPT_FLAG_DATA_PUBLIC) == 0 );
625
626
1.17k
    SYMCRYPT_ASSERT( pCurve->FMod != 0 );
627
1.17k
    SYMCRYPT_ASSERT( pCurve->eCoordinates != 0 );
628
1.17k
    SYMCRYPT_ASSERT( pCurve->cbModElement != 0 );
629
630
1.17k
    SYMCRYPT_ASSERT( cbScratch >= SYMCRYPT_SCRATCH_BYTES_FOR_GETSET_VALUE_ECURVE_OPERATIONS( pCurve ) );
631
632
    // Check that the buffer is of correct size
633
1.17k
    if ( cbSrc != SymCryptEcpointFormatNumberofElements[ eformat ] * SymCryptEcurveSizeofFieldElement( pCurve ) )
634
0
    {
635
0
        scError = SYMCRYPT_BUFFER_TOO_SMALL;
636
0
        goto cleanup;
637
0
    }
638
1.17k
    cbSrc = cbSrc / SymCryptEcpointFormatNumberofElements[ eformat ];
639
640
1.17k
    cbTemp = SymCryptSizeofIntFromDigits( publicKeyDigits );
641
1.17k
    SYMCRYPT_ASSERT( cbScratch > cbTemp );
642
643
1.17k
    piTemp = SymCryptIntCreate( pbScratch, cbTemp, publicKeyDigits );
644
645
    // Validate the coordinate of the input public key is less than the field modulus
646
3.51k
    for ( UINT32 i = 0; i < SymCryptEcpointFormatNumberofElements[eformat]; i++ )
647
2.34k
    {
648
2.34k
        scError = SymCryptIntSetValue( pbSrc + i * cbSrc, cbSrc, nformat, piTemp );
649
2.34k
        if (scError != SYMCRYPT_NO_ERROR)
650
0
        {
651
0
            goto cleanup;
652
0
        }
653
654
2.34k
        if ( !SymCryptIntIsLessThan( piTemp, SymCryptIntFromModulus( pCurve->FMod ) ) )
655
0
        {
656
0
            scError = SYMCRYPT_INVALID_ARGUMENT;
657
0
            goto cleanup;
658
0
        }
659
2.34k
    }
660
661
    // Create the large point
662
1.17k
    cbLarge = SymCryptSizeofEcpointEx( pCurve->cbModElement, SYMCRYPT_ECPOINT_FORMAT_MAX_LENGTH );
663
1.17k
    SYMCRYPT_ASSERT( cbScratch > cbLarge );
664
1.17k
    poLarge = SymCryptEcpointCreateEx( pbScratch, cbLarge, pCurve, SYMCRYPT_ECPOINT_FORMAT_MAX_LENGTH );
665
1.17k
    if ( poLarge == NULL )
666
0
    {
667
0
        scError = SYMCRYPT_INVALID_BLOB;
668
0
        goto cleanup;
669
0
    }
670
671
    // Setting the point coordinates into the big point
672
3.51k
    for (UINT32 i=0; i<SymCryptEcpointFormatNumberofElements[eformat]; i++)
673
2.34k
    {
674
2.34k
        peTmp = (PSYMCRYPT_MODELEMENT)((PBYTE)poLarge + SYMCRYPT_INTERNAL_ECPOINT_COORDINATE_OFFSET( pCurve, i ));
675
2.34k
        if ( peTmp == NULL )
676
0
        {
677
0
            scError = SYMCRYPT_INVALID_BLOB;
678
0
            goto cleanup;
679
0
        }
680
681
2.34k
        scError = SymCryptModElementSetValue(
682
2.34k
                            pbSrc,
683
2.34k
                            cbSrc,
684
2.34k
                            nformat,
685
2.34k
                            pCurve->FMod,
686
2.34k
                            peTmp,
687
2.34k
                            pbScratch + cbLarge,
688
2.34k
                            cbScratch - cbLarge );
689
2.34k
        if ( scError != SYMCRYPT_NO_ERROR )
690
0
        {
691
0
            goto cleanup;
692
0
        }
693
2.34k
        pbSrc += cbSrc;
694
2.34k
    }
695
696
    // Transform the big point into the destination point
697
1.17k
    scError = SymCryptEcpointTransform( pCurve, poLarge, poDst, eformat, TRUE, flags, pbScratch + cbLarge, cbScratch - cbLarge);
698
699
1.17k
cleanup:
700
1.17k
    return scError;
701
1.17k
}
702
703
SYMCRYPT_ERROR
704
SYMCRYPT_CALL
705
SymCryptEcpointGetValue(
706
    _In_                            PCSYMCRYPT_ECURVE       pCurve,
707
    _In_                            PCSYMCRYPT_ECPOINT      poSrc,
708
                                    SYMCRYPT_NUMBER_FORMAT  nformat,
709
                                    SYMCRYPT_ECPOINT_FORMAT eformat,
710
    _Out_writes_bytes_(cbDst)       PBYTE                   pbDst,
711
                                    SIZE_T                  cbDst,
712
                                    UINT32                  flags,
713
    _Out_writes_bytes_( cbScratch ) PBYTE                   pbScratch,
714
                                    SIZE_T                  cbScratch )
715
912
{
716
912
    SYMCRYPT_ERROR          scError = SYMCRYPT_NOT_IMPLEMENTED;
717
912
    PSYMCRYPT_MODELEMENT    peTmp = NULL;       // Temporary MODELEMENT handle
718
912
    PSYMCRYPT_ECPOINT       poLarge = NULL;     // ECPOINT with the largest format available
719
912
    UINT32                  cbLarge = 0;
720
912
    SIZE_T                  cbDstElem;
721
722
912
    SYMCRYPT_ASSERT( (flags & ~SYMCRYPT_FLAG_DATA_PUBLIC) == 0 );
723
912
    SYMCRYPT_ASSERT( pCurve->FMod != 0 );
724
912
    SYMCRYPT_ASSERT( pCurve->eCoordinates != 0 );
725
912
    SYMCRYPT_ASSERT( pCurve->cbModElement != 0 );
726
727
912
    SYMCRYPT_ASSERT( cbScratch >= SYMCRYPT_SCRATCH_BYTES_FOR_GETSET_VALUE_ECURVE_OPERATIONS( pCurve ) );
728
729
    // Check that the buffer is of correct size
730
912
    if ( cbDst != SymCryptEcpointFormatNumberofElements[ eformat ] * SymCryptEcurveSizeofFieldElement( pCurve ) )
731
0
    {
732
0
        scError = SYMCRYPT_BUFFER_TOO_SMALL;
733
0
        goto cleanup;
734
0
    }
735
912
    SYMCRYPT_ASSERT( SymCryptEcpointFormatNumberofElements[ eformat ] > 0 );
736
912
    cbDstElem = cbDst / SymCryptEcpointFormatNumberofElements[ eformat ];
737
738
    // Create the big point
739
912
    cbLarge = SymCryptSizeofEcpointEx( pCurve->cbModElement, SYMCRYPT_ECPOINT_FORMAT_MAX_LENGTH );
740
912
    SYMCRYPT_ASSERT( cbScratch > cbLarge );
741
912
    poLarge = SymCryptEcpointCreateEx( pbScratch, cbLarge, pCurve, SYMCRYPT_ECPOINT_FORMAT_MAX_LENGTH );
742
912
    if ( poLarge == NULL )
743
0
    {
744
0
        scError = SYMCRYPT_INVALID_BLOB;
745
0
        goto cleanup;
746
0
    }
747
748
    // Transform the source point into the big point if needed
749
912
    scError = SymCryptEcpointTransform( pCurve, poSrc, poLarge, eformat, FALSE, flags, pbScratch + cbLarge, cbScratch - cbLarge);
750
912
    if (scError != SYMCRYPT_NO_ERROR)
751
0
    {
752
0
        goto cleanup;
753
0
    }
754
755
    // Getting the point coordinates into the destination buffer
756
2.41k
    for (UINT32 i=0; i<SymCryptEcpointFormatNumberofElements[eformat]; i++)
757
1.49k
    {
758
1.49k
        SYMCRYPT_ASSERT( cbDst >= cbDstElem );
759
1.49k
        peTmp = (PSYMCRYPT_MODELEMENT)( (PBYTE)poLarge + SYMCRYPT_INTERNAL_ECPOINT_COORDINATE_OFFSET( pCurve, i ) );
760
1.49k
        if ( peTmp == NULL )
761
0
        {
762
0
            scError = SYMCRYPT_INVALID_BLOB;
763
0
            goto cleanup;
764
0
        }
765
766
1.49k
        scError = SymCryptModElementGetValue(
767
1.49k
                            pCurve->FMod,
768
1.49k
                            peTmp,
769
1.49k
                            pbDst,
770
1.49k
                            cbDstElem,
771
1.49k
                            nformat,
772
1.49k
                            pbScratch + cbLarge,
773
1.49k
                            cbScratch - cbLarge );
774
1.49k
        if ( scError != SYMCRYPT_NO_ERROR )
775
0
        {
776
0
            goto cleanup;
777
0
        }
778
1.49k
        pbDst += cbDstElem;
779
1.49k
        cbDst -= cbDstElem;
780
1.49k
    }
781
782
912
cleanup:
783
784
912
    return scError;
785
912
}