Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/libs/symcrypt/lib/crt.c
15010 views
1
//
2
// crt.c Chinese Remainder Theorem Algorithms
3
//
4
// Copyright (c) Microsoft Corporation. Licensed under the MIT license.
5
//
6
7
#include "precomp.h"
8
9
SYMCRYPT_ERROR
10
SYMCRYPT_CALL
11
SymCryptCrtGenerateForTwoCoprimes(
12
_In_ PCSYMCRYPT_MODULUS pmP,
13
_In_ PCSYMCRYPT_MODULUS pmQ,
14
UINT32 flags,
15
_Out_ PSYMCRYPT_MODELEMENT peInvQModP,
16
_Out_ PSYMCRYPT_MODELEMENT peInvPModQ,
17
_Out_writes_bytes_( cbScratch )
18
PBYTE pbScratch,
19
SIZE_T cbScratch )
20
{
21
SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
22
23
PCSYMCRYPT_INT piSrc1 = NULL;
24
PCSYMCRYPT_INT piSrc2 = NULL;
25
26
PSYMCRYPT_INT piInvSrc1ModSrc2 = NULL;
27
PSYMCRYPT_INT piInvSrc2ModSrc1 = NULL;
28
29
UINT32 nDigits = 0;
30
UINT32 cbInt = 0;
31
32
BOOLEAN oddP = FALSE;
33
34
SYMCRYPT_ASSERT( pmP != NULL );
35
SYMCRYPT_ASSERT( pmQ != NULL );
36
37
nDigits = SYMCRYPT_MAX( SymCryptModulusDigitsizeOfObject( pmP ), SymCryptModulusDigitsizeOfObject( pmQ ));
38
39
// Create two temporary integers
40
cbInt = SymCryptSizeofIntFromDigits( nDigits );
41
42
SYMCRYPT_ASSERT( cbScratch >= 2*cbInt + SYMCRYPT_SCRATCH_BYTES_FOR_EXTENDED_GCD( nDigits ));
43
44
piInvSrc1ModSrc2 = SymCryptIntCreate( pbScratch, cbInt, nDigits ); pbScratch += cbInt; cbScratch -= cbInt;
45
piInvSrc2ModSrc1 = SymCryptIntCreate( pbScratch, cbInt, nDigits ); pbScratch += cbInt; cbScratch -= cbInt;
46
47
oddP = ((SymCryptIntGetValueLsbits32(SymCryptIntFromModulus( (PSYMCRYPT_MODULUS) pmP )) & 1) == 1);
48
if (oddP)
49
{
50
piSrc1 = SymCryptIntFromModulus( (PSYMCRYPT_MODULUS) pmQ );
51
piSrc2 = SymCryptIntFromModulus( (PSYMCRYPT_MODULUS) pmP );
52
}
53
else
54
{
55
piSrc1 = SymCryptIntFromModulus( (PSYMCRYPT_MODULUS) pmP );
56
piSrc2 = SymCryptIntFromModulus( (PSYMCRYPT_MODULUS) pmQ );
57
}
58
59
// IntExtendedGcd requirements:
60
// - First argument > 0
61
// - Second argument odd
62
if( SymCryptIntIsEqualUint32(piSrc1, 0) ||
63
((SymCryptIntGetValueLsbits32(piSrc2) & 1) != 1) )
64
{
65
scError = SYMCRYPT_INVALID_ARGUMENT;
66
goto cleanup;
67
}
68
69
// Extended GCD
70
SymCryptIntExtendedGcd( piSrc1, piSrc2, flags, NULL, NULL, piInvSrc1ModSrc2, piInvSrc2ModSrc1, pbScratch, cbScratch );
71
72
if (oddP)
73
{
74
SymCryptIntToModElement( piInvSrc2ModSrc1, pmQ, peInvPModQ, pbScratch, cbScratch );
75
SymCryptIntToModElement( piInvSrc1ModSrc2, pmP, peInvQModP, pbScratch, cbScratch );
76
}
77
else
78
{
79
SymCryptIntToModElement( piInvSrc2ModSrc1, pmP, peInvQModP, pbScratch, cbScratch );
80
SymCryptIntToModElement( piInvSrc1ModSrc2, pmQ, peInvPModQ, pbScratch, cbScratch );
81
}
82
83
cleanup:
84
return scError;
85
}
86
87
88
SYMCRYPT_ERROR
89
SYMCRYPT_CALL
90
SymCryptCrtGenerateInverses(
91
UINT32 nCoprimes,
92
_In_reads_( nCoprimes ) PCSYMCRYPT_MODULUS * ppmCoprimes,
93
UINT32 flags,
94
_Out_writes_( nCoprimes ) PSYMCRYPT_MODELEMENT * ppeCrtInverses,
95
_Out_writes_bytes_( cbScratch ) PBYTE pbScratch,
96
SIZE_T cbScratch )
97
{
98
SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
99
100
if (nCoprimes == 2)
101
{
102
SymCryptCrtGenerateForTwoCoprimes(
103
ppmCoprimes[0],
104
ppmCoprimes[1],
105
flags,
106
ppeCrtInverses[0],
107
ppeCrtInverses[1],
108
pbScratch,
109
cbScratch );
110
}
111
else
112
{
113
scError = SYMCRYPT_INVALID_ARGUMENT;
114
goto cleanup;
115
}
116
117
cleanup:
118
return scError;
119
}
120
121
SYMCRYPT_ERROR
122
SYMCRYPT_CALL
123
SymCryptCrtSolve(
124
UINT32 nCoprimes,
125
_In_reads_( nCoprimes ) PCSYMCRYPT_MODULUS * ppmCoprimes,
126
_In_reads_( nCoprimes ) PCSYMCRYPT_MODELEMENT * ppeCrtInverses,
127
_In_reads_( nCoprimes ) PCSYMCRYPT_MODELEMENT * ppeCrtRemainders,
128
UINT32 flags,
129
_Out_ PSYMCRYPT_INT piSolution,
130
_Out_writes_bytes_( cbScratch ) PBYTE pbScratch,
131
SIZE_T cbScratch )
132
{
133
SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
134
135
SYMCRYPT_ASSERT( nCoprimes >= 2 );
136
137
PSYMCRYPT_INT piTmp = NULL;
138
PSYMCRYPT_MODELEMENT peTmp = NULL;
139
140
PSYMCRYPT_INT piDouble = NULL;
141
142
UINT32 nDigitsMax = 0;
143
144
UINT32 cbInt = 0;
145
UINT32 cbModElement = 0;
146
UINT32 cbDouble = 0;
147
148
UINT32 carry = 0;
149
150
UNREFERENCED_PARAMETER( flags );
151
152
nDigitsMax = SYMCRYPT_MAX( SymCryptModulusDigitsizeOfObject( ppmCoprimes[0] ), SymCryptModulusDigitsizeOfObject( ppmCoprimes[1] ) );
153
154
cbInt = SymCryptSizeofIntFromDigits( nDigitsMax );
155
cbModElement = SymCryptSizeofModElementFromModulus( ppmCoprimes[0] );
156
cbDouble = SymCryptSizeofIntFromDigits( 2*nDigitsMax );
157
158
if( cbDouble == 0 )
159
{
160
// It is possible that cbDouble would not fit within the maximum integer
161
scError = SYMCRYPT_INVALID_ARGUMENT;
162
goto cleanup;
163
}
164
165
SYMCRYPT_ASSERT( cbScratch >= cbInt + cbModElement + cbDouble +
166
SYMCRYPT_MAX( SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( nDigitsMax ),
167
SYMCRYPT_SCRATCH_BYTES_FOR_INT_MUL( 2*nDigitsMax ) )
168
);
169
170
// Create temporaries
171
piTmp = SymCryptIntCreate( pbScratch, cbInt, nDigitsMax ); pbScratch += cbInt; cbScratch -= cbInt;
172
173
peTmp = SymCryptModElementCreate( pbScratch, cbModElement, ppmCoprimes[0] ); pbScratch += cbModElement; cbScratch -= cbModElement;
174
175
piDouble = SymCryptIntCreate( pbScratch, cbDouble, 2*nDigitsMax ); pbScratch += cbDouble; cbScratch -= cbDouble;
176
177
if (nCoprimes == 2)
178
{
179
//
180
// Let r0 and r1 be the two remainders modulo p and q respectively
181
// Then we calculate (q^{-1}(r0 - r1) mod p)*q + r1
182
//
183
SymCryptModElementToInt( ppmCoprimes[1], ppeCrtRemainders[1], piTmp, pbScratch, cbScratch ); // Convert r1 to Int
184
SymCryptIntToModElement( piTmp, ppmCoprimes[0], peTmp, pbScratch, cbScratch ); // Convert it to r1 mod p
185
186
SymCryptModSub( ppmCoprimes[0], ppeCrtRemainders[0], peTmp, peTmp, pbScratch, cbScratch ); // (r0 - r1) mod p
187
SymCryptModMul( ppmCoprimes[0], ppeCrtInverses[0], peTmp, peTmp, pbScratch, cbScratch ); // q^{-1}*(r0 - r1) mod p
188
SymCryptModElementToInt( ppmCoprimes[0], peTmp, piTmp, pbScratch, cbScratch ); // Convert it to integer
189
190
SymCryptIntMulMixedSize( piTmp, SymCryptIntFromModulus((PSYMCRYPT_MODULUS)ppmCoprimes[1]), piDouble, pbScratch, cbScratch ); // Multiply by q
191
scError = SymCryptIntCopyMixedSize( piDouble, piSolution ); // Copy it into the solution
192
if (scError != SYMCRYPT_NO_ERROR)
193
{
194
goto cleanup;
195
}
196
197
SymCryptModElementToInt( ppmCoprimes[1], ppeCrtRemainders[1], piTmp, pbScratch, cbScratch ); // Convert r1 to integer
198
199
carry = SymCryptIntAddMixedSize( piTmp, piSolution, piSolution ); // Add it to the solution
200
201
if (carry>0)
202
{
203
scError = SYMCRYPT_INVALID_ARGUMENT;
204
goto cleanup;
205
}
206
}
207
else
208
{
209
scError = SYMCRYPT_INVALID_ARGUMENT;
210
goto cleanup;
211
}
212
213
cleanup:
214
return scError;
215
}
216
217