/src/SymCrypt/lib/ec_mul.c
Line | Count | Source (jump to first uncovered line) |
1 | | // |
2 | | // ec_mul.c Generic multiplication algorithms for elliptic curves |
3 | | // |
4 | | // Copyright (c) Microsoft Corporation. Licensed under the MIT license. |
5 | | // |
6 | | // |
7 | | |
8 | | #include "precomp.h" |
9 | | |
10 | | // |
11 | | // Most of the following algorithms were presented in the paper |
12 | | // "Selecting Elliptic Curves for Cryptography: An Efficiency and |
13 | | // Security Analysis" by Bos, Costello, Longa, and Naehrig |
14 | | // |
15 | | |
16 | | // |
17 | | // The following is an adaptation of algorithm 4: "Precomputation |
18 | | // scheme for Weierstrass curves" |
19 | | // |
20 | | // Input: Point P and number of precomputed points nPoints (=2^(w-2)) |
21 | | // |
22 | | // Output: P[i] = (2*i+1)P for 0<=i<2^(w-2) |
23 | | // |
24 | | // Remarks: |
25 | | // 1. We store each point in an array of 4*2^(w-2) = 2^w modelements where |
26 | | // each point is represented with X,Y,Z Jacobian coordinates and the W=-Y |
27 | | // negated Y coordinate (so that we can get the negative of a point easily) |
28 | | // 2. The source point P is already in the 0'th position of the array. |
29 | | // |
30 | | VOID |
31 | | SYMCRYPT_CALL |
32 | | SymCryptPrecomputation( |
33 | | _In_ PCSYMCRYPT_ECURVE pCurve, |
34 | | UINT32 nPoints, |
35 | | _In_reads_( SYMCRYPT_ECURVE_SW_MAX_NPRECOMP_POINTS ) |
36 | | PSYMCRYPT_ECPOINT * poPIs, |
37 | | _Out_ PSYMCRYPT_ECPOINT poQ, |
38 | | _Out_writes_bytes_( cbScratch ) |
39 | | PBYTE pbScratch, |
40 | | SIZE_T cbScratch ) |
41 | 1.20k | { |
42 | 1.20k | SYMCRYPT_ASSERT( SymCryptEcurveIsSame(pCurve, poQ->pCurve) ); |
43 | | // Calculation for Q = 2*P |
44 | 1.20k | SymCryptEcpointDouble( pCurve, poPIs[0], poQ, 0, pbScratch, cbScratch ); |
45 | | |
46 | 19.2k | for (UINT32 i=1; i<nPoints; i++) |
47 | 18.0k | { |
48 | | // Calculation for (2i+1)*P = i*Q + P |
49 | 18.0k | SymCryptEcpointAddDiffNonZero( pCurve, poQ, poPIs[i-1], poPIs[i], pbScratch, cbScratch ); |
50 | 18.0k | } |
51 | 1.20k | } |
52 | | |
53 | | VOID |
54 | | SYMCRYPT_CALL |
55 | | SymCryptOfflinePrecomputation( |
56 | | _In_ PSYMCRYPT_ECURVE pCurve, |
57 | | _Out_writes_bytes_( cbScratch ) |
58 | | PBYTE pbScratch, |
59 | | SIZE_T cbScratch ) |
60 | 946 | { |
61 | 946 | PSYMCRYPT_ECPOINT poQ = NULL; |
62 | | |
63 | 946 | UINT32 cbEcpoint = SymCryptSizeofEcpointFromCurve( pCurve ); |
64 | | |
65 | 946 | SYMCRYPT_ASSERT( cbScratch >= cbEcpoint + SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( pCurve->FModDigits ) ); |
66 | | |
67 | 946 | poQ = SymCryptEcpointCreate( pbScratch, cbEcpoint, pCurve ); |
68 | 946 | SYMCRYPT_ASSERT( poQ != NULL ); |
69 | 946 | pbScratch += cbEcpoint; |
70 | 946 | cbScratch -= cbEcpoint; |
71 | | |
72 | 946 | SymCryptPrecomputation( |
73 | 946 | pCurve, |
74 | 946 | pCurve->info.sw.nPrecompPoints, |
75 | 946 | pCurve->info.sw.poPrecompPoints, |
76 | 946 | poQ, |
77 | 946 | pbScratch, |
78 | 946 | cbScratch ); |
79 | 946 | } |
80 | | |
81 | | // Mask which is 0xffffffff only when _index == _target |
82 | 968k | #define DELTA_MASK( _index, _target) SYMCRYPT_MASK32_ZERO( (_index) ^ (_target) ) |
83 | | |
84 | | // |
85 | | // The following is an adaptation of algorithm 1: "Variable-base scalar multiplication |
86 | | // using the fixed-window method" |
87 | | // |
88 | | SYMCRYPT_ERROR |
89 | | SYMCRYPT_CALL |
90 | | SymCryptEcpointScalarMulFixedWindow( |
91 | | _In_ PCSYMCRYPT_ECURVE pCurve, |
92 | | _In_ PCSYMCRYPT_INT piScalar, |
93 | | _In_opt_ |
94 | | PCSYMCRYPT_ECPOINT poSrc, |
95 | | UINT32 flags, |
96 | | _Out_ PSYMCRYPT_ECPOINT poDst, |
97 | | _Out_writes_bytes_( cbScratch ) |
98 | | PBYTE pbScratch, |
99 | | SIZE_T cbScratch ) |
100 | 795 | { |
101 | 795 | SYMCRYPT_ERROR scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE; |
102 | | |
103 | 795 | PCSYMCRYPT_MODULUS FMod = pCurve->FMod; |
104 | | |
105 | 795 | UINT32 i, j; |
106 | | |
107 | 795 | UINT32 w = pCurve->info.sw.window; |
108 | 795 | UINT32 nPrecompPoints = pCurve->info.sw.nPrecompPoints; |
109 | | // dcl - assuming that nRecodedDigits has some reasonably small range - please document |
110 | | // so that we can know usage of this variable will not cause problems |
111 | | // Also, documentation of inputs, notes, etc at the function definition would be quite helpful |
112 | 795 | UINT32 nRecodedDigits = ((pCurve->GOrdBitsize + w - 2) / (w-1)) + 1; |
113 | | |
114 | | // Masks |
115 | 795 | UINT32 fZero = 0; |
116 | 795 | UINT32 fEven = 0; |
117 | 795 | UINT32 indexMask = 0; |
118 | | |
119 | 795 | BOOLEAN bPrecompOffline = FALSE; |
120 | | |
121 | | // ==================================================== |
122 | | // Temporaries |
123 | 795 | PSYMCRYPT_MODELEMENT peT = NULL; |
124 | 795 | PSYMCRYPT_ECPOINT poPIs[SYMCRYPT_ECURVE_SW_MAX_NPRECOMP_POINTS] = { 0 }; |
125 | 795 | PSYMCRYPT_ECPOINT poQ = NULL; |
126 | 795 | PSYMCRYPT_ECPOINT poTmp = NULL; |
127 | 795 | PSYMCRYPT_INT piRem = NULL; |
128 | 795 | PSYMCRYPT_INT piTmp = NULL; |
129 | 795 | PUINT32 absofKIs = NULL; |
130 | 795 | PUINT32 sigofKIs = NULL; |
131 | | // =================================================== |
132 | | |
133 | 795 | PSYMCRYPT_MODELEMENT peQX = NULL; |
134 | 795 | PSYMCRYPT_MODELEMENT peQY = NULL; |
135 | 795 | PSYMCRYPT_MODELEMENT peQZ = NULL; |
136 | | |
137 | 795 | SIZE_T cbEcpoint = SymCryptSizeofEcpointFromCurve( pCurve ); |
138 | 795 | SIZE_T cbScalar = SymCryptSizeofIntFromDigits( pCurve->GOrdDigits ); |
139 | | |
140 | | // Make sure we only specify the correct flags |
141 | 795 | if ((flags & ~SYMCRYPT_FLAG_ECC_LL_COFACTOR_MUL) != 0) |
142 | 0 | { |
143 | 0 | scError = SYMCRYPT_INVALID_ARGUMENT; |
144 | 0 | goto exit; |
145 | 0 | } |
146 | | |
147 | | // Check if poSrc is NULL and if yes set it to G |
148 | 795 | if (poSrc == NULL) |
149 | 726 | { |
150 | 726 | poSrc = pCurve->G; |
151 | 726 | bPrecompOffline = TRUE; |
152 | 726 | } |
153 | | |
154 | 795 | SYMCRYPT_ASSERT( SYMCRYPT_CURVE_IS_SHORT_WEIERSTRASS_TYPE(pCurve) || |
155 | 795 | SYMCRYPT_CURVE_IS_TWISTED_EDWARDS_TYPE(pCurve) ); |
156 | 795 | SYMCRYPT_ASSERT( SymCryptEcurveIsSame(pCurve, poSrc->pCurve) && SymCryptEcurveIsSame(pCurve, poDst->pCurve) ); |
157 | 795 | SYMCRYPT_ASSERT( cbScratch >= SYMCRYPT_INTERNAL_SCRATCH_BYTES_FOR_SCALAR_ECURVE_OPERATIONS(pCurve, 1) ); |
158 | | |
159 | 795 | SYMCRYPT_ASSERT( cbScratch >= |
160 | 795 | pCurve->cbModElement + |
161 | 795 | (nPrecompPoints+2)*cbEcpoint + |
162 | 795 | 2*cbScalar + |
163 | 795 | ((2*nRecodedDigits*sizeof(UINT32) + SYMCRYPT_ASYM_ALIGN_VALUE - 1)/SYMCRYPT_ASYM_ALIGN_VALUE )*SYMCRYPT_ASYM_ALIGN_VALUE + |
164 | 795 | SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_ECURVE_OPERATIONS( pCurve ) ); |
165 | | |
166 | | // Creating temporary modelement |
167 | 795 | peT = SymCryptModElementCreate( pbScratch, pCurve->cbModElement, FMod ); |
168 | 795 | SYMCRYPT_ASSERT( peT != NULL ); |
169 | 795 | pbScratch += pCurve->cbModElement; |
170 | | |
171 | | // Creating temporary precomputed points (if needed) |
172 | 795 | SYMCRYPT_ASSERT( nPrecompPoints <= SYMCRYPT_ECURVE_SW_MAX_NPRECOMP_POINTS ); |
173 | 13.5k | for (i=0; i<nPrecompPoints; i++) |
174 | 12.7k | { |
175 | 12.7k | if (bPrecompOffline) |
176 | 11.6k | { |
177 | 11.6k | poPIs[i] = pCurve->info.sw.poPrecompPoints[i]; |
178 | 11.6k | } |
179 | 1.10k | else |
180 | 1.10k | { |
181 | 1.10k | poPIs[i] = SymCryptEcpointCreate( pbScratch, cbEcpoint, pCurve ); |
182 | 1.10k | SYMCRYPT_ASSERT( poPIs[i] != NULL ); |
183 | 1.10k | pbScratch += cbEcpoint; |
184 | 1.10k | } |
185 | 12.7k | } |
186 | | |
187 | | // Creating temporary points |
188 | 795 | poQ = SymCryptEcpointCreate( pbScratch, cbEcpoint, pCurve ); |
189 | 795 | SYMCRYPT_ASSERT( poQ != NULL ); |
190 | 795 | pbScratch += cbEcpoint; |
191 | | |
192 | 795 | poTmp = SymCryptEcpointCreate( pbScratch, cbEcpoint, pCurve ); |
193 | 795 | SYMCRYPT_ASSERT( poTmp != NULL ); |
194 | 795 | pbScratch += cbEcpoint; |
195 | | |
196 | | // Creating temporary scalar for the remainder |
197 | 795 | piRem = SymCryptIntCreate( pbScratch, cbScalar, pCurve->GOrdDigits ); |
198 | 795 | SYMCRYPT_ASSERT( piRem != NULL); |
199 | 795 | pbScratch += cbScalar; |
200 | | |
201 | 795 | piTmp = SymCryptIntCreate( pbScratch, cbScalar, pCurve->GOrdDigits ); |
202 | 795 | SYMCRYPT_ASSERT( piTmp != NULL); |
203 | 795 | pbScratch += cbScalar; |
204 | | |
205 | | // Fixing pointers to recoded digits (be careful that the remaining space is SYMCRYPT_ASYM_ALIGNed) |
206 | 795 | absofKIs = (PUINT32) pbScratch; |
207 | 795 | pbScratch += nRecodedDigits * sizeof(UINT32); |
208 | 795 | sigofKIs = (PUINT32) pbScratch; |
209 | 795 | pbScratch += nRecodedDigits * sizeof(UINT32); |
210 | 795 | pbScratch = (PBYTE) ( ((ULONG_PTR)pbScratch + SYMCRYPT_ASYM_ALIGN_VALUE - 1) & ~(SYMCRYPT_ASYM_ALIGN_VALUE - 1) ); |
211 | | |
212 | | // Fixing remaining scratch space size |
213 | 795 | cbScratch -= ( pCurve->cbModElement + (nPrecompPoints+2)*cbEcpoint + 2*cbScalar ); |
214 | 795 | cbScratch -= (((2*nRecodedDigits*sizeof(UINT32) + SYMCRYPT_ASYM_ALIGN_VALUE - 1)/SYMCRYPT_ASYM_ALIGN_VALUE )*SYMCRYPT_ASYM_ALIGN_VALUE); |
215 | | |
216 | | // |
217 | | // Main algorithm |
218 | | // |
219 | | |
220 | | // It is the caller's responsibility to ensure that the provided piScalar <= GOrd, double check this in debug mode |
221 | 795 | SYMCRYPT_ASSERT( !SymCryptIntIsLessThan( SymCryptIntFromModulus( pCurve->GOrd ), piScalar ) ); |
222 | | |
223 | | // Store k into an int |
224 | 795 | SymCryptIntCopy( piScalar, piRem ); |
225 | | |
226 | | // Check if k is 0 |
227 | 795 | fZero = SymCryptIntIsEqualUint32( piRem, 0 ); |
228 | | |
229 | | // Or if the src point is zero |
230 | 795 | fZero |= SymCryptEcpointIsZero( pCurve, poSrc, pbScratch, cbScratch ); |
231 | | |
232 | | // Check if k is even and convert it to r-k if true |
233 | 795 | fEven = SYMCRYPT_MASK32_ZERO(SymCryptIntGetBit( piRem, 0 )); |
234 | 795 | SymCryptIntSubSameSize( SymCryptIntFromModulus(pCurve->GOrd), piRem, piTmp); |
235 | 795 | SymCryptIntMaskedCopy( piTmp, piRem, fEven ); |
236 | | |
237 | | // Recoding stage |
238 | 795 | SymCryptFixedWindowRecoding( w, piRem, piTmp, absofKIs, sigofKIs, nRecodedDigits ); |
239 | | |
240 | | // Precomputation stage |
241 | 795 | if (!bPrecompOffline) |
242 | 69 | { |
243 | | // Copy the first point in the start of the poPIs array |
244 | 69 | SymCryptEcpointCopy( pCurve, poSrc, poPIs[0] ); |
245 | | |
246 | 69 | SymCryptPrecomputation( pCurve, nPrecompPoints, poPIs, poQ, pbScratch, cbScratch ); |
247 | 69 | } |
248 | | |
249 | | |
250 | | // Get the pointers to Q |
251 | 795 | peQX = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 0, pCurve, poQ ); |
252 | 795 | peQY = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 1, pCurve, poQ ); |
253 | 795 | peQZ = SYMCRYPT_INTERNAL_ECPOINT_COORDINATE( 2, pCurve, poQ ); |
254 | | |
255 | | // Q = P[ (|k_t|-1)/2 ] in memory access side-channel safe way |
256 | | // That is, we touch all the precomputed points. The access pattern of KIs is fixed. |
257 | 13.5k | for (j=0; j<nPrecompPoints; j++) |
258 | 12.7k | { |
259 | 12.7k | indexMask = DELTA_MASK( j, absofKIs[nRecodedDigits-1] ); |
260 | 12.7k | SymCryptEcpointMaskedCopy( pCurve, poPIs[j], poQ, indexMask); |
261 | 12.7k | } |
262 | | |
263 | 59.7k | for (i=nRecodedDigits - 2; i>0; i--) |
264 | 58.9k | { |
265 | | // Q = 2^(w-1) * Q |
266 | 353k | for (j=0; j<w-1; j++) |
267 | 294k | { |
268 | 294k | SymCryptEcpointDouble( pCurve, poQ, poQ, 0, pbScratch, cbScratch ); |
269 | 294k | } |
270 | | |
271 | | // Copy the required precomputed point into poTmp (touch all points) |
272 | 1.00M | for (j=0; j<nPrecompPoints; j++) |
273 | 942k | { |
274 | 942k | indexMask = DELTA_MASK( j, absofKIs[i] ); |
275 | 942k | SymCryptEcpointMaskedCopy( pCurve, poPIs[j], poTmp, indexMask); |
276 | 942k | } |
277 | | |
278 | | // Negate if needed |
279 | 58.9k | SymCryptEcpointNegate( pCurve, poTmp, sigofKIs[i], pbScratch, cbScratch ); |
280 | | |
281 | | // Do the addition Q + s_i P[k_i] |
282 | 58.9k | SymCryptEcpointAddDiffNonZero( pCurve, poQ, poTmp, poQ, pbScratch, cbScratch ); |
283 | 58.9k | } |
284 | | |
285 | | // Q = 2^(w-1) * Q |
286 | 4.77k | for (j=0; j<w-1; j++) |
287 | 3.97k | { |
288 | 3.97k | SymCryptEcpointDouble( pCurve, poQ, poQ, 0, pbScratch, cbScratch ); |
289 | 3.97k | } |
290 | | |
291 | | // Copy the point s_0 P[k_0] into poTmp |
292 | 13.5k | for (j=0; j<nPrecompPoints; j++) |
293 | 12.7k | { |
294 | 12.7k | indexMask = DELTA_MASK( j, absofKIs[0] ); |
295 | 12.7k | SymCryptEcpointMaskedCopy( pCurve, poPIs[j], poTmp, indexMask); |
296 | 12.7k | } |
297 | | |
298 | | // Negate if needed |
299 | 795 | SymCryptEcpointNegate( pCurve, poTmp, sigofKIs[0], pbScratch, cbScratch ); |
300 | | |
301 | | // Complete addition routine |
302 | 795 | SymCryptEcpointAdd( pCurve, poQ, poTmp, poQ, 0, pbScratch, cbScratch ); |
303 | | |
304 | | // If even invert |
305 | 795 | SymCryptEcpointNegate( pCurve, poQ, fEven, pbScratch, cbScratch ); |
306 | | |
307 | | // Multiply by the cofactor (if needed) by continuing the doubling |
308 | 795 | if ((pCurve->coFactorPower!=0) && ((flags & SYMCRYPT_FLAG_ECC_LL_COFACTOR_MUL) != 0)) |
309 | 47 | { |
310 | 141 | for (j=0; j<pCurve->coFactorPower; j++) |
311 | 94 | { |
312 | 94 | SymCryptEcpointDouble( pCurve, poQ, poQ, 0, pbScratch, cbScratch ); |
313 | 94 | } |
314 | 47 | } |
315 | | |
316 | | // If the resultant point is zero, ensure it will be set to the canonical zero point |
317 | 795 | fZero |= SymCryptEcpointIsZero( pCurve, poQ, pbScratch, cbScratch ); |
318 | | |
319 | | // Set the zero point |
320 | 795 | SymCryptEcpointSetZero( pCurve, poTmp, pbScratch, cbScratch ); |
321 | 795 | SymCryptEcpointMaskedCopy( pCurve, poTmp, poQ, fZero ); |
322 | | |
323 | | // Output the result (normalized flag == FALSE) |
324 | 795 | SymCryptEcpointCopy( pCurve, poQ, poDst ); |
325 | | |
326 | 795 | scError = SYMCRYPT_NO_ERROR; |
327 | | |
328 | 795 | exit: |
329 | | |
330 | 795 | return scError; |
331 | 795 | } |
332 | | |
333 | | // |
334 | | // The following is an adaptation of algorithm 9: "Double-scalar multiplication using the |
335 | | // width-w NAF with interleaving" |
336 | | // |
337 | | SYMCRYPT_ERROR |
338 | | SYMCRYPT_CALL |
339 | | SymCryptEcpointMultiScalarMulWnafWithInterleaving( |
340 | | _In_ PCSYMCRYPT_ECURVE pCurve, |
341 | | _In_reads_( nPoints ) PCSYMCRYPT_INT * piSrcScalarArray, |
342 | | _In_reads_( nPoints ) PCSYMCRYPT_ECPOINT * poSrcEcpointArray, |
343 | | _In_ UINT32 nPoints, |
344 | | _In_ UINT32 flags, |
345 | | _Out_ PSYMCRYPT_ECPOINT poDst, |
346 | | _Out_writes_bytes_( cbScratch ) PBYTE pbScratch, |
347 | | SIZE_T cbScratch ) |
348 | 191 | { |
349 | 191 | SYMCRYPT_ERROR scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE; |
350 | | |
351 | 191 | UINT32 i, j; |
352 | | |
353 | 191 | UINT32 w = pCurve->info.sw.window; |
354 | 191 | UINT32 nPrecompPoints = pCurve->info.sw.nPrecompPoints; // One table for each base |
355 | 191 | UINT32 nRecodedDigits = pCurve->GOrdBitsize + 1; // Notice the difference with the fixed window |
356 | | |
357 | | // Masks |
358 | 191 | UINT32 fZero[SYMCRYPT_ECURVE_MULTI_SCALAR_MUL_MAX_NPOINTS] = { 0 }; |
359 | 191 | UINT32 fZeroTot = 0xffffffff; |
360 | | |
361 | 191 | BOOLEAN bPrecompOffline = FALSE; |
362 | | |
363 | | // ==================================================== |
364 | | // Temporaries |
365 | 191 | PSYMCRYPT_ECPOINT poPIs[SYMCRYPT_ECURVE_SW_MAX_NPRECOMP_POINTS] = { 0 }; |
366 | 191 | PSYMCRYPT_ECPOINT poQ = NULL; |
367 | 191 | PSYMCRYPT_ECPOINT poTmp = NULL; |
368 | 191 | PSYMCRYPT_INT piRem = NULL; |
369 | 191 | PSYMCRYPT_INT piTmp = NULL; |
370 | | |
371 | 191 | PUINT32 absofKIs = NULL; |
372 | 191 | PUINT32 sigofKIs = NULL; |
373 | | // =================================================== |
374 | | |
375 | 191 | SIZE_T cbEcpoint = SymCryptSizeofEcpointFromCurve( pCurve ); |
376 | 191 | SIZE_T cbScalar = SymCryptSizeofIntFromDigits( pCurve->GOrdDigits ); |
377 | | |
378 | 191 | PBYTE pbScratchEnd = pbScratch + cbScratch; |
379 | 191 | UNREFERENCED_PARAMETER( pbScratchEnd ); // Used in asserts |
380 | | |
381 | | // Make sure we only specify the correct flags |
382 | 191 | if ((flags & ~(SYMCRYPT_FLAG_DATA_PUBLIC | SYMCRYPT_FLAG_ECC_LL_COFACTOR_MUL)) != 0) |
383 | 0 | { |
384 | 0 | scError = SYMCRYPT_INVALID_ARGUMENT; |
385 | 0 | goto exit; |
386 | 0 | } |
387 | | |
388 | | // Check the maximum number of points |
389 | 191 | if (nPoints > SYMCRYPT_ECURVE_MULTI_SCALAR_MUL_MAX_NPOINTS) |
390 | 0 | { |
391 | 0 | scError = SYMCRYPT_NOT_IMPLEMENTED; |
392 | 0 | goto exit; |
393 | 0 | } |
394 | | |
395 | | // Check if the first point is NULL |
396 | 191 | if (poSrcEcpointArray[0] == NULL) |
397 | 191 | { |
398 | 191 | poSrcEcpointArray[0] = pCurve->G; |
399 | 191 | bPrecompOffline = TRUE; |
400 | 191 | } |
401 | | |
402 | | // Make sure that the non side-channel flag is specified |
403 | 191 | if ((flags & SYMCRYPT_FLAG_DATA_PUBLIC) == 0 ) |
404 | 0 | { |
405 | 0 | scError = SYMCRYPT_NOT_IMPLEMENTED; |
406 | 0 | goto exit; |
407 | 0 | } |
408 | | |
409 | 191 | SYMCRYPT_ASSERT( SYMCRYPT_CURVE_IS_SHORT_WEIERSTRASS_TYPE(pCurve) || |
410 | 191 | SYMCRYPT_CURVE_IS_TWISTED_EDWARDS_TYPE(pCurve) ); |
411 | 191 | SYMCRYPT_ASSERT( SymCryptEcurveIsSame(pCurve, poDst->pCurve) ); |
412 | 191 | SYMCRYPT_ASSERT( cbScratch >= SYMCRYPT_INTERNAL_SCRATCH_BYTES_FOR_SCALAR_ECURVE_OPERATIONS(pCurve, nPoints) ); |
413 | | |
414 | | // Creating temporary precomputed points (if needed for the first point) |
415 | 6.30k | for (i=0; i<nPoints*nPrecompPoints; i++) |
416 | 6.11k | { |
417 | 6.11k | if ((i<nPrecompPoints) && bPrecompOffline) |
418 | 3.05k | { |
419 | 3.05k | poPIs[i] = pCurve->info.sw.poPrecompPoints[i]; |
420 | 3.05k | } |
421 | 3.05k | else |
422 | 3.05k | { |
423 | 3.05k | SYMCRYPT_ASSERT( pbScratch + cbEcpoint <= pbScratchEnd ); |
424 | 3.05k | poPIs[i] = SymCryptEcpointCreate( pbScratch, cbEcpoint, pCurve ); |
425 | 3.05k | SYMCRYPT_ASSERT( poPIs[i] != NULL ); |
426 | 3.05k | pbScratch += cbEcpoint; |
427 | 3.05k | } |
428 | 6.11k | } |
429 | | |
430 | 191 | SYMCRYPT_ASSERT( pbScratch + 2*cbEcpoint + 2*cbScalar + 2*nPoints*nRecodedDigits*sizeof(UINT32) <= pbScratchEnd ); |
431 | | // Creating temporary points |
432 | 191 | poQ = SymCryptEcpointCreate( pbScratch, cbEcpoint, pCurve ); |
433 | 191 | SYMCRYPT_ASSERT( poQ != NULL ); |
434 | 191 | pbScratch += cbEcpoint; |
435 | | |
436 | 191 | poTmp = SymCryptEcpointCreate( pbScratch, cbEcpoint, pCurve ); |
437 | 191 | SYMCRYPT_ASSERT( poTmp != NULL ); |
438 | 191 | pbScratch += cbEcpoint; |
439 | | |
440 | | // Creating temporary scalar for the remainder |
441 | 191 | piRem = SymCryptIntCreate( pbScratch, cbScalar, pCurve->GOrdDigits ); |
442 | 191 | SYMCRYPT_ASSERT( piRem != NULL); |
443 | 191 | pbScratch += cbScalar; |
444 | | |
445 | 191 | piTmp = SymCryptIntCreate( pbScratch, cbScalar, pCurve->GOrdDigits ); |
446 | 191 | SYMCRYPT_ASSERT( piTmp != NULL); |
447 | 191 | pbScratch += cbScalar; |
448 | | |
449 | | // Fixing pointers to recoded digits (be careful that the remaining space is SYMCRYPT_ASYM_ALIGNed) |
450 | 191 | absofKIs = (PUINT32) pbScratch; |
451 | 191 | pbScratch += nPoints * nRecodedDigits * sizeof(UINT32); |
452 | 191 | sigofKIs = (PUINT32) pbScratch; |
453 | 191 | pbScratch += nPoints * nRecodedDigits * sizeof(UINT32); |
454 | 191 | pbScratch = (PBYTE) ( ((ULONG_PTR)pbScratch + SYMCRYPT_ASYM_ALIGN_VALUE - 1) & ~(SYMCRYPT_ASYM_ALIGN_VALUE - 1) ); |
455 | | |
456 | | // Fixing remaining scratch space size |
457 | | // dcl - my guess is that the values here are small enough that there should not be a problem, but |
458 | | // would be better if that were documented. |
459 | 191 | cbScratch -= ( (nPoints*nPrecompPoints+2)*cbEcpoint + 2*cbScalar ); |
460 | 191 | cbScratch -= (((2*nPoints*nRecodedDigits*sizeof(UINT32) + SYMCRYPT_ASYM_ALIGN_VALUE - 1)/SYMCRYPT_ASYM_ALIGN_VALUE )*SYMCRYPT_ASYM_ALIGN_VALUE); |
461 | | |
462 | | // |
463 | | // Main algorithm |
464 | | // |
465 | 573 | for (j = 0; j<nPoints; j++) |
466 | 382 | { |
467 | 382 | SYMCRYPT_ASSERT( SymCryptEcurveIsSame(pCurve, poSrcEcpointArray[j]->pCurve) ); |
468 | | |
469 | | // Check if k is 0 or if the src point is zero |
470 | 382 | fZero[j] = ( SymCryptIntIsEqualUint32( piSrcScalarArray[j], 0 ) | SymCryptEcpointIsZero( pCurve, poSrcEcpointArray[j], pbScratch, cbScratch ) ); |
471 | 382 | fZeroTot &= fZero[j]; |
472 | | |
473 | | // Skip the recoding stage (and all remaining steps) if this point will give result zero |
474 | 382 | if (!fZero[j]) |
475 | 351 | { |
476 | 351 | SymCryptIntCopy( piSrcScalarArray[j], piRem ); |
477 | | |
478 | | // Recoding stage |
479 | 351 | SymCryptWidthNafRecoding( w, piRem, &absofKIs[j*nRecodedDigits], &sigofKIs[j*nRecodedDigits], nRecodedDigits ); |
480 | | |
481 | | // Precomputation stage |
482 | 351 | if ((j>0) || !bPrecompOffline) |
483 | 191 | { |
484 | | // Copy the first point in the start of the poPIs array |
485 | 191 | SymCryptEcpointCopy( pCurve, poSrcEcpointArray[j], poPIs[j*nPrecompPoints] ); |
486 | | |
487 | 191 | SymCryptPrecomputation( pCurve, nPrecompPoints, &poPIs[j*nPrecompPoints], poQ, pbScratch, cbScratch ); |
488 | 191 | } |
489 | 351 | } |
490 | 382 | } |
491 | | |
492 | | // Set poQ to zero point |
493 | 191 | SymCryptEcpointSetZero( pCurve, poQ, pbScratch, cbScratch ); |
494 | | |
495 | 191 | if (!fZeroTot) |
496 | 191 | { |
497 | | // Main loop |
498 | 78.5k | for (INT32 i = nRecodedDigits-1; i>-1; i--) |
499 | 78.3k | { |
500 | 78.3k | SymCryptEcpointDouble( pCurve, poQ, poQ, 0, pbScratch, cbScratch ); |
501 | | |
502 | 235k | for (j = 0; j<nPoints; j++) |
503 | 156k | { |
504 | 156k | if (!fZero[j] && sigofKIs[j*nRecodedDigits + i] != 0) |
505 | 20.3k | { |
506 | 20.3k | SymCryptEcpointCopy( pCurve, poPIs[j*nPrecompPoints + absofKIs[j*nRecodedDigits + i]/2], poTmp ); |
507 | | |
508 | 20.3k | if (sigofKIs[j*nRecodedDigits + i] == 0xffffffff) |
509 | 9.94k | { |
510 | 9.94k | SymCryptEcpointNegate( pCurve, poTmp, 0xffffffff, pbScratch, cbScratch ); |
511 | 9.94k | } |
512 | | |
513 | 20.3k | SymCryptEcpointAdd( pCurve, poQ, poTmp, poQ, SYMCRYPT_FLAG_DATA_PUBLIC, pbScratch, cbScratch ); |
514 | 20.3k | } |
515 | 156k | } |
516 | 78.3k | } |
517 | 191 | } |
518 | | |
519 | | // Multiply by the cofactor (if needed) by continuing the doubling |
520 | 191 | if ((pCurve->coFactorPower!=0) && ((flags & SYMCRYPT_FLAG_ECC_LL_COFACTOR_MUL) != 0)) |
521 | 0 | { |
522 | 0 | for (j=0; j<pCurve->coFactorPower; j++) |
523 | 0 | { |
524 | 0 | SymCryptEcpointDouble( pCurve, poQ, poQ, 0, pbScratch, cbScratch ); |
525 | 0 | } |
526 | 0 | } |
527 | | |
528 | | // If the resultant point is zero, ensure it will be set to the canonical zero point |
529 | 191 | if ( SymCryptEcpointIsZero( pCurve, poQ, pbScratch, cbScratch ) ) |
530 | 0 | { |
531 | | // Set poQ to zero point |
532 | 0 | SymCryptEcpointSetZero( pCurve, poQ, pbScratch, cbScratch ); |
533 | 0 | } |
534 | | |
535 | | // Copy the result to the destination (normalized flag == FALSE) |
536 | 191 | SymCryptEcpointCopy( pCurve, poQ, poDst ); |
537 | | |
538 | 191 | scError = SYMCRYPT_NO_ERROR; |
539 | | |
540 | 191 | exit: |
541 | 191 | return scError; |
542 | 191 | } |
543 | | |
544 | | VOID |
545 | | SYMCRYPT_CALL |
546 | | SymCryptEcpointGenericSetRandom( |
547 | | _In_ PCSYMCRYPT_ECURVE pCurve, |
548 | | _Out_ PSYMCRYPT_INT piScalar, |
549 | | _Out_ PSYMCRYPT_ECPOINT poDst, |
550 | | _Out_writes_bytes_( cbScratch ) |
551 | | PBYTE pbScratch, |
552 | | SIZE_T cbScratch ) |
553 | 0 | { |
554 | 0 | PSYMCRYPT_MODELEMENT peScalar = NULL; |
555 | 0 | SYMCRYPT_ASSERT( SymCryptEcurveIsSame(pCurve, poDst->pCurve) ); |
556 | 0 | SYMCRYPT_ASSERT( cbScratch >= SYMCRYPT_INTERNAL_SCRATCH_BYTES_FOR_SCALAR_ECURVE_OPERATIONS(pCurve, 1) ); |
557 | 0 | SYMCRYPT_ASSERT( cbScratch >= pCurve->cbModElement ); |
558 | |
|
559 | 0 | peScalar = SymCryptModElementCreate( pbScratch, pCurve->cbModElement, pCurve->GOrd ); |
560 | 0 | SYMCRYPT_ASSERT( peScalar != NULL ); |
561 | | |
562 | | // Setting a random mod element in the [1, SubgroupOrder-1] set |
563 | 0 | SymCryptModSetRandom( pCurve->GOrd, peScalar, (SYMCRYPT_FLAG_MODRANDOM_ALLOW_ONE|SYMCRYPT_FLAG_MODRANDOM_ALLOW_MINUSONE), pbScratch + pCurve->cbModElement, cbScratch - pCurve->cbModElement ); |
564 | | |
565 | | // Setting the integer |
566 | 0 | SymCryptModElementToInt( pCurve->GOrd, peScalar, piScalar, pbScratch + pCurve->cbModElement, cbScratch - pCurve->cbModElement ); |
567 | | |
568 | | // Do the multiplication (pass over the entire scratch space as it is not needed anymore) |
569 | | // !! Explicitly not checking the error return here as the only error is from specifying invalid flags !! |
570 | 0 | SymCryptEcpointScalarMul( pCurve, piScalar, NULL, 0, poDst, pbScratch, cbScratch ); |
571 | 0 | } |