Coverage Report

Created: 2024-11-21 07:03

/src/SymCrypt/lib/fdef_mod.c
Line
Count
Source (jump to first uncovered line)
1
//
2
// fdef_int.c   INT functions for default number format
3
//
4
// Copyright (c) Microsoft Corporation. Licensed under the MIT license.
5
//
6
7
#include "precomp.h"
8
9
PSYMCRYPT_MODULUS
10
SYMCRYPT_CALL
11
SymCryptFdefModulusAllocate( UINT32 nDigits )
12
0
{
13
0
    PVOID               p = NULL;
14
0
    UINT32              cb;
15
0
    PSYMCRYPT_MODULUS   res = NULL;
16
17
    //
18
    // The nDigits requirements are enforced by SymCryptFdefSizeofModulusFromDigits. Thus
19
    // the result does not overflow and is upper bounded by 2^19.
20
    //
21
0
    cb = SymCryptFdefSizeofModulusFromDigits( nDigits );
22
23
0
    if( cb != 0 )
24
0
    {
25
0
        p = SymCryptCallbackAlloc( cb );
26
0
    }
27
28
0
    if( p == NULL )
29
0
    {
30
0
        goto cleanup;
31
0
    }
32
33
0
    res = SymCryptFdefModulusCreate( p, cb, nDigits );
34
35
0
cleanup:
36
0
    return res;
37
0
}
38
39
VOID
40
SYMCRYPT_CALL
41
SymCryptFdefModulusFree( _Out_ PSYMCRYPT_MODULUS pmObj )
42
0
{
43
0
    SymCryptModulusWipe( pmObj );
44
0
    SymCryptCallbackFree( pmObj );
45
0
}
46
47
UINT32
48
SYMCRYPT_CALL
49
SymCryptFdefSizeofModulusFromDigits( UINT32 nDigits )
50
3.78k
{
51
3.78k
    SYMCRYPT_ASSERT( nDigits != 0 );
52
3.78k
    SYMCRYPT_ASSERT( nDigits <= SYMCRYPT_FDEF_UPB_DIGITS );
53
54
    // Ensure we do not overflow the following calculation when provided with invalid inputs
55
3.78k
    if( nDigits == 0 || nDigits > SYMCRYPT_FDEF_UPB_DIGITS )
56
0
    {
57
0
        return 0;
58
0
    }
59
60
    // Room for the Modulus structure, the Divisor, the negated divisor, and the R^2 Montgomery factor
61
    //
62
3.78k
    return SYMCRYPT_FIELD_OFFSET( SYMCRYPT_MODULUS, Divisor ) + SymCryptFdefSizeofDivisorFromDigits( nDigits ) + (2 * nDigits * SYMCRYPT_FDEF_DIGIT_SIZE);
63
3.78k
}
64
65
PSYMCRYPT_MODULUS
66
SYMCRYPT_CALL
67
SymCryptFdefModulusCreate(
68
    _Out_writes_bytes_( cbBuffer )  PBYTE   pbBuffer,
69
                                    SIZE_T  cbBuffer,
70
                                    UINT32  nDigits )
71
1.89k
{
72
1.89k
    PSYMCRYPT_MODULUS pmMod = NULL;
73
1.89k
    UINT32 cb = SymCryptFdefSizeofModulusFromDigits( nDigits );
74
75
1.89k
    const UINT32 offset = SYMCRYPT_FIELD_OFFSET( SYMCRYPT_MODULUS, Divisor );
76
77
1.89k
    SYMCRYPT_ASSERT( cb >= sizeof(SYMCRYPT_MODULUS) );
78
1.89k
    SYMCRYPT_ASSERT( cbBuffer >= cb );
79
1.89k
    if( (cb == 0) || (cbBuffer < cb) )
80
0
    {
81
0
        goto cleanup; // return NULL
82
0
    }
83
84
1.89k
    SYMCRYPT_ASSERT_ASYM_ALIGNED( pbBuffer );
85
1.89k
    pmMod = (PSYMCRYPT_MODULUS) pbBuffer;
86
87
1.89k
    pmMod->type = 'gM' << 16;
88
1.89k
    pmMod->nDigits = nDigits;
89
90
    //
91
    // The nDigits requirements are enforced by SymCryptFdefSizeofModulusFromDigits. Thus
92
    // the result does not overflow and is upper bounded by 2^19.
93
    //
94
1.89k
    pmMod->cbSize = cb;
95
1.89k
    pmMod->flags = 0;
96
97
    // The following is bounded by 2^17
98
1.89k
    pmMod->cbModElement = nDigits * SYMCRYPT_FDEF_DIGIT_SIZE;
99
100
1.89k
    SymCryptFdefDivisorCreate( pbBuffer + offset, cbBuffer - offset, nDigits );
101
102
    // We don't have a modulus value yet, so we don't create/initialize any implementation-specific things.
103
104
1.89k
    SYMCRYPT_SET_MAGIC( pmMod );
105
106
1.89k
cleanup:
107
1.89k
    return pmMod;
108
1.89k
}
109
110
VOID
111
SYMCRYPT_CALL
112
SymCryptFdefModulusInitGeneric(
113
    _Inout_                         PSYMCRYPT_MODULUS       pmMod,
114
    _Out_writes_bytes_( cbScratch ) PBYTE                   pbScratch,
115
                                    SIZE_T                  cbScratch )
116
946
{
117
946
    UNREFERENCED_PARAMETER( pmMod );
118
946
    UNREFERENCED_PARAMETER( pbScratch );
119
946
    UNREFERENCED_PARAMETER( cbScratch );
120
946
}
121
122
123
VOID
124
SymCryptFdefModulusCopy(
125
    _In_    PCSYMCRYPT_MODULUS  pmSrc,
126
    _Out_   PSYMCRYPT_MODULUS   pmDst )
127
0
{
128
0
    SYMCRYPT_ASSERT( pmSrc->nDigits == pmDst->nDigits );
129
130
0
    if( pmSrc != pmDst )
131
0
    {
132
0
        memcpy( pmDst, pmSrc, pmDst->cbSize );
133
134
0
        SymCryptFdefDivisorCopyFixup( &pmSrc->Divisor, &pmDst->Divisor );
135
136
        // Copy the type-specific fields
137
0
        SYMCRYPT_MOD_CALL( pmSrc ) modulusCopyFixup( pmSrc, pmDst );
138
139
0
        SYMCRYPT_SET_MAGIC( pmDst );
140
0
    }
141
0
}
142
143
VOID
144
SYMCRYPT_CALL
145
SymCryptFdefModulusCopyFixupGeneric(
146
    _In_                            PCSYMCRYPT_MODULUS      pmSrc,
147
    _Out_                           PSYMCRYPT_MODULUS       pmDst )
148
0
{
149
    // Only have to handle the type-specific fields, which we don't have any of.
150
0
    UNREFERENCED_PARAMETER( pmSrc );
151
0
    UNREFERENCED_PARAMETER( pmDst );
152
0
}
153
154
155
PSYMCRYPT_MODELEMENT
156
SYMCRYPT_CALL
157
SymCryptFdefModElementAllocate( _In_ PCSYMCRYPT_MODULUS pmMod )
158
0
{
159
0
    PVOID                   p;
160
0
    UINT32                  cb;
161
0
    PSYMCRYPT_MODELEMENT    res = NULL;
162
163
    //
164
    // The nDigits requirements are enforced by the modulus object. Thus
165
    // the result does not overflow and is upper bounded by 2^17.
166
    //
167
0
    cb = SymCryptFdefSizeofModElementFromModulus( pmMod );
168
169
0
    p = SymCryptCallbackAlloc( cb );
170
171
0
    if( p == NULL )
172
0
    {
173
0
        goto cleanup;
174
0
    }
175
176
0
    res = SymCryptFdefModElementCreate( p, cb, pmMod );
177
178
0
cleanup:
179
0
    return res;
180
0
}
181
182
VOID
183
SYMCRYPT_CALL
184
SymCryptFdefModElementFree(
185
    _In_    PCSYMCRYPT_MODULUS      pmMod,
186
    _Out_   PSYMCRYPT_MODELEMENT    peObj )
187
0
{
188
0
    SymCryptFdefModElementWipe( pmMod, peObj );
189
0
    SymCryptCallbackFree( peObj );
190
0
}
191
192
UINT32
193
SYMCRYPT_CALL
194
SymCryptFdefSizeofModElementFromModulus( PCSYMCRYPT_MODULUS pmMod )
195
2.43M
{
196
    // Upper bounded by 2^17 since the modulus is up to SYMCRYPT_INT_MAXBITS = 2^20 bits.
197
2.43M
    return pmMod->cbModElement;
198
2.43M
}
199
200
PSYMCRYPT_MODELEMENT
201
SYMCRYPT_CALL
202
SymCryptFdefModElementCreate(
203
    _Out_writes_bytes_( cbBuffer )  PBYTE               pbBuffer,
204
                                    SIZE_T              cbBuffer,
205
                                    PCSYMCRYPT_MODULUS  pmMod )
206
2.34M
{
207
2.34M
    PSYMCRYPT_MODELEMENT pDst = (PSYMCRYPT_MODELEMENT) pbBuffer;
208
209
2.34M
    UNREFERENCED_PARAMETER( pmMod );
210
2.34M
    UNREFERENCED_PARAMETER( cbBuffer );
211
212
2.34M
    SYMCRYPT_ASSERT_ASYM_ALIGNED( pbBuffer );
213
2.34M
    SYMCRYPT_ASSERT( cbBuffer >= SymCryptFdefSizeofModElementFromModulus( pmMod ) );
214
2.34M
    SYMCRYPT_ASSERT( cbBuffer >= pmMod->nDigits*SYMCRYPT_FDEF_DIGIT_SIZE );
215
216
    //
217
    // We have various optimizations where we use only part of the last digit
218
    // Simple and fast solution: always wipe the last digit
219
    //
220
2.34M
#if (SYMCRYPT_CPU_AMD64 | SYMCRYPT_CPU_ARM64)
221
2.34M
    UINT32 nDigits = pmMod->nDigits;
222
223
2.34M
    SymCryptWipeKnownSize( pbBuffer + (nDigits-1) * SYMCRYPT_FDEF_DIGIT_SIZE, SYMCRYPT_FDEF_DIGIT_SIZE );
224
2.34M
#endif
225
226
    // There is nothing to initialize...
227
228
2.34M
    return pDst;
229
2.34M
}
230
231
VOID
232
SYMCRYPT_CALL
233
SymCryptFdefModElementWipe(
234
    _In_    PCSYMCRYPT_MODULUS      pmMod,
235
    _Out_   PSYMCRYPT_MODELEMENT    peDst )
236
0
{
237
0
    SymCryptWipe( peDst, pmMod->cbModElement );
238
0
}
239
240
VOID
241
SymCryptFdefModElementCopy(
242
    _In_    PCSYMCRYPT_MODULUS      pmMod,
243
    _In_    PCSYMCRYPT_MODELEMENT   peSrc,
244
    _Out_   PSYMCRYPT_MODELEMENT    peDst )
245
57.5k
{
246
57.5k
    if( peSrc != peDst )
247
57.5k
    {
248
57.5k
        memcpy( peDst, peSrc, pmMod->cbModElement );
249
57.5k
    }
250
57.5k
}
251
252
VOID
253
SymCryptFdefModElementMaskedCopy(
254
    _In_    PCSYMCRYPT_MODULUS      pmMod,
255
    _In_    PCSYMCRYPT_MODELEMENT   peSrc,
256
    _Out_   PSYMCRYPT_MODELEMENT    peDst,
257
            UINT32                  mask )
258
82.7k
{
259
82.7k
    SymCryptFdefMaskedCopy( (PCBYTE) peSrc, (PBYTE) peDst, pmMod->nDigits, mask );
260
82.7k
}
261
262
263
PSYMCRYPT_DIVISOR
264
SYMCRYPT_CALL
265
SymCryptFdefDivisorFromModulus( _In_ PSYMCRYPT_MODULUS pmSrc )
266
603
{
267
603
    return &pmSrc->Divisor;
268
603
}
269
270
VOID
271
SymCryptFdefModElementConditionalSwap(
272
    _In_       PCSYMCRYPT_MODULUS    pmMod,
273
    _Inout_    PSYMCRYPT_MODELEMENT  peData1,
274
    _Inout_    PSYMCRYPT_MODELEMENT  peData2,
275
    _In_       UINT32                cond )
276
0
{
277
0
    SymCryptFdefConditionalSwap( (PBYTE) &peData1->d.uint32[0], (PBYTE) &peData2->d.uint32[0], pmMod->nDigits, cond );
278
0
}
279
280
PSYMCRYPT_INT
281
SYMCRYPT_CALL
282
SymCryptFdefIntFromModulus( _In_ PSYMCRYPT_MODULUS pmSrc )
283
8.22k
{
284
285
8.22k
    return SymCryptFdefIntFromDivisor( &pmSrc->Divisor );
286
8.22k
}
287
288
UINT32
289
SYMCRYPT_CALL
290
SymCryptFdefDecideModulusType( PCSYMCRYPT_INT piSrc, UINT32 nDigits, UINT32 averageOperations, UINT32 flags )
291
1.89k
{
292
1.89k
    UINT32 res = 0;
293
1.89k
    BOOLEAN disableMontgomery = 0;
294
1.89k
    BYTE tempBuf[64];
295
1.89k
    PCSYMCRYPT_MODULUS_TYPE_SELECTION_ENTRY pEntry;
296
297
1.89k
    UINT32 nBitsizeOfValue = SymCryptIntBitsizeOfValue( piSrc );
298
1.89k
    UINT32 modulusFeatures = 0;
299
300
1.89k
    if( !disableMontgomery &&
301
1.89k
        ( flags & (SYMCRYPT_FLAG_DATA_PUBLIC | SYMCRYPT_FLAG_MODULUS_PARITY_PUBLIC)) != 0 &&
302
1.89k
        (SymCryptIntGetValueLsbits32( piSrc ) & 1) == 1 &&
303
1.89k
        averageOperations >= 10 )
304
946
    {
305
946
        modulusFeatures |= SYMCRYPT_MODULUS_FEATURE_MONTGOMERY;
306
307
        // Specific modulus value detection
308
946
        if( (flags & SYMCRYPT_FLAG_DATA_PUBLIC) != 0 )
309
946
        {
310
            // Detect if modulus value is the P384 field modulus (convert piSrc to big endian and do comparison with known value of P384 modulus)
311
946
            if( nBitsizeOfValue == 384 &&
312
946
                SymCryptFdefRawGetValue(SYMCRYPT_FDEF_INT_PUINT32(piSrc), SYMCRYPT_FDEF_DIGITS_FROM_BITS(384), tempBuf, 64, SYMCRYPT_NUMBER_FORMAT_MSB_FIRST) == SYMCRYPT_NO_ERROR )
313
285
            {
314
                // First 16 bytes are guaranteed to be zero because nBitsizeOfValue is 384
315
285
                if( memcmp(tempBuf+16, ((PBYTE)SymCryptEcurveParamsNistP384) + sizeof(SYMCRYPT_ECURVE_PARAMS), 48) == 0 )
316
262
                {
317
262
                    modulusFeatures |= SYMCRYPT_MODULUS_FEATURE_NISTP384;
318
262
                }
319
285
            }
320
321
            // Detect if modulus value is the P256 field modulus (not currently used)
322
            // if( nBitsizeOfValue == 256 && 
323
            //     SymCryptFdefRawGetValue(SYMCRYPT_FDEF_INT_PUINT32(piSrc), SYMCRYPT_FDEF_DIGITS_FROM_BITS(256), tempBuf, 64, SYMCRYPT_NUMBER_FORMAT_MSB_FIRST) == SYMCRYPT_NO_ERROR )
324
            // {
325
            //     // First 32 bytes are guaranteed to be zero because nBitsizeOfValue is 256
326
            //     if( memcmp(tempBuf+32, ((PBYTE)SymCryptEcurveParamsNistP256) + sizeof(SYMCRYPT_ECURVE_PARAMS), 32) == 0 )
327
            //     {
328
            //         modulusFeatures |= SYMCRYPT_MODULUS_FEATURE_NISTP256;
329
            //     }
330
            // }
331
946
        }
332
946
    }
333
334
1.89k
    pEntry = SymCryptModulusTypeSelections;
335
336
1.89k
    for(;;)
337
13.7k
    {
338
13.7k
        if( SYMCRYPT_CPU_FEATURES_PRESENT( pEntry->cpuFeatures ) &&
339
13.7k
            (pEntry->maxBits == 0 || (nDigits <= SymCryptDigitsFromBits( pEntry->maxBits ) && nBitsizeOfValue <= pEntry->maxBits )) &&
340
13.7k
            (pEntry->modulusFeatures & ~modulusFeatures) == 0
341
13.7k
            )
342
1.89k
        {
343
1.89k
            res = pEntry->type;
344
1.89k
            break;
345
1.89k
        }
346
11.8k
        pEntry++;
347
11.8k
    }
348
349
1.89k
    return res;
350
1.89k
}
351
352
VOID
353
SYMCRYPT_CALL
354
SymCryptFdefModSetPostGeneric(
355
    _In_                            PCSYMCRYPT_MODULUS      pmMod,
356
    _Inout_                         PSYMCRYPT_MODELEMENT    peObj,
357
    _Out_writes_bytes_( cbScratch ) PBYTE                   pbScratch,
358
                                    SIZE_T                  cbScratch )
359
1.43k
{
360
1.43k
    UNREFERENCED_PARAMETER( pmMod );
361
1.43k
    UNREFERENCED_PARAMETER( peObj );
362
1.43k
    UNREFERENCED_PARAMETER( pbScratch );
363
1.43k
    UNREFERENCED_PARAMETER( cbScratch );
364
1.43k
}
365
366
PCUINT32
367
SYMCRYPT_CALL
368
SymCryptFdefModPreGetGeneric(
369
    _In_                            PCSYMCRYPT_MODULUS      pmMod,
370
    _In_                            PCSYMCRYPT_MODELEMENT   peObj,
371
    _Out_writes_bytes_( cbScratch ) PBYTE                   pbScratch,
372
                                    SIZE_T                  cbScratch )
373
650
{
374
650
    UNREFERENCED_PARAMETER( pmMod );
375
650
    UNREFERENCED_PARAMETER( pbScratch );
376
650
    UNREFERENCED_PARAMETER( cbScratch );
377
378
650
    return &peObj->d.uint32[0];
379
650
}
380
381
382
383
VOID
384
SYMCRYPT_CALL
385
SymCryptFdefIntToModulus(
386
    _In_                            PCSYMCRYPT_INT      piSrc,
387
    _Out_                           PSYMCRYPT_MODULUS   pmDst,
388
                                    UINT32              averageOperations,
389
                                    UINT32              flags,
390
    _Out_writes_bytes_( cbScratch ) PBYTE               pbScratch,
391
                                    SIZE_T              cbScratch )
392
1.89k
{
393
1.89k
    pmDst->flags = flags;
394
1.89k
    SymCryptIntToDivisor( piSrc, &pmDst->Divisor, averageOperations, flags & SYMCRYPT_FLAG_DATA_PUBLIC, pbScratch, cbScratch );
395
396
1.89k
    pmDst->type = SymCryptFdefDecideModulusType( piSrc, pmDst->nDigits, averageOperations, flags );
397
398
    // Set inv64 - note the value is only valid if the modulus is odd, but the computation
399
    // is constant time regardless of the parity, so we can safely compute it in all cases
400
1.89k
    pmDst->inv64 = 0 - SymCryptInverseMod2e64( SymCryptIntGetValueLsbits64(piSrc) );
401
402
1.89k
    SYMCRYPT_MOD_CALL( pmDst ) modulusInit( pmDst, pbScratch, cbScratch );
403
1.89k
}
404
405
VOID
406
SYMCRYPT_CALL
407
SymCryptFdefIntToModElement(
408
    _In_                            PCSYMCRYPT_INT          piSrc,
409
    _In_                            PCSYMCRYPT_MODULUS      pmMod,
410
    _Out_                           PSYMCRYPT_MODELEMENT    peDst,
411
    _Out_writes_bytes_( cbScratch ) PBYTE                   pbScratch,
412
                                    SIZE_T                  cbScratch )
413
1.17k
{
414
1.17k
    SymCryptFdefRawDivMod(
415
1.17k
        SYMCRYPT_FDEF_INT_PUINT32( piSrc ),
416
1.17k
        piSrc->nDigits,
417
1.17k
        &pmMod->Divisor,
418
1.17k
        NULL,                   // throw away the quotient
419
1.17k
        &peDst->d.uint32[0],
420
1.17k
        pbScratch,
421
1.17k
        cbScratch );
422
423
1.17k
    SYMCRYPT_MOD_CALL( pmMod ) modSetPost( pmMod, peDst, pbScratch, cbScratch );
424
1.17k
}
425
426
VOID
427
SYMCRYPT_CALL
428
SymCryptFdefModElementToIntGeneric(
429
    _In_                            PCSYMCRYPT_MODULUS      pmMod,
430
    _In_reads_bytes_( pmMod->nDigits * SYMCRYPT_FDEF_DIGIT_SIZE )
431
                                    PCUINT32                pSrc,
432
    _Out_                           PSYMCRYPT_INT           piDst,
433
    _Out_writes_bytes_( cbScratch ) PBYTE                   pbScratch,
434
                                    SIZE_T                  cbScratch )
435
1.61k
{
436
1.61k
    memcpy( SYMCRYPT_FDEF_INT_PUINT32( piDst ), pSrc, pmMod->nDigits * SYMCRYPT_FDEF_DIGIT_SIZE );
437
438
1.61k
    SymCryptWipe( &SYMCRYPT_FDEF_INT_PUINT32( piDst )[pmMod->nDigits * SYMCRYPT_FDEF_DIGIT_NUINT32], (piDst->nDigits - pmMod->nDigits) * SYMCRYPT_FDEF_DIGIT_SIZE );
439
440
1.61k
    SymCryptFdefClaimScratch( pbScratch, cbScratch, SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( pmMod->nDigits ) );
441
1.61k
}
442
443
SYMCRYPT_ERROR
444
SYMCRYPT_CALL
445
SymCryptFdefModElementSetValueGeneric(
446
    _In_reads_bytes_( cbSrc )       PCBYTE                  pbSrc,
447
                                    SIZE_T                  cbSrc,
448
                                    SYMCRYPT_NUMBER_FORMAT  format,
449
    _In_                            PCSYMCRYPT_MODULUS      pmMod,
450
    _Out_                           PSYMCRYPT_MODELEMENT    peDst,
451
    _Out_writes_bytes_( cbScratch ) PBYTE                   pbScratch,
452
                                    SIZE_T                  cbScratch )
453
4.36k
{
454
4.36k
    SYMCRYPT_ERROR scError;
455
4.36k
    UINT32  nDigits = pmMod->nDigits;
456
457
4.36k
    SymCryptFdefClaimScratch( pbScratch, cbScratch, SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( nDigits ) );
458
459
4.36k
    SYMCRYPT_ASSERT( cbSrc <= nDigits * SYMCRYPT_FDEF_DIGIT_SIZE );
460
461
4.36k
    scError = SymCryptFdefRawSetValue( pbSrc, cbSrc, format, &peDst->d.uint32[0], nDigits );
462
4.36k
    if( scError != SYMCRYPT_NO_ERROR )
463
0
    {
464
0
        goto cleanup;
465
0
    }
466
467
4.36k
    SymCryptFdefRawDivMod(
468
4.36k
        &peDst->d.uint32[0],
469
4.36k
        nDigits,
470
4.36k
        &pmMod->Divisor,
471
4.36k
        NULL,
472
4.36k
        &peDst->d.uint32[0],
473
4.36k
        pbScratch,
474
4.36k
        cbScratch );
475
476
4.36k
    scError = SYMCRYPT_NO_ERROR;
477
478
4.36k
cleanup:
479
4.36k
    return scError;
480
4.36k
}
481
482
SYMCRYPT_ERROR
483
SYMCRYPT_CALL
484
SymCryptFdefModElementGetValue(
485
    _In_                            PCSYMCRYPT_MODULUS      pmMod,
486
    _In_                            PCSYMCRYPT_MODELEMENT   peSrc,
487
    _Out_writes_bytes_( cbDst )     PBYTE                   pbDst,
488
                                    SIZE_T                  cbDst,
489
                                    SYMCRYPT_NUMBER_FORMAT  format,
490
    _Out_writes_bytes_( cbScratch ) PBYTE                   pbScratch,
491
                                    SIZE_T                  cbScratch )
492
1.76k
{
493
1.76k
    SYMCRYPT_ERROR scError;
494
1.76k
    PCUINT32 pUint32;
495
1.76k
    UINT32  nDigits = pmMod->nDigits;
496
497
498
1.76k
    SymCryptFdefClaimScratch( pbScratch, cbScratch, SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( nDigits ) );
499
500
1.76k
    SYMCRYPT_ASSERT( cbDst <= nDigits * SYMCRYPT_FDEF_DIGIT_SIZE );
501
502
1.76k
    pUint32 = SYMCRYPT_MOD_CALL( pmMod ) modPreGet( pmMod, peSrc, pbScratch, cbScratch );
503
504
1.76k
    scError = SymCryptFdefRawGetValue( pUint32, nDigits, pbDst, cbDst, format );
505
506
1.76k
    return scError;
507
1.76k
}
508
509
UINT32
510
SYMCRYPT_CALL
511
SymCryptFdefModElementIsEqual(
512
    _In_    PCSYMCRYPT_MODULUS     pmMod,
513
    _In_    PCSYMCRYPT_MODELEMENT  peSrc1,
514
    _In_    PCSYMCRYPT_MODELEMENT  peSrc2 )
515
4.34k
{
516
4.34k
    UINT32 d;
517
4.34k
    UINT32 i;
518
519
4.34k
    d = 0;
520
91.9k
    for( i=0; i < pmMod->nDigits * SYMCRYPT_FDEF_DIGIT_NUINT32 ; i++ )
521
87.5k
    {
522
87.5k
        d |= peSrc1->d.uint32[i] ^ peSrc2->d.uint32[i];
523
87.5k
    }
524
525
4.34k
    return SYMCRYPT_MASK32_ZERO( d );
526
4.34k
}
527
528
UINT32
529
SYMCRYPT_CALL
530
SymCryptFdefModElementIsZero(
531
    _In_    PCSYMCRYPT_MODULUS     pmMod,
532
    _In_    PCSYMCRYPT_MODELEMENT  peSrc )
533
77.3k
{
534
77.3k
    UINT32 d;
535
77.3k
    UINT32 i;
536
537
77.3k
    d = 0;
538
1.94M
    for( i=0; i < pmMod->nDigits * SYMCRYPT_FDEF_DIGIT_NUINT32 ; i++ )
539
1.86M
    {
540
1.86M
        d |= peSrc->d.uint32[i];        // Check that all bits are zero
541
1.86M
    }
542
543
77.3k
    return SYMCRYPT_MASK32_ZERO( d );
544
77.3k
}
545
546
VOID
547
SYMCRYPT_CALL
548
SymCryptFdefModAddGeneric(
549
    _In_                            PCSYMCRYPT_MODULUS      pmMod,
550
    _In_                            PCSYMCRYPT_MODELEMENT   peSrc1,
551
    _In_                            PCSYMCRYPT_MODELEMENT   peSrc2,
552
    _Out_                           PSYMCRYPT_MODELEMENT    peDst,
553
    _Out_writes_bytes_( cbScratch ) PBYTE                   pbScratch,
554
                                    SIZE_T                  cbScratch )
555
145k
{
556
145k
    UINT32 c;
557
145k
    UINT32 d;
558
145k
    UINT32 nDigits = pmMod->nDigits;
559
560
145k
    SymCryptFdefClaimScratch( pbScratch, cbScratch, SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( nDigits ) );
561
145k
    SYMCRYPT_ASSERT( cbScratch >= nDigits*SYMCRYPT_FDEF_DIGIT_SIZE );
562
563
    //
564
    // Doing add/cmp/sub might be faster or not.
565
    // Masked add is hard because the mask operations destroy the carry flag.
566
    //
567
568
  // dcl - cleanup?
569
570
//    c = SymCryptFdefRawAdd( &pSrc1->uint32[0], &pSrc2->uint32[0], &pDst->uint32[0], nDigits);
571
//    d = SymCryptFdefRawSub( &pDst->uint32[0], &pMod->Divisor.Int.uint32[0], &pDst->uint32[0], nDigits );
572
//    e = SymCryptFdefRawMaskedAdd( &pDst->uint32[0], &pMod->Divisor.Int.uint32[0], 0 - (c^d), nDigits );
573
574
145k
    c = SymCryptFdefRawAdd( &peSrc1->d.uint32[0], &peSrc2->d.uint32[0], &peDst->d.uint32[0], nDigits );
575
145k
    d = SymCryptFdefRawSub( &peDst->d.uint32[0], SYMCRYPT_FDEF_INT_PUINT32( &pmMod->Divisor.Int ), (PUINT32) pbScratch, nDigits );
576
145k
    SymCryptFdefMaskedCopy( pbScratch, (PBYTE) &peDst->d.uint32[0], nDigits, (c^d) - 1 );
577
578
    // We can't have a carry in the first addition, and no carry in the subtraction.
579
145k
    SYMCRYPT_ASSERT( !( c == 1 && d == 0 ) );
580
145k
}
581
582
VOID
583
SYMCRYPT_CALL
584
SymCryptFdefModSubGeneric(
585
    _In_                            PCSYMCRYPT_MODULUS      pmMod,
586
    _In_                            PCSYMCRYPT_MODELEMENT   peSrc1,
587
    _In_                            PCSYMCRYPT_MODELEMENT   peSrc2,
588
    _Out_                           PSYMCRYPT_MODELEMENT    peDst,
589
    _Out_writes_bytes_( cbScratch ) PBYTE                   pbScratch,
590
                                    SIZE_T                  cbScratch )
591
303k
{
592
303k
    UINT32 c;
593
303k
    UINT32 d;
594
303k
    UINT32 nDigits = pmMod->nDigits;
595
596
303k
    SymCryptFdefClaimScratch( pbScratch, cbScratch, SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( nDigits ) );
597
303k
    SYMCRYPT_ASSERT( cbScratch >= nDigits*SYMCRYPT_FDEF_DIGIT_SIZE );
598
599
303k
    c = SymCryptFdefRawSub( &peSrc1->d.uint32[0], &peSrc2->d.uint32[0], &peDst->d.uint32[0], nDigits );
600
303k
    d = SymCryptFdefRawAdd( &peDst->d.uint32[0], SYMCRYPT_FDEF_INT_PUINT32( &pmMod->Divisor.Int ), (PUINT32) pbScratch, nDigits );
601
303k
    SymCryptFdefMaskedCopy( pbScratch, (PBYTE) &peDst->d.uint32[0], nDigits, 0 - c );
602
603
303k
    SYMCRYPT_ASSERT( !(c == 1 && d == 0) );
604
303k
}
605
606
607
VOID
608
SYMCRYPT_CALL
609
SymCryptFdefModNegGeneric(
610
    _In_                            PCSYMCRYPT_MODULUS      pmMod,
611
    _In_                            PCSYMCRYPT_MODELEMENT   peSrc,
612
    _Out_                           PSYMCRYPT_MODELEMENT    peDst,
613
    _Out_writes_bytes_( cbScratch ) PBYTE                   pbScratch,
614
                                    SIZE_T                  cbScratch )
615
83.3k
{
616
83.3k
    UINT32 nDigits = pmMod->nDigits;
617
83.3k
    UINT32 isZero;
618
83.3k
    UINT32 i;
619
620
83.3k
    SymCryptFdefClaimScratch( pbScratch, cbScratch, SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( nDigits ) );
621
622
    //
623
    // We have to be careful to handle the value 0 properly as it does NOT map to Modulus - Value.
624
    //
625
83.3k
    isZero = SymCryptFdefRawIsEqualUint32( &peSrc->d.uint32[0], nDigits , 0 );
626
83.3k
    SymCryptFdefRawSub( SYMCRYPT_FDEF_INT_PUINT32( &pmMod->Divisor.Int ), &peSrc->d.uint32[0], &peDst->d.uint32[0], nDigits );
627
628
    // Now we set the result to zero if the input was zero
629
1.83M
    for( i=0; i< nDigits * SYMCRYPT_FDEF_DIGIT_NUINT32; i++ )
630
1.75M
    {
631
1.75M
        peDst->d.uint32[i] &= ~isZero;
632
1.75M
    }
633
83.3k
}
634
635
VOID
636
SYMCRYPT_CALL
637
SymCryptFdefModElementSetValueUint32Generic(
638
                                    UINT32                  value,
639
    _In_                            PCSYMCRYPT_MODULUS      pmMod,
640
    _Out_                           PSYMCRYPT_MODELEMENT    peDst,
641
    _Out_writes_bytes_( cbScratch ) PBYTE                   pbScratch,
642
                                    SIZE_T                  cbScratch )
643
6.75k
{
644
6.75k
    UINT32 nDigits = pmMod->nDigits;
645
646
6.75k
    SymCryptFdefClaimScratch( pbScratch, cbScratch, SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( nDigits ) );
647
648
6.75k
    if( pmMod->Divisor.nBits <= 32 && value >= SYMCRYPT_FDEF_INT_PUINT32( &pmMod->Divisor.Int )[0] )
649
0
    {
650
        // The value is >=  the modulus; this is not supported
651
652
        // For now do a possibly non-sidechannel safe, but mathematically correct modulo operation
653
0
        value %= SYMCRYPT_FDEF_INT_PUINT32( &pmMod->Divisor.Int )[0];
654
0
    }
655
656
6.75k
    peDst->d.uint32[0] = value;
657
658
6.75k
    SymCryptWipe( &peDst->d.uint32[1], nDigits * SYMCRYPT_FDEF_DIGIT_SIZE - sizeof( UINT32 ) );
659
6.75k
}
660
661
VOID
662
SYMCRYPT_CALL
663
SymCryptFdefModElementSetValueNegUint32(
664
                                    UINT32                  value,
665
    _In_                            PCSYMCRYPT_MODULUS      pmMod,
666
    _Out_                           PSYMCRYPT_MODELEMENT    peDst,
667
    _Out_writes_bytes_( cbScratch ) PBYTE                   pbScratch,
668
                                    SIZE_T                  cbScratch )
669
852
{
670
852
    UINT32 nDigits = pmMod->nDigits;
671
672
852
    SymCryptFdefClaimScratch( pbScratch, cbScratch, SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( nDigits ) );
673
674
852
    if( pmMod->Divisor.nBits <= 32 && value >= SYMCRYPT_FDEF_INT_PUINT32( &pmMod->Divisor.Int )[0] )
675
0
    {
676
        // The value is >=  the modulus; this is not supported.
677
678
        // For now do a possibly non-sidechannel safe, but mathematically correct modulo operation
679
0
        value %= SYMCRYPT_FDEF_INT_PUINT32( &pmMod->Divisor.Int )[0];
680
0
    }
681
682
852
    if( value == 0 )
683
0
    {
684
0
        SymCryptWipe( &peDst->d.uint32[0], nDigits * SYMCRYPT_FDEF_DIGIT_SIZE );
685
852
    } else {
686
852
        SymCryptFdefRawSubUint32( SYMCRYPT_FDEF_INT_PUINT32( &pmMod->Divisor.Int ), value, &peDst->d.uint32[0], nDigits );
687
852
    }
688
689
    //
690
    // Possible future optimization: we can optimize the value==0 and value==1 cases on a per-type basis
691
    //
692
852
    SYMCRYPT_MOD_CALL( pmMod ) modSetPost( pmMod, peDst, pbScratch, cbScratch );
693
852
}
694
695
// In the worst case there is a 1 in 8 chance of successfully generating a value
696
// This is when the modulus is 4 (nBits of modulus is 3), and 0, 1, and -1 are disallowed.
697
// In this case, having 1000 retries, there is a ~ 2^-193 chance of failure unless SymCryptCallbackRandom
698
// is completely broken. This passes the bar of being reasonable to Fatal.
699
536
#define FDEF_MOD_SET_RANDOM_GENERIC_LIMIT   (1000)
700
701
VOID
702
SYMCRYPT_CALL
703
SymCryptFdefModSetRandomGeneric(
704
    _In_                            PCSYMCRYPT_MODULUS      pmMod,
705
    _Out_                           PSYMCRYPT_MODELEMENT    peDst,
706
                                    UINT32                  flags,
707
    _Out_writes_bytes_( cbScratch ) PBYTE                   pbScratch,
708
                                    SIZE_T                  cbScratch )
709
268
{
710
268
    UINT32 offset;
711
268
    UINT32 ulimit;
712
268
    UINT32 nDigits = pmMod->nDigits;
713
268
    PUINT32 pTmp = (PUINT32) pbScratch;
714
268
    UINT32 nUsedBytes;
715
268
    UINT32 mask;
716
268
    UINT32 c;
717
268
    UINT32 cntr;
718
268
    PUINT32 pDst = &peDst->d.uint32[0];
719
268
    PCUINT32 pMod = SYMCRYPT_FDEF_INT_PUINT32( &pmMod->Divisor.Int );
720
721
268
    SymCryptFdefClaimScratch( pbScratch, cbScratch, SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( nDigits ) );
722
723
268
    if( (flags & SYMCRYPT_FLAG_MODRANDOM_ALLOW_ZERO) != 0 )
724
0
    {
725
        // SYMCRYPT_FLAG_MODRANDOM_ALLOW_ZERO => SYMCRYPT_FLAG_MODRANDOM_ALLOW_ONE
726
0
        offset = 0;
727
268
    } else if( (flags & SYMCRYPT_FLAG_MODRANDOM_ALLOW_ONE) != 0 )
728
268
    {
729
268
        offset = 1;
730
268
    } else
731
0
    {
732
0
        offset = 2;
733
0
    }
734
735
268
    if( (flags & SYMCRYPT_FLAG_MODRANDOM_ALLOW_MINUSONE ) )
736
268
    {
737
268
        ulimit = 0;
738
268
    } else {
739
0
        ulimit = 1;
740
0
    }
741
742
    //
743
    // Special case for small divisors:
744
    //  When the divisor is 1, 2, or 3 we always allow returning -1
745
    //  We may also allow returning 1 or 0 depending on the flags specified
746
268
    if ( pmMod->Divisor.nBits < 3 )
747
0
    {
748
        // At a minimum, allow -1
749
0
        offset = SYMCRYPT_MIN(offset, pMod[0] - 1);
750
0
        ulimit = 0;
751
0
    }
752
753
    // Set pTmp to pMod-(offset+ulimit)
754
268
    SYMCRYPT_ASSERT( nDigits * SYMCRYPT_FDEF_DIGIT_SIZE <= cbScratch );
755
268
    c = SymCryptFdefRawSubUint32( pMod, offset + ulimit, pTmp, nDigits );
756
268
    SYMCRYPT_ASSERT( c == 0 );
757
758
268
    nUsedBytes = (pmMod->Divisor.nBits + 7)/8;
759
268
    mask = 0x100 >> ( (8-pmMod->Divisor.nBits) & 7);
760
268
    mask -= 1;
761
762
    // Wipe any bytes we won't fill with random
763
268
    SymCryptWipe( (PBYTE)pDst + nUsedBytes, (nDigits * SYMCRYPT_FDEF_DIGIT_SIZE) - nUsedBytes );
764
765
268
    for(cntr=0; cntr<FDEF_MOD_SET_RANDOM_GENERIC_LIMIT; cntr++)
766
268
    {
767
        // Try random values until we get one we like
768
268
        SymCryptCallbackRandom( (PBYTE)pDst, nUsedBytes );
769
268
        ((PBYTE)pDst)[nUsedBytes-1] &= (BYTE) mask;
770
771
        // Compare value to pMod-(offset+ulimit)
772
268
        if( SymCryptFdefRawIsLessThan( pDst, pTmp, nDigits ) )
773
268
        {
774
            // The value is within required range [0, Divisor-offset-ulimit)
775
268
            break;
776
268
        }
777
268
    }
778
779
    // Wipe all the digits in pTmp
780
268
    SymCryptWipe( pTmp, nDigits * SYMCRYPT_FDEF_DIGIT_SIZE );
781
782
268
    if (cntr >= FDEF_MOD_SET_RANDOM_GENERIC_LIMIT)
783
0
    {
784
0
        SymCryptFatal( 'rndc');
785
0
    }
786
787
    // Add the offset which allows us to avoid 0 and/or 1 if required.
788
    // Now result is in range [offset, Divisor-ulimit)
789
268
    c = SymCryptFdefRawAddUint32( pDst, offset, pDst, nDigits );
790
268
    SYMCRYPT_ASSERT( c == 0 );
791
268
}
792
793
VOID
794
SYMCRYPT_CALL
795
SymCryptFdefModDivSmallPow2Generic(
796
    _In_                        PCSYMCRYPT_MODULUS      pmMod,
797
    _In_                        PCSYMCRYPT_MODELEMENT   peSrc,
798
    _In_range_(1, NATIVE_BITS)  UINT32                  exp,
799
    _Out_                       PSYMCRYPT_MODELEMENT    peDst)
800
337k
{
801
337k
    UINT32 nDigits = pmMod->nDigits;
802
337k
    UINT32 mask;
803
337k
    UINT64 t;
804
337k
    UINT64 u;
805
337k
    UINT32 i;
806
337k
    PCUINT32 pMod = SYMCRYPT_FDEF_INT_PUINT32( &pmMod->Divisor.Int );
807
808
    // mod must be odd
809
337k
    SYMCRYPT_ASSERT( (pMod[0] & 1) != 0 );
810
337k
    SYMCRYPT_ASSERT( (exp >= 1) && (exp <= NATIVE_BITS) );
811
812
337k
    do
813
675k
    {
814
675k
        mask = (UINT32)0 - (peSrc->d.uint32[0] & 1);
815
816
675k
        t = (UINT64) peSrc->d.uint32[0] + (pMod[0] & mask);
817
675k
        u = (UINT32) t;
818
675k
        t >>= 32;
819
820
15.7M
        for( i = 1; i < nDigits * SYMCRYPT_FDEF_DIGIT_NUINT32; i++ )
821
15.0M
        {
822
15.0M
            t += pMod[i] & mask;
823
15.0M
            t += peSrc->d.uint32[i];
824
825
15.0M
            u |= t << 32;
826
827
15.0M
            peDst->d.uint32[i-1] = (UINT32)(u >> 1);
828
15.0M
            t >>= 32;
829
15.0M
            u >>= 32;
830
15.0M
        }
831
675k
        u |= t << 32;
832
675k
        peDst->d.uint32[i-1] = (UINT32)( u >> 1 );
833
834
675k
        exp -= 1;
835
836
        // First iteration reads from peSrc and writes to peDst
837
        // subsequent iterations must read from and write to peDst
838
675k
        peSrc = peDst;
839
675k
    } while (exp > 0);
840
337k
}
841
842
VOID
843
SYMCRYPT_CALL
844
SymCryptFdefModDivSmallPow2(
845
    _In_                        PCSYMCRYPT_MODULUS      pmMod,
846
    _In_                        PCSYMCRYPT_MODELEMENT   peSrc,
847
    _In_range_(1, NATIVE_BITS)  UINT32                  exp,
848
    _Out_                       PSYMCRYPT_MODELEMENT    peDst )
849
337k
{
850
    
851
337k
#if SYMCRYPT_CPU_AMD64
852
337k
    if( SYMCRYPT_CPU_FEATURES_PRESENT( SYMCRYPT_CPU_FEATURES_FOR_MULX ) )
853
0
    {
854
0
        SymCryptFdefModDivSmallPow2Mulx( pmMod, peSrc, exp, peDst );
855
0
    }
856
337k
    else
857
337k
    {
858
        // Currently SymCryptAsm does not support AMD64 functions with shl/shr/shrd
859
        // by a variable count, as this needs special handling of the rcx (cl) register
860
        // For now we just fallback to the generic implementation on machines without MULX
861
337k
        SymCryptFdefModDivSmallPow2Generic( pmMod, peSrc, exp, peDst );
862
337k
    }
863
#elif SYMCRYPT_CPU_ARM64
864
    SymCryptFdefModDivSmallPow2Asm( pmMod, peSrc, exp, peDst );
865
#else
866
    SymCryptFdefModDivSmallPow2Generic( pmMod, peSrc, exp, peDst );
867
#endif
868
337k
}
869
870
VOID
871
SYMCRYPT_CALL
872
SymCryptFdefModDivPow2(
873
    _In_                            PCSYMCRYPT_MODULUS      pmMod,
874
    _In_                            PCSYMCRYPT_MODELEMENT   peSrc,
875
                                    UINT32                  exp,
876
    _Out_                           PSYMCRYPT_MODELEMENT    peDst,
877
    _Out_writes_bytes_( cbScratch ) PBYTE                   pbScratch,
878
                                    SIZE_T                  cbScratch )
879
0
{
880
0
    UINT32 shiftAmount;
881
882
0
    UNREFERENCED_PARAMETER(pbScratch);
883
0
    UNREFERENCED_PARAMETER(cbScratch);
884
885
    // mod must be odd
886
0
    SYMCRYPT_ASSERT( (SYMCRYPT_FDEF_INT_PUINT32(&pmMod->Divisor.Int)[0] & 1) != 0 );
887
888
0
    if( exp == 0 )
889
0
    {
890
        // If exp is 0 we just need to copy peSrc to peDst
891
0
        SymCryptFdefModElementCopy( pmMod, peSrc, peDst );
892
0
        return;
893
0
    }
894
895
0
    do
896
0
    {
897
0
        shiftAmount = SYMCRYPT_MIN(NATIVE_BITS, exp);
898
0
        SymCryptFdefModDivSmallPow2( pmMod, peSrc, shiftAmount, peDst );
899
0
        exp -= shiftAmount;
900
901
        // First iteration reads from peSrc and writes to peDst
902
        // subsequent iterations must read from and write to peDst
903
0
        peSrc = peDst;
904
0
    } while( exp > 0 );
905
0
}
906
907
VOID
908
SYMCRYPT_CALL
909
SymCryptFdefModMulGeneric(
910
    _In_                            PCSYMCRYPT_MODULUS      pmMod,
911
    _In_                            PCSYMCRYPT_MODELEMENT   peSrc1,
912
    _In_                            PCSYMCRYPT_MODELEMENT   peSrc2,
913
    _Out_                           PSYMCRYPT_MODELEMENT    peDst,
914
    _Out_writes_bytes_( cbScratch ) PBYTE                   pbScratch,
915
                                    SIZE_T                  cbScratch )
916
1.24k
{
917
1.24k
    UINT32 nDigits = pmMod->nDigits;
918
1.24k
    PUINT32 pTmp = (PUINT32) pbScratch;
919
1.24k
    UINT32  scratchOffset = 2 * nDigits * SYMCRYPT_FDEF_DIGIT_SIZE;
920
921
1.24k
    SymCryptFdefClaimScratch( pbScratch, cbScratch, SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( nDigits ) );
922
1.24k
    SYMCRYPT_ASSERT( cbScratch >= SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( nDigits ) );
923
1.24k
    SYMCRYPT_ASSERT( SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( nDigits ) >= scratchOffset + SYMCRYPT_FDEF_SCRATCH_BYTES_FOR_INT_DIVMOD( 2 * nDigits, nDigits ) );
924
1.24k
    SYMCRYPT_ASSERT_ASYM_ALIGNED( pbScratch );
925
926
    // Tmp space is enough for the product plus the DivMod scratch
927
928
1.24k
    SymCryptFdefRawMul( &peSrc1->d.uint32[0], nDigits, &peSrc2->d.uint32[0], nDigits, pTmp );
929
930
1.24k
    SymCryptFdefRawDivMod( pTmp, 2*nDigits, &pmMod->Divisor, NULL, &peDst->d.uint32[0], pbScratch + scratchOffset, cbScratch - scratchOffset );
931
1.24k
}
932
933
VOID
934
SYMCRYPT_CALL
935
SymCryptFdefModSquareGeneric(
936
    _In_                            PCSYMCRYPT_MODULUS      pmMod,
937
    _In_                            PCSYMCRYPT_MODELEMENT   peSrc,
938
    _Out_                           PSYMCRYPT_MODELEMENT    peDst,
939
    _Out_writes_bytes_( cbScratch ) PBYTE                   pbScratch,
940
                                    SIZE_T                  cbScratch )
941
0
{
942
0
    UINT32 nDigits = pmMod->nDigits;
943
0
    PUINT32 pTmp = (PUINT32) pbScratch;
944
0
    UINT32  scratchOffset = 2 * nDigits * SYMCRYPT_FDEF_DIGIT_SIZE;
945
946
0
    SymCryptFdefClaimScratch( pbScratch, cbScratch, SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( nDigits ) );
947
0
    SYMCRYPT_ASSERT( cbScratch >= SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( nDigits ) );
948
0
    SYMCRYPT_ASSERT( SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( nDigits ) >= scratchOffset + SYMCRYPT_FDEF_SCRATCH_BYTES_FOR_INT_DIVMOD( 2 * nDigits, nDigits ) );
949
0
    SYMCRYPT_ASSERT_ASYM_ALIGNED( pbScratch );
950
951
    // Tmp space is enough for the product plus the DivMod scratch
952
953
0
    SymCryptFdefRawSquare( &peSrc->d.uint32[0], nDigits, pTmp );
954
955
0
    SymCryptFdefRawDivMod( pTmp, 2*nDigits, &pmMod->Divisor, NULL, &peDst->d.uint32[0], pbScratch + scratchOffset, cbScratch - scratchOffset );
956
0
}
957
958
SYMCRYPT_ERROR
959
SYMCRYPT_CALL
960
SymCryptFdefModInvGeneric(
961
    _In_                            PCSYMCRYPT_MODULUS      pmMod,
962
    _In_                            PCSYMCRYPT_MODELEMENT   peSrc,
963
    _Out_                           PSYMCRYPT_MODELEMENT    peDst,
964
                                    UINT32                  flags,
965
    _Out_writes_bytes_( cbScratch ) PBYTE                   pbScratch,
966
                                    SIZE_T                  cbScratch )
967
1.23k
{
968
1.23k
    SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
969
1.23k
    UINT32 nDigits = pmMod->nDigits;
970
1.23k
    UINT32 nBytes;
971
1.23k
    UINT32 c;
972
1.23k
    UINT32 leastSignificantUint32;
973
1.23k
    UINT32 trailingZeros;
974
975
    //
976
    // This function is called on Montgomery moduli so we can't directly call specifically optimized modular operations from here.
977
    //
978
    // For now we use dispatch functions with pmMod to perform potentially optimized modular operations.
979
    // This approach makes sense when on average the cost of dispatch is less than the benefit using an optimized operation.
980
    // The alternative is to make specialized ModInv routines for different types of moduli, but we do not yet do this to
981
    // reduce code duplication / code size.
982
    //
983
984
1.23k
    SYMCRYPT_ASSERT( cbScratch >= SYMCRYPT_SCRATCH_BYTES_FOR_MODINV( nDigits ) );
985
986
1.23k
    if( (pmMod->flags & (SYMCRYPT_FLAG_DATA_PUBLIC | SYMCRYPT_FLAG_MODULUS_PRIME )) != (SYMCRYPT_FLAG_DATA_PUBLIC | SYMCRYPT_FLAG_MODULUS_PRIME ) )
987
0
    {
988
        // Inversion over non-public or non-prime moduli currently not supported.
989
        // Our blinding below only works for prime moduli.
990
        // As the modulus cannot be blinded, it requires a fully side-channel safe algorithm which is much more complicated and
991
        // slower.
992
        // When this is necessary, we will add a second ModInv implementation for those cases.
993
0
        scError = SYMCRYPT_INVALID_ARGUMENT;
994
0
        goto cleanup;
995
0
    }
996
997
    //
998
    // Algorithm:
999
    // R = random nonzero value mod Mod
1000
    // X := Src * R (mod Mod)
1001
    // A = X
1002
    // B = Mod
1003
    // Va = 1
1004
    // Vb = 0
1005
    // invariant: A = Va*X (mod Mod), B = Vb*X (mod Mod),
1006
    //
1007
    // if( A == 0 ): error
1008
    //
1009
    // verify (A | B) is odd
1010
    // if B even: swap (A,B), swap( Va, Vb)
1011
    //
1012
    //  repeat:
1013
    //      while( A even ):
1014
    //          A /= 2; Va /= 2 (mod Mod)
1015
    //      if( A == 1 ): break1
1016
    //      (A, Va, B, Vb) = (B-A, Vb - Va, A, Va)
1017
    //      if( A == 0 ): error (not co-prime)
1018
1019
1.23k
    nBytes = SymCryptSizeofModElementFromModulus( pmMod );
1020
1021
1.23k
    SYMCRYPT_ASSERT( cbScratch >= 4*nBytes );
1022
1.23k
    PSYMCRYPT_MODELEMENT peR = SymCryptModElementCreate( pbScratch, nBytes, pmMod );
1023
1.23k
    pbScratch += nBytes;
1024
1.23k
    PSYMCRYPT_MODELEMENT peX = SymCryptModElementCreate( pbScratch, nBytes, pmMod );
1025
1.23k
    pbScratch += nBytes;
1026
1.23k
    PSYMCRYPT_MODELEMENT peVa = SymCryptModElementCreate( pbScratch, nBytes, pmMod );
1027
1.23k
    pbScratch += nBytes;
1028
1.23k
    PSYMCRYPT_MODELEMENT peVb = SymCryptModElementCreate( pbScratch, nBytes, pmMod );
1029
1.23k
    pbScratch += nBytes;
1030
1.23k
    cbScratch -= 4*nBytes;
1031
1032
1.23k
    PSYMCRYPT_MODELEMENT peVtmpPtr;
1033
1034
1.23k
    nBytes = SymCryptSizeofIntFromDigits( nDigits );
1035
1.23k
    SYMCRYPT_ASSERT( cbScratch >= 3 * nBytes );
1036
1.23k
    PSYMCRYPT_INT piA = SymCryptIntCreate( pbScratch, nBytes, nDigits );
1037
1.23k
    pbScratch += nBytes;
1038
1.23k
    PSYMCRYPT_INT piB = SymCryptIntCreate( pbScratch, nBytes, nDigits );
1039
1.23k
    pbScratch += nBytes;
1040
1.23k
    PSYMCRYPT_INT piT = SymCryptIntCreate( pbScratch, nBytes, nDigits );
1041
1.23k
    pbScratch += nBytes;
1042
1.23k
    cbScratch -= 3*nBytes;
1043
1044
1.23k
    PSYMCRYPT_INT piTmpPtr;
1045
1046
1.23k
    SYMCRYPT_ASSERT( cbScratch >= SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( nDigits ) );
1047
1048
    // If the data is not public, multiply by a random blinding factor; otherwise copy the value
1049
1.23k
    if( (flags & SYMCRYPT_FLAG_DATA_PUBLIC) == 0 )
1050
268
    {
1051
268
        SymCryptModSetRandom( pmMod, peR, SYMCRYPT_FLAG_MODRANDOM_ALLOW_ONE | SYMCRYPT_FLAG_MODRANDOM_ALLOW_MINUSONE, pbScratch, cbScratch );   //R = random
1052
268
        SymCryptModMul( pmMod, peR, peSrc, peX, pbScratch, cbScratch );     // X = R * Src
1053
268
    } else
1054
969
    {
1055
969
        SymCryptModElementCopy( pmMod, peSrc, peX );
1056
969
    }
1057
1058
    // Set up piA and piB
1059
1.23k
    SymCryptFdefModElementToIntGeneric( pmMod, &peX->d.uint32[0], piA, pbScratch, cbScratch );   // A = X
1060
1.23k
    SymCryptIntCopy( SymCryptIntFromModulus( (PSYMCRYPT_MODULUS) pmMod ), piB );          // B = Mod
1061
1062
    // Reject if A = 0, B = 0, or A and B both even
1063
1.23k
    if( SymCryptIntIsEqualUint32( piA, 0 ) |
1064
1.23k
        SymCryptIntIsEqualUint32( piB, 0 ) |
1065
1.23k
        (((SymCryptIntGetValueLsbits32( piA ) | SymCryptIntGetValueLsbits32( piB )) & 1) ^ 1) )
1066
0
    {
1067
0
        scError = SYMCRYPT_INVALID_ARGUMENT;
1068
0
        goto cleanup;
1069
0
    }
1070
1071
1.23k
    if( SymCryptIntIsEqualUint32( piB, 2 ) )
1072
0
    {
1073
        // Mod = 2 is a valid input. Luckilly, modular inversion is easy.
1074
        // The rest of the code assumes that Mod is odd. Other even values are not prime.
1075
0
        SymCryptModElementCopy( pmMod, peSrc, peDst);
1076
0
        goto cleanup;
1077
0
    }
1078
1079
1.23k
    SymCryptFdefModElementSetValueUint32Generic( 1, pmMod, peVa, pbScratch, cbScratch );               // Va = 1
1080
1.23k
    SymCryptFdefModElementSetValueUint32Generic( 0, pmMod, peVb, pbScratch, cbScratch );               // Vb = 0
1081
1082
1.23k
    for(;;)
1083
337k
    {
1084
        // invariant: A = Va*X (mod Mod), B = Vb*X (mod Mod), A != 0, B > 1.
1085
        // Remove factors of 2 from A. This loop terminates because A != 0
1086
337k
        leastSignificantUint32 = SymCryptIntGetValueLsbits32(piA);
1087
674k
        while( (leastSignificantUint32 & 1) == 0 )
1088
337k
        {
1089
337k
            trailingZeros = SymCryptCountTrailingZeros32( leastSignificantUint32 );
1090
337k
            SymCryptIntDivPow2( piA, trailingZeros, piA );
1091
337k
            SymCryptFdefModDivSmallPow2( pmMod, peVa, trailingZeros, peVa );
1092
337k
            leastSignificantUint32 = SymCryptIntGetValueLsbits32(piA);
1093
337k
        }
1094
1095
337k
        if( SymCryptIntIsEqualUint32( piA, 1 ) )
1096
1.23k
        {
1097
            // A = 1 = Va * X (mod Mod), so Va is the inverse of X
1098
1.23k
            break;
1099
1.23k
        }
1100
1101
336k
        c = SymCryptIntSubSameSize( piB, piA, piT );
1102
1103
        // If A != 1 and A=B, then A is the GCD of the original inputs, and there is no inverse
1104
336k
        if( SymCryptIntIsEqualUint32( piT, 0 ) )
1105
0
        {
1106
0
            scError = SYMCRYPT_INVALID_ARGUMENT;
1107
0
            goto cleanup;
1108
0
        }
1109
1110
336k
        if( c == 0 )
1111
182k
        {
1112
            // B > A, we set B to B-A and swap (B,A)
1113
            // that way we continue our halving on B-A
1114
1115
182k
            SymCryptIntCopy( piT, piB );
1116
182k
            SymCryptModSub( pmMod, peVb, peVa, peVb, pbScratch, cbScratch );
1117
1118
182k
            piTmpPtr  = piB;  piB  = piA;  piA  = piTmpPtr;
1119
182k
            peVtmpPtr = peVb; peVb = peVa; peVa = peVtmpPtr;
1120
182k
        } else {
1121
            // B < A, Set A to A-B and continue halving A
1122
153k
            SymCryptIntNeg( piT, piA );
1123
153k
            SymCryptModSub( pmMod, peVa, peVb, peVa, pbScratch, cbScratch );
1124
153k
        }
1125
336k
    }
1126
1127
    // 1 = A = Va * X (mod Mod), so Va is the inverse of X
1128
    // Check computation that we can test in the debugger
1129
1.23k
    SymCryptModMul( pmMod, peVa, peX, peVb, pbScratch, cbScratch );
1130
1131
    // Actual answer
1132
1133
    // If the data is not public, multiply by the random blinding factor; otherwise copy the value
1134
1.23k
    if( (flags & SYMCRYPT_FLAG_DATA_PUBLIC) == 0 )
1135
268
    {
1136
268
        SymCryptModMul( pmMod, peVa, peR, peDst, pbScratch, cbScratch );
1137
268
    } else
1138
969
    {
1139
969
        SymCryptModElementCopy( pmMod, peVa, peDst );
1140
969
    }
1141
1142
1.23k
cleanup:
1143
1.23k
    return scError;
1144
1.23k
}
1145
1146
1147
//=============================
1148
// Montgomery representation
1149
1150
VOID
1151
SYMCRYPT_CALL
1152
SymCryptFdefModulusInitMontgomeryInternal(
1153
    _Inout_                         PSYMCRYPT_MODULUS       pmMod,
1154
                                    UINT32                  nUint32Used,           // R = 2^{32 * this parameter}
1155
    _Out_writes_bytes_( cbScratch ) PBYTE                   pbScratch,
1156
                                    SIZE_T                  cbScratch )
1157
946
{
1158
    // Scratch space is big enough for an nDigit+1 byte value + sufficient divmod scratch
1159
946
    PUINT32 pR2;
1160
946
    UINT32  cbR2;
1161
946
    UINT32 nDigits;
1162
1163
946
    PUINT32 modR2;
1164
946
    PUINT32 negDivisor;
1165
1166
946
    nDigits = pmMod->nDigits;
1167
946
    modR2 = (PUINT32)((PBYTE)&pmMod->Divisor + SymCryptFdefSizeofDivisorFromDigits( nDigits ));
1168
1169
946
    SYMCRYPT_ASSERT_ASYM_ALIGNED( pbScratch );
1170
1171
946
    pmMod->tm.montgomery.Rsqr = modR2;
1172
946
    negDivisor = (PUINT32)((PBYTE)modR2 + (nDigits * SYMCRYPT_FDEF_DIGIT_SIZE));
1173
1174
    // We pre-compute R^2 mod M
1175
1176
946
    pR2 = (PUINT32) pbScratch;
1177
946
    cbR2 = (2*nDigits + 1) * SYMCRYPT_FDEF_DIGIT_SIZE;
1178
946
    SYMCRYPT_ASSERT( cbScratch >= cbR2 );
1179
946
    SYMCRYPT_ASSERT( cbScratch >= 2 * nUint32Used * sizeof(UINT32) );
1180
1181
    // Set it to R^2
1182
946
    SymCryptWipe( pR2, cbR2 );
1183
946
    pR2[ 2 * nUint32Used ] = 1;
1184
946
    SymCryptFdefRawDivMod( pR2, 2*nDigits + 1, &pmMod->Divisor, NULL, modR2, pbScratch + cbR2, cbScratch - cbR2 );
1185
1186
946
    SymCryptFdefRawNeg( SYMCRYPT_FDEF_INT_PUINT32( &pmMod->Divisor.Int ), 0, negDivisor, nDigits );
1187
946
}
1188
1189
VOID
1190
SYMCRYPT_CALL
1191
SymCryptFdefModulusInitMontgomery(
1192
    _Inout_                         PSYMCRYPT_MODULUS       pmMod,
1193
    _Out_writes_bytes_( cbScratch ) PBYTE                   pbScratch,
1194
                                    SIZE_T                  cbScratch )
1195
43
{
1196
43
    SymCryptFdefModulusInitMontgomeryInternal( pmMod, pmMod->nDigits * SYMCRYPT_FDEF_DIGIT_NUINT32, pbScratch, cbScratch );
1197
43
}
1198
1199
VOID
1200
SymCryptFdefMontgomeryReduceC(
1201
    _In_                                                                PCSYMCRYPT_MODULUS  pmMod,
1202
    _Inout_updates_( 2 * pmMod->nDigits * SYMCRYPT_FDEF_DIGIT_NUINT32 ) PUINT32             pSrc,
1203
    _Out_writes_( pmMod->nDigits * SYMCRYPT_FDEF_DIGIT_NUINT32 )        PUINT32             pDst )
1204
0
{
1205
0
    UINT32 nDigits = pmMod->nDigits;
1206
0
    UINT32 nWords = nDigits * SYMCRYPT_FDEF_DIGIT_NUINT32;
1207
0
    PCUINT32 pMod = SYMCRYPT_FDEF_INT_PUINT32( &pmMod->Divisor.Int );
1208
1209
0
    UINT32 hc = 0;
1210
0
    for( UINT32 i=0; i<nWords; i++ )
1211
0
    {
1212
0
        UINT32 m = (UINT32)pmMod->inv64 * pSrc[0];
1213
0
        UINT64 c = 0;
1214
0
        for( UINT32 j = 0; j < nWords; j++ )
1215
0
        {
1216
            // Invariant: c < 2^32
1217
0
            c += SYMCRYPT_MUL32x32TO64( pMod[j], m );
1218
0
            c += pSrc[j];
1219
            // There is no overflow on C because the max value is
1220
            // (2^32 - 1) * (2^32 - 1) + 2^32 - 1 + 2^32 - 1 = 2^64 - 1.
1221
0
            pSrc[j] = (UINT32) c;
1222
0
            c >>= 32;
1223
0
        }
1224
0
        c = c + pSrc[nWords] + hc;
1225
0
        pSrc[nWords] = (UINT32) c;
1226
0
        hc = c >> 32;
1227
0
        pSrc++;
1228
0
    }
1229
0
    SYMCRYPT_ASSERT( hc < 2 );
1230
1231
0
    UINT32 d = SymCryptFdefRawSub( pSrc, pMod, pDst, nDigits );
1232
1233
0
    SYMCRYPT_ASSERT( hc <= d );     // if hc = 1, then d = 1 is mandatory
1234
1235
0
    SymCryptFdefMaskedCopy( (PCBYTE) pSrc, (PBYTE) pDst, nDigits, hc - (hc | d) );  // copy only if hc=0, d=1
1236
0
}
1237
1238
VOID
1239
SymCryptFdefMontgomeryReduce(
1240
    _In_                                                                PCSYMCRYPT_MODULUS  pmMod,
1241
    _Inout_updates_( 2 * pmMod->nDigits * SYMCRYPT_FDEF_DIGIT_NUINT32 ) PUINT32             pSrc,
1242
    _Out_writes_( pmMod->nDigits * SYMCRYPT_FDEF_DIGIT_NUINT32 )        PUINT32             pDst )
1243
456k
{
1244
456k
#if SYMCRYPT_CPU_AMD64
1245
456k
    if( SYMCRYPT_CPU_FEATURES_PRESENT( SYMCRYPT_CPU_FEATURES_FOR_MULX ) )
1246
0
    {
1247
0
        SymCryptFdefMontgomeryReduceMulx( pmMod, pSrc, pDst );
1248
456k
    } else {
1249
456k
        SymCryptFdefMontgomeryReduceAsm( pmMod, pSrc, pDst );
1250
456k
    }
1251
#elif SYMCRYPT_CPU_X86 | SYMCRYPT_CPU_ARM64 | SYMCRYPT_CPU_ARM
1252
    SymCryptFdefMontgomeryReduceAsm( pmMod, pSrc, pDst );
1253
#else
1254
    SymCryptFdefMontgomeryReduceC( pmMod, pSrc, pDst );
1255
#endif
1256
456k
}
1257
1258
1259
VOID
1260
SYMCRYPT_CALL
1261
SymCryptFdefModSetPostMontgomery(
1262
    _In_                            PCSYMCRYPT_MODULUS      pmMod,
1263
    _Inout_                         PSYMCRYPT_MODELEMENT    peObj,
1264
    _Out_writes_bytes_( cbScratch ) PBYTE                   pbScratch,
1265
                                    SIZE_T                  cbScratch )
1266
577
{
1267
    // Montgomery representation for X is R*X mod M where R = 2^<nDigits * bits-per-digit>
1268
    // Montgomery reduction performs an implicit division by R
1269
    // This function converts to the internal representation by multiplying by R^2 mod M and then performing a Montgomery reduction
1270
577
    UINT32 nDigits = pmMod->nDigits;
1271
1272
  // dcl - this should not incur significant cost, consider checking always
1273
577
    SYMCRYPT_ASSERT( cbScratch >= nDigits * 2 * SYMCRYPT_FDEF_DIGIT_SIZE );
1274
577
    UNREFERENCED_PARAMETER( cbScratch );
1275
1276
577
    SymCryptFdefRawMul( &peObj->d.uint32[0], nDigits, pmMod->tm.montgomery.Rsqr, nDigits, (PUINT32) pbScratch );
1277
577
    SymCryptFdefMontgomeryReduce( pmMod, (PUINT32) pbScratch, &peObj->d.uint32[0] );
1278
577
}
1279
1280
PCUINT32
1281
SYMCRYPT_CALL
1282
SymCryptFdefModPreGetMontgomery(
1283
    _In_                            PCSYMCRYPT_MODULUS      pmMod,
1284
    _In_                            PCSYMCRYPT_MODELEMENT   peObj,
1285
    _Out_writes_bytes_( cbScratch ) PBYTE                   pbScratch,
1286
                                    SIZE_T                  cbScratch )
1287
64
{
1288
64
    PUINT32 pTmp = (PUINT32) pbScratch;
1289
64
    UINT32 nDigits = pmMod->nDigits;
1290
1291
  // dcl - this should not incur significant cost, consider checking always
1292
64
    SYMCRYPT_ASSERT( cbScratch >= nDigits * 2 * SYMCRYPT_FDEF_DIGIT_SIZE );
1293
64
    UNREFERENCED_PARAMETER( cbScratch );
1294
1295
64
    memcpy( pTmp, &peObj->d.uint32[0], nDigits * SYMCRYPT_FDEF_DIGIT_SIZE );
1296
64
    SymCryptWipe( pTmp + nDigits * SYMCRYPT_FDEF_DIGIT_NUINT32, nDigits * SYMCRYPT_FDEF_DIGIT_SIZE );
1297
64
    SymCryptFdefMontgomeryReduce( pmMod, pTmp, pTmp );
1298
1299
64
    return pTmp;
1300
64
}
1301
1302
VOID
1303
SYMCRYPT_CALL
1304
SymCryptFdefModulusCopyFixupMontgomery(
1305
    _In_                            PCSYMCRYPT_MODULUS      pmSrc,
1306
    _Out_                           PSYMCRYPT_MODULUS       pmDst )
1307
0
{
1308
    // We only have to fix up the Montgomery-specific stuff here
1309
  // dcl - not sure I understand why you pass pmSrc here
1310
0
    UNREFERENCED_PARAMETER( pmSrc );
1311
0
    pmDst->tm.montgomery.Rsqr = (PUINT32)((PBYTE)&pmDst->Divisor + SymCryptFdefSizeofDivisorFromDigits( pmDst->nDigits ));
1312
0
}
1313
1314
VOID
1315
SYMCRYPT_CALL
1316
SymCryptFdefModMulMontgomery(
1317
    _In_                            PCSYMCRYPT_MODULUS      pmMod,
1318
    _In_                            PCSYMCRYPT_MODELEMENT   peSrc1,
1319
    _In_                            PCSYMCRYPT_MODELEMENT   peSrc2,
1320
    _Out_                           PSYMCRYPT_MODELEMENT    peDst,
1321
    _Out_writes_bytes_( cbScratch ) PBYTE                   pbScratch,
1322
                                    SIZE_T                  cbScratch )
1323
300k
{
1324
300k
    UINT32 nDigits = pmMod->nDigits;
1325
300k
    PUINT32 pTmp = (PUINT32) pbScratch;
1326
1327
  // dcl - missing assert?
1328
300k
    UNREFERENCED_PARAMETER( cbScratch );
1329
300k
    SYMCRYPT_ASSERT( cbScratch >= 2 * nDigits * SYMCRYPT_FDEF_DIGIT_SIZE );
1330
1331
300k
    SymCryptFdefRawMul( &peSrc1->d.uint32[0], nDigits, &peSrc2->d.uint32[0], nDigits, pTmp );
1332
300k
    SymCryptFdefMontgomeryReduce( pmMod, pTmp, &peDst->d.uint32[0] );
1333
300k
}
1334
1335
#if SYMCRYPT_CPU_AMD64
1336
VOID
1337
SYMCRYPT_CALL
1338
SymCryptFdefModMulMontgomeryMulx(
1339
    _In_                            PCSYMCRYPT_MODULUS      pmMod,
1340
    _In_                            PCSYMCRYPT_MODELEMENT   peSrc1,
1341
    _In_                            PCSYMCRYPT_MODELEMENT   peSrc2,
1342
    _Out_                           PSYMCRYPT_MODELEMENT    peDst,
1343
    _Out_writes_bytes_( cbScratch ) PBYTE                   pbScratch,
1344
                                    SIZE_T                  cbScratch )
1345
0
{
1346
0
    UINT32 nDigits = pmMod->nDigits;
1347
0
    PUINT32 pTmp = (PUINT32) pbScratch;
1348
1349
0
    UNREFERENCED_PARAMETER( cbScratch );
1350
0
    SYMCRYPT_ASSERT( cbScratch >= 2 * nDigits * SYMCRYPT_FDEF_DIGIT_SIZE );
1351
1352
0
    SymCryptFdefRawMulMulx( &peSrc1->d.uint32[0], nDigits, &peSrc2->d.uint32[0], nDigits, pTmp );
1353
0
    SymCryptFdefMontgomeryReduceMulx( pmMod, pTmp, &peDst->d.uint32[0] );
1354
0
}
1355
1356
VOID
1357
SYMCRYPT_CALL
1358
SymCryptFdefModMulMontgomeryMulx1024(
1359
    _In_                            PCSYMCRYPT_MODULUS      pmMod,
1360
    _In_                            PCSYMCRYPT_MODELEMENT   peSrc1,
1361
    _In_                            PCSYMCRYPT_MODELEMENT   peSrc2,
1362
    _Out_                           PSYMCRYPT_MODELEMENT    peDst,
1363
    _Out_writes_bytes_( cbScratch ) PBYTE                   pbScratch,
1364
                                    SIZE_T                  cbScratch )
1365
0
{
1366
0
    UINT32 nDigits = pmMod->nDigits;
1367
0
    PUINT32 pTmp = (PUINT32) pbScratch;
1368
1369
0
    UNREFERENCED_PARAMETER( cbScratch );
1370
0
    SYMCRYPT_ASSERT( cbScratch >= 2 * nDigits * SYMCRYPT_FDEF_DIGIT_SIZE );
1371
1372
0
    SymCryptFdefRawMulMulx1024( &peSrc1->d.uint32[0], &peSrc2->d.uint32[0], nDigits, pTmp );
1373
0
    SymCryptFdefMontgomeryReduceMulx1024( pmMod, pTmp, &peDst->d.uint32[0] );
1374
0
}
1375
#endif
1376
1377
1378
VOID
1379
SYMCRYPT_CALL
1380
SymCryptFdefModSquareMontgomery(
1381
    _In_                            PCSYMCRYPT_MODULUS      pmMod,
1382
    _In_                            PCSYMCRYPT_MODELEMENT   peSrc,
1383
    _Out_                           PSYMCRYPT_MODELEMENT    peDst,
1384
    _Out_writes_bytes_( cbScratch ) PBYTE                   pbScratch,
1385
                                    SIZE_T                  cbScratch )
1386
155k
{
1387
155k
    UINT32 nDigits = pmMod->nDigits;
1388
155k
    PUINT32 pTmp = (PUINT32) pbScratch;
1389
1390
155k
    UNREFERENCED_PARAMETER( cbScratch );
1391
155k
    SYMCRYPT_ASSERT( cbScratch >= 2 * nDigits * SYMCRYPT_FDEF_DIGIT_SIZE );
1392
1393
155k
    SymCryptFdefRawSquare( &peSrc->d.uint32[0], nDigits, pTmp );
1394
155k
    SymCryptFdefMontgomeryReduce( pmMod, pTmp, &peDst->d.uint32[0] );
1395
155k
}
1396
1397
1398
#if SYMCRYPT_CPU_AMD64
1399
VOID
1400
SYMCRYPT_CALL
1401
SymCryptFdefModSquareMontgomeryMulx(
1402
    _In_                            PCSYMCRYPT_MODULUS      pmMod,
1403
    _In_                            PCSYMCRYPT_MODELEMENT   peSrc,
1404
    _Out_                           PSYMCRYPT_MODELEMENT    peDst,
1405
    _Out_writes_bytes_( cbScratch ) PBYTE                   pbScratch,
1406
                                    SIZE_T                  cbScratch )
1407
0
{
1408
0
    UINT32 nDigits = pmMod->nDigits;
1409
0
    PUINT32 pTmp = (PUINT32) pbScratch;
1410
1411
0
    UNREFERENCED_PARAMETER( cbScratch );
1412
0
    SYMCRYPT_ASSERT( cbScratch >= 2 * nDigits * SYMCRYPT_FDEF_DIGIT_SIZE );
1413
1414
0
    SymCryptFdefRawSquareMulx( &peSrc->d.uint32[0], nDigits, pTmp );
1415
0
    SymCryptFdefMontgomeryReduceMulx( pmMod, pTmp, &peDst->d.uint32[0] );
1416
0
}
1417
1418
VOID
1419
SYMCRYPT_CALL
1420
SymCryptFdefModSquareMontgomeryMulx1024(
1421
    _In_                            PCSYMCRYPT_MODULUS      pmMod,
1422
    _In_                            PCSYMCRYPT_MODELEMENT   peSrc,
1423
    _Out_                           PSYMCRYPT_MODELEMENT    peDst,
1424
    _Out_writes_bytes_( cbScratch ) PBYTE                   pbScratch,
1425
                                    SIZE_T                  cbScratch )
1426
0
{
1427
0
    UINT32 nDigits = pmMod->nDigits;
1428
0
    PUINT32 pTmp = (PUINT32) pbScratch;
1429
1430
0
    UNREFERENCED_PARAMETER( cbScratch );
1431
0
    SYMCRYPT_ASSERT( cbScratch >= 2 * nDigits * SYMCRYPT_FDEF_DIGIT_SIZE );
1432
1433
0
    SymCryptFdefRawSquareMulx1024( &peSrc->d.uint32[0], nDigits, pTmp );
1434
0
    SymCryptFdefMontgomeryReduceMulx1024( pmMod, pTmp, &peDst->d.uint32[0] );
1435
0
}
1436
#endif
1437
1438
SYMCRYPT_ERROR
1439
SYMCRYPT_CALL
1440
SymCryptFdefModInvMontgomery(
1441
    _In_                            PCSYMCRYPT_MODULUS      pmMod,
1442
    _In_                            PCSYMCRYPT_MODELEMENT   peSrc,
1443
    _Out_                           PSYMCRYPT_MODELEMENT    peDst,
1444
                                    UINT32                  flags,
1445
    _Out_writes_bytes_( cbScratch ) PBYTE                   pbScratch,
1446
                                    SIZE_T                  cbScratch )
1447
43
{
1448
43
    SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
1449
43
    UINT32 nDigits = pmMod->nDigits;
1450
43
    UINT32 nBytes = nDigits * SYMCRYPT_FDEF_DIGIT_SIZE;
1451
43
    PUINT32 pTmp = (PUINT32) pbScratch;
1452
1453
43
    SYMCRYPT_ASSERT_ASYM_ALIGNED( pTmp );
1454
1455
    //
1456
    // We have R*X; we first apply the montgomery reduction twice to get X/R, and then invert that
1457
    // using the generic inversion to get R/X.
1458
    //
1459
43
  SYMCRYPT_ASSERT( cbScratch >= 2 * nBytes );
1460
43
    memcpy( pTmp, &peSrc->d.uint32[0], nBytes );
1461
1462
43
    SymCryptWipe( (PBYTE)pTmp + nBytes, nBytes );
1463
43
    SymCryptFdefMontgomeryReduce( pmMod, pTmp, pTmp );
1464
1465
43
    SymCryptWipe( (PBYTE)pTmp + nBytes, nBytes );
1466
43
    SymCryptFdefMontgomeryReduce( pmMod, pTmp, &peDst->d.uint32[0] );
1467
1468
43
    scError = SymCryptFdefModInvGeneric( pmMod, peDst, peDst, flags, pbScratch, cbScratch );
1469
1470
43
    return scError;
1471
43
}
1472
1473
#if SYMCRYPT_CPU_AMD64
1474
1475
//=====================================
1476
// 256-bit Montgomery modulus code
1477
//
1478
1479
SYMCRYPT_ERROR
1480
SYMCRYPT_CALL
1481
SymCryptFdefModInvMontgomery256(
1482
    _In_                            PCSYMCRYPT_MODULUS      pmMod,
1483
    _In_                            PCSYMCRYPT_MODELEMENT   peSrc,
1484
    _Out_                           PSYMCRYPT_MODELEMENT    peDst,
1485
                                    UINT32                  flags,
1486
    _Out_writes_bytes_( cbScratch ) PBYTE                   pbScratch,
1487
                                    SIZE_T                  cbScratch )
1488
0
{
1489
0
    SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
1490
0
    UINT32 nBytes = 32;
1491
0
    PUINT32 pTmp = (PUINT32) pbScratch;
1492
1493
0
    SYMCRYPT_ASSERT_ASYM_ALIGNED( pTmp );
1494
1495
    //
1496
    // We have R*X; we first apply the montgomery reduction twice to get X/R, and then invert that
1497
    // using the generic inversion to get R/X.
1498
    //
1499
0
    SYMCRYPT_ASSERT( cbScratch >= 2 * nBytes );
1500
0
    memcpy( pTmp, &peSrc->d.uint32[0], nBytes );
1501
1502
0
    SymCryptWipe( (PBYTE)pTmp + nBytes, nBytes );
1503
0
    SymCryptFdefMontgomeryReduce256Asm( pmMod, pTmp, pTmp );
1504
1505
0
    SymCryptWipe( (PBYTE)pTmp + nBytes, nBytes );
1506
0
    SymCryptFdefMontgomeryReduce256Asm( pmMod, pTmp, &peDst->d.uint32[0] );
1507
1508
0
    scError = SymCryptFdefModInvGeneric( pmMod, peDst, peDst, flags, pbScratch, cbScratch );
1509
1510
0
    return scError;
1511
0
}
1512
1513
VOID
1514
SYMCRYPT_CALL
1515
SymCryptFdefModSetPostMontgomeryMulx256(
1516
    _In_                            PCSYMCRYPT_MODULUS      pmMod,
1517
    _Inout_                         PSYMCRYPT_MODELEMENT    peObj,
1518
    _Out_writes_bytes_( cbScratch ) PBYTE                   pbScratch,
1519
                                    SIZE_T                  cbScratch )
1520
0
{
1521
    // Montgomery representation for X is R*X mod M where R = 2^<nDigits * bits-per-digit>
1522
    // Montgomery reduction performs an implicit division by R
1523
    // This function converts to the internal representation by multiplying by R^2 mod M and then performing a Montgomery reduction
1524
0
    UINT32 nDigits = pmMod->nDigits;
1525
1526
0
    SYMCRYPT_ASSERT( cbScratch >= nDigits * 2 * SYMCRYPT_FDEF_DIGIT_SIZE );
1527
0
    UNREFERENCED_PARAMETER( pbScratch );
1528
0
    UNREFERENCED_PARAMETER( cbScratch );
1529
0
    UNREFERENCED_PARAMETER( nDigits );
1530
1531
0
    SymCryptFdefModMulMontgomeryMulx256Asm( pmMod, (PSYMCRYPT_MODELEMENT) pmMod->tm.montgomery.Rsqr, peObj, peObj );
1532
0
}
1533
1534
PCUINT32
1535
SYMCRYPT_CALL
1536
SymCryptFdefModPreGetMontgomery256(
1537
    _In_                            PCSYMCRYPT_MODULUS      pmMod,
1538
    _In_                            PCSYMCRYPT_MODELEMENT   peObj,
1539
    _Out_writes_bytes_( cbScratch ) PBYTE                   pbScratch,
1540
                                    SIZE_T                  cbScratch )
1541
0
{
1542
0
    PUINT32 pTmp = (PUINT32) pbScratch;
1543
0
    UINT32 nDigits = 1;
1544
1545
0
    SYMCRYPT_ASSERT( cbScratch >= nDigits * SYMCRYPT_FDEF_DIGIT_SIZE );
1546
0
    UNREFERENCED_PARAMETER( cbScratch );
1547
1548
0
    memcpy( pTmp, &peObj->d.uint32[0], nDigits * SYMCRYPT_FDEF_DIGIT_SIZE );
1549
0
    SymCryptFdefMontgomeryReduce256Asm( pmMod, pTmp, pTmp );
1550
1551
    // This gives the right result, but relies on peObj having zeroed upper half
1552
    // on AMD64 when digits are 512 bits. This should be true - check in a CHKed build.
1553
0
    for( UINT32 i=8; i<16; ++i )
1554
0
    {
1555
0
        SYMCRYPT_ASSERT( pTmp[i] == 0 );
1556
0
    }
1557
1558
    // Wipe the extra bytes
1559
    // SymCryptWipeKnownSize( pTmp + (SYMCRYPT_FDEF_DIGIT_NUINT32 / 2), 32 );
1560
1561
0
    return pTmp;
1562
0
}
1563
1564
VOID
1565
SYMCRYPT_CALL
1566
SymCryptFdefModulusInitMontgomery256(
1567
    _Inout_                         PSYMCRYPT_MODULUS       pmMod,
1568
    _Out_writes_bytes_( cbScratch ) PBYTE                   pbScratch,
1569
                                    SIZE_T                  cbScratch )
1570
0
{
1571
0
    SymCryptFdefModulusInitMontgomeryInternal( pmMod, 8, pbScratch, cbScratch );
1572
0
}
1573
1574
//=====================================
1575
// 384-bit Montgomery modulus code
1576
//
1577
1578
VOID
1579
SYMCRYPT_CALL
1580
SymCryptFdefModSetPostMontgomeryMulxP384(
1581
    _In_                            PCSYMCRYPT_MODULUS      pmMod,
1582
    _Inout_                         PSYMCRYPT_MODELEMENT    peObj,
1583
    _Out_writes_bytes_( cbScratch ) PBYTE                   pbScratch,
1584
                                    SIZE_T                  cbScratch )
1585
0
{
1586
    // Montgomery representation for X is R*X mod M where R = 2^<nDigits * bits-per-digit>
1587
    // Montgomery reduction performs an implicit division by R
1588
    // This function converts to the internal representation by multiplying by R^2 mod M and then performing a Montgomery reduction
1589
0
    UINT32 nDigits = pmMod->nDigits;
1590
1591
0
    SYMCRYPT_ASSERT( cbScratch >= nDigits * 2 * SYMCRYPT_FDEF_DIGIT_SIZE );
1592
0
    UNREFERENCED_PARAMETER( pbScratch );
1593
0
    UNREFERENCED_PARAMETER( cbScratch );
1594
0
    UNREFERENCED_PARAMETER( nDigits );
1595
1596
0
    SymCryptFdefModMulMontgomeryMulxP384Asm( pmMod, (PSYMCRYPT_MODELEMENT) pmMod->tm.montgomery.Rsqr, peObj, peObj );
1597
0
}
1598
1599
#if 0
1600
//=====================================
1601
// 512-bit Montgomery modulus code
1602
//
1603
1604
VOID
1605
SYMCRYPT_CALL
1606
SymCryptFdefModMulMontgomery512(
1607
    _In_                            PCSYMCRYPT_MODULUS      pmMod,
1608
    _In_                            PCSYMCRYPT_MODELEMENT   peSrc1,
1609
    _In_                            PCSYMCRYPT_MODELEMENT   peSrc2,
1610
    _Out_                           PSYMCRYPT_MODELEMENT    peDst,
1611
    _Out_writes_bytes_( cbScratch ) PBYTE                   pbScratch,
1612
                                    SIZE_T                  cbScratch )
1613
{
1614
    UINT32 nDigits = pmMod->nDigits;
1615
    PUINT32 pTmp = (PUINT32) pbScratch;
1616
1617
    SYMCRYPT_ASSERT( cbScratch >= nDigits * 2 * SYMCRYPT_FDEF_DIGIT_SIZE );
1618
    UNREFERENCED_PARAMETER( cbScratch );
1619
1620
    SymCryptFdefRawMul512Asm( &peSrc1->d.uint32[0], &peSrc2->d.uint32[0], nDigits, pTmp );
1621
    SymCryptFdefMontgomeryReduce512Asm( pmMod, pTmp, &peDst->d.uint32[0] );
1622
}
1623
1624
VOID
1625
SYMCRYPT_CALL
1626
SymCryptFdefModSquareMontgomery512(
1627
    _In_                            PCSYMCRYPT_MODULUS      pmMod,
1628
    _In_                            PCSYMCRYPT_MODELEMENT   peSrc,
1629
    _Out_                           PSYMCRYPT_MODELEMENT    peDst,
1630
    _Out_writes_bytes_( cbScratch ) PBYTE                   pbScratch,
1631
                                    SIZE_T                  cbScratch )
1632
{
1633
    UINT32 nDigits = pmMod->nDigits;
1634
    PUINT32 pTmp = (PUINT32) pbScratch;
1635
1636
    SYMCRYPT_ASSERT( cbScratch >= nDigits * 2 * SYMCRYPT_FDEF_DIGIT_SIZE );
1637
    UNREFERENCED_PARAMETER( cbScratch );
1638
1639
    SymCryptFdefRawSquare512Asm( &peSrc->d.uint32[0], nDigits, pTmp );
1640
    SymCryptFdefMontgomeryReduce512Asm( pmMod, pTmp, &peDst->d.uint32[0] );
1641
}
1642
1643
//=====================================
1644
// 1024-bit Montgomery modulus code
1645
//
1646
1647
VOID
1648
SYMCRYPT_CALL
1649
SymCryptFdefModMulMontgomery1024(
1650
    _In_                            PCSYMCRYPT_MODULUS      pmMod,
1651
    _In_                            PCSYMCRYPT_MODELEMENT   peSrc1,
1652
    _In_                            PCSYMCRYPT_MODELEMENT   peSrc2,
1653
    _Out_                           PSYMCRYPT_MODELEMENT    peDst,
1654
    _Out_writes_bytes_( cbScratch ) PBYTE                   pbScratch,
1655
                                    SIZE_T                  cbScratch )
1656
{
1657
    UINT32 nDigits = pmMod->nDigits;
1658
    PUINT32 pTmp = (PUINT32) pbScratch;
1659
1660
    SYMCRYPT_ASSERT( cbScratch >= nDigits * 2 * SYMCRYPT_FDEF_DIGIT_SIZE );
1661
    UNREFERENCED_PARAMETER( cbScratch );
1662
1663
    SymCryptFdefRawMul1024Asm( &peSrc1->d.uint32[0], &peSrc2->d.uint32[0], nDigits, pTmp );
1664
    SymCryptFdefMontgomeryReduce1024Asm( pmMod, pTmp, &peDst->d.uint32[0] );
1665
}
1666
1667
VOID
1668
SYMCRYPT_CALL
1669
SymCryptFdefModSquareMontgomery1024(
1670
    _In_                            PCSYMCRYPT_MODULUS      pmMod,
1671
    _In_                            PCSYMCRYPT_MODELEMENT   peSrc,
1672
    _Out_                           PSYMCRYPT_MODELEMENT    peDst,
1673
    _Out_writes_bytes_( cbScratch ) PBYTE                   pbScratch,
1674
                                    SIZE_T                  cbScratch )
1675
{
1676
    UINT32 nDigits = pmMod->nDigits;
1677
    PUINT32 pTmp = (PUINT32) pbScratch;
1678
1679
    SYMCRYPT_ASSERT( cbScratch >= nDigits * 2 * SYMCRYPT_FDEF_DIGIT_SIZE );
1680
    UNREFERENCED_PARAMETER( cbScratch );
1681
1682
    SymCryptFdefRawSquare1024Asm( &peSrc->d.uint32[0], nDigits, pTmp );
1683
    SymCryptFdefMontgomeryReduce1024Asm( pmMod, pTmp, &peDst->d.uint32[0] );
1684
}
1685
#endif
1686
1687
#endif