Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/libs/symcrypt/lib/fdef_mod.c
15010 views
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
{
13
PVOID p = NULL;
14
UINT32 cb;
15
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
cb = SymCryptFdefSizeofModulusFromDigits( nDigits );
22
23
if( cb != 0 )
24
{
25
p = SymCryptCallbackAlloc( cb );
26
}
27
28
if( p == NULL )
29
{
30
goto cleanup;
31
}
32
33
res = SymCryptFdefModulusCreate( p, cb, nDigits );
34
35
cleanup:
36
return res;
37
}
38
39
VOID
40
SYMCRYPT_CALL
41
SymCryptFdefModulusFree( _Out_ PSYMCRYPT_MODULUS pmObj )
42
{
43
SymCryptModulusWipe( pmObj );
44
SymCryptCallbackFree( pmObj );
45
}
46
47
UINT32
48
SYMCRYPT_CALL
49
SymCryptFdefSizeofModulusFromDigits( UINT32 nDigits )
50
{
51
SYMCRYPT_ASSERT( nDigits != 0 );
52
SYMCRYPT_ASSERT( nDigits <= SYMCRYPT_FDEF_UPB_DIGITS );
53
54
// Ensure we do not overflow the following calculation when provided with invalid inputs
55
if( nDigits == 0 || nDigits > SYMCRYPT_FDEF_UPB_DIGITS )
56
{
57
return 0;
58
}
59
60
// Room for the Modulus structure, the Divisor, the negated divisor, and the R^2 Montgomery factor
61
//
62
return SYMCRYPT_FIELD_OFFSET( SYMCRYPT_MODULUS, Divisor ) + SymCryptFdefSizeofDivisorFromDigits( nDigits ) + (2 * nDigits * SYMCRYPT_FDEF_DIGIT_SIZE);
63
}
64
65
PSYMCRYPT_MODULUS
66
SYMCRYPT_CALL
67
SymCryptFdefModulusCreate(
68
_Out_writes_bytes_( cbBuffer ) PBYTE pbBuffer,
69
SIZE_T cbBuffer,
70
UINT32 nDigits )
71
{
72
PSYMCRYPT_MODULUS pmMod = NULL;
73
UINT32 cb = SymCryptFdefSizeofModulusFromDigits( nDigits );
74
75
const UINT32 offset = SYMCRYPT_FIELD_OFFSET( SYMCRYPT_MODULUS, Divisor );
76
77
SYMCRYPT_ASSERT( cb >= sizeof(SYMCRYPT_MODULUS) );
78
SYMCRYPT_ASSERT( cbBuffer >= cb );
79
if( (cb == 0) || (cbBuffer < cb) )
80
{
81
goto cleanup; // return NULL
82
}
83
84
SYMCRYPT_ASSERT_ASYM_ALIGNED( pbBuffer );
85
pmMod = (PSYMCRYPT_MODULUS) pbBuffer;
86
87
pmMod->type = 'gM' << 16;
88
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
pmMod->cbSize = cb;
95
pmMod->flags = 0;
96
97
// The following is bounded by 2^17
98
pmMod->cbModElement = nDigits * SYMCRYPT_FDEF_DIGIT_SIZE;
99
100
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
SYMCRYPT_SET_MAGIC( pmMod );
105
106
cleanup:
107
return pmMod;
108
}
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
{
117
UNREFERENCED_PARAMETER( pmMod );
118
UNREFERENCED_PARAMETER( pbScratch );
119
UNREFERENCED_PARAMETER( cbScratch );
120
}
121
122
123
VOID
124
SymCryptFdefModulusCopy(
125
_In_ PCSYMCRYPT_MODULUS pmSrc,
126
_Out_ PSYMCRYPT_MODULUS pmDst )
127
{
128
SYMCRYPT_ASSERT( pmSrc->nDigits == pmDst->nDigits );
129
130
if( pmSrc != pmDst )
131
{
132
memcpy( pmDst, pmSrc, pmDst->cbSize );
133
134
SymCryptFdefDivisorCopyFixup( &pmSrc->Divisor, &pmDst->Divisor );
135
136
// Copy the type-specific fields
137
SYMCRYPT_MOD_CALL( pmSrc ) modulusCopyFixup( pmSrc, pmDst );
138
139
SYMCRYPT_SET_MAGIC( pmDst );
140
}
141
}
142
143
VOID
144
SYMCRYPT_CALL
145
SymCryptFdefModulusCopyFixupGeneric(
146
_In_ PCSYMCRYPT_MODULUS pmSrc,
147
_Out_ PSYMCRYPT_MODULUS pmDst )
148
{
149
// Only have to handle the type-specific fields, which we don't have any of.
150
UNREFERENCED_PARAMETER( pmSrc );
151
UNREFERENCED_PARAMETER( pmDst );
152
}
153
154
155
PSYMCRYPT_MODELEMENT
156
SYMCRYPT_CALL
157
SymCryptFdefModElementAllocate( _In_ PCSYMCRYPT_MODULUS pmMod )
158
{
159
PVOID p;
160
UINT32 cb;
161
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
cb = SymCryptFdefSizeofModElementFromModulus( pmMod );
168
169
p = SymCryptCallbackAlloc( cb );
170
171
if( p == NULL )
172
{
173
goto cleanup;
174
}
175
176
res = SymCryptFdefModElementCreate( p, cb, pmMod );
177
178
cleanup:
179
return res;
180
}
181
182
VOID
183
SYMCRYPT_CALL
184
SymCryptFdefModElementFree(
185
_In_ PCSYMCRYPT_MODULUS pmMod,
186
_Out_ PSYMCRYPT_MODELEMENT peObj )
187
{
188
SymCryptFdefModElementWipe( pmMod, peObj );
189
SymCryptCallbackFree( peObj );
190
}
191
192
UINT32
193
SYMCRYPT_CALL
194
SymCryptFdefSizeofModElementFromModulus( PCSYMCRYPT_MODULUS pmMod )
195
{
196
// Upper bounded by 2^17 since the modulus is up to SYMCRYPT_INT_MAXBITS = 2^20 bits.
197
return pmMod->cbModElement;
198
}
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
{
207
PSYMCRYPT_MODELEMENT pDst = (PSYMCRYPT_MODELEMENT) pbBuffer;
208
209
UNREFERENCED_PARAMETER( pmMod );
210
UNREFERENCED_PARAMETER( cbBuffer );
211
212
SYMCRYPT_ASSERT_ASYM_ALIGNED( pbBuffer );
213
SYMCRYPT_ASSERT( cbBuffer >= SymCryptFdefSizeofModElementFromModulus( pmMod ) );
214
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
#if (SYMCRYPT_CPU_AMD64 | SYMCRYPT_CPU_ARM64)
221
UINT32 nDigits = pmMod->nDigits;
222
223
SymCryptWipeKnownSize( pbBuffer + (nDigits-1) * SYMCRYPT_FDEF_DIGIT_SIZE, SYMCRYPT_FDEF_DIGIT_SIZE );
224
#endif
225
226
// There is nothing to initialize...
227
228
return pDst;
229
}
230
231
VOID
232
SYMCRYPT_CALL
233
SymCryptFdefModElementWipe(
234
_In_ PCSYMCRYPT_MODULUS pmMod,
235
_Out_ PSYMCRYPT_MODELEMENT peDst )
236
{
237
SymCryptWipe( peDst, pmMod->cbModElement );
238
}
239
240
VOID
241
SymCryptFdefModElementCopy(
242
_In_ PCSYMCRYPT_MODULUS pmMod,
243
_In_ PCSYMCRYPT_MODELEMENT peSrc,
244
_Out_ PSYMCRYPT_MODELEMENT peDst )
245
{
246
if( peSrc != peDst )
247
{
248
memcpy( peDst, peSrc, pmMod->cbModElement );
249
}
250
}
251
252
VOID
253
SymCryptFdefModElementMaskedCopy(
254
_In_ PCSYMCRYPT_MODULUS pmMod,
255
_In_ PCSYMCRYPT_MODELEMENT peSrc,
256
_Out_ PSYMCRYPT_MODELEMENT peDst,
257
UINT32 mask )
258
{
259
SymCryptFdefMaskedCopy( (PCBYTE) peSrc, (PBYTE) peDst, pmMod->nDigits, mask );
260
}
261
262
263
PSYMCRYPT_DIVISOR
264
SYMCRYPT_CALL
265
SymCryptFdefDivisorFromModulus( _In_ PSYMCRYPT_MODULUS pmSrc )
266
{
267
return &pmSrc->Divisor;
268
}
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
{
277
SymCryptFdefConditionalSwap( (PBYTE) &peData1->d.uint32[0], (PBYTE) &peData2->d.uint32[0], pmMod->nDigits, cond );
278
}
279
280
PSYMCRYPT_INT
281
SYMCRYPT_CALL
282
SymCryptFdefIntFromModulus( _In_ PSYMCRYPT_MODULUS pmSrc )
283
{
284
285
return SymCryptFdefIntFromDivisor( &pmSrc->Divisor );
286
}
287
288
UINT32
289
SYMCRYPT_CALL
290
SymCryptFdefDecideModulusType( PCSYMCRYPT_INT piSrc, UINT32 nDigits, UINT32 averageOperations, UINT32 flags )
291
{
292
UINT32 res = 0;
293
BOOLEAN disableMontgomery = 0;
294
BYTE tempBuf[64];
295
PCSYMCRYPT_MODULUS_TYPE_SELECTION_ENTRY pEntry;
296
297
UINT32 nBitsizeOfValue = SymCryptIntBitsizeOfValue( piSrc );
298
UINT32 modulusFeatures = 0;
299
300
if( !disableMontgomery &&
301
( flags & (SYMCRYPT_FLAG_DATA_PUBLIC | SYMCRYPT_FLAG_MODULUS_PARITY_PUBLIC)) != 0 &&
302
(SymCryptIntGetValueLsbits32( piSrc ) & 1) == 1 &&
303
averageOperations >= 10 )
304
{
305
modulusFeatures |= SYMCRYPT_MODULUS_FEATURE_MONTGOMERY;
306
307
// Specific modulus value detection
308
if( (flags & SYMCRYPT_FLAG_DATA_PUBLIC) != 0 )
309
{
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
if( nBitsizeOfValue == 384 &&
312
SymCryptFdefRawGetValue(SYMCRYPT_FDEF_INT_PUINT32(piSrc), SYMCRYPT_FDEF_DIGITS_FROM_BITS(384), tempBuf, 64, SYMCRYPT_NUMBER_FORMAT_MSB_FIRST) == SYMCRYPT_NO_ERROR )
313
{
314
// First 16 bytes are guaranteed to be zero because nBitsizeOfValue is 384
315
if( memcmp(tempBuf+16, ((PBYTE)SymCryptEcurveParamsNistP384) + sizeof(SYMCRYPT_ECURVE_PARAMS), 48) == 0 )
316
{
317
modulusFeatures |= SYMCRYPT_MODULUS_FEATURE_NISTP384;
318
}
319
}
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
}
332
}
333
334
pEntry = SymCryptModulusTypeSelections;
335
336
for(;;)
337
{
338
if( SYMCRYPT_CPU_FEATURES_PRESENT( pEntry->cpuFeatures ) &&
339
(pEntry->maxBits == 0 || (nDigits <= SymCryptDigitsFromBits( pEntry->maxBits ) && nBitsizeOfValue <= pEntry->maxBits )) &&
340
(pEntry->modulusFeatures & ~modulusFeatures) == 0
341
)
342
{
343
res = pEntry->type;
344
break;
345
}
346
pEntry++;
347
}
348
349
return res;
350
}
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
{
360
UNREFERENCED_PARAMETER( pmMod );
361
UNREFERENCED_PARAMETER( peObj );
362
UNREFERENCED_PARAMETER( pbScratch );
363
UNREFERENCED_PARAMETER( cbScratch );
364
}
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
{
374
UNREFERENCED_PARAMETER( pmMod );
375
UNREFERENCED_PARAMETER( pbScratch );
376
UNREFERENCED_PARAMETER( cbScratch );
377
378
return &peObj->d.uint32[0];
379
}
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
{
393
pmDst->flags = flags;
394
SymCryptIntToDivisor( piSrc, &pmDst->Divisor, averageOperations, flags & SYMCRYPT_FLAG_DATA_PUBLIC, pbScratch, cbScratch );
395
396
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
pmDst->inv64 = 0 - SymCryptInverseMod2e64( SymCryptIntGetValueLsbits64(piSrc) );
401
402
SYMCRYPT_MOD_CALL( pmDst ) modulusInit( pmDst, pbScratch, cbScratch );
403
}
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
{
414
SymCryptFdefRawDivMod(
415
SYMCRYPT_FDEF_INT_PUINT32( piSrc ),
416
piSrc->nDigits,
417
&pmMod->Divisor,
418
NULL, // throw away the quotient
419
&peDst->d.uint32[0],
420
pbScratch,
421
cbScratch );
422
423
SYMCRYPT_MOD_CALL( pmMod ) modSetPost( pmMod, peDst, pbScratch, cbScratch );
424
}
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
{
436
memcpy( SYMCRYPT_FDEF_INT_PUINT32( piDst ), pSrc, pmMod->nDigits * SYMCRYPT_FDEF_DIGIT_SIZE );
437
438
SymCryptWipe( &SYMCRYPT_FDEF_INT_PUINT32( piDst )[pmMod->nDigits * SYMCRYPT_FDEF_DIGIT_NUINT32], (piDst->nDigits - pmMod->nDigits) * SYMCRYPT_FDEF_DIGIT_SIZE );
439
440
SymCryptFdefClaimScratch( pbScratch, cbScratch, SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( pmMod->nDigits ) );
441
}
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
{
454
SYMCRYPT_ERROR scError;
455
UINT32 nDigits = pmMod->nDigits;
456
457
SymCryptFdefClaimScratch( pbScratch, cbScratch, SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( nDigits ) );
458
459
SYMCRYPT_ASSERT( cbSrc <= nDigits * SYMCRYPT_FDEF_DIGIT_SIZE );
460
461
scError = SymCryptFdefRawSetValue( pbSrc, cbSrc, format, &peDst->d.uint32[0], nDigits );
462
if( scError != SYMCRYPT_NO_ERROR )
463
{
464
goto cleanup;
465
}
466
467
SymCryptFdefRawDivMod(
468
&peDst->d.uint32[0],
469
nDigits,
470
&pmMod->Divisor,
471
NULL,
472
&peDst->d.uint32[0],
473
pbScratch,
474
cbScratch );
475
476
scError = SYMCRYPT_NO_ERROR;
477
478
cleanup:
479
return scError;
480
}
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
{
493
SYMCRYPT_ERROR scError;
494
PCUINT32 pUint32;
495
UINT32 nDigits = pmMod->nDigits;
496
497
498
SymCryptFdefClaimScratch( pbScratch, cbScratch, SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( nDigits ) );
499
500
SYMCRYPT_ASSERT( cbDst <= nDigits * SYMCRYPT_FDEF_DIGIT_SIZE );
501
502
pUint32 = SYMCRYPT_MOD_CALL( pmMod ) modPreGet( pmMod, peSrc, pbScratch, cbScratch );
503
504
scError = SymCryptFdefRawGetValue( pUint32, nDigits, pbDst, cbDst, format );
505
506
return scError;
507
}
508
509
UINT32
510
SYMCRYPT_CALL
511
SymCryptFdefModElementIsEqual(
512
_In_ PCSYMCRYPT_MODULUS pmMod,
513
_In_ PCSYMCRYPT_MODELEMENT peSrc1,
514
_In_ PCSYMCRYPT_MODELEMENT peSrc2 )
515
{
516
UINT32 d;
517
UINT32 i;
518
519
d = 0;
520
for( i=0; i < pmMod->nDigits * SYMCRYPT_FDEF_DIGIT_NUINT32 ; i++ )
521
{
522
d |= peSrc1->d.uint32[i] ^ peSrc2->d.uint32[i];
523
}
524
525
return SYMCRYPT_MASK32_ZERO( d );
526
}
527
528
UINT32
529
SYMCRYPT_CALL
530
SymCryptFdefModElementIsZero(
531
_In_ PCSYMCRYPT_MODULUS pmMod,
532
_In_ PCSYMCRYPT_MODELEMENT peSrc )
533
{
534
UINT32 d;
535
UINT32 i;
536
537
d = 0;
538
for( i=0; i < pmMod->nDigits * SYMCRYPT_FDEF_DIGIT_NUINT32 ; i++ )
539
{
540
d |= peSrc->d.uint32[i]; // Check that all bits are zero
541
}
542
543
return SYMCRYPT_MASK32_ZERO( d );
544
}
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
{
556
UINT32 c;
557
UINT32 d;
558
UINT32 nDigits = pmMod->nDigits;
559
560
SymCryptFdefClaimScratch( pbScratch, cbScratch, SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( nDigits ) );
561
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
c = SymCryptFdefRawAdd( &peSrc1->d.uint32[0], &peSrc2->d.uint32[0], &peDst->d.uint32[0], nDigits );
575
d = SymCryptFdefRawSub( &peDst->d.uint32[0], SYMCRYPT_FDEF_INT_PUINT32( &pmMod->Divisor.Int ), (PUINT32) pbScratch, nDigits );
576
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
SYMCRYPT_ASSERT( !( c == 1 && d == 0 ) );
580
}
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
{
592
UINT32 c;
593
UINT32 d;
594
UINT32 nDigits = pmMod->nDigits;
595
596
SymCryptFdefClaimScratch( pbScratch, cbScratch, SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( nDigits ) );
597
SYMCRYPT_ASSERT( cbScratch >= nDigits*SYMCRYPT_FDEF_DIGIT_SIZE );
598
599
c = SymCryptFdefRawSub( &peSrc1->d.uint32[0], &peSrc2->d.uint32[0], &peDst->d.uint32[0], nDigits );
600
d = SymCryptFdefRawAdd( &peDst->d.uint32[0], SYMCRYPT_FDEF_INT_PUINT32( &pmMod->Divisor.Int ), (PUINT32) pbScratch, nDigits );
601
SymCryptFdefMaskedCopy( pbScratch, (PBYTE) &peDst->d.uint32[0], nDigits, 0 - c );
602
603
SYMCRYPT_ASSERT( !(c == 1 && d == 0) );
604
}
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
{
616
UINT32 nDigits = pmMod->nDigits;
617
UINT32 isZero;
618
UINT32 i;
619
620
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
isZero = SymCryptFdefRawIsEqualUint32( &peSrc->d.uint32[0], nDigits , 0 );
626
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
for( i=0; i< nDigits * SYMCRYPT_FDEF_DIGIT_NUINT32; i++ )
630
{
631
peDst->d.uint32[i] &= ~isZero;
632
}
633
}
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
{
644
UINT32 nDigits = pmMod->nDigits;
645
646
SymCryptFdefClaimScratch( pbScratch, cbScratch, SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( nDigits ) );
647
648
if( pmMod->Divisor.nBits <= 32 && value >= SYMCRYPT_FDEF_INT_PUINT32( &pmMod->Divisor.Int )[0] )
649
{
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
value %= SYMCRYPT_FDEF_INT_PUINT32( &pmMod->Divisor.Int )[0];
654
}
655
656
peDst->d.uint32[0] = value;
657
658
SymCryptWipe( &peDst->d.uint32[1], nDigits * SYMCRYPT_FDEF_DIGIT_SIZE - sizeof( UINT32 ) );
659
}
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
{
670
UINT32 nDigits = pmMod->nDigits;
671
672
SymCryptFdefClaimScratch( pbScratch, cbScratch, SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( nDigits ) );
673
674
if( pmMod->Divisor.nBits <= 32 && value >= SYMCRYPT_FDEF_INT_PUINT32( &pmMod->Divisor.Int )[0] )
675
{
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
value %= SYMCRYPT_FDEF_INT_PUINT32( &pmMod->Divisor.Int )[0];
680
}
681
682
if( value == 0 )
683
{
684
SymCryptWipe( &peDst->d.uint32[0], nDigits * SYMCRYPT_FDEF_DIGIT_SIZE );
685
} else {
686
SymCryptFdefRawSubUint32( SYMCRYPT_FDEF_INT_PUINT32( &pmMod->Divisor.Int ), value, &peDst->d.uint32[0], nDigits );
687
}
688
689
//
690
// Possible future optimization: we can optimize the value==0 and value==1 cases on a per-type basis
691
//
692
SYMCRYPT_MOD_CALL( pmMod ) modSetPost( pmMod, peDst, pbScratch, cbScratch );
693
}
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
#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
{
710
UINT32 offset;
711
UINT32 ulimit;
712
UINT32 nDigits = pmMod->nDigits;
713
PUINT32 pTmp = (PUINT32) pbScratch;
714
UINT32 nUsedBytes;
715
UINT32 mask;
716
UINT32 c;
717
UINT32 cntr;
718
PUINT32 pDst = &peDst->d.uint32[0];
719
PCUINT32 pMod = SYMCRYPT_FDEF_INT_PUINT32( &pmMod->Divisor.Int );
720
721
SymCryptFdefClaimScratch( pbScratch, cbScratch, SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( nDigits ) );
722
723
if( (flags & SYMCRYPT_FLAG_MODRANDOM_ALLOW_ZERO) != 0 )
724
{
725
// SYMCRYPT_FLAG_MODRANDOM_ALLOW_ZERO => SYMCRYPT_FLAG_MODRANDOM_ALLOW_ONE
726
offset = 0;
727
} else if( (flags & SYMCRYPT_FLAG_MODRANDOM_ALLOW_ONE) != 0 )
728
{
729
offset = 1;
730
} else
731
{
732
offset = 2;
733
}
734
735
if( (flags & SYMCRYPT_FLAG_MODRANDOM_ALLOW_MINUSONE ) )
736
{
737
ulimit = 0;
738
} else {
739
ulimit = 1;
740
}
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
if ( pmMod->Divisor.nBits < 3 )
747
{
748
// At a minimum, allow -1
749
offset = SYMCRYPT_MIN(offset, pMod[0] - 1);
750
ulimit = 0;
751
}
752
753
// Set pTmp to pMod-(offset+ulimit)
754
SYMCRYPT_ASSERT( nDigits * SYMCRYPT_FDEF_DIGIT_SIZE <= cbScratch );
755
c = SymCryptFdefRawSubUint32( pMod, offset + ulimit, pTmp, nDigits );
756
SYMCRYPT_ASSERT( c == 0 );
757
758
nUsedBytes = (pmMod->Divisor.nBits + 7)/8;
759
mask = 0x100 >> ( (8-pmMod->Divisor.nBits) & 7);
760
mask -= 1;
761
762
// Wipe any bytes we won't fill with random
763
SymCryptWipe( (PBYTE)pDst + nUsedBytes, (nDigits * SYMCRYPT_FDEF_DIGIT_SIZE) - nUsedBytes );
764
765
for(cntr=0; cntr<FDEF_MOD_SET_RANDOM_GENERIC_LIMIT; cntr++)
766
{
767
// Try random values until we get one we like
768
SymCryptCallbackRandom( (PBYTE)pDst, nUsedBytes );
769
((PBYTE)pDst)[nUsedBytes-1] &= (BYTE) mask;
770
771
// Compare value to pMod-(offset+ulimit)
772
if( SymCryptFdefRawIsLessThan( pDst, pTmp, nDigits ) )
773
{
774
// The value is within required range [0, Divisor-offset-ulimit)
775
break;
776
}
777
}
778
779
// Wipe all the digits in pTmp
780
SymCryptWipe( pTmp, nDigits * SYMCRYPT_FDEF_DIGIT_SIZE );
781
782
if (cntr >= FDEF_MOD_SET_RANDOM_GENERIC_LIMIT)
783
{
784
SymCryptFatal( 'rndc');
785
}
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
c = SymCryptFdefRawAddUint32( pDst, offset, pDst, nDigits );
790
SYMCRYPT_ASSERT( c == 0 );
791
}
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
{
801
UINT32 nDigits = pmMod->nDigits;
802
UINT32 mask;
803
UINT64 t;
804
UINT64 u;
805
UINT32 i;
806
PCUINT32 pMod = SYMCRYPT_FDEF_INT_PUINT32( &pmMod->Divisor.Int );
807
808
// mod must be odd
809
SYMCRYPT_ASSERT( (pMod[0] & 1) != 0 );
810
SYMCRYPT_ASSERT( (exp >= 1) && (exp <= NATIVE_BITS) );
811
812
do
813
{
814
mask = (UINT32)0 - (peSrc->d.uint32[0] & 1);
815
816
t = (UINT64) peSrc->d.uint32[0] + (pMod[0] & mask);
817
u = (UINT32) t;
818
t >>= 32;
819
820
for( i = 1; i < nDigits * SYMCRYPT_FDEF_DIGIT_NUINT32; i++ )
821
{
822
t += pMod[i] & mask;
823
t += peSrc->d.uint32[i];
824
825
u |= t << 32;
826
827
peDst->d.uint32[i-1] = (UINT32)(u >> 1);
828
t >>= 32;
829
u >>= 32;
830
}
831
u |= t << 32;
832
peDst->d.uint32[i-1] = (UINT32)( u >> 1 );
833
834
exp -= 1;
835
836
// First iteration reads from peSrc and writes to peDst
837
// subsequent iterations must read from and write to peDst
838
peSrc = peDst;
839
} while (exp > 0);
840
}
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
{
850
851
#if SYMCRYPT_CPU_AMD64
852
if( SYMCRYPT_CPU_FEATURES_PRESENT( SYMCRYPT_CPU_FEATURES_FOR_MULX ) )
853
{
854
SymCryptFdefModDivSmallPow2Mulx( pmMod, peSrc, exp, peDst );
855
}
856
else
857
{
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
SymCryptFdefModDivSmallPow2Generic( pmMod, peSrc, exp, peDst );
862
}
863
#elif SYMCRYPT_CPU_ARM64
864
SymCryptFdefModDivSmallPow2Asm( pmMod, peSrc, exp, peDst );
865
#else
866
SymCryptFdefModDivSmallPow2Generic( pmMod, peSrc, exp, peDst );
867
#endif
868
}
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
{
880
UINT32 shiftAmount;
881
882
UNREFERENCED_PARAMETER(pbScratch);
883
UNREFERENCED_PARAMETER(cbScratch);
884
885
// mod must be odd
886
SYMCRYPT_ASSERT( (SYMCRYPT_FDEF_INT_PUINT32(&pmMod->Divisor.Int)[0] & 1) != 0 );
887
888
if( exp == 0 )
889
{
890
// If exp is 0 we just need to copy peSrc to peDst
891
SymCryptFdefModElementCopy( pmMod, peSrc, peDst );
892
return;
893
}
894
895
do
896
{
897
shiftAmount = SYMCRYPT_MIN(NATIVE_BITS, exp);
898
SymCryptFdefModDivSmallPow2( pmMod, peSrc, shiftAmount, peDst );
899
exp -= shiftAmount;
900
901
// First iteration reads from peSrc and writes to peDst
902
// subsequent iterations must read from and write to peDst
903
peSrc = peDst;
904
} while( exp > 0 );
905
}
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
{
917
UINT32 nDigits = pmMod->nDigits;
918
PUINT32 pTmp = (PUINT32) pbScratch;
919
UINT32 scratchOffset = 2 * nDigits * SYMCRYPT_FDEF_DIGIT_SIZE;
920
921
SymCryptFdefClaimScratch( pbScratch, cbScratch, SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( nDigits ) );
922
SYMCRYPT_ASSERT( cbScratch >= SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( nDigits ) );
923
SYMCRYPT_ASSERT( SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( nDigits ) >= scratchOffset + SYMCRYPT_FDEF_SCRATCH_BYTES_FOR_INT_DIVMOD( 2 * nDigits, nDigits ) );
924
SYMCRYPT_ASSERT_ASYM_ALIGNED( pbScratch );
925
926
// Tmp space is enough for the product plus the DivMod scratch
927
928
SymCryptFdefRawMul( &peSrc1->d.uint32[0], nDigits, &peSrc2->d.uint32[0], nDigits, pTmp );
929
930
SymCryptFdefRawDivMod( pTmp, 2*nDigits, &pmMod->Divisor, NULL, &peDst->d.uint32[0], pbScratch + scratchOffset, cbScratch - scratchOffset );
931
}
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
{
942
UINT32 nDigits = pmMod->nDigits;
943
PUINT32 pTmp = (PUINT32) pbScratch;
944
UINT32 scratchOffset = 2 * nDigits * SYMCRYPT_FDEF_DIGIT_SIZE;
945
946
SymCryptFdefClaimScratch( pbScratch, cbScratch, SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( nDigits ) );
947
SYMCRYPT_ASSERT( cbScratch >= SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( nDigits ) );
948
SYMCRYPT_ASSERT( SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( nDigits ) >= scratchOffset + SYMCRYPT_FDEF_SCRATCH_BYTES_FOR_INT_DIVMOD( 2 * nDigits, nDigits ) );
949
SYMCRYPT_ASSERT_ASYM_ALIGNED( pbScratch );
950
951
// Tmp space is enough for the product plus the DivMod scratch
952
953
SymCryptFdefRawSquare( &peSrc->d.uint32[0], nDigits, pTmp );
954
955
SymCryptFdefRawDivMod( pTmp, 2*nDigits, &pmMod->Divisor, NULL, &peDst->d.uint32[0], pbScratch + scratchOffset, cbScratch - scratchOffset );
956
}
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
{
968
SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
969
UINT32 nDigits = pmMod->nDigits;
970
UINT32 nBytes;
971
UINT32 c;
972
UINT32 leastSignificantUint32;
973
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
SYMCRYPT_ASSERT( cbScratch >= SYMCRYPT_SCRATCH_BYTES_FOR_MODINV( nDigits ) );
985
986
if( (pmMod->flags & (SYMCRYPT_FLAG_DATA_PUBLIC | SYMCRYPT_FLAG_MODULUS_PRIME )) != (SYMCRYPT_FLAG_DATA_PUBLIC | SYMCRYPT_FLAG_MODULUS_PRIME ) )
987
{
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
scError = SYMCRYPT_INVALID_ARGUMENT;
994
goto cleanup;
995
}
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
nBytes = SymCryptSizeofModElementFromModulus( pmMod );
1020
1021
SYMCRYPT_ASSERT( cbScratch >= 4*nBytes );
1022
PSYMCRYPT_MODELEMENT peR = SymCryptModElementCreate( pbScratch, nBytes, pmMod );
1023
pbScratch += nBytes;
1024
PSYMCRYPT_MODELEMENT peX = SymCryptModElementCreate( pbScratch, nBytes, pmMod );
1025
pbScratch += nBytes;
1026
PSYMCRYPT_MODELEMENT peVa = SymCryptModElementCreate( pbScratch, nBytes, pmMod );
1027
pbScratch += nBytes;
1028
PSYMCRYPT_MODELEMENT peVb = SymCryptModElementCreate( pbScratch, nBytes, pmMod );
1029
pbScratch += nBytes;
1030
cbScratch -= 4*nBytes;
1031
1032
PSYMCRYPT_MODELEMENT peVtmpPtr;
1033
1034
nBytes = SymCryptSizeofIntFromDigits( nDigits );
1035
SYMCRYPT_ASSERT( cbScratch >= 3 * nBytes );
1036
PSYMCRYPT_INT piA = SymCryptIntCreate( pbScratch, nBytes, nDigits );
1037
pbScratch += nBytes;
1038
PSYMCRYPT_INT piB = SymCryptIntCreate( pbScratch, nBytes, nDigits );
1039
pbScratch += nBytes;
1040
PSYMCRYPT_INT piT = SymCryptIntCreate( pbScratch, nBytes, nDigits );
1041
pbScratch += nBytes;
1042
cbScratch -= 3*nBytes;
1043
1044
PSYMCRYPT_INT piTmpPtr;
1045
1046
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
if( (flags & SYMCRYPT_FLAG_DATA_PUBLIC) == 0 )
1050
{
1051
SymCryptModSetRandom( pmMod, peR, SYMCRYPT_FLAG_MODRANDOM_ALLOW_ONE | SYMCRYPT_FLAG_MODRANDOM_ALLOW_MINUSONE, pbScratch, cbScratch ); //R = random
1052
SymCryptModMul( pmMod, peR, peSrc, peX, pbScratch, cbScratch ); // X = R * Src
1053
} else
1054
{
1055
SymCryptModElementCopy( pmMod, peSrc, peX );
1056
}
1057
1058
// Set up piA and piB
1059
SymCryptFdefModElementToIntGeneric( pmMod, &peX->d.uint32[0], piA, pbScratch, cbScratch ); // A = X
1060
SymCryptIntCopy( SymCryptIntFromModulus( (PSYMCRYPT_MODULUS) pmMod ), piB ); // B = Mod
1061
1062
// Reject if A = 0, B = 0, or A and B both even
1063
if( SymCryptIntIsEqualUint32( piA, 0 ) |
1064
SymCryptIntIsEqualUint32( piB, 0 ) |
1065
(((SymCryptIntGetValueLsbits32( piA ) | SymCryptIntGetValueLsbits32( piB )) & 1) ^ 1) )
1066
{
1067
scError = SYMCRYPT_INVALID_ARGUMENT;
1068
goto cleanup;
1069
}
1070
1071
if( SymCryptIntIsEqualUint32( piB, 2 ) )
1072
{
1073
// Mod = 2 is a valid input. Luckily, modular inversion is easy.
1074
// The rest of the code assumes that Mod is odd. Other even values are not prime.
1075
SymCryptModElementCopy( pmMod, peSrc, peDst);
1076
goto cleanup;
1077
}
1078
1079
SymCryptFdefModElementSetValueUint32Generic( 1, pmMod, peVa, pbScratch, cbScratch ); // Va = 1
1080
SymCryptFdefModElementSetValueUint32Generic( 0, pmMod, peVb, pbScratch, cbScratch ); // Vb = 0
1081
1082
for(;;)
1083
{
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
leastSignificantUint32 = SymCryptIntGetValueLsbits32(piA);
1087
while( (leastSignificantUint32 & 1) == 0 )
1088
{
1089
trailingZeros = SymCryptCountTrailingZeros32( leastSignificantUint32 );
1090
SymCryptIntDivPow2( piA, trailingZeros, piA );
1091
SymCryptFdefModDivSmallPow2( pmMod, peVa, trailingZeros, peVa );
1092
leastSignificantUint32 = SymCryptIntGetValueLsbits32(piA);
1093
}
1094
1095
if( SymCryptIntIsEqualUint32( piA, 1 ) )
1096
{
1097
// A = 1 = Va * X (mod Mod), so Va is the inverse of X
1098
break;
1099
}
1100
1101
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
if( SymCryptIntIsEqualUint32( piT, 0 ) )
1105
{
1106
scError = SYMCRYPT_INVALID_ARGUMENT;
1107
goto cleanup;
1108
}
1109
1110
if( c == 0 )
1111
{
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
SymCryptIntCopy( piT, piB );
1116
SymCryptModSub( pmMod, peVb, peVa, peVb, pbScratch, cbScratch );
1117
1118
piTmpPtr = piB; piB = piA; piA = piTmpPtr;
1119
peVtmpPtr = peVb; peVb = peVa; peVa = peVtmpPtr;
1120
} else {
1121
// B < A, Set A to A-B and continue halving A
1122
SymCryptIntNeg( piT, piA );
1123
SymCryptModSub( pmMod, peVa, peVb, peVa, pbScratch, cbScratch );
1124
}
1125
}
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
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
if( (flags & SYMCRYPT_FLAG_DATA_PUBLIC) == 0 )
1135
{
1136
SymCryptModMul( pmMod, peVa, peR, peDst, pbScratch, cbScratch );
1137
} else
1138
{
1139
SymCryptModElementCopy( pmMod, peVa, peDst );
1140
}
1141
1142
cleanup:
1143
return scError;
1144
}
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
{
1158
// Scratch space is big enough for an nDigit+1 byte value + sufficient divmod scratch
1159
PUINT32 pR2;
1160
UINT32 cbR2;
1161
UINT32 nDigits;
1162
1163
PUINT32 modR2;
1164
PUINT32 negDivisor;
1165
1166
nDigits = pmMod->nDigits;
1167
modR2 = (PUINT32)((PBYTE)&pmMod->Divisor + SymCryptFdefSizeofDivisorFromDigits( nDigits ));
1168
1169
SYMCRYPT_ASSERT_ASYM_ALIGNED( pbScratch );
1170
1171
pmMod->tm.montgomery.Rsqr = modR2;
1172
negDivisor = (PUINT32)((PBYTE)modR2 + (nDigits * SYMCRYPT_FDEF_DIGIT_SIZE));
1173
1174
// We pre-compute R^2 mod M
1175
1176
pR2 = (PUINT32) pbScratch;
1177
cbR2 = (2*nDigits + 1) * SYMCRYPT_FDEF_DIGIT_SIZE;
1178
SYMCRYPT_ASSERT( cbScratch >= cbR2 );
1179
SYMCRYPT_ASSERT( cbScratch >= 2 * nUint32Used * sizeof(UINT32) );
1180
1181
// Set it to R^2
1182
SymCryptWipe( pR2, cbR2 );
1183
pR2[ 2 * nUint32Used ] = 1;
1184
SymCryptFdefRawDivMod( pR2, 2*nDigits + 1, &pmMod->Divisor, NULL, modR2, pbScratch + cbR2, cbScratch - cbR2 );
1185
1186
SymCryptFdefRawNeg( SYMCRYPT_FDEF_INT_PUINT32( &pmMod->Divisor.Int ), 0, negDivisor, nDigits );
1187
}
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
{
1196
SymCryptFdefModulusInitMontgomeryInternal( pmMod, pmMod->nDigits * SYMCRYPT_FDEF_DIGIT_NUINT32, pbScratch, cbScratch );
1197
}
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
{
1205
UINT32 nDigits = pmMod->nDigits;
1206
UINT32 nWords = nDigits * SYMCRYPT_FDEF_DIGIT_NUINT32;
1207
PCUINT32 pMod = SYMCRYPT_FDEF_INT_PUINT32( &pmMod->Divisor.Int );
1208
1209
UINT32 hc = 0;
1210
for( UINT32 i=0; i<nWords; i++ )
1211
{
1212
UINT32 m = (UINT32)pmMod->inv64 * pSrc[0];
1213
UINT64 c = 0;
1214
for( UINT32 j = 0; j < nWords; j++ )
1215
{
1216
// Invariant: c < 2^32
1217
c += SYMCRYPT_MUL32x32TO64( pMod[j], m );
1218
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
pSrc[j] = (UINT32) c;
1222
c >>= 32;
1223
}
1224
c = c + pSrc[nWords] + hc;
1225
pSrc[nWords] = (UINT32) c;
1226
hc = c >> 32;
1227
pSrc++;
1228
}
1229
SYMCRYPT_ASSERT( hc < 2 );
1230
1231
UINT32 d = SymCryptFdefRawSub( pSrc, pMod, pDst, nDigits );
1232
1233
SYMCRYPT_ASSERT( hc <= d ); // if hc = 1, then d = 1 is mandatory
1234
1235
SymCryptFdefMaskedCopy( (PCBYTE) pSrc, (PBYTE) pDst, nDigits, hc - (hc | d) ); // copy only if hc=0, d=1
1236
}
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
{
1244
#if SYMCRYPT_CPU_AMD64
1245
if( SYMCRYPT_CPU_FEATURES_PRESENT( SYMCRYPT_CPU_FEATURES_FOR_MULX ) )
1246
{
1247
SymCryptFdefMontgomeryReduceMulx( pmMod, pSrc, pDst );
1248
} else {
1249
SymCryptFdefMontgomeryReduceAsm( pmMod, pSrc, pDst );
1250
}
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
}
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
{
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
UINT32 nDigits = pmMod->nDigits;
1271
1272
// dcl - this should not incur significant cost, consider checking always
1273
SYMCRYPT_ASSERT( cbScratch >= nDigits * 2 * SYMCRYPT_FDEF_DIGIT_SIZE );
1274
UNREFERENCED_PARAMETER( cbScratch );
1275
1276
SymCryptFdefRawMul( &peObj->d.uint32[0], nDigits, pmMod->tm.montgomery.Rsqr, nDigits, (PUINT32) pbScratch );
1277
SymCryptFdefMontgomeryReduce( pmMod, (PUINT32) pbScratch, &peObj->d.uint32[0] );
1278
}
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
{
1288
PUINT32 pTmp = (PUINT32) pbScratch;
1289
UINT32 nDigits = pmMod->nDigits;
1290
1291
// dcl - this should not incur significant cost, consider checking always
1292
SYMCRYPT_ASSERT( cbScratch >= nDigits * 2 * SYMCRYPT_FDEF_DIGIT_SIZE );
1293
UNREFERENCED_PARAMETER( cbScratch );
1294
1295
memcpy( pTmp, &peObj->d.uint32[0], nDigits * SYMCRYPT_FDEF_DIGIT_SIZE );
1296
SymCryptWipe( pTmp + nDigits * SYMCRYPT_FDEF_DIGIT_NUINT32, nDigits * SYMCRYPT_FDEF_DIGIT_SIZE );
1297
SymCryptFdefMontgomeryReduce( pmMod, pTmp, pTmp );
1298
1299
return pTmp;
1300
}
1301
1302
VOID
1303
SYMCRYPT_CALL
1304
SymCryptFdefModulusCopyFixupMontgomery(
1305
_In_ PCSYMCRYPT_MODULUS pmSrc,
1306
_Out_ PSYMCRYPT_MODULUS pmDst )
1307
{
1308
// We only have to fix up the Montgomery-specific stuff here
1309
// dcl - not sure I understand why you pass pmSrc here
1310
UNREFERENCED_PARAMETER( pmSrc );
1311
pmDst->tm.montgomery.Rsqr = (PUINT32)((PBYTE)&pmDst->Divisor + SymCryptFdefSizeofDivisorFromDigits( pmDst->nDigits ));
1312
}
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
{
1324
UINT32 nDigits = pmMod->nDigits;
1325
PUINT32 pTmp = (PUINT32) pbScratch;
1326
1327
// dcl - missing assert?
1328
UNREFERENCED_PARAMETER( cbScratch );
1329
SYMCRYPT_ASSERT( cbScratch >= 2 * nDigits * SYMCRYPT_FDEF_DIGIT_SIZE );
1330
1331
SymCryptFdefRawMul( &peSrc1->d.uint32[0], nDigits, &peSrc2->d.uint32[0], nDigits, pTmp );
1332
SymCryptFdefMontgomeryReduce( pmMod, pTmp, &peDst->d.uint32[0] );
1333
}
1334
1335
#if 0 && 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
{
1346
UINT32 nDigits = pmMod->nDigits;
1347
PUINT32 pTmp = (PUINT32) pbScratch;
1348
1349
UNREFERENCED_PARAMETER( cbScratch );
1350
SYMCRYPT_ASSERT( cbScratch >= 2 * nDigits * SYMCRYPT_FDEF_DIGIT_SIZE );
1351
1352
SymCryptFdefRawMulMulx( &peSrc1->d.uint32[0], nDigits, &peSrc2->d.uint32[0], nDigits, pTmp );
1353
SymCryptFdefMontgomeryReduceMulx( pmMod, pTmp, &peDst->d.uint32[0] );
1354
}
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
{
1366
UINT32 nDigits = pmMod->nDigits;
1367
PUINT32 pTmp = (PUINT32) pbScratch;
1368
1369
UNREFERENCED_PARAMETER( cbScratch );
1370
SYMCRYPT_ASSERT( cbScratch >= 2 * nDigits * SYMCRYPT_FDEF_DIGIT_SIZE );
1371
1372
SymCryptFdefRawMulMulx1024( &peSrc1->d.uint32[0], &peSrc2->d.uint32[0], nDigits, pTmp );
1373
SymCryptFdefMontgomeryReduceMulx1024( pmMod, pTmp, &peDst->d.uint32[0] );
1374
}
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
{
1387
UINT32 nDigits = pmMod->nDigits;
1388
PUINT32 pTmp = (PUINT32) pbScratch;
1389
1390
UNREFERENCED_PARAMETER( cbScratch );
1391
SYMCRYPT_ASSERT( cbScratch >= 2 * nDigits * SYMCRYPT_FDEF_DIGIT_SIZE );
1392
1393
SymCryptFdefRawSquare( &peSrc->d.uint32[0], nDigits, pTmp );
1394
SymCryptFdefMontgomeryReduce( pmMod, pTmp, &peDst->d.uint32[0] );
1395
}
1396
1397
1398
#if 0 && 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
{
1408
UINT32 nDigits = pmMod->nDigits;
1409
PUINT32 pTmp = (PUINT32) pbScratch;
1410
1411
UNREFERENCED_PARAMETER( cbScratch );
1412
SYMCRYPT_ASSERT( cbScratch >= 2 * nDigits * SYMCRYPT_FDEF_DIGIT_SIZE );
1413
1414
SymCryptFdefRawSquareMulx( &peSrc->d.uint32[0], nDigits, pTmp );
1415
SymCryptFdefMontgomeryReduceMulx( pmMod, pTmp, &peDst->d.uint32[0] );
1416
}
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
{
1427
UINT32 nDigits = pmMod->nDigits;
1428
PUINT32 pTmp = (PUINT32) pbScratch;
1429
1430
UNREFERENCED_PARAMETER( cbScratch );
1431
SYMCRYPT_ASSERT( cbScratch >= 2 * nDigits * SYMCRYPT_FDEF_DIGIT_SIZE );
1432
1433
SymCryptFdefRawSquareMulx1024( &peSrc->d.uint32[0], nDigits, pTmp );
1434
SymCryptFdefMontgomeryReduceMulx1024( pmMod, pTmp, &peDst->d.uint32[0] );
1435
}
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
{
1448
SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
1449
UINT32 nDigits = pmMod->nDigits;
1450
UINT32 nBytes = nDigits * SYMCRYPT_FDEF_DIGIT_SIZE;
1451
PUINT32 pTmp = (PUINT32) pbScratch;
1452
1453
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
SYMCRYPT_ASSERT( cbScratch >= 2 * nBytes );
1460
memcpy( pTmp, &peSrc->d.uint32[0], nBytes );
1461
1462
SymCryptWipe( (PBYTE)pTmp + nBytes, nBytes );
1463
SymCryptFdefMontgomeryReduce( pmMod, pTmp, pTmp );
1464
1465
SymCryptWipe( (PBYTE)pTmp + nBytes, nBytes );
1466
SymCryptFdefMontgomeryReduce( pmMod, pTmp, &peDst->d.uint32[0] );
1467
1468
scError = SymCryptFdefModInvGeneric( pmMod, peDst, peDst, flags, pbScratch, cbScratch );
1469
1470
return scError;
1471
}
1472
1473
#if 0 && 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
{
1489
SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
1490
UINT32 nBytes = 32;
1491
PUINT32 pTmp = (PUINT32) pbScratch;
1492
1493
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
SYMCRYPT_ASSERT( cbScratch >= 2 * nBytes );
1500
memcpy( pTmp, &peSrc->d.uint32[0], nBytes );
1501
1502
SymCryptWipe( (PBYTE)pTmp + nBytes, nBytes );
1503
SymCryptFdefMontgomeryReduce256Asm( pmMod, pTmp, pTmp );
1504
1505
SymCryptWipe( (PBYTE)pTmp + nBytes, nBytes );
1506
SymCryptFdefMontgomeryReduce256Asm( pmMod, pTmp, &peDst->d.uint32[0] );
1507
1508
scError = SymCryptFdefModInvGeneric( pmMod, peDst, peDst, flags, pbScratch, cbScratch );
1509
1510
return scError;
1511
}
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
{
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
UINT32 nDigits = pmMod->nDigits;
1525
1526
SYMCRYPT_ASSERT( cbScratch >= nDigits * 2 * SYMCRYPT_FDEF_DIGIT_SIZE );
1527
UNREFERENCED_PARAMETER( pbScratch );
1528
UNREFERENCED_PARAMETER( cbScratch );
1529
UNREFERENCED_PARAMETER( nDigits );
1530
1531
SymCryptFdefModMulMontgomeryMulx256Asm( pmMod, (PSYMCRYPT_MODELEMENT) pmMod->tm.montgomery.Rsqr, peObj, peObj );
1532
}
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
{
1542
PUINT32 pTmp = (PUINT32) pbScratch;
1543
UINT32 nDigits = 1;
1544
1545
SYMCRYPT_ASSERT( cbScratch >= nDigits * SYMCRYPT_FDEF_DIGIT_SIZE );
1546
UNREFERENCED_PARAMETER( cbScratch );
1547
1548
memcpy( pTmp, &peObj->d.uint32[0], nDigits * SYMCRYPT_FDEF_DIGIT_SIZE );
1549
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
for( UINT32 i=8; i<16; ++i )
1554
{
1555
SYMCRYPT_ASSERT( pTmp[i] == 0 );
1556
}
1557
1558
// Wipe the extra bytes
1559
// SymCryptWipeKnownSize( pTmp + (SYMCRYPT_FDEF_DIGIT_NUINT32 / 2), 32 );
1560
1561
return pTmp;
1562
}
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
{
1571
SymCryptFdefModulusInitMontgomeryInternal( pmMod, 8, pbScratch, cbScratch );
1572
}
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
{
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
UINT32 nDigits = pmMod->nDigits;
1590
1591
SYMCRYPT_ASSERT( cbScratch >= nDigits * 2 * SYMCRYPT_FDEF_DIGIT_SIZE );
1592
UNREFERENCED_PARAMETER( pbScratch );
1593
UNREFERENCED_PARAMETER( cbScratch );
1594
UNREFERENCED_PARAMETER( nDigits );
1595
1596
SymCryptFdefModMulMontgomeryMulxP384Asm( pmMod, (PSYMCRYPT_MODELEMENT) pmMod->tm.montgomery.Rsqr, peObj, peObj );
1597
}
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
1688
1689
/* Wine hack: asm not supported yet */
1690
1691
VOID
1692
SYMCRYPT_CALL
1693
SymCryptFdefMontgomeryReduceAsm(
1694
_In_ PCSYMCRYPT_MODULUS pmMod,
1695
_Inout_ PUINT32 pSrc,
1696
_Out_ PUINT32 pDst )
1697
{
1698
SymCryptFdefMontgomeryReduceC( pmMod, pSrc, pDst );
1699
}
1700
1701
VOID
1702
SYMCRYPT_CALL
1703
SymCryptFdefModDivSmallPow2Mulx(
1704
_In_ PCSYMCRYPT_MODULUS pmMod,
1705
_In_ PCSYMCRYPT_MODELEMENT peSrc,
1706
_In_range_(1, NATIVE_BITS) UINT32 exp,
1707
_Out_ PSYMCRYPT_MODELEMENT peDst )
1708
{
1709
SymCryptFdefModDivSmallPow2Generic( pmMod, peSrc, exp, peDst );
1710
}
1711
1712
VOID
1713
SYMCRYPT_CALL
1714
SymCryptFdefMontgomeryReduceMulx(
1715
_In_ PCSYMCRYPT_MODULUS pmMod,
1716
_Inout_ PUINT32 pSrc,
1717
_Out_ PUINT32 pDst )
1718
{
1719
SymCryptFdefMontgomeryReduceC( pmMod, pSrc, pDst );
1720
}
1721
1722
VOID
1723
SYMCRYPT_CALL
1724
SymCryptFdefModDivSmallPow2Asm(
1725
_In_ PCSYMCRYPT_MODULUS pmMod,
1726
_In_ PCSYMCRYPT_MODELEMENT peSrc,
1727
_In_range_(1, NATIVE_BITS) UINT32 exp,
1728
_Out_ PSYMCRYPT_MODELEMENT peDst )
1729
{
1730
SymCryptFdefModDivSmallPow2Generic( pmMod, peSrc, exp, peDst );
1731
}
1732
1733