Line | Count | Source (jump to first uncovered line) |
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 | 0 | { |
21 | 0 | SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR; |
22 | |
|
23 | 0 | PCSYMCRYPT_INT piSrc1 = NULL; |
24 | 0 | PCSYMCRYPT_INT piSrc2 = NULL; |
25 | |
|
26 | 0 | PSYMCRYPT_INT piInvSrc1ModSrc2 = NULL; |
27 | 0 | PSYMCRYPT_INT piInvSrc2ModSrc1 = NULL; |
28 | |
|
29 | 0 | UINT32 nDigits = 0; |
30 | 0 | UINT32 cbInt = 0; |
31 | |
|
32 | 0 | BOOLEAN oddP = FALSE; |
33 | |
|
34 | 0 | SYMCRYPT_ASSERT( pmP != NULL ); |
35 | 0 | SYMCRYPT_ASSERT( pmQ != NULL ); |
36 | |
|
37 | 0 | nDigits = SYMCRYPT_MAX( SymCryptModulusDigitsizeOfObject( pmP ), SymCryptModulusDigitsizeOfObject( pmQ )); |
38 | | |
39 | | // Create two temporary integers |
40 | 0 | cbInt = SymCryptSizeofIntFromDigits( nDigits ); |
41 | |
|
42 | 0 | SYMCRYPT_ASSERT( cbScratch >= 2*cbInt + SYMCRYPT_SCRATCH_BYTES_FOR_EXTENDED_GCD( nDigits )); |
43 | |
|
44 | 0 | piInvSrc1ModSrc2 = SymCryptIntCreate( pbScratch, cbInt, nDigits ); pbScratch += cbInt; cbScratch -= cbInt; |
45 | 0 | piInvSrc2ModSrc1 = SymCryptIntCreate( pbScratch, cbInt, nDigits ); pbScratch += cbInt; cbScratch -= cbInt; |
46 | |
|
47 | 0 | oddP = ((SymCryptIntGetValueLsbits32(SymCryptIntFromModulus( (PSYMCRYPT_MODULUS) pmP )) & 1) == 1); |
48 | 0 | if (oddP) |
49 | 0 | { |
50 | 0 | piSrc1 = SymCryptIntFromModulus( (PSYMCRYPT_MODULUS) pmQ ); |
51 | 0 | piSrc2 = SymCryptIntFromModulus( (PSYMCRYPT_MODULUS) pmP ); |
52 | 0 | } |
53 | 0 | else |
54 | 0 | { |
55 | 0 | piSrc1 = SymCryptIntFromModulus( (PSYMCRYPT_MODULUS) pmP ); |
56 | 0 | piSrc2 = SymCryptIntFromModulus( (PSYMCRYPT_MODULUS) pmQ ); |
57 | 0 | } |
58 | | |
59 | | // IntExtendedGcd requirements: |
60 | | // - First argument > 0 |
61 | | // - Second argument odd |
62 | 0 | if( SymCryptIntIsEqualUint32(piSrc1, 0) || |
63 | 0 | ((SymCryptIntGetValueLsbits32(piSrc2) & 1) != 1) ) |
64 | 0 | { |
65 | 0 | scError = SYMCRYPT_INVALID_ARGUMENT; |
66 | 0 | goto cleanup; |
67 | 0 | } |
68 | | |
69 | | // Extended GCD |
70 | 0 | SymCryptIntExtendedGcd( piSrc1, piSrc2, flags, NULL, NULL, piInvSrc1ModSrc2, piInvSrc2ModSrc1, pbScratch, cbScratch ); |
71 | |
|
72 | 0 | if (oddP) |
73 | 0 | { |
74 | 0 | SymCryptIntToModElement( piInvSrc2ModSrc1, pmQ, peInvPModQ, pbScratch, cbScratch ); |
75 | 0 | SymCryptIntToModElement( piInvSrc1ModSrc2, pmP, peInvQModP, pbScratch, cbScratch ); |
76 | 0 | } |
77 | 0 | else |
78 | 0 | { |
79 | 0 | SymCryptIntToModElement( piInvSrc2ModSrc1, pmP, peInvQModP, pbScratch, cbScratch ); |
80 | 0 | SymCryptIntToModElement( piInvSrc1ModSrc2, pmQ, peInvPModQ, pbScratch, cbScratch ); |
81 | 0 | } |
82 | |
|
83 | 0 | cleanup: |
84 | 0 | return scError; |
85 | 0 | } |
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 | 0 | { |
98 | 0 | SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR; |
99 | |
|
100 | 0 | if (nCoprimes == 2) |
101 | 0 | { |
102 | 0 | SymCryptCrtGenerateForTwoCoprimes( |
103 | 0 | ppmCoprimes[0], |
104 | 0 | ppmCoprimes[1], |
105 | 0 | flags, |
106 | 0 | ppeCrtInverses[0], |
107 | 0 | ppeCrtInverses[1], |
108 | 0 | pbScratch, |
109 | 0 | cbScratch ); |
110 | 0 | } |
111 | 0 | else |
112 | 0 | { |
113 | 0 | scError = SYMCRYPT_INVALID_ARGUMENT; |
114 | 0 | goto cleanup; |
115 | 0 | } |
116 | | |
117 | 0 | cleanup: |
118 | 0 | return scError; |
119 | 0 | } |
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 | 0 | { |
133 | 0 | SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR; |
134 | |
|
135 | 0 | SYMCRYPT_ASSERT( nCoprimes >= 2 ); |
136 | |
|
137 | 0 | PSYMCRYPT_INT piTmp = NULL; |
138 | 0 | PSYMCRYPT_MODELEMENT peTmp = NULL; |
139 | |
|
140 | 0 | PSYMCRYPT_INT piDouble = NULL; |
141 | |
|
142 | 0 | UINT32 nDigitsMax = 0; |
143 | |
|
144 | 0 | UINT32 cbInt = 0; |
145 | 0 | UINT32 cbModElement = 0; |
146 | 0 | UINT32 cbDouble = 0; |
147 | |
|
148 | 0 | UINT32 carry = 0; |
149 | |
|
150 | 0 | UNREFERENCED_PARAMETER( flags ); |
151 | |
|
152 | 0 | nDigitsMax = SYMCRYPT_MAX( SymCryptModulusDigitsizeOfObject( ppmCoprimes[0] ), SymCryptModulusDigitsizeOfObject( ppmCoprimes[1] ) ); |
153 | |
|
154 | 0 | cbInt = SymCryptSizeofIntFromDigits( nDigitsMax ); |
155 | 0 | cbModElement = SymCryptSizeofModElementFromModulus( ppmCoprimes[0] ); |
156 | 0 | cbDouble = SymCryptSizeofIntFromDigits( 2*nDigitsMax ); |
157 | |
|
158 | 0 | if( cbDouble == 0 ) |
159 | 0 | { |
160 | | // It is possible that cbDouble would not fit within the maximum integer |
161 | 0 | scError = SYMCRYPT_INVALID_ARGUMENT; |
162 | 0 | goto cleanup; |
163 | 0 | } |
164 | | |
165 | 0 | SYMCRYPT_ASSERT( cbScratch >= cbInt + cbModElement + cbDouble + |
166 | 0 | SYMCRYPT_MAX( SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( nDigitsMax ), |
167 | 0 | SYMCRYPT_SCRATCH_BYTES_FOR_INT_MUL( 2*nDigitsMax ) ) |
168 | 0 | ); |
169 | | |
170 | | // Create temporaries |
171 | 0 | piTmp = SymCryptIntCreate( pbScratch, cbInt, nDigitsMax ); pbScratch += cbInt; cbScratch -= cbInt; |
172 | |
|
173 | 0 | peTmp = SymCryptModElementCreate( pbScratch, cbModElement, ppmCoprimes[0] ); pbScratch += cbModElement; cbScratch -= cbModElement; |
174 | |
|
175 | 0 | piDouble = SymCryptIntCreate( pbScratch, cbDouble, 2*nDigitsMax ); pbScratch += cbDouble; cbScratch -= cbDouble; |
176 | |
|
177 | 0 | if (nCoprimes == 2) |
178 | 0 | { |
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 | 0 | SymCryptModElementToInt( ppmCoprimes[1], ppeCrtRemainders[1], piTmp, pbScratch, cbScratch ); // Convert r1 to Int |
184 | 0 | SymCryptIntToModElement( piTmp, ppmCoprimes[0], peTmp, pbScratch, cbScratch ); // Convert it to r1 mod p |
185 | |
|
186 | 0 | SymCryptModSub( ppmCoprimes[0], ppeCrtRemainders[0], peTmp, peTmp, pbScratch, cbScratch ); // (r0 - r1) mod p |
187 | 0 | SymCryptModMul( ppmCoprimes[0], ppeCrtInverses[0], peTmp, peTmp, pbScratch, cbScratch ); // q^{-1}*(r0 - r1) mod p |
188 | 0 | SymCryptModElementToInt( ppmCoprimes[0], peTmp, piTmp, pbScratch, cbScratch ); // Convert it to integer |
189 | |
|
190 | 0 | SymCryptIntMulMixedSize( piTmp, SymCryptIntFromModulus((PSYMCRYPT_MODULUS)ppmCoprimes[1]), piDouble, pbScratch, cbScratch ); // Multiply by q |
191 | 0 | scError = SymCryptIntCopyMixedSize( piDouble, piSolution ); // Copy it into the solution |
192 | 0 | if (scError != SYMCRYPT_NO_ERROR) |
193 | 0 | { |
194 | 0 | goto cleanup; |
195 | 0 | } |
196 | | |
197 | 0 | SymCryptModElementToInt( ppmCoprimes[1], ppeCrtRemainders[1], piTmp, pbScratch, cbScratch ); // Convert r1 to integer |
198 | |
|
199 | 0 | carry = SymCryptIntAddMixedSize( piTmp, piSolution, piSolution ); // Add it to the solution |
200 | |
|
201 | 0 | if (carry>0) |
202 | 0 | { |
203 | 0 | scError = SYMCRYPT_INVALID_ARGUMENT; |
204 | 0 | goto cleanup; |
205 | 0 | } |
206 | 0 | } |
207 | 0 | else |
208 | 0 | { |
209 | 0 | scError = SYMCRYPT_INVALID_ARGUMENT; |
210 | 0 | goto cleanup; |
211 | 0 | } |
212 | | |
213 | 0 | cleanup: |
214 | 0 | return scError; |
215 | 0 | } |