1 /**************************************************************************/
2 /* */
3 /* Copyright (c) Microsoft Corporation. All rights reserved. */
4 /* */
5 /* This software is licensed under the Microsoft Software License */
6 /* Terms for Microsoft Azure RTOS. Full text of the license can be */
7 /* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
8 /* and in the root directory of this software. */
9 /* */
10 /**************************************************************************/
11
12
13 /**************************************************************************/
14 /**************************************************************************/
15 /** */
16 /** NetX Crypto Component */
17 /** */
18 /** Huge Number */
19 /** */
20 /**************************************************************************/
21 /**************************************************************************/
22
23 #define NX_CRYPTO_SOURCE_CODE
24
25
26 /* Include necessary system files. */
27 #include "stdio.h"
28 #include "nx_crypto.h"
29 #include "nx_crypto_huge_number.h"
30
31 /**************************************************************************/
32 /* */
33 /* FUNCTION RELEASE */
34 /* */
35 /* _nx_crypto_huge_number_is_zero PORTABLE C */
36 /* 6.1 */
37 /* AUTHOR */
38 /* */
39 /* Timothy Stapko, Microsoft Corporation */
40 /* */
41 /* DESCRIPTION */
42 /* */
43 /* This function returns whether number x is zero or not. */
44 /* */
45 /* INPUT */
46 /* */
47 /* x Huge number x */
48 /* */
49 /* OUTPUT */
50 /* */
51 /* Status NX_CRYPTO_TRUE: x is zero */
52 /* NX_CRYPTO_FALSE: x is nonzero */
53 /* */
54 /* CALLS */
55 /* */
56 /* None */
57 /* */
58 /* CALLED BY */
59 /* */
60 /* _nx_crypto_ec_point_is_infinite Check if the point is infinite*/
61 /* _nx_crypto_ec_secp192r1_reduce Reduce the value of curve */
62 /* secp192r1 */
63 /* _nx_crypto_ec_secp224r1_reduce Reduce the value of curve */
64 /* secp224r1 */
65 /* _nx_crypto_ec_secp256r1_reduce Reduce the value of curve */
66 /* secp256r1 */
67 /* _nx_crypto_ec_secp384r1_reduce Reduce the value of curve */
68 /* secp384r1 */
69 /* _nx_crypto_ec_secp521r1_reduce Reduce the value of curve */
70 /* secp521r1 */
71 /* _nx_crypto_huge_number_inverse_modulus */
72 /* Perform an inverse modulus */
73 /* operation */
74 /* _nx_crypto_huge_number_inverse_modulus_prime */
75 /* Perform an inverse modulus */
76 /* operation for prime number */
77 /* */
78 /* RELEASE HISTORY */
79 /* */
80 /* DATE NAME DESCRIPTION */
81 /* */
82 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
83 /* 09-30-2020 Timothy Stapko Modified comment(s), */
84 /* resulting in version 6.1 */
85 /* */
86 /**************************************************************************/
_nx_crypto_huge_number_is_zero(NX_CRYPTO_HUGE_NUMBER * x)87 NX_CRYPTO_KEEP UINT _nx_crypto_huge_number_is_zero(NX_CRYPTO_HUGE_NUMBER *x)
88 {
89 UINT i;
90
91 for (i = 0; i < x -> nx_crypto_huge_number_size; i++)
92 {
93 if (x -> nx_crypto_huge_number_data[i])
94 {
95
96 /* Found one value that is not zero. */
97 return(NX_CRYPTO_FALSE);
98 }
99 }
100
101 /* All values are zero. */
102 return(NX_CRYPTO_TRUE);
103 }
104
105 /**************************************************************************/
106 /* */
107 /* FUNCTION RELEASE */
108 /* */
109 /* _nx_crypto_huge_number_add PORTABLE C */
110 /* 6.1 */
111 /* AUTHOR */
112 /* */
113 /* Timothy Stapko, Microsoft Corporation */
114 /* */
115 /* DESCRIPTION */
116 /* */
117 /* This function calculates addition for huge numbers. */
118 /* */
119 /* Note: Result is stored in left. */
120 /* */
121 /* INPUT */
122 /* */
123 /* left Huge number left */
124 /* right Huge number right */
125 /* */
126 /* OUTPUT */
127 /* */
128 /* None */
129 /* */
130 /* CALLS */
131 /* */
132 /* _nx_crypto_huge_number_add_unsigned Calculate addition for */
133 /* unsigned huge numbers */
134 /* _nx_crypto_huge_number_subtract_unsigned */
135 /* Calculate subtraction for */
136 /* unsigned huge numbers */
137 /* _nx_crypto_huge_number_compare_unsigned */
138 /* Compare two unsigned */
139 /* huge numbers */
140 /* */
141 /* CALLED BY */
142 /* */
143 /* _nx_crypto_ec_secp192r1_reduce Reduce the value of curve */
144 /* secp192r1 */
145 /* _nx_crypto_ec_secp224r1_reduce Reduce the value of curve */
146 /* secp224r1 */
147 /* _nx_crypto_ec_secp256r1_reduce Reduce the value of curve */
148 /* secp256r1 */
149 /* _nx_crypto_ec_secp384r1_reduce Reduce the value of curve */
150 /* secp384r1 */
151 /* _nx_crypto_ec_secp521r1_reduce Reduce the value of curve */
152 /* secp521r1 */
153 /* _nx_crypto_huge_number_modulus Perform a modulus operation */
154 /* _nx_crypto_huge_number_inverse_modulus */
155 /* Perform an inverse modulus */
156 /* operation */
157 /* _nx_crypto_huge_number_inverse_modulus_prime */
158 /* Perform an inverse modulus */
159 /* operation for prime number */
160 /* _nx_crypto_huge_number_crt_power_modulus */
161 /* Raise a huge number for CRT */
162 /* */
163 /* RELEASE HISTORY */
164 /* */
165 /* DATE NAME DESCRIPTION */
166 /* */
167 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
168 /* 09-30-2020 Timothy Stapko Modified comment(s), */
169 /* resulting in version 6.1 */
170 /* */
171 /**************************************************************************/
_nx_crypto_huge_number_add(NX_CRYPTO_HUGE_NUMBER * left,NX_CRYPTO_HUGE_NUMBER * right)172 NX_CRYPTO_KEEP VOID _nx_crypto_huge_number_add(NX_CRYPTO_HUGE_NUMBER *left, NX_CRYPTO_HUGE_NUMBER *right)
173 {
174 UINT cmp;
175
176 cmp = _nx_crypto_huge_number_compare_unsigned(left, right);
177
178 if (left -> nx_crypto_huge_number_is_negative == right -> nx_crypto_huge_number_is_negative)
179 {
180 _nx_crypto_huge_number_add_unsigned(left, right);
181 }
182 else
183 {
184
185 if (cmp == NX_CRYPTO_HUGE_NUMBER_EQUAL)
186 {
187 NX_CRYPTO_HUGE_NUMBER_SET_DIGIT(left, 0);
188 }
189 else if (cmp == NX_CRYPTO_HUGE_NUMBER_LESS)
190 {
191 _nx_crypto_huge_number_subtract_unsigned(right, left, left);
192 left -> nx_crypto_huge_number_is_negative = right -> nx_crypto_huge_number_is_negative;
193 }
194 else
195 {
196 _nx_crypto_huge_number_subtract_unsigned(left, right, left);
197 }
198 }
199 }
200
201 /**************************************************************************/
202 /* */
203 /* FUNCTION RELEASE */
204 /* */
205 /* _nx_crypto_huge_number_subtract PORTABLE C */
206 /* 6.1.10 */
207 /* AUTHOR */
208 /* */
209 /* Timothy Stapko, Microsoft Corporation */
210 /* */
211 /* DESCRIPTION */
212 /* */
213 /* This function calculates subtraction for huge numbers. */
214 /* */
215 /* Note: Result is stored in left. */
216 /* */
217 /* INPUT */
218 /* */
219 /* left Huge number left */
220 /* right Huge number right */
221 /* */
222 /* OUTPUT */
223 /* */
224 /* None */
225 /* */
226 /* CALLS */
227 /* */
228 /* _nx_crypto_huge_number_add_unsigned Calculate addition for */
229 /* unsigned huge numbers */
230 /* _nx_crypto_huge_number_subtract_unsigned */
231 /* Calculate subtraction for */
232 /* unsigned huge numbers */
233 /* _nx_crypto_huge_number_compare_unsigned */
234 /* Compare two unsigned */
235 /* huge numbers */
236 /* */
237 /* CALLED BY */
238 /* */
239 /* Perform Schnorr ZKP generation*/
240 /* _nx_crypto_ec_secp224r1_reduce Reduce the value of curve */
241 /* secp224r1 */
242 /* _nx_crypto_ec_secp256r1_reduce Reduce the value of curve */
243 /* secp256r1 */
244 /* _nx_crypto_ec_secp384r1_reduce Reduce the value of curve */
245 /* secp384r1 */
246 /* _nx_crypto_ecjpake_schnorr_zkp_generate */
247 /* _nx_crypto_huge_number_inverse_modulus */
248 /* Perform an inverse modulus */
249 /* operation */
250 /* _nx_crypto_huge_number_inverse_modulus_prime */
251 /* Perform an inverse modulus */
252 /* operation for prime number */
253 /* _nx_crypto_huge_number_mont Perform Montgomery reduction */
254 /* for multiplication */
255 /* _nx_crypto_huge_number_crt_power_modulus */
256 /* Raise a huge number for CRT */
257 /* */
258 /* RELEASE HISTORY */
259 /* */
260 /* DATE NAME DESCRIPTION */
261 /* */
262 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
263 /* 09-30-2020 Timothy Stapko Modified comment(s), */
264 /* resulting in version 6.1 */
265 /* 01-31-2022 Timothy Stapko Modified comment(s), and */
266 /* improved performance, */
267 /* resulting in version 6.1.10 */
268 /* */
269 /**************************************************************************/
_nx_crypto_huge_number_subtract(NX_CRYPTO_HUGE_NUMBER * left,NX_CRYPTO_HUGE_NUMBER * right)270 NX_CRYPTO_KEEP VOID _nx_crypto_huge_number_subtract(NX_CRYPTO_HUGE_NUMBER *left, NX_CRYPTO_HUGE_NUMBER *right)
271 {
272 UINT cmp;
273
274 cmp = _nx_crypto_huge_number_compare_unsigned(left, right);
275
276 if (left -> nx_crypto_huge_number_is_negative != right -> nx_crypto_huge_number_is_negative)
277 {
278 _nx_crypto_huge_number_add_unsigned(left, right);
279 }
280 else
281 {
282
283 if (cmp == NX_CRYPTO_HUGE_NUMBER_EQUAL)
284 {
285 NX_CRYPTO_HUGE_NUMBER_SET_DIGIT(left, 0);
286 }
287 else if (cmp == NX_CRYPTO_HUGE_NUMBER_LESS)
288 {
289 _nx_crypto_huge_number_subtract_unsigned(right, left, left);
290 left -> nx_crypto_huge_number_is_negative = !(right -> nx_crypto_huge_number_is_negative);
291 }
292 else
293 {
294 _nx_crypto_huge_number_subtract_unsigned(left, right, left);
295 }
296 }
297 }
298
299 /**************************************************************************/
300 /* */
301 /* FUNCTION RELEASE */
302 /* */
303 /* _nx_crypto_huge_number_add_unsigned PORTABLE C */
304 /* 6.1 */
305 /* AUTHOR */
306 /* */
307 /* Timothy Stapko, Microsoft Corporation */
308 /* */
309 /* DESCRIPTION */
310 /* */
311 /* This function calculates addition for unsigned huge numbers. */
312 /* */
313 /* Note: Result is stored in left. */
314 /* */
315 /* INPUT */
316 /* */
317 /* left Huge number left */
318 /* right Huge number right */
319 /* */
320 /* OUTPUT */
321 /* */
322 /* None */
323 /* */
324 /* CALLS */
325 /* */
326 /* None */
327 /* */
328 /* CALLED BY */
329 /* */
330 /* _nx_crypto_ec_add_reduce Perform addition between */
331 /* two huge numbers */
332 /* _nx_crypto_ec_subtract_digit_reduce Perform subtraction between */
333 /* huge number and digit number*/
334 /* _nx_crypto_ec_subtract_reduce Perform subtraction between */
335 /* two huge numbers */
336 /* _nx_crypto_huge_number_add Calculate addition for */
337 /* huge numbers */
338 /* _nx_crypto_huge_number_subtract Calculate subtraction for */
339 /* huge numbers */
340 /* */
341 /* RELEASE HISTORY */
342 /* */
343 /* DATE NAME DESCRIPTION */
344 /* */
345 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
346 /* 09-30-2020 Timothy Stapko Modified comment(s), */
347 /* resulting in version 6.1 */
348 /* */
349 /**************************************************************************/
_nx_crypto_huge_number_add_unsigned(NX_CRYPTO_HUGE_NUMBER * left,NX_CRYPTO_HUGE_NUMBER * right)350 NX_CRYPTO_KEEP VOID _nx_crypto_huge_number_add_unsigned(NX_CRYPTO_HUGE_NUMBER *left, NX_CRYPTO_HUGE_NUMBER *right)
351 {
352 UINT i;
353 HN_UBASE2 product;
354 HN_UBASE *left_buffer;
355 HN_UBASE *right_buffer;
356 HN_UBASE *result_buffer = left -> nx_crypto_huge_number_data;
357 UINT left_size;
358 UINT right_size;
359
360 product = 0;
361
362 /* Make sure the size of left is no less than the size of right. */
363 if (left -> nx_crypto_huge_number_size < right -> nx_crypto_huge_number_size)
364 {
365 left_buffer = right -> nx_crypto_huge_number_data;
366 right_buffer = left -> nx_crypto_huge_number_data;
367 left_size = right -> nx_crypto_huge_number_size;
368 right_size = left -> nx_crypto_huge_number_size;
369 }
370 else
371 {
372 left_buffer = left -> nx_crypto_huge_number_data;
373 right_buffer = right -> nx_crypto_huge_number_data;
374 left_size = left -> nx_crypto_huge_number_size;
375 right_size = right -> nx_crypto_huge_number_size;
376 }
377
378 /* Calculate the result for common length. */
379 for (i = 0; i < right_size; i++)
380 {
381 product = (product >> HN_SHIFT) + left_buffer[i] + right_buffer[i];
382 result_buffer[i] = product & HN_MASK;
383 }
384
385 /* Calculate the carry. */
386 for (; i < left_size; i++)
387 {
388 product = (product >> HN_SHIFT) + left_buffer[i];
389 result_buffer[i] = product & HN_MASK;
390 }
391
392 /* Save or drop the carry? */
393 if ((product >> HN_SHIFT) &&
394 ((i << HN_SIZE_SHIFT) < left -> nx_crypto_huge_buffer_size))
395 {
396
397 /* Save the carry. */
398 result_buffer[i] = 1;
399 left -> nx_crypto_huge_number_size = i + 1;
400 }
401 else
402 {
403 left -> nx_crypto_huge_number_size = i;
404 }
405 }
406
407 /**************************************************************************/
408 /* */
409 /* FUNCTION RELEASE */
410 /* */
411 /* _nx_crypto_huge_number_subtract_unsigned PORTABLE C */
412 /* 6.1 */
413 /* AUTHOR */
414 /* */
415 /* Timothy Stapko, Microsoft Corporation */
416 /* */
417 /* DESCRIPTION */
418 /* */
419 /* This function calculates subtraction for unsigned huge numbers. */
420 /* */
421 /* Note: Left must be no less than right. */
422 /* */
423 /* INPUT */
424 /* */
425 /* left Huge number left */
426 /* right Huge number right */
427 /* result Huge number result */
428 /* */
429 /* OUTPUT */
430 /* */
431 /* None */
432 /* */
433 /* CALLS */
434 /* */
435 /* _nx_crypto_huge_number_adjust_size Adjust the size of a huge */
436 /* number to remove leading */
437 /* zeroes */
438 /* */
439 /* CALLED BY */
440 /* */
441 /* _nx_crypto_huge_number_add Calculate addition for */
442 /* huge numbers */
443 /* _nx_crypto_huge_number_subtract Calculate subtraction for */
444 /* huge numbers */
445 /* */
446 /* RELEASE HISTORY */
447 /* */
448 /* DATE NAME DESCRIPTION */
449 /* */
450 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
451 /* 09-30-2020 Timothy Stapko Modified comment(s), */
452 /* resulting in version 6.1 */
453 /* */
454 /**************************************************************************/
_nx_crypto_huge_number_subtract_unsigned(NX_CRYPTO_HUGE_NUMBER * left,NX_CRYPTO_HUGE_NUMBER * right,NX_CRYPTO_HUGE_NUMBER * result)455 NX_CRYPTO_KEEP VOID _nx_crypto_huge_number_subtract_unsigned(NX_CRYPTO_HUGE_NUMBER *left,
456 NX_CRYPTO_HUGE_NUMBER *right,
457 NX_CRYPTO_HUGE_NUMBER *result)
458 {
459 UINT i;
460 HN_UBASE2 product;
461 HN_UBASE *left_buffer = left -> nx_crypto_huge_number_data;
462 HN_UBASE *right_buffer = right -> nx_crypto_huge_number_data;
463 HN_UBASE *result_buffer = result -> nx_crypto_huge_number_data;
464
465 /* Note, in following loops,
466 * borrow = 1 - (product >> HN_SHIFT) */
467 product = HN_RADIX;
468
469 /* Calculate the result for common length. */
470 for (i = 0; i < right -> nx_crypto_huge_number_size; i++)
471 {
472 product >>= HN_SHIFT;
473 product += (HN_UBASE2)((HN_RADIX - 1) + left_buffer[i] - right_buffer[i]);
474 result_buffer[i] = (product & HN_MASK);
475 }
476
477 /* Calculate the borrow. */
478 for (; i < left -> nx_crypto_huge_number_size; i++)
479 {
480 product >>= HN_SHIFT;
481 product += (HN_UBASE2)((HN_RADIX - 1) + left_buffer[i]);
482 result_buffer[i] = (product & HN_MASK);
483 }
484
485 result -> nx_crypto_huge_number_size = left -> nx_crypto_huge_number_size;
486 _nx_crypto_huge_number_adjust_size(result);
487 }
488
489 /**************************************************************************/
490 /* */
491 /* FUNCTION RELEASE */
492 /* */
493 /* _nx_crypto_huge_number_add_digit_unsigned PORTABLE C */
494 /* 6.1 */
495 /* AUTHOR */
496 /* */
497 /* Timothy Stapko, Microsoft Corporation */
498 /* */
499 /* DESCRIPTION */
500 /* */
501 /* This function calculates addition for unsigned huge number and */
502 /* digit. */
503 /* */
504 /* Note: Result is stored in value. */
505 /* */
506 /* INPUT */
507 /* */
508 /* value Huge number number */
509 /* digit Digit value */
510 /* */
511 /* OUTPUT */
512 /* */
513 /* None */
514 /* */
515 /* CALLS */
516 /* */
517 /* None */
518 /* */
519 /* CALLED BY */
520 /* */
521 /* _nx_crypto_huge_number_add_digit */
522 /* _nx_crypto_huge_number_subtract_digit */
523 /* */
524 /* RELEASE HISTORY */
525 /* */
526 /* DATE NAME DESCRIPTION */
527 /* */
528 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
529 /* 09-30-2020 Timothy Stapko Modified comment(s), */
530 /* resulting in version 6.1 */
531 /* */
532 /**************************************************************************/
_nx_crypto_huge_number_add_digit_unsigned(NX_CRYPTO_HUGE_NUMBER * value,HN_UBASE digit)533 NX_CRYPTO_KEEP VOID _nx_crypto_huge_number_add_digit_unsigned(NX_CRYPTO_HUGE_NUMBER *value, HN_UBASE digit)
534 {
535 UINT i;
536 HN_UBASE2 product;
537 HN_UBASE *buffer = value -> nx_crypto_huge_number_data;
538 UINT size = value -> nx_crypto_huge_number_size;
539
540 product = (HN_UBASE2)buffer[0] + digit;
541 buffer[0] = product & HN_MASK;
542
543 /* Process carry. */
544 for (i = 1; (i < size) && ((product >> HN_SHIFT) != 0); i++)
545 {
546 product = (HN_UBASE)buffer[i] + 1;
547 buffer[i] = product & HN_MASK;
548 }
549
550 /* Save or drop the carry? */
551 if ((product >> HN_SHIFT) && (i == size))
552 {
553 buffer[i] = 1;
554 value -> nx_crypto_huge_number_size = i + 1;
555 }
556 }
557
558 /**************************************************************************/
559 /* */
560 /* FUNCTION RELEASE */
561 /* */
562 /* _nx_crypto_huge_number_subtract_digit_unsigned PORTABLE C */
563 /* 6.1 */
564 /* AUTHOR */
565 /* */
566 /* Timothy Stapko, Microsoft Corporation */
567 /* */
568 /* DESCRIPTION */
569 /* */
570 /* This function calculates subtraction for unsigned huge number and */
571 /* digit. */
572 /* */
573 /* Note: Result is stored in value. Left must be no less than right. */
574 /* */
575 /* INPUT */
576 /* */
577 /* value Huge number number */
578 /* digit Digit value */
579 /* */
580 /* OUTPUT */
581 /* */
582 /* None */
583 /* */
584 /* CALLS */
585 /* */
586 /* _nx_crypto_huge_number_adjust_size Adjust the size of a huge */
587 /* number to remove leading */
588 /* zeroes */
589 /* */
590 /* CALLED BY */
591 /* */
592 /* _nx_crypto_ec_subtract_digit_reduce Perform subtraction between */
593 /* huge number and digit number*/
594 /* _nx_crypto_huge_number_add_digit Calculate addition for */
595 /* huge number and digit */
596 /* _nx_crypto_huge_number_subtract_digit Calculate subtraction for */
597 /* huge number and digit */
598 /* */
599 /* RELEASE HISTORY */
600 /* */
601 /* DATE NAME DESCRIPTION */
602 /* */
603 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
604 /* 09-30-2020 Timothy Stapko Modified comment(s), */
605 /* resulting in version 6.1 */
606 /* */
607 /**************************************************************************/
_nx_crypto_huge_number_subtract_digit_unsigned(NX_CRYPTO_HUGE_NUMBER * value,HN_UBASE digit)608 NX_CRYPTO_KEEP VOID _nx_crypto_huge_number_subtract_digit_unsigned(NX_CRYPTO_HUGE_NUMBER *value, HN_UBASE digit)
609 {
610 UINT i;
611 HN_UBASE2 product;
612 HN_UBASE *buffer = value -> nx_crypto_huge_number_data;
613 UINT size = value -> nx_crypto_huge_number_size;
614
615 product = (HN_UBASE2)(HN_RADIX + buffer[0] - digit);
616 buffer[0] = product & HN_MASK;
617
618 /* Process borrow. */
619 for (i = 1; (i < size) && ((product >> HN_SHIFT) == 0); i++)
620 {
621 product = (HN_UBASE2)(HN_RADIX + (HN_UBASE)buffer[i] - 1);
622 buffer[i] = product & HN_MASK;
623 }
624
625 _nx_crypto_huge_number_adjust_size(value);
626 }
627
628 /**************************************************************************/
629 /* */
630 /* FUNCTION RELEASE */
631 /* */
632 /* _nx_crypto_huge_number_left PORTABLE C */
633 /* 6.1 */
634 /* AUTHOR */
635 /* */
636 /* Timothy Stapko, Microsoft Corporation */
637 /* */
638 /* DESCRIPTION */
639 /* */
640 /* This function shifts left N bits. The shift must be less than */
641 /* the value of HN_SHIFT. */
642 /* */
643 /* INPUT */
644 /* */
645 /* x Huge number x */
646 /* */
647 /* OUTPUT */
648 /* */
649 /* None */
650 /* */
651 /* CALLS */
652 /* */
653 /* None */
654 /* */
655 /* CALLED BY */
656 /* */
657 /* _nx_crypto_ec_secp256r1_reduce Reduce the value of curve */
658 /* secp256r1 */
659 /* _nx_crypto_ec_secp384r1_reduce Reduce the value of curve */
660 /* secp384r1 */
661 /* */
662 /* RELEASE HISTORY */
663 /* */
664 /* DATE NAME DESCRIPTION */
665 /* */
666 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
667 /* 09-30-2020 Timothy Stapko Modified comment(s), */
668 /* resulting in version 6.1 */
669 /* */
670 /**************************************************************************/
_nx_crypto_huge_number_shift_left(NX_CRYPTO_HUGE_NUMBER * x,UINT shift)671 NX_CRYPTO_KEEP VOID _nx_crypto_huge_number_shift_left(NX_CRYPTO_HUGE_NUMBER *x, UINT shift)
672 {
673 UINT i;
674 HN_UBASE *x_buffer = x -> nx_crypto_huge_number_data;
675
676 /* Left shift. */
677 i = x -> nx_crypto_huge_number_size;
678 x_buffer[i] = x_buffer[i - 1] >> (HN_SHIFT - shift);
679 for (i--; i > 0; i--)
680 {
681 x_buffer[i] = (x_buffer[i - 1] >> (HN_SHIFT - shift)) | (x_buffer[i] << shift);
682 }
683 x_buffer[0] <<= shift;
684
685 if (x_buffer[x -> nx_crypto_huge_number_size] != 0)
686 {
687 x -> nx_crypto_huge_number_size++;
688 }
689 }
690
691 /**************************************************************************/
692 /* */
693 /* FUNCTION RELEASE */
694 /* */
695 /* _nx_crypto_huge_number_shift_right PORTABLE C */
696 /* 6.1 */
697 /* AUTHOR */
698 /* */
699 /* Timothy Stapko, Microsoft Corporation */
700 /* */
701 /* DESCRIPTION */
702 /* */
703 /* This function shifts right N bits. The shift must be less than */
704 /* the value of HN_SHIFT. */
705 /* */
706 /* INPUT */
707 /* */
708 /* x Huge number x */
709 /* shift Bits to shift right */
710 /* */
711 /* OUTPUT */
712 /* */
713 /* None */
714 /* */
715 /* CALLS */
716 /* */
717 /* _nx_crypto_huge_number_adjust_size Adjust the size of a huge */
718 /* number to remove leading */
719 /* zeroes */
720 /* */
721 /* CALLED BY */
722 /* */
723 /* _nx_crypto_huge_number_inverse_modulus */
724 /* Perform an inverse modulus */
725 /* operation */
726 /* _nx_crypto_huge_number_inverse_modulus_prime */
727 /* Perform an inverse modulus */
728 /* operation for prime number */
729 /* _nx_crypto_ec_secp521r1_reduce Reduce the value of curve */
730 /* secp521r1 */
731 /* */
732 /* RELEASE HISTORY */
733 /* */
734 /* DATE NAME DESCRIPTION */
735 /* */
736 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
737 /* 09-30-2020 Timothy Stapko Modified comment(s), */
738 /* resulting in version 6.1 */
739 /* */
740 /**************************************************************************/
_nx_crypto_huge_number_shift_right(NX_CRYPTO_HUGE_NUMBER * x,UINT shift)741 NX_CRYPTO_KEEP VOID _nx_crypto_huge_number_shift_right(NX_CRYPTO_HUGE_NUMBER *x, UINT shift)
742 {
743 UINT i;
744 HN_UBASE *x_buffer = x -> nx_crypto_huge_number_data;
745
746 /* Right shift. */
747 for (i = 0; i < x -> nx_crypto_huge_number_size - 1; i++)
748 {
749 x_buffer[i] = (x_buffer[i + 1] << (HN_SHIFT - shift)) | (x_buffer[i] >> shift);
750 }
751 x_buffer[i] >>= shift;
752
753 _nx_crypto_huge_number_adjust_size(x);
754 }
755
756 /**************************************************************************/
757 /* */
758 /* FUNCTION RELEASE */
759 /* */
760 /* _nx_crypto_huge_number_adjust_size PORTABLE C */
761 /* 6.1 */
762 /* AUTHOR */
763 /* */
764 /* Timothy Stapko, Microsoft Corporation */
765 /* */
766 /* DESCRIPTION */
767 /* */
768 /* This function adjusts the size of a huge number to include only */
769 /* those bytes which are actually significant to the value - */
770 /* essentially removing leading zero bytes. */
771 /* */
772 /* INPUT */
773 /* */
774 /* val Pointer to huge number */
775 /* */
776 /* OUTPUT */
777 /* */
778 /* None */
779 /* */
780 /* CALLS */
781 /* */
782 /* None */
783 /* */
784 /* CALLED BY */
785 /* */
786 /* _nx_crypto_huge_number_setup Setup huge number */
787 /* _nx_crypto_huge_number_subtract_unsigned */
788 /* Calculate subtraction for */
789 /* unsigned huge numbers */
790 /* _nx_crypto_huge_number_subtract_digit_unsigned */
791 /* Calculate subtraction for */
792 /* unsigned huge numbers */
793 /* _nx_crypto_huge_number_shift_right Shift right for huge number */
794 /* _nx_crypto_huge_number_multiply Multiply two huge numbers */
795 /* _nx_crypto_huge_number_square Compute the square of a value */
796 /* _nx_crypto_huge_number_mont Perform Montgomery reduction */
797 /* for multiplication */
798 /* _nx_crypto_huge_number_mont_power_modulus */
799 /* Raise a huge number for */
800 /* montgomery reduction */
801 /* RELEASE HISTORY */
802 /* */
803 /* DATE NAME DESCRIPTION */
804 /* */
805 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
806 /* 09-30-2020 Timothy Stapko Modified comment(s), */
807 /* resulting in version 6.1 */
808 /* */
809 /**************************************************************************/
_nx_crypto_huge_number_adjust_size(NX_CRYPTO_HUGE_NUMBER * val)810 NX_CRYPTO_KEEP VOID _nx_crypto_huge_number_adjust_size(NX_CRYPTO_HUGE_NUMBER *val)
811 {
812
813 INT size;
814
815 /* Start at the most significant "digit" and work backwards. */
816 for (size = (INT)(val -> nx_crypto_huge_number_size - 1); size >= 0; size--)
817 {
818 if (val -> nx_crypto_huge_number_data[size] != 0)
819 {
820
821 /* Size is now the index of the last non-zero byte,
822 so the size is one more than that. */
823 val -> nx_crypto_huge_number_size = (UINT)(size + 1);
824 return;
825 }
826 }
827
828 /* The result is zero. */
829 val -> nx_crypto_huge_number_is_negative = NX_CRYPTO_FALSE;
830 val -> nx_crypto_huge_number_size = 1;
831 }
832
833 /**************************************************************************/
834 /* */
835 /* FUNCTION RELEASE */
836 /* */
837 /* _nx_crypto_huge_number_compare PORTABLE C */
838 /* 6.1 */
839 /* AUTHOR */
840 /* */
841 /* Timothy Stapko, Microsoft Corporation */
842 /* */
843 /* DESCRIPTION */
844 /* */
845 /* This function compares two huge numbers and returns equal, less- */
846 /* than, or greater-than. */
847 /* */
848 /* INPUT */
849 /* */
850 /* left First operand */
851 /* right Second operand */
852 /* */
853 /* OUTPUT */
854 /* */
855 /* Result Equal, less-than, greater */
856 /* */
857 /* CALLS */
858 /* */
859 /* _nx_crypto_huge_number_compare_unsigned */
860 /* Compare two unsigned */
861 /* huge numbers */
862 /* */
863 /* CALLED BY */
864 /* */
865 /* _nx_crypto_ec_point_is_infinite Check if the point is infinite*/
866 /* _nx_crypto_ec_secp192r1_reduce Reduce the value of curve */
867 /* secp192r1 */
868 /* _nx_crypto_ec_secp224r1_reduce Reduce the value of curve */
869 /* secp224r1 */
870 /* _nx_crypto_ec_secp256r1_reduce Reduce the value of curve */
871 /* secp256r1 */
872 /* _nx_crypto_ec_secp384r1_reduce Reduce the value of curve */
873 /* secp384r1 */
874 /* _nx_crypto_ec_secp521r1_reduce Reduce the value of curve */
875 /* secp521r1 */
876 /* _nx_crypto_ecjpake_schnorr_zkp_generate */
877 /* Perform Schnorr ZKP generation*/
878 /* _nx_crypto_huge_number_inverse_modulus */
879 /* Perform an inverse modulus */
880 /* operation */
881 /* _nx_crypto_huge_number_inverse_modulus_prime */
882 /* Perform an inverse modulus */
883 /* operation for prime number */
884 /* _nx_crypto_huge_number_mont Perform Montgomery reduction */
885 /* for multiplication */
886 /* */
887 /* RELEASE HISTORY */
888 /* */
889 /* DATE NAME DESCRIPTION */
890 /* */
891 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
892 /* 09-30-2020 Timothy Stapko Modified comment(s), */
893 /* resulting in version 6.1 */
894 /* */
895 /**************************************************************************/
_nx_crypto_huge_number_compare(NX_CRYPTO_HUGE_NUMBER * left,NX_CRYPTO_HUGE_NUMBER * right)896 NX_CRYPTO_KEEP UINT _nx_crypto_huge_number_compare(NX_CRYPTO_HUGE_NUMBER *left, NX_CRYPTO_HUGE_NUMBER *right)
897 {
898 if (left -> nx_crypto_huge_number_is_negative != right -> nx_crypto_huge_number_is_negative)
899 {
900 if (left -> nx_crypto_huge_number_is_negative)
901 {
902 return(NX_CRYPTO_HUGE_NUMBER_LESS);
903 }
904 else
905 {
906 return(NX_CRYPTO_HUGE_NUMBER_GREATER);
907 }
908 }
909
910 if (left -> nx_crypto_huge_number_is_negative)
911 {
912 return(_nx_crypto_huge_number_compare_unsigned(right, left));
913 }
914 else
915 {
916 return(_nx_crypto_huge_number_compare_unsigned(left, right));
917 }
918 }
919
920
921 /**************************************************************************/
922 /* */
923 /* FUNCTION RELEASE */
924 /* */
925 /* _nx_crypto_huge_number_compare_unsigned PORTABLE C */
926 /* 6.1 */
927 /* AUTHOR */
928 /* */
929 /* Timothy Stapko, Microsoft Corporation */
930 /* */
931 /* DESCRIPTION */
932 /* */
933 /* This function compares two huge numbers and returns equal, less- */
934 /* than, or greater-than. Sign is ignored. Results are in relation to */
935 /* the first operand (e.g. left > right returns greater-than). The */
936 /* algorithm properly handles leading zeroes so operands with different*/
937 /* buffer sizes are handled properly. */
938 /* */
939 /* The shift component is a specialty optimization for the fast */
940 /* modulus routine (_nx_crypto_huge_number_modulus). */
941 /* */
942 /* INPUT */
943 /* */
944 /* left First operand */
945 /* right Second operand */
946 /* */
947 /* OUTPUT */
948 /* */
949 /* Result Equal, less-than, greater */
950 /* */
951 /* CALLS */
952 /* */
953 /* None */
954 /* */
955 /* CALLED BY */
956 /* */
957 /* _nx_crypto_ec_add_digit_reduce Perform addition between huge */
958 /* number and digit number */
959 /* _nx_crypto_ec_add_reduce Perform addition between */
960 /* two huge numbers */
961 /* _nx_crypto_ec_secp192r1_reduce Reduce the value of curve */
962 /* secp192r1 */
963 /* _nx_crypto_ec_secp224r1_reduce Reduce the value of curve */
964 /* secp224r1 */
965 /* _nx_crypto_ec_secp256r1_reduce Reduce the value of curve */
966 /* secp256r1 */
967 /* _nx_crypto_ec_secp384r1_reduce Reduce the value of curve */
968 /* secp384r1 */
969 /* _nx_crypto_ec_secp521r1_reduce Reduce the value of curve */
970 /* secp521r1 */
971 /* _nx_crypto_huge_number_add Calculate addition for */
972 /* huge numbers */
973 /* _nx_crypto_huge_number_subtract Calculate subtraction for */
974 /* huge numbers */
975 /* _nx_crypto_huge_number_compare Compare two huge numbers */
976 /* _nx_crypto_huge_number_modulus Perform a modulus operation */
977 /* */
978 /* RELEASE HISTORY */
979 /* */
980 /* DATE NAME DESCRIPTION */
981 /* */
982 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
983 /* 09-30-2020 Timothy Stapko Modified comment(s), */
984 /* resulting in version 6.1 */
985 /* */
986 /**************************************************************************/
_nx_crypto_huge_number_compare_unsigned(NX_CRYPTO_HUGE_NUMBER * left,NX_CRYPTO_HUGE_NUMBER * right)987 NX_CRYPTO_KEEP UINT _nx_crypto_huge_number_compare_unsigned(NX_CRYPTO_HUGE_NUMBER *left,
988 NX_CRYPTO_HUGE_NUMBER *right)
989 {
990
991 INT i;
992 UINT left_size;
993 UINT right_size;
994
995 left_size = left -> nx_crypto_huge_number_size;
996 right_size = right -> nx_crypto_huge_number_size;
997
998 /* Adjust the size for zero at the front. */
999 while (left_size && (left -> nx_crypto_huge_number_data[left_size - 1] == 0))
1000 {
1001 left_size--;
1002 }
1003 while (right_size && (right -> nx_crypto_huge_number_data[right_size - 1] == 0))
1004 {
1005 right_size--;
1006 }
1007
1008 if (left_size > right_size)
1009 {
1010 return(NX_CRYPTO_HUGE_NUMBER_GREATER);
1011 }
1012 if (right_size > left_size)
1013 {
1014 return(NX_CRYPTO_HUGE_NUMBER_LESS);
1015 }
1016
1017 /* Keep comparing bytes while they are equal and we have indexes left. */
1018 for (i = (INT)left_size - 1; i >= 0; i--)
1019 {
1020 if (left -> nx_crypto_huge_number_data[i] > right -> nx_crypto_huge_number_data[i])
1021 {
1022 return(NX_CRYPTO_HUGE_NUMBER_GREATER);
1023 }
1024 else if (right -> nx_crypto_huge_number_data[i] > left -> nx_crypto_huge_number_data[i])
1025 {
1026 return(NX_CRYPTO_HUGE_NUMBER_LESS);
1027 }
1028 }
1029
1030 /* If we reach here, the numbers are equal. */
1031 return(NX_CRYPTO_HUGE_NUMBER_EQUAL);
1032 }
1033
1034
1035 /**************************************************************************/
1036 /* */
1037 /* FUNCTION RELEASE */
1038 /* */
1039 /* _nx_crypto_huge_number_multiply PORTABLE C */
1040 /* 6.1 */
1041 /* AUTHOR */
1042 /* */
1043 /* Timothy Stapko, Microsoft Corporation */
1044 /* */
1045 /* DESCRIPTION */
1046 /* */
1047 /* This function multiplies two huge numbers and places the result */
1048 /* in the result buffer which must be large enough to hold the */
1049 /* resulting value. */
1050 /* */
1051 /* INPUT */
1052 /* */
1053 /* left First operand */
1054 /* right Second operand */
1055 /* result Result */
1056 /* */
1057 /* OUTPUT */
1058 /* */
1059 /* Status Operation result status */
1060 /* */
1061 /* CALLS */
1062 /* */
1063 /* _nx_crypto_huge_number_adjust_size Adjust the size of a huge */
1064 /* number to remove leading */
1065 /* zeroes */
1066 /* */
1067 /* CALLED BY */
1068 /* */
1069 /* _nx_crypto_ecjpake_public_key_generate */
1070 /* Perform public key generation */
1071 /* _nx_crypto_ecjpake_schnorr_zkp_generate */
1072 /* Perform Schnorr ZKP generation*/
1073 /* _nx_crypto_huge_number_power_modulus Raise a huge number */
1074 /* _nx_crypto_huge_number_crt_power_modulus */
1075 /* Raise a huge number for CRT */
1076 /* */
1077 /* RELEASE HISTORY */
1078 /* */
1079 /* DATE NAME DESCRIPTION */
1080 /* */
1081 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
1082 /* 09-30-2020 Timothy Stapko Modified comment(s), */
1083 /* resulting in version 6.1 */
1084 /* */
1085 /**************************************************************************/
_nx_crypto_huge_number_multiply(NX_CRYPTO_HUGE_NUMBER * left,NX_CRYPTO_HUGE_NUMBER * right,NX_CRYPTO_HUGE_NUMBER * result)1086 NX_CRYPTO_KEEP VOID _nx_crypto_huge_number_multiply(NX_CRYPTO_HUGE_NUMBER *left,
1087 NX_CRYPTO_HUGE_NUMBER *right,
1088 NX_CRYPTO_HUGE_NUMBER *result)
1089 {
1090
1091 UINT index, right_index; /* Loop variables */
1092 HN_UBASE *left_buffer, *right_buffer;
1093 HN_UBASE2 product;
1094 UINT left_size, right_size;
1095 HN_UBASE *result_buffer;
1096 HN_UBASE *temp_ptr;
1097
1098 left_size = left -> nx_crypto_huge_number_size;
1099 right_size = right -> nx_crypto_huge_number_size;
1100 left_buffer = left -> nx_crypto_huge_number_data;
1101 right_buffer = right -> nx_crypto_huge_number_data;
1102
1103 /* The temp buffer serves as "buckets". During each itegration, the products of two digits are accumucated into
1104 this buckets. Since each "digit" is 16-bit, by using 32-bit buckets, the carry can be accumulated in to the
1105 top 16-bits of the bucket. Therefore, we don't need to worry about "carry" bit during each iteration. */
1106
1107 result_buffer = result -> nx_crypto_huge_number_data;
1108 result -> nx_crypto_huge_number_size = (left_size + right_size);
1109
1110 /* Zero out the buckets since we are going to accumulate "digits" there. */
1111 NX_CRYPTO_MEMSET(result_buffer, 0, (left_size + right_size) << HN_SIZE_SHIFT);
1112
1113 /* Loop over the operands, grabbing a "digit" at a time and calculating the product accounting for carry. */
1114 for (index = 0; index < left_size; ++index)
1115 {
1116
1117 /* If the "digit" on the left is zero, there is no need to loop through the "digits" on the right. */
1118 if (left_buffer[index] == 0)
1119 {
1120 /* Yes the digit ont he left is zero. Continue to the next iteration. */
1121 continue;
1122 }
1123
1124 product = 0;
1125 temp_ptr = result_buffer + index;
1126 for (right_index = 0; right_index < right_size; ++right_index, ++temp_ptr)
1127 {
1128 /* Multiple "digit" from the left with the one the left. */
1129 product >>= HN_SHIFT;
1130 product += (HN_UBASE2)left_buffer[index] * (HN_UBASE2)right_buffer[right_index] + *temp_ptr;
1131
1132 /* The result (in product) could be two parts: the top digit the the lower digit. */
1133 /* Accumulate the lower digit into the "bucket" and the top digit to the next "bucket". */
1134 *temp_ptr = (product & HN_MASK);
1135 }
1136 *temp_ptr = (HN_UBASE)((product >> HN_SHIFT));
1137 }
1138
1139 /* Set is_negative. */
1140 if (left -> nx_crypto_huge_number_is_negative == right -> nx_crypto_huge_number_is_negative)
1141 {
1142 result -> nx_crypto_huge_number_is_negative = NX_CRYPTO_FALSE;
1143 }
1144 else
1145 {
1146 result -> nx_crypto_huge_number_is_negative = NX_CRYPTO_TRUE;
1147 }
1148
1149 _nx_crypto_huge_number_adjust_size(result);
1150
1151 return;
1152 }
1153
1154 /**************************************************************************/
1155 /* */
1156 /* FUNCTION RELEASE */
1157 /* */
1158 /* _nx_crypto_huge_number_multiply_digit PORTABLE C */
1159 /* 6.1 */
1160 /* AUTHOR */
1161 /* */
1162 /* Timothy Stapko, Microsoft Corporation */
1163 /* */
1164 /* DESCRIPTION */
1165 /* */
1166 /* This function multiplies huge number with digit and replace the */
1167 /* result in the result buffer which must be large enough to hold the */
1168 /* resulting value. */
1169 /* */
1170 /* INPUT */
1171 /* */
1172 /* value Huge number number */
1173 /* digit Digit value */
1174 /* result Result */
1175 /* */
1176 /* OUTPUT */
1177 /* */
1178 /* Status Operation result status */
1179 /* */
1180 /* CALLS */
1181 /* */
1182 /* None */
1183 /* */
1184 /* CALLED BY */
1185 /* */
1186 /* Application Code */
1187 /* */
1188 /* RELEASE HISTORY */
1189 /* */
1190 /* DATE NAME DESCRIPTION */
1191 /* */
1192 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
1193 /* 09-30-2020 Timothy Stapko Modified comment(s), */
1194 /* resulting in version 6.1 */
1195 /* */
1196 /**************************************************************************/
_nx_crypto_huge_number_multiply_digit(NX_CRYPTO_HUGE_NUMBER * value,HN_UBASE digit,NX_CRYPTO_HUGE_NUMBER * result)1197 NX_CRYPTO_KEEP VOID _nx_crypto_huge_number_multiply_digit(NX_CRYPTO_HUGE_NUMBER *value,
1198 HN_UBASE digit,
1199 NX_CRYPTO_HUGE_NUMBER *result)
1200 {
1201
1202 UINT i;
1203 UINT size;
1204 HN_UBASE2 product;
1205 HN_UBASE *value_buffer;
1206 HN_UBASE *result_buffer;
1207
1208 if (digit == 0)
1209 {
1210 result -> nx_crypto_huge_number_data[0] = 0;
1211 result -> nx_crypto_huge_number_size = 1;
1212 result -> nx_crypto_huge_number_is_negative = NX_CRYPTO_FALSE;
1213 return;
1214 }
1215
1216 size = value -> nx_crypto_huge_number_size;
1217 value_buffer = value -> nx_crypto_huge_number_data;
1218 result_buffer = result -> nx_crypto_huge_number_data;
1219
1220 /* Loop over the operands, grabbing a "digit" at a time and calculating the product accounting for carry. */
1221 product = 0;
1222 for (i = 0; i < size; i++)
1223 {
1224 product >>= HN_SHIFT;
1225 product += (HN_UBASE2)value_buffer[i] * digit;
1226 result_buffer[i] = (product & HN_MASK);
1227 }
1228 if ((product >> HN_SHIFT) != 0)
1229 {
1230 result -> nx_crypto_huge_number_size = value -> nx_crypto_huge_number_size + 1;
1231 result_buffer[i] = (HN_UBASE)(product >> HN_SHIFT);
1232 }
1233 else
1234 {
1235 result -> nx_crypto_huge_number_size = value -> nx_crypto_huge_number_size;
1236 }
1237 result -> nx_crypto_huge_number_is_negative = value -> nx_crypto_huge_number_is_negative;
1238
1239 return;
1240 }
1241
1242 /**************************************************************************/
1243 /* */
1244 /* FUNCTION RELEASE */
1245 /* */
1246 /* _nx_crypto_huge_number_square PORTABLE C */
1247 /* 6.1 */
1248 /* AUTHOR */
1249 /* */
1250 /* Timothy Stapko, Microsoft Corporation */
1251 /* */
1252 /* DESCRIPTION */
1253 /* */
1254 /* This function computes the square of a value, and places the */
1255 /* result in the result buffer. The value buffer must be large enough */
1256 /* to hold the computed result. */
1257 /* */
1258 /* INPUT */
1259 /* */
1260 /* value Value buffer */
1261 /* result Result buffer */
1262 /* */
1263 /* OUTPUT */
1264 /* */
1265 /* None */
1266 /* */
1267 /* CALLS */
1268 /* */
1269 /* _nx_crypto_huge_number_adjust_size Adjust the size of a huge */
1270 /* number to remove leading */
1271 /* zeroes */
1272 /* */
1273 /* CALLED BY */
1274 /* */
1275 /* _nx_crypto_huge_number_power_modulus Raise a huge number */
1276 /* _nx_crypto_huge_number_mont_power_modulus */
1277 /* Raise a huge number for */
1278 /* montgomery reduction */
1279 /* */
1280 /* RELEASE HISTORY */
1281 /* */
1282 /* DATE NAME DESCRIPTION */
1283 /* */
1284 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
1285 /* 09-30-2020 Timothy Stapko Modified comment(s), */
1286 /* resulting in version 6.1 */
1287 /* */
1288 /**************************************************************************/
_nx_crypto_huge_number_square(NX_CRYPTO_HUGE_NUMBER * value,NX_CRYPTO_HUGE_NUMBER * result)1289 NX_CRYPTO_KEEP VOID _nx_crypto_huge_number_square(NX_CRYPTO_HUGE_NUMBER *value, NX_CRYPTO_HUGE_NUMBER *result)
1290 {
1291 HN_UBASE2 product;
1292 UINT value_size;
1293 UINT result_size;
1294 HN_UBASE *value_buffer;
1295 HN_UBASE *result_buffer;
1296 UINT i, j;
1297
1298 /* Using Yang et al.'s squaring algorithm. */
1299 value_size = value -> nx_crypto_huge_number_size;
1300 result_size = (value_size << 1);
1301 result -> nx_crypto_huge_number_size = result_size;
1302 value_buffer = value -> nx_crypto_huge_number_data;
1303 result_buffer = result -> nx_crypto_huge_number_data;
1304
1305 NX_CRYPTO_MEMSET(result_buffer, 0, result_size << HN_SIZE_SHIFT);
1306
1307 for (i = 0; i < value_size; i++)
1308 {
1309 product = 0;
1310 for (j = i + 1; j < value_size; j++)
1311 {
1312 product >>= HN_SHIFT;
1313 product += result_buffer[i + j] + (HN_UBASE2)value_buffer[i] * value_buffer[j];
1314 result_buffer[i + j] = product & HN_MASK;
1315 }
1316 result_buffer[i + j] = (HN_UBASE)(product >> HN_SHIFT);
1317 }
1318
1319 for (i = result_size - 1; i > 0; i--)
1320 {
1321 result_buffer[i] = (result_buffer[i] << 1) | (result_buffer[i - 1] >> (HN_SHIFT - 1));
1322 }
1323 result_buffer[0] <<= 1;
1324
1325 product = 0;
1326 for (i = 0; i < value_size; i++)
1327 {
1328 product >>= HN_SHIFT;
1329 product += result_buffer[i << 1] + (HN_UBASE2)value_buffer[i] * value_buffer[i];
1330 result_buffer[i << 1] = product & HN_MASK;
1331 product >>= HN_SHIFT;
1332 product += result_buffer[(i << 1) + 1];
1333 result_buffer[(i << 1) + 1] = product & HN_MASK;
1334 }
1335
1336 result -> nx_crypto_huge_number_is_negative = NX_CRYPTO_FALSE;
1337 _nx_crypto_huge_number_adjust_size(result);
1338 }
1339
1340 /**************************************************************************/
1341 /* */
1342 /* FUNCTION RELEASE */
1343 /* */
1344 /* _nx_crypto_huge_number_modulus PORTABLE C */
1345 /* 6.1.11 */
1346 /* AUTHOR */
1347 /* */
1348 /* Timothy Stapko, Microsoft Corporation */
1349 /* */
1350 /* DESCRIPTION */
1351 /* */
1352 /* This function performs a modulus operation on the dividend and */
1353 /* divisor operands and places the remainder in the dividend buffer. */
1354 /* */
1355 /* The algorithm uses a digit-based division, with a 16-bit short */
1356 /* as a "digit". */
1357 /* */
1358 /* NORE: The dividend operand is destroyed during the operation. */
1359 /* The divisor is preserved. No additional scratch buffer */
1360 /* required during this operation. */
1361 /* */
1362 /* */
1363 /* INPUT */
1364 /* */
1365 /* dividend First operand */
1366 /* divisor Second operand */
1367 /* */
1368 /* OUTPUT */
1369 /* */
1370 /* None */
1371 /* */
1372 /* CALLS */
1373 /* */
1374 /* _nx_crypto_huge_number_compare_unsigned */
1375 /* Compare two unsigned */
1376 /* huge numbers */
1377 /* _nx_crypto_huge_number_add Calculate addition for */
1378 /* huge numbers */
1379 /* */
1380 /* CALLED BY */
1381 /* */
1382 /* _nx_crypto_ec_fp_reduce Reduce huge number for */
1383 /* common prime field */
1384 /* _nx_crypto_ecjpake_key_exchange_generate */
1385 /* Generate key exchange message */
1386 /* _nx_crypto_ecjpake_key_exchange_process */
1387 /* Process key exchange message */
1388 /* _nx_crypto_ecjpake_public_key_generate */
1389 /* Perform public key generation */
1390 /* _nx_crypto_ecjpake_schnorr_zkp_generate */
1391 /* Perform Schnorr ZKP generation*/
1392 /* _nx_crypto_ecjpake_schnorr_zkp_hash Perform Schnorr ZKP hash */
1393 /* calculation */
1394 /* _nx_crypto_huge_number_power_modulus Raise a huge number */
1395 /* _nx_crypto_huge_number_inverse_modulus */
1396 /* Perform an inverse modulus */
1397 /* operation */
1398 /* _nx_crypto_huge_number_inverse_modulus_prime */
1399 /* Perform an inverse modulus */
1400 /* operation for prime number */
1401 /* _nx_crypto_huge_number_mont_power_modulus */
1402 /* Raise a huge number for */
1403 /* montgomery reduction */
1404 /* _nx_crypto_huge_number_crt_power_modulus */
1405 /* Raise a huge number for CRT */
1406 /* */
1407 /* RELEASE HISTORY */
1408 /* */
1409 /* DATE NAME DESCRIPTION */
1410 /* */
1411 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
1412 /* 09-30-2020 Timothy Stapko Modified comment(s), and */
1413 /* fixed variable type issue, */
1414 /* resulting in version 6.1 */
1415 /* 04-25-2022 Yuxin Zhou Modified comment(s), */
1416 /* fixed division by zero bug, */
1417 /* resulting in version 6.1.11 */
1418 /* */
1419 /**************************************************************************/
_nx_crypto_huge_number_modulus(NX_CRYPTO_HUGE_NUMBER * dividend,NX_CRYPTO_HUGE_NUMBER * divisor)1420 NX_CRYPTO_KEEP VOID _nx_crypto_huge_number_modulus(NX_CRYPTO_HUGE_NUMBER *dividend, NX_CRYPTO_HUGE_NUMBER *divisor)
1421 {
1422 UINT result_length, divisor_length; /* In number of USHORT words. */
1423 UINT compare_value;
1424 UINT i;
1425 UINT shift; /* In number of USHORT words. */
1426 HN_UBASE *result_buffer, *divisor_buffer;
1427 HN_UBASE2 scale;
1428 HN_UBASE divisor_msb;
1429 HN_UBASE dividend_msb;
1430 HN_UBASE2 product;
1431 HN_UBASE2 value, carry;
1432 HN_UBASE borrow;
1433 UINT index;
1434 NX_CRYPTO_HUGE_NUMBER *result;
1435
1436
1437 /* The algorithm used here is an implementation of the traditional long division.
1438 One 16-bit unsigned integer is treated as a "digit". It starts with the 2 most-significant digits
1439 of the dividend and the most significant digit of the divisor to come up with an estimate of a scale value. After
1440 subtracting the product of the scale and divisor.
1441
1442 To prevent the scale value from being too big, we also look into the second digit of the divisor.
1443 If the 2nd digit is greater or equal to 0x80, the scale value is reduced.
1444
1445 scale
1446 ____________________________
1447 BBbbxxxx )AAAAxxxxxxxxxxxxxxxxxx
1448 / CCCCxxxxxx
1449
1450 In the figure above, AAAA (dividend_msb) is the top 2 digits picked up from the dividend.
1451 BB isthe top digit picked up from the divisor. To prevent overflow, the next digit bb is
1452 examined. If bb equals or is greater than 0x80, BB is incremented by 1, effectively reducing
1453 the scale.
1454
1455 Then dividend subtracts the product of divisor and scale (with a left "shift").
1456
1457 keep going through this operation till the remainder is less than the divisor.
1458 */
1459
1460 /* Copy dividend into result */
1461 result = dividend;
1462
1463 /* If the dividend is smaller than the divisor, the remainder is simply the dividend so we are done. */
1464 compare_value = _nx_crypto_huge_number_compare_unsigned(result, divisor);
1465 if (compare_value == NX_CRYPTO_HUGE_NUMBER_LESS)
1466 {
1467 if (result -> nx_crypto_huge_number_is_negative)
1468 {
1469 _nx_crypto_huge_number_add(result, divisor);
1470 }
1471 return;
1472 }
1473
1474 /* Get divisor_length and result_legnth, which are converted to number of USHORT */
1475 divisor_length = divisor -> nx_crypto_huge_number_size - 1;
1476 result_length = result -> nx_crypto_huge_number_size - 1;
1477
1478 /* Get local pointers into our buffers for easier reading. */
1479 result_buffer = result -> nx_crypto_huge_number_data;
1480 divisor_buffer = divisor -> nx_crypto_huge_number_data;
1481
1482 // divisor_buffer[divisor_length + 1] = 0;
1483
1484 /* First, obtain our divisor_msb value. */
1485 while (divisor_buffer[divisor_length] == 0)
1486 {
1487 divisor_length--;
1488 }
1489 divisor_msb = divisor_buffer[divisor_length] >> (HN_SHIFT >> 1);
1490
1491
1492 divisor_msb++;
1493
1494 /* Going through the scale/subtraction loop till the dividend is less than
1495 divisor. At this point the value in the dividend buffer is the remainder. */
1496
1497 /* Obtain reuslt_length */
1498 result_length = result -> nx_crypto_huge_number_size - 1;
1499 while (compare_value != NX_CRYPTO_HUGE_NUMBER_LESS)
1500 {
1501 dividend_msb = result_buffer[result_length] >> (HN_SHIFT >> 1);
1502 shift = result_length - divisor_length;
1503
1504 if (shift && (dividend_msb < divisor_msb))
1505 {
1506 dividend_msb = result_buffer[result_length];
1507 shift--;
1508
1509 if (dividend_msb < divisor_msb)
1510 {
1511 dividend_msb = (result_buffer[result_length] << (HN_SHIFT >> 1)) |
1512 (result_buffer[result_length - 1] >> (HN_SHIFT >> 1));
1513 scale = dividend_msb / divisor_msb;
1514 }
1515 else
1516 {
1517 scale = ((HN_UBASE2)(dividend_msb / divisor_msb)) << (HN_SHIFT >> 1);
1518 }
1519 }
1520 else if (shift)
1521 {
1522 scale = dividend_msb / divisor_msb;
1523 }
1524 else
1525 {
1526 scale = result_buffer[result_length] / ((HN_UBASE2)divisor_buffer[divisor_length] + 1);
1527 if (scale == 0)
1528 {
1529 scale = 1;
1530 }
1531 }
1532
1533
1534 carry = 0;
1535 borrow = 0;
1536 i = 0;
1537
1538 for (index = shift; index < result_length; index++)
1539 {
1540 product = divisor_buffer[i] * scale;
1541 product += carry;
1542
1543 carry = product >> HN_SHIFT; /* The carry bits used for the next itegration. */
1544
1545 value = result_buffer[index] + (HN_UBASE2)(HN_BASE)borrow;
1546 value = value - (product & HN_MASK);
1547
1548 borrow = (HN_UBASE)(value >> HN_SHIFT); /* The borrow bit used for the next itegration. */
1549
1550 result_buffer[index] = (HN_UBASE)(value & HN_MASK);
1551
1552 i++;
1553 }
1554
1555 if (i <= divisor_length)
1556 {
1557 product = divisor_buffer[i] * scale + carry;
1558 }
1559 else
1560 {
1561 product = carry;
1562 }
1563
1564 value = result_buffer[index] + (HN_UBASE2)(HN_BASE)borrow;
1565 value = value - (product & HN_MASK);
1566
1567 borrow = (HN_UBASE)(value >> HN_SHIFT); /* The borrow bit used for the next itegration. */
1568
1569 result_buffer[index] = (HN_UBASE)(value & HN_MASK);
1570
1571 while ((index > 0) && (result_buffer[index] == 0))
1572 {
1573 index--;
1574 }
1575 result_length = index;
1576
1577 result -> nx_crypto_huge_number_size = index + 1;
1578 if (result_length <= divisor_length)
1579 {
1580
1581 compare_value = _nx_crypto_huge_number_compare_unsigned(result, divisor);
1582 }
1583 }
1584
1585 if (result -> nx_crypto_huge_number_is_negative)
1586 {
1587 _nx_crypto_huge_number_add(result, divisor);
1588 }
1589 return;
1590 }
1591
1592 /**************************************************************************/
1593 /* */
1594 /* FUNCTION RELEASE */
1595 /* */
1596 /* _nx_crypto_huge_number_setup PORTABLE C */
1597 /* 6.1 */
1598 /* AUTHOR */
1599 /* */
1600 /* Timothy Stapko, Microsoft Corporation */
1601 /* */
1602 /* DESCRIPTION */
1603 /* */
1604 /* This function raises a huge number to the power of a second huge */
1605 /* number using a third huge number as a modulus. The result is placed */
1606 /* in a fourth huge number. */
1607 /* */
1608 /* NOTE: This function makes use of the Huge Number scratch buffers. */
1609 /* Each operand and the result must have the */
1610 /* nx_crypto_huge_number_scratch member set to point to a buffer */
1611 /* of size equal to the number data buffer and that size stored */
1612 /* in the nx_crypto_huge_buffer_size member. */
1613 /* INPUT */
1614 /* */
1615 /* number Number being exponentiated */
1616 /* exponent Exponent number */
1617 /* modulus Modulus number */
1618 /* result Result buffer */
1619 /* */
1620 /* OUTPUT */
1621 /* */
1622 /* Status Operation result status */
1623 /* */
1624 /* CALLS */
1625 /* */
1626 /* None */
1627 /* */
1628 /* CALLED BY */
1629 /* */
1630 /* _nx_crypto_dh_compute_secret Computes the Diffie-Hellman */
1631 /* shared secret */
1632 /* _nx_crypto_ec_point_setup Set up point from byte steam */
1633 /* _nx_crypto_ec_secp192r1_reduce Reduce the value of curve */
1634 /* secp192r1 */
1635 /* _nx_crypto_ec_secp224r1_reduce Reduce the value of curve */
1636 /* secp224r1 */
1637 /* _nx_crypto_ec_secp256r1_reduce Reduce the value of curve */
1638 /* secp256r1 */
1639 /* _nx_crypto_ec_secp384r1_reduce Reduce the value of curve */
1640 /* secp384r1 */
1641 /* _nx_crypto_ec_secp521r1_reduce Reduce the value of curve */
1642 /* secp521r1 */
1643 /* _nx_crypto_ecjpake_hello_process Process hello message */
1644 /* _nx_crypto_ecjpake_key_exchange_generate */
1645 /* Generate key exchange message */
1646 /* _nx_crypto_ecjpake_key_exchange_process */
1647 /* Process key exchange message */
1648 /* _nx_crypto_ecjpake_schnorr_zkp_hash Perform Schnorr ZKP hash */
1649 /* calculation */
1650 /* _nx_crypto_rsa_operation Perform an RSA operation */
1651 /* */
1652 /* RELEASE HISTORY */
1653 /* */
1654 /* DATE NAME DESCRIPTION */
1655 /* */
1656 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
1657 /* 09-30-2020 Timothy Stapko Modified comment(s), */
1658 /* resulting in version 6.1 */
1659 /* */
1660 /**************************************************************************/
_nx_crypto_huge_number_setup(NX_CRYPTO_HUGE_NUMBER * number,const UCHAR * byte_stream,UINT size)1661 NX_CRYPTO_KEEP UINT _nx_crypto_huge_number_setup(NX_CRYPTO_HUGE_NUMBER *number, const UCHAR *byte_stream, UINT size)
1662 {
1663
1664 UINT i = 0;
1665 HN_UBASE *destination;
1666 HN_UBASE word;
1667 UINT num_words;
1668
1669 /* Remove leading zeros in the byte stream. */
1670 while (size > 0 && *byte_stream == 0)
1671 {
1672 size--;
1673 byte_stream++;
1674 }
1675
1676 /* Handle the case when the huge number is zero. */
1677 if (size == 0)
1678 {
1679 if (number -> nx_crypto_huge_buffer_size < sizeof(HN_UBASE))
1680 {
1681 return(NX_CRYPTO_SIZE_ERROR);
1682 }
1683
1684 number -> nx_crypto_huge_number_data[0] = 0;
1685 number -> nx_crypto_huge_number_size = 1;
1686 number -> nx_crypto_huge_number_is_negative = NX_CRYPTO_FALSE;
1687
1688 return(NX_CRYPTO_SUCCESS);
1689 }
1690
1691 num_words = (size + HN_SIZE_ROUND) >> HN_SIZE_SHIFT;
1692
1693 /* Make sure the huge number buffer size is large enough to hold the value. */
1694 if (number -> nx_crypto_huge_buffer_size < (num_words << HN_SIZE_SHIFT))
1695 {
1696 return(NX_CRYPTO_SIZE_ERROR);
1697 }
1698
1699 destination = number -> nx_crypto_huge_number_data + num_words - 1;
1700
1701
1702 if (size & HN_SIZE_ROUND)
1703 {
1704 #if (NX_CRYPTO_HUGE_NUMBER_BITS == 16)
1705 word = byte_stream[0];
1706 i++;
1707 #else /* NX_CRYPTO_HUGE_NUMBER_BITS == 32 */
1708 if ((size & HN_SIZE_ROUND) == 1)
1709 {
1710 word = byte_stream[0];
1711 i++;
1712 }
1713 else if ((size & HN_SIZE_ROUND) == 2)
1714 {
1715 word = (HN_UBASE)((byte_stream[0] << 8) | byte_stream[1]);
1716 i += 2;
1717 }
1718 else
1719 {
1720 word = (HN_UBASE)((byte_stream[0] << 16) | (byte_stream[1] << 8) | byte_stream[2]);
1721 i += 3;
1722 }
1723 #endif
1724 *destination = word;
1725 destination--;
1726 }
1727
1728 for (; i < size; i += sizeof(HN_UBASE))
1729 {
1730 #if (NX_CRYPTO_HUGE_NUMBER_BITS == 16)
1731 word = (HN_UBASE)((byte_stream[i] << 8) | (byte_stream[i + 1]));
1732 #else /* NX_CRYPTO_HUGE_NUMBER_BITS == 32 */
1733 word = (HN_UBASE)((byte_stream[i] << 24) |
1734 (byte_stream[i + 1] << 16) |
1735 (byte_stream[i + 2] << 8) |
1736 (byte_stream[i + 3]));
1737 #endif
1738 *destination = word;
1739 destination--;
1740 }
1741
1742 number -> nx_crypto_huge_number_size = num_words;
1743 number -> nx_crypto_huge_number_is_negative = NX_CRYPTO_FALSE;
1744
1745 return(NX_CRYPTO_SUCCESS);
1746 }
1747
1748 /**************************************************************************/
1749 /* */
1750 /* FUNCTION RELEASE */
1751 /* */
1752 /* _nx_crypto_huge_number_rbg PORTABLE C */
1753 /* 6.1 */
1754 /* AUTHOR */
1755 /* */
1756 /* Timothy Stapko, Microsoft Corporation */
1757 /* */
1758 /* DESCRIPTION */
1759 /* */
1760 /* This function generates random huge number with specified bits. */
1761 /* The result buffer must be large enough to hold random huge number. */
1762 /* */
1763 /* INPUT */
1764 /* */
1765 /* bits Random number bits */
1766 /* result Pointer to random number */
1767 /* */
1768 /* OUTPUT */
1769 /* */
1770 /* None */
1771 /* */
1772 /* CALLS */
1773 /* */
1774 /* None */
1775 /* */
1776 /* CALLED BY */
1777 /* */
1778 /* Application */
1779 /* */
1780 /* RELEASE HISTORY */
1781 /* */
1782 /* DATE NAME DESCRIPTION */
1783 /* */
1784 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
1785 /* 09-30-2020 Timothy Stapko Modified comment(s), */
1786 /* resulting in version 6.1 */
1787 /* */
1788 /**************************************************************************/
_nx_crypto_huge_number_rbg(UINT bits,UCHAR * result)1789 NX_CRYPTO_KEEP UINT _nx_crypto_huge_number_rbg(UINT bits, UCHAR *result)
1790 {
1791 UCHAR *ptr = result;
1792 UINT random_number;
1793 UINT temp;
1794 UINT mask;
1795
1796 while (bits >= 32)
1797 {
1798
1799 /* Generate random number for each 32 bits. */
1800 random_number = (UINT)NX_CRYPTO_RAND();
1801 ptr[0] = (UCHAR)(random_number & 0xFF);
1802 ptr[1] = (UCHAR)((random_number >> 8) & 0xFF);
1803 ptr[2] = (UCHAR)((random_number >> 16) & 0xFF);
1804 ptr[3] = (UCHAR)((random_number >> 24) & 0xFF);
1805 bits -= 32;
1806 ptr += 4;
1807 }
1808
1809 if (bits == 0)
1810 {
1811
1812 /* Every bits are generated. */
1813 return(NX_CRYPTO_SUCCESS);
1814 }
1815
1816 /* Process left bits between 1 and 31. */
1817 random_number = (UINT)NX_CRYPTO_RAND();
1818
1819 /* Get remaining bits. */
1820 temp = (bits + 7) >> 3;
1821 switch (temp)
1822 {
1823 case 4:
1824 *ptr++ = (UCHAR)(random_number & 0xFF);
1825 random_number >>= 8;
1826 /* fallthrough */
1827 case 3:
1828 *ptr++ = (UCHAR)(random_number & 0xFF);
1829 random_number >>= 8;
1830 /* fallthrough */
1831 case 2:
1832 *ptr++ = (UCHAR)(random_number & 0xFF);
1833 random_number >>= 8;
1834 /* fallthrough */
1835 case 1:
1836 *ptr++ = (UCHAR)(random_number & 0xFF);
1837 random_number >>= 8;
1838 /* fallthrough */
1839 default:
1840 break;
1841 }
1842
1843 /* Zero out extra bits generated. */
1844 bits = bits & 7;
1845 if (bits)
1846 {
1847 mask = (UINT)((1 << bits) - 1);
1848 result[0] = (UCHAR)(result[0] & mask);
1849 }
1850
1851 return(NX_CRYPTO_SUCCESS);
1852 }
1853
1854 /**************************************************************************/
1855 /* */
1856 /* FUNCTION RELEASE */
1857 /* */
1858 /* _nx_crypto_huge_number_extract PORTABLE C */
1859 /* 6.1 */
1860 /* AUTHOR */
1861 /* */
1862 /* Timothy Stapko, Microsoft Corporation */
1863 /* */
1864 /* DESCRIPTION */
1865 /* */
1866 /* This function extracts huge number to buffer. */
1867 /* */
1868 /* INPUT */
1869 /* */
1870 /* number Huge number */
1871 /* byte_stream Output buffer */
1872 /* byte_stream_size Size of output buffer */
1873 /* huge_number_size Size of huge number in bytes */
1874 /* */
1875 /* OUTPUT */
1876 /* */
1877 /* Status Operation result status */
1878 /* */
1879 /* CALLS */
1880 /* */
1881 /* None */
1882 /* */
1883 /* CALLED BY */
1884 /* */
1885 /* _nx_crypto_dh_compute_secret Computes the Diffie-Hellman */
1886 /* shared secret */
1887 /* _nx_crypto_dh_setup Set up Diffie-Hellman context */
1888 /* _nx_crypto_ec_point_extract_uncompressed */
1889 /* Extract point to byte stream */
1890 /* in uncompressed format */
1891 /* _nx_crypto_ec_secp192r1_reduce Reduce the value of curve */
1892 /* secp192r1 */
1893 /* _nx_crypto_ec_secp224r1_reduce Reduce the value of curve */
1894 /* secp224r1 */
1895 /* _nx_crypto_ec_secp256r1_reduce Reduce the value of curve */
1896 /* secp256r1 */
1897 /* _nx_crypto_ec_secp384r1_reduce Reduce the value of curve */
1898 /* secp384r1 */
1899 /* _nx_crypto_ec_secp521r1_reduce Reduce the value of curve */
1900 /* secp521r1 */
1901 /* _nx_crypto_ecjpake_hello_generate Generate hello message */
1902 /* _nx_crypto_ecjpake_key_exchange_generate */
1903 /* Generate key exchange message */
1904 /* _nx_crypto_ecjpake_pre_master_secret_generate */
1905 /* Generate pre master secret */
1906 /* _nx_crypto_rsa_operation Perform an RSA operation */
1907 /* */
1908 /* RELEASE HISTORY */
1909 /* */
1910 /* DATE NAME DESCRIPTION */
1911 /* */
1912 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
1913 /* 09-30-2020 Timothy Stapko Modified comment(s), */
1914 /* resulting in version 6.1 */
1915 /* */
1916 /**************************************************************************/
_nx_crypto_huge_number_extract(NX_CRYPTO_HUGE_NUMBER * number,UCHAR * byte_stream,UINT byte_stream_size,UINT * huge_number_size)1917 NX_CRYPTO_KEEP UINT _nx_crypto_huge_number_extract(NX_CRYPTO_HUGE_NUMBER *number, UCHAR *byte_stream,
1918 UINT byte_stream_size, UINT *huge_number_size)
1919 {
1920 INT i = 0;
1921 HN_UBASE *word;
1922 HN_UBASE value;
1923 UCHAR *bytes;
1924
1925
1926 if ((number -> nx_crypto_huge_number_size << HN_SIZE_SHIFT) > byte_stream_size)
1927 {
1928 /* User byte stream buffer too small. */
1929 return(NX_CRYPTO_NOT_SUCCESSFUL);
1930 }
1931
1932 bytes = byte_stream;
1933
1934 word = number -> nx_crypto_huge_number_data;
1935 for (i = (INT)(number -> nx_crypto_huge_number_size - 1); i >= 0; i--)
1936 {
1937 value = word[i];
1938 #if (NX_CRYPTO_HUGE_NUMBER_BITS == 16)
1939 *bytes = value >> 8;
1940 *(bytes + 1) = value & 0xFF;
1941 #else /* NX_CRYPTO_HUGE_NUMBER_BITS == 32 */
1942 *bytes = (UCHAR)(value >> 24);
1943 *(bytes + 1) = (value >> 16) & 0xFF;
1944 *(bytes + 2) = (value >> 8) & 0xFF;
1945 *(bytes + 3) = value & 0xFF;
1946 #endif
1947 bytes += sizeof(HN_UBASE);
1948 }
1949 *huge_number_size = (number -> nx_crypto_huge_number_size << HN_SIZE_SHIFT);
1950
1951 return(NX_CRYPTO_SUCCESS);
1952 }
1953
1954 /**************************************************************************/
1955 /* */
1956 /* FUNCTION RELEASE */
1957 /* */
1958 /* _nx_crypto_huge_number_extract_fixed_size PORTABLE C */
1959 /* 6.1 */
1960 /* AUTHOR */
1961 /* */
1962 /* Timothy Stapko, Microsoft Corporation */
1963 /* */
1964 /* DESCRIPTION */
1965 /* */
1966 /* This function extracts huge number to a buffer with fixed size. */
1967 /* */
1968 /* INPUT */
1969 /* */
1970 /* number Huge number */
1971 /* byte_stream Output buffer */
1972 /* byte_stream_size Size of output buffer */
1973 /* */
1974 /* OUTPUT */
1975 /* */
1976 /* Status Operation result status */
1977 /* */
1978 /* CALLS */
1979 /* */
1980 /* None */
1981 /* */
1982 /* CALLED BY */
1983 /* */
1984 /* _nx_crypto_ecdsa_sign Sign hash data using ECDSA. */
1985 /* */
1986 /* RELEASE HISTORY */
1987 /* */
1988 /* DATE NAME DESCRIPTION */
1989 /* */
1990 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
1991 /* 09-30-2020 Timothy Stapko Modified comment(s), */
1992 /* resulting in version 6.1 */
1993 /* */
1994 /**************************************************************************/
_nx_crypto_huge_number_extract_fixed_size(NX_CRYPTO_HUGE_NUMBER * number,UCHAR * byte_stream,UINT byte_stream_size)1995 NX_CRYPTO_KEEP UINT _nx_crypto_huge_number_extract_fixed_size(NX_CRYPTO_HUGE_NUMBER *number,
1996 UCHAR *byte_stream, UINT byte_stream_size)
1997 {
1998 INT i = 0;
1999 HN_UBASE *word;
2000 HN_UBASE value;
2001 UCHAR *bytes;
2002 UINT leading_count = 0;
2003 UINT num_size_adjusted;
2004
2005 word = number -> nx_crypto_huge_number_data;
2006
2007 num_size_adjusted = number -> nx_crypto_huge_number_size;
2008 do
2009 {
2010 num_size_adjusted--;
2011 value = word[num_size_adjusted];
2012 } while (value == 0 && num_size_adjusted > 0);
2013 num_size_adjusted++;
2014
2015 #if (NX_CRYPTO_HUGE_NUMBER_BITS == 16)
2016 if ((value & 0xFF00) == 0)
2017 {
2018 leading_count = 1;
2019 }
2020 #else
2021 if ((value & 0xFFFFFF00) == 0)
2022 {
2023 leading_count = 3;
2024 }
2025 else if ((value & 0xFFFF0000) == 0)
2026 {
2027 leading_count = 2;
2028 }
2029 else if ((value & 0xFF000000) == 0)
2030 {
2031 leading_count = 1;
2032 }
2033 #endif
2034
2035 if ((num_size_adjusted << HN_SIZE_SHIFT) - leading_count > byte_stream_size)
2036 {
2037 /* User byte stream buffer too small. */
2038 return(NX_CRYPTO_SIZE_ERROR);
2039 }
2040
2041 byte_stream_size -= (num_size_adjusted << HN_SIZE_SHIFT) - leading_count;
2042
2043 if (byte_stream_size > 0)
2044 {
2045 NX_CRYPTO_MEMSET(byte_stream, 0, byte_stream_size);
2046 }
2047
2048 bytes = byte_stream + byte_stream_size;
2049
2050 #if (NX_CRYPTO_HUGE_NUMBER_BITS == 16)
2051 if (leading_count == 0)
2052 {
2053 *bytes = (UCHAR)(value >> 8);
2054 bytes++;
2055 }
2056 #else
2057 if (leading_count == 0)
2058 {
2059 *bytes = (UCHAR)(value >> 24);
2060 bytes++;
2061 }
2062 if (leading_count <= 1)
2063 {
2064 *bytes = (UCHAR)((value >> 16) & 0xFF);
2065 bytes++;
2066 }
2067 if (leading_count <= 2)
2068 {
2069 *bytes = (UCHAR)((value >> 8) & 0xFF);
2070 bytes++;
2071 }
2072 #endif
2073
2074 *bytes = (UCHAR)(value & 0xFF);
2075 bytes++;
2076
2077 for (i = (INT)(num_size_adjusted - 2); i >= 0; i--)
2078 {
2079 value = word[i];
2080 #if (NX_CRYPTO_HUGE_NUMBER_BITS == 16)
2081 *bytes = value >> 8;
2082 *(bytes + 1) = value & 0xFF;
2083 #else /* NX_CRYPTO_HUGE_NUMBER_BITS == 32 */
2084 *bytes = (UCHAR)(value >> 24);
2085 *(bytes + 1) = (value >> 16) & 0xFF;
2086 *(bytes + 2) = (value >> 8) & 0xFF;
2087 *(bytes + 3) = value & 0xFF;
2088 #endif
2089 bytes += sizeof(HN_UBASE);
2090 }
2091
2092 return(NX_CRYPTO_SUCCESS);
2093 }
2094
2095 /**************************************************************************/
2096 /* */
2097 /* FUNCTION RELEASE */
2098 /* */
2099 /* _nx_crypto_huge_number_inverse_modulus_prime */
2100 /* PORTABLE C */
2101 /* 6.1 */
2102 /* AUTHOR */
2103 /* */
2104 /* Timothy Stapko, Microsoft Corporation */
2105 /* */
2106 /* DESCRIPTION */
2107 /* */
2108 /* This function performs an inverse modulus operation. The size of */
2109 /* scratch is required to be larger than 4 * (max(len(p), len(a)) + 1) */
2110 /* times of size of radix. p must be prime number. */
2111 /* r = a ^ (-1) mod p */
2112 /* */
2113 /* INPUT */
2114 /* */
2115 /* a Huge number a */
2116 /* p Huge number modulo p */
2117 /* r Huge number r */
2118 /* scratch Buffer used to hold */
2119 /* intermediate data */
2120 /* */
2121 /* OUTPUT */
2122 /* */
2123 /* Status Operation result status */
2124 /* */
2125 /* CALLS */
2126 /* */
2127 /* NX_CRYPTO_HUGE_NUMBER_COPY Copy huge number */
2128 /* NX_CRYPTO_HUGE_NUMBER_INITIALIZE Initialize the buffer of */
2129 /* huge number */
2130 /* NX_CRYPTO_HUGE_NUMBER_SET_DIGIT Set value of huge number */
2131 /* between 0 and (HN_RADIX - 1)*/
2132 /* _nx_crypto_huge_number_is_zero Check if number is zero or not*/
2133 /* _nx_crypto_huge_number_add Calculate addition for */
2134 /* huge numbers */
2135 /* _nx_crypto_huge_number_subtract Calculate subtraction for */
2136 /* huge numbers */
2137 /* _nx_crypto_huge_number_shift_right Shift right for huge number */
2138 /* _nx_crypto_huge_number_compare Compare two huge numbers */
2139 /* _nx_crypto_huge_number_modulus Perform a modulus operation */
2140 /* */
2141 /* CALLED BY */
2142 /* */
2143 /* _nx_crypto_ec_fp_affine_add Perform addition for points of*/
2144 /* affine */
2145 /* _nx_crypto_ec_point_fp_projective_to_affine */
2146 /* Convert point from projective */
2147 /* to affine */
2148 /* _nx_crypto_huge_number_crt_power_modulus */
2149 /* Raise a huge number for CRT */
2150 /* */
2151 /* RELEASE HISTORY */
2152 /* */
2153 /* DATE NAME DESCRIPTION */
2154 /* */
2155 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
2156 /* 09-30-2020 Timothy Stapko Modified comment(s), */
2157 /* resulting in version 6.1 */
2158 /* */
2159 /**************************************************************************/
_nx_crypto_huge_number_inverse_modulus_prime(NX_CRYPTO_HUGE_NUMBER * a,NX_CRYPTO_HUGE_NUMBER * p,NX_CRYPTO_HUGE_NUMBER * r,HN_UBASE * scratch)2160 NX_CRYPTO_KEEP UINT _nx_crypto_huge_number_inverse_modulus_prime(NX_CRYPTO_HUGE_NUMBER *a,
2161 NX_CRYPTO_HUGE_NUMBER *p,
2162 NX_CRYPTO_HUGE_NUMBER *r,
2163 HN_UBASE *scratch)
2164 {
2165 NX_CRYPTO_HUGE_NUMBER u, v, A, C;
2166 UINT buffer_size;
2167
2168 if (p -> nx_crypto_huge_number_size > a -> nx_crypto_huge_number_size)
2169 {
2170 buffer_size = (p -> nx_crypto_huge_number_size + 1) << HN_SIZE_SHIFT;
2171 }
2172 else
2173 {
2174 buffer_size = (a -> nx_crypto_huge_number_size + 1) << HN_SIZE_SHIFT;
2175 }
2176
2177 /* Buffer usage: 6 * buffer_size */
2178 NX_CRYPTO_HUGE_NUMBER_INITIALIZE(&u, scratch, buffer_size);
2179 NX_CRYPTO_HUGE_NUMBER_INITIALIZE(&v, scratch, buffer_size);
2180 NX_CRYPTO_HUGE_NUMBER_INITIALIZE(&A, scratch, buffer_size);
2181 NX_CRYPTO_HUGE_NUMBER_INITIALIZE(&C, scratch, buffer_size);
2182
2183 NX_CRYPTO_HUGE_NUMBER_COPY(&u, a);
2184 NX_CRYPTO_HUGE_NUMBER_COPY(&v, p);
2185 NX_CRYPTO_HUGE_NUMBER_SET_DIGIT(&A, 1);
2186 NX_CRYPTO_HUGE_NUMBER_SET_DIGIT(&C, 0);
2187
2188 while (!_nx_crypto_huge_number_is_zero(&u))
2189 {
2190 while (NX_CRYPTO_HUGE_NUMBER_IS_EVEN(&u))
2191 {
2192 _nx_crypto_huge_number_shift_right(&u, 1);
2193 if (NX_CRYPTO_HUGE_NUMBER_IS_EVEN(&A))
2194 {
2195 _nx_crypto_huge_number_shift_right(&A, 1);
2196 }
2197 else
2198 {
2199 _nx_crypto_huge_number_add(&A, p);
2200 _nx_crypto_huge_number_shift_right(&A, 1);
2201 }
2202 }
2203
2204 while (NX_CRYPTO_HUGE_NUMBER_IS_EVEN(&v))
2205 {
2206 _nx_crypto_huge_number_shift_right(&v, 1);
2207 if (NX_CRYPTO_HUGE_NUMBER_IS_EVEN(&C))
2208 {
2209 _nx_crypto_huge_number_shift_right(&C, 1);
2210 }
2211 else
2212 {
2213 _nx_crypto_huge_number_add(&C, p);
2214 _nx_crypto_huge_number_shift_right(&C, 1);
2215 }
2216 }
2217
2218 if (_nx_crypto_huge_number_compare(&u, &v) != NX_CRYPTO_HUGE_NUMBER_LESS)
2219 {
2220 _nx_crypto_huge_number_subtract(&u, &v);
2221 _nx_crypto_huge_number_subtract(&A, &C);
2222 }
2223 else
2224 {
2225 _nx_crypto_huge_number_subtract(&v, &u);
2226 _nx_crypto_huge_number_subtract(&C, &A);
2227 }
2228 }
2229
2230 _nx_crypto_huge_number_modulus(&C, p);
2231 NX_CRYPTO_HUGE_NUMBER_COPY(r, &C);
2232
2233 return(NX_CRYPTO_SUCCESS);
2234 }
2235
2236 /**************************************************************************/
2237 /* */
2238 /* FUNCTION RELEASE */
2239 /* */
2240 /* _nx_crypto_huge_number_inverse_modulus PORTABLE C */
2241 /* 6.1 */
2242 /* AUTHOR */
2243 /* */
2244 /* Timothy Stapko, Microsoft Corporation */
2245 /* */
2246 /* DESCRIPTION */
2247 /* */
2248 /* This function performs an inverse modulus operation. The size of */
2249 /* scratch is required to be larger than 6 * (max(len(m), len(a)) + 1) */
2250 /* times of size of radix. */
2251 /* r = a ^ (-1) mod m */
2252 /* */
2253 /* INPUT */
2254 /* */
2255 /* a Huge number a */
2256 /* m Huge number modulo */
2257 /* r Huge number r */
2258 /* scratch Buffer used to hold */
2259 /* intermediate data */
2260 /* */
2261 /* OUTPUT */
2262 /* */
2263 /* Status Operation result status */
2264 /* */
2265 /* CALLS */
2266 /* */
2267 /* NX_CRYPTO_HUGE_NUMBER_COPY Copy huge number */
2268 /* NX_CRYPTO_HUGE_NUMBER_INITIALIZE Initialize the buffer of */
2269 /* huge number */
2270 /* NX_CRYPTO_HUGE_NUMBER_SET_DIGIT Set value of huge number */
2271 /* between 0 and (HN_RADIX - 1)*/
2272 /* _nx_crypto_huge_number_is_zero Check if number is zero or not*/
2273 /* _nx_crypto_huge_number_add Calculate addition for */
2274 /* huge numbers */
2275 /* _nx_crypto_huge_number_subtract Calculate subtraction for */
2276 /* huge numbers */
2277 /* _nx_crypto_huge_number_shift_right Shift right for huge number */
2278 /* _nx_crypto_huge_number_compare Compare two huge numbers */
2279 /* _nx_crypto_huge_number_modulus Perform a modulus operation */
2280 /* */
2281 /* CALLED BY */
2282 /* */
2283 /* _nx_crypto_huge_number_mont_power_modulus */
2284 /* Raise a huge number for */
2285 /* montgomery reduction */
2286 /* */
2287 /* RELEASE HISTORY */
2288 /* */
2289 /* DATE NAME DESCRIPTION */
2290 /* */
2291 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
2292 /* 09-30-2020 Timothy Stapko Modified comment(s), and */
2293 /* fixed input validation, */
2294 /* resulting in version 6.1 */
2295 /* */
2296 /**************************************************************************/
_nx_crypto_huge_number_inverse_modulus(NX_CRYPTO_HUGE_NUMBER * a,NX_CRYPTO_HUGE_NUMBER * m,NX_CRYPTO_HUGE_NUMBER * r,HN_UBASE * scratch)2297 NX_CRYPTO_KEEP UINT _nx_crypto_huge_number_inverse_modulus(NX_CRYPTO_HUGE_NUMBER *a,
2298 NX_CRYPTO_HUGE_NUMBER *m,
2299 NX_CRYPTO_HUGE_NUMBER *r,
2300 HN_UBASE *scratch)
2301 {
2302 NX_CRYPTO_HUGE_NUMBER u, v, A, B, C, D;
2303 UINT buffer_size;
2304
2305 if (NX_CRYPTO_HUGE_NUMBER_IS_EVEN(m) && NX_CRYPTO_HUGE_NUMBER_IS_EVEN(a))
2306 {
2307
2308 /* gcd(m, a) <> 1.
2309 * a is not invertible modulo m. */
2310 return(NX_CRYPTO_NOT_SUCCESSFUL);
2311 }
2312
2313 if(_nx_crypto_huge_number_is_zero(a))
2314 {
2315
2316 /* zero is not invertible */
2317 return(NX_CRYPTO_NOT_SUCCESSFUL);
2318 }
2319
2320 if (m -> nx_crypto_huge_number_size > a -> nx_crypto_huge_number_size)
2321 {
2322 buffer_size = (m -> nx_crypto_huge_number_size + 1) << HN_SIZE_SHIFT;
2323 }
2324 else
2325 {
2326 buffer_size = (a -> nx_crypto_huge_number_size + 1) << HN_SIZE_SHIFT;
2327 }
2328
2329 /* Buffer usage: 6 * buffer_size */
2330 NX_CRYPTO_HUGE_NUMBER_INITIALIZE(&u, scratch, buffer_size);
2331 NX_CRYPTO_HUGE_NUMBER_INITIALIZE(&v, scratch, buffer_size);
2332 NX_CRYPTO_HUGE_NUMBER_INITIALIZE(&A, scratch, buffer_size);
2333 NX_CRYPTO_HUGE_NUMBER_INITIALIZE(&B, scratch, buffer_size);
2334 NX_CRYPTO_HUGE_NUMBER_INITIALIZE(&C, scratch, buffer_size);
2335 NX_CRYPTO_HUGE_NUMBER_INITIALIZE(&D, scratch, buffer_size);
2336
2337 NX_CRYPTO_HUGE_NUMBER_COPY(&u, m);
2338 NX_CRYPTO_HUGE_NUMBER_COPY(&v, a);
2339 NX_CRYPTO_HUGE_NUMBER_SET_DIGIT(&A, 1);
2340 NX_CRYPTO_HUGE_NUMBER_SET_DIGIT(&B, 0);
2341 NX_CRYPTO_HUGE_NUMBER_SET_DIGIT(&C, 0);
2342 NX_CRYPTO_HUGE_NUMBER_SET_DIGIT(&D, 1);
2343
2344 for (;;)
2345 {
2346 while (NX_CRYPTO_HUGE_NUMBER_IS_EVEN(&u))
2347 {
2348 _nx_crypto_huge_number_shift_right(&u, 1);
2349
2350 if (NX_CRYPTO_HUGE_NUMBER_IS_EVEN(&A) && NX_CRYPTO_HUGE_NUMBER_IS_EVEN(&B))
2351 {
2352 _nx_crypto_huge_number_shift_right(&A, 1);
2353 _nx_crypto_huge_number_shift_right(&B, 1);
2354 }
2355 else
2356 {
2357 _nx_crypto_huge_number_add(&A, a);
2358 _nx_crypto_huge_number_shift_right(&A, 1);
2359 _nx_crypto_huge_number_subtract(&B, m);
2360 _nx_crypto_huge_number_shift_right(&B, 1);
2361 }
2362 }
2363
2364 while (NX_CRYPTO_HUGE_NUMBER_IS_EVEN(&v))
2365 {
2366 _nx_crypto_huge_number_shift_right(&v, 1);
2367 if (NX_CRYPTO_HUGE_NUMBER_IS_EVEN(&C) && NX_CRYPTO_HUGE_NUMBER_IS_EVEN(&D))
2368 {
2369 _nx_crypto_huge_number_shift_right(&C, 1);
2370 _nx_crypto_huge_number_shift_right(&D, 1);
2371 }
2372 else
2373 {
2374 _nx_crypto_huge_number_add(&C, a);
2375 _nx_crypto_huge_number_shift_right(&C, 1);
2376 _nx_crypto_huge_number_subtract(&D, m);
2377 _nx_crypto_huge_number_shift_right(&D, 1);
2378 }
2379 }
2380
2381 if (_nx_crypto_huge_number_compare(&u, &v) != NX_CRYPTO_HUGE_NUMBER_LESS)
2382 {
2383 _nx_crypto_huge_number_subtract(&u, &v);
2384 _nx_crypto_huge_number_subtract(&A, &C);
2385 _nx_crypto_huge_number_subtract(&B, &D);
2386 }
2387 else
2388 {
2389 _nx_crypto_huge_number_subtract(&v, &u);
2390 _nx_crypto_huge_number_subtract(&C, &A);
2391 _nx_crypto_huge_number_subtract(&D, &B);
2392 }
2393
2394 if (_nx_crypto_huge_number_is_zero(&u))
2395 {
2396 _nx_crypto_huge_number_modulus(&D, m);
2397 NX_CRYPTO_HUGE_NUMBER_COPY(r, &D);
2398 break;
2399 }
2400 }
2401
2402 return(NX_CRYPTO_SUCCESS);
2403 }
2404
2405 /**************************************************************************/
2406 /* */
2407 /* FUNCTION RELEASE */
2408 /* */
2409 /* _nx_crypto_huge_number_mont PORTABLE C */
2410 /* 6.1 */
2411 /* AUTHOR */
2412 /* */
2413 /* Timothy Stapko, Microsoft Corporation */
2414 /* */
2415 /* DESCRIPTION */
2416 /* */
2417 /* This function performs Montgomery reduction for multiplication. */
2418 /* r = (x * y) * R ^ (-1) mod m */
2419 /* */
2420 /* INPUT */
2421 /* */
2422 /* m Huge number m */
2423 /* mi mi = -m ^ (-1) mod radix */
2424 /* x Huge number x */
2425 /* y Huge number y */
2426 /* result Huge number r */
2427 /* */
2428 /* OUTPUT */
2429 /* */
2430 /* None */
2431 /* */
2432 /* CALLS */
2433 /* */
2434 /* _nx_crypto_huge_number_subtract Calculate subtraction for */
2435 /* huge numbers */
2436 /* _nx_crypto_huge_number_adjust_size Adjust the size of a huge */
2437 /* number to remove leading */
2438 /* zeroes */
2439 /* _nx_crypto_huge_number_compare Compare two huge numbers */
2440 /* */
2441 /* CALLED BY */
2442 /* */
2443 /* _nx_crypto_huge_number_mont_power_modulus */
2444 /* Raise a huge number for */
2445 /* montgomery reduction */
2446 /* */
2447 /* RELEASE HISTORY */
2448 /* */
2449 /* DATE NAME DESCRIPTION */
2450 /* */
2451 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
2452 /* 09-30-2020 Timothy Stapko Modified comment(s), */
2453 /* resulting in version 6.1 */
2454 /* */
2455 /**************************************************************************/
_nx_crypto_huge_number_mont(NX_CRYPTO_HUGE_NUMBER * m,UINT mi,NX_CRYPTO_HUGE_NUMBER * x,NX_CRYPTO_HUGE_NUMBER * y,NX_CRYPTO_HUGE_NUMBER * result)2456 NX_CRYPTO_KEEP VOID _nx_crypto_huge_number_mont(NX_CRYPTO_HUGE_NUMBER *m, UINT mi,
2457 NX_CRYPTO_HUGE_NUMBER *x,
2458 NX_CRYPTO_HUGE_NUMBER *y,
2459 NX_CRYPTO_HUGE_NUMBER *result)
2460 {
2461 UINT i, j;
2462 HN_UBASE u;
2463 HN_UBASE xi;
2464 HN_UBASE2 product;
2465 UINT m_len = m -> nx_crypto_huge_number_size;
2466 UINT x_len = x -> nx_crypto_huge_number_size;
2467 UINT y_len = y -> nx_crypto_huge_number_size;
2468 HN_UBASE *m_buffer = m -> nx_crypto_huge_number_data;
2469 HN_UBASE *x_buffer = x -> nx_crypto_huge_number_data;
2470 HN_UBASE *y_buffer = y -> nx_crypto_huge_number_data;
2471 HN_UBASE *result_buffer = result -> nx_crypto_huge_number_data;
2472
2473 NX_CRYPTO_MEMSET(result -> nx_crypto_huge_number_data, 0, (m_len + 1) * sizeof(HN_UBASE));
2474
2475 for (i = 0; i < x_len; i++)
2476 {
2477
2478 xi = x_buffer[i];
2479
2480 /* r = (r + x[i] * y + u * m) / radix */
2481 product = 0;
2482 for (j = 0; j < y_len; j++)
2483 {
2484 product >>= HN_SHIFT;
2485 product += result_buffer[j] + (HN_UBASE2)xi * y_buffer[j];
2486 result_buffer[j] = (product & HN_MASK);
2487 }
2488 for (; j < (m_len + 1); j++)
2489 {
2490 product >>= HN_SHIFT;
2491 product += result_buffer[j];
2492 result_buffer[j] = (product & HN_MASK);
2493 }
2494
2495 /* u = (r[0] + x[i] * y[0]) * mi mod radix */
2496 u = result_buffer[0] * mi;
2497
2498 product = result_buffer[0] + (HN_UBASE2)u * m_buffer[0];
2499 for (j = 1; j < m_len; j++)
2500 {
2501 product >>= HN_SHIFT;
2502 product += result_buffer[j] + (HN_UBASE2)u * m_buffer[j];
2503 result_buffer[j - 1] = (product & HN_MASK);
2504 }
2505 product >>= HN_SHIFT;
2506 product += result_buffer[j];
2507 result_buffer[j - 1] = (product & HN_MASK);
2508 result_buffer[j] = (HN_UBASE)(product >> HN_SHIFT);
2509 }
2510
2511 for (; i < m_len; i++)
2512 {
2513
2514 /* u = (r[0] + x[i] * y[0]) * mi mod radix */
2515 u = ((result_buffer[0] * mi) & HN_MASK);
2516
2517 /* r = (r + x[i] * y + u * m) / radix */
2518 product = result_buffer[0] + (HN_UBASE2)u * m_buffer[0];
2519 for (j = 1; j < m_len; j++)
2520 {
2521 product >>= HN_SHIFT;
2522 product += result_buffer[j] + (HN_UBASE2)u * m_buffer[j];
2523 result_buffer[j - 1] = (product & HN_MASK);
2524 }
2525 product >>= HN_SHIFT;
2526 product += result_buffer[j];
2527 result_buffer[j - 1] = (product & HN_MASK);
2528 result_buffer[j] = (HN_UBASE)(product >> HN_SHIFT);
2529 }
2530
2531 /* Set result size. */
2532 result -> nx_crypto_huge_number_size = m_len + 1;
2533 _nx_crypto_huge_number_adjust_size(result);
2534
2535 if (_nx_crypto_huge_number_compare(result, m) != NX_CRYPTO_HUGE_NUMBER_LESS)
2536 {
2537
2538 /* r = r - m. */
2539 _nx_crypto_huge_number_subtract(result, m);
2540 }
2541 }
2542
2543 /**************************************************************************/
2544 /* */
2545 /* FUNCTION RELEASE */
2546 /* */
2547 /* _nx_crypto_huge_number_mont_power_modulus PORTABLE C */
2548 /* 6.1.9 */
2549 /* AUTHOR */
2550 /* */
2551 /* Timothy Stapko, Microsoft Corporation */
2552 /* */
2553 /* DESCRIPTION */
2554 /* */
2555 /* This function raises a huge number to the power of a second huge */
2556 /* number using a third huge number as a modulus. The result is placed */
2557 /* in a fourth huge number. Montgomery reduction is used. */
2558 /* scratch is required to be larger than twice of buffer size of m */
2559 /* plus 8 bytes. */
2560 /* */
2561 /* INPUT */
2562 /* */
2563 /* x Number being exponentiated */
2564 /* e Exponent number */
2565 /* m Modulus number */
2566 /* result Result buffer */
2567 /* scratch Buffer used to hold */
2568 /* intermediate data */
2569 /* */
2570 /* OUTPUT */
2571 /* */
2572 /* Status Operation result status */
2573 /* */
2574 /* CALLS */
2575 /* */
2576 /* NX_CRYPTO_HUGE_NUMBER_COPY Copy huge number */
2577 /* NX_CRYPTO_HUGE_NUMBER_INITIALIZE Initialize the buffer of */
2578 /* huge number */
2579 /* NX_CRYPTO_HUGE_NUMBER_SET_DIGIT Set value of huge number */
2580 /* between 0 and (HN_RADIX - 1)*/
2581 /* _nx_crypto_huge_number_adjust_size Adjust the size of a huge */
2582 /* number to remove leading */
2583 /* zeroes */
2584 /* _nx_crypto_huge_number_modulus Perform a modulus operation */
2585 /* _nx_crypto_huge_number_inverse_modulus */
2586 /* Perform an inverse modulus */
2587 /* operation */
2588 /* _nx_crypto_huge_number_mont Perform Montgomery reduction */
2589 /* for multiplication */
2590 /* _nx_crypto_huge_number_square Compute the square of a value */
2591 /* */
2592 /* CALLED BY */
2593 /* */
2594 /* _nx_crypto_dh_compute_secret Computes the Diffie-Hellman */
2595 /* shared secret */
2596 /* _nx_crypto_dh_setup Set up Diffie-Hellman context */
2597 /* _nx_crypto_huge_number_crt_power_modulus */
2598 /* Raise a huge number for CRT */
2599 /* _nx_crypto_rsa_operation Perform an RSA operation */
2600 /* */
2601 /* RELEASE HISTORY */
2602 /* */
2603 /* DATE NAME DESCRIPTION */
2604 /* */
2605 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
2606 /* 09-30-2020 Timothy Stapko Modified comment(s), */
2607 /* resulting in version 6.1 */
2608 /* 10-15-2021 Bhupendra Naphade Modified comment(s), */
2609 /* resulting in version 6.1.9 */
2610 /* */
2611 /**************************************************************************/
_nx_crypto_huge_number_mont_power_modulus(NX_CRYPTO_HUGE_NUMBER * x,NX_CRYPTO_HUGE_NUMBER * e,NX_CRYPTO_HUGE_NUMBER * m,NX_CRYPTO_HUGE_NUMBER * result,HN_UBASE * scratch)2612 NX_CRYPTO_KEEP VOID _nx_crypto_huge_number_mont_power_modulus(NX_CRYPTO_HUGE_NUMBER *x,
2613 NX_CRYPTO_HUGE_NUMBER *e,
2614 NX_CRYPTO_HUGE_NUMBER *m,
2615 NX_CRYPTO_HUGE_NUMBER *result,
2616 HN_UBASE *scratch)
2617 {
2618 UINT m_len;
2619 NX_CRYPTO_HUGE_NUMBER xx;
2620 NX_CRYPTO_HUGE_NUMBER temp;
2621 NX_CRYPTO_HUGE_NUMBER digit;
2622 NX_CRYPTO_HUGE_NUMBER radix;
2623 NX_CRYPTO_HUGE_NUMBER mi;
2624 NX_CRYPTO_HUGE_NUMBER m0;
2625 HN_UBASE digit_value;
2626 HN_UBASE *val;
2627 HN_UBASE radix_buffer[2] = {0, 1};
2628 HN_UBASE mm_buffer[2];
2629 HN_UBASE cur_block;
2630 UINT bit, exp_size;
2631 NX_CRYPTO_HUGE_NUMBER *operand, *temp_result, *temp_swap;
2632
2633 /* Adjust sizes before performing the calculation. */
2634 _nx_crypto_huge_number_adjust_size(x);
2635 _nx_crypto_huge_number_adjust_size(e);
2636 _nx_crypto_huge_number_adjust_size(m);
2637
2638 /* Initialize const huge numbers. */
2639 radix.nx_crypto_huge_number_data = radix_buffer;
2640 radix.nx_crypto_huge_number_size = 2;
2641 radix.nx_crypto_huge_number_is_negative = NX_CRYPTO_FALSE;
2642 radix.nx_crypto_huge_buffer_size = sizeof(radix_buffer);
2643 m0.nx_crypto_huge_number_data = m -> nx_crypto_huge_number_data;
2644 m0.nx_crypto_huge_number_size = 1;
2645 m0.nx_crypto_huge_buffer_size = 4;
2646 m0.nx_crypto_huge_number_is_negative = NX_CRYPTO_FALSE;
2647 mi.nx_crypto_huge_number_data = mm_buffer;
2648 mi.nx_crypto_huge_buffer_size = sizeof(mm_buffer);
2649
2650 /* mi = -m^(-1) mod radix */
2651 _nx_crypto_huge_number_inverse_modulus(&m0, &radix, &mi, scratch);
2652 mm_buffer[0] = (HN_UBASE)(HN_RADIX - mm_buffer[0]);
2653
2654 /* Set buffers. */
2655 /* Buffer usage: 2 * buffer_size of m + 8 */
2656 NX_CRYPTO_HUGE_NUMBER_INITIALIZE(&xx, scratch, m -> nx_crypto_huge_buffer_size + sizeof(HN_UBASE));
2657 NX_CRYPTO_HUGE_NUMBER_INITIALIZE(&temp, scratch, m -> nx_crypto_huge_buffer_size + sizeof(HN_UBASE));
2658 NX_CRYPTO_HUGE_NUMBER_INITIALIZE_DIGIT(&digit, &digit_value, 1);
2659
2660
2661 /* x' = radix ^ m_len mod m */
2662 m_len = m -> nx_crypto_huge_number_size;
2663 val = temp.nx_crypto_huge_number_data;
2664 NX_CRYPTO_MEMSET(val, 0, (m_len << HN_SIZE_SHIFT));
2665 temp.nx_crypto_huge_number_size = m_len + 1;
2666 val[m_len] = 1;
2667 _nx_crypto_huge_number_modulus(&temp, m);
2668
2669 /* xx = mont(x, radix ^ (2 * m_len) mod m)*/
2670 _nx_crypto_huge_number_square(&temp, result);
2671 _nx_crypto_huge_number_modulus(result, m);
2672 _nx_crypto_huge_number_mont(m, mm_buffer[0], x, result, &xx);
2673
2674 /* result = x' */
2675 NX_CRYPTO_HUGE_NUMBER_COPY(result, &temp);
2676
2677 /* Clear out the result since we need it to start with a simple value. */
2678
2679 operand = result;
2680 temp_result = &temp;
2681
2682 exp_size = e -> nx_crypto_huge_number_size;
2683 val = e -> nx_crypto_huge_number_data + (exp_size - 1);
2684
2685 /* Loop through the bits of the exponent. For each bit set, multiply the result by the running square. */
2686 for (; (ULONG)val >= (ULONG)(e -> nx_crypto_huge_number_data); val--)
2687 {
2688 /* Current byte in the exponent determines whether we multiply or not. */
2689 cur_block = *val;
2690
2691 /* Loop over the bits in the current byte to see whether we add or not. */
2692 for (bit = 0; bit < HN_SHIFT; bit++)
2693 {
2694
2695 /* A non-zero bit means we need to multiply. */
2696 if (cur_block & (1u << (NX_CRYPTO_HUGE_NUMBER_BITS - (1 + bit))))
2697 {
2698
2699 /* result = mont(result, result) */
2700 _nx_crypto_huge_number_mont(m, mm_buffer[0], operand, operand, temp_result);
2701
2702 /* result = mont(result, xx) */
2703 _nx_crypto_huge_number_mont(m, mm_buffer[0], temp_result, &xx, operand);
2704 }
2705 else
2706 {
2707
2708 /* result = mont(result, result) */
2709 _nx_crypto_huge_number_mont(m, mm_buffer[0], operand, operand, temp_result);
2710 temp_swap = temp_result;
2711 temp_result = operand;
2712 operand = temp_swap;
2713 }
2714 }
2715 }
2716
2717 /* result = mont(result, 1) */
2718 _nx_crypto_huge_number_mont(m, mm_buffer[0], &digit, operand, temp_result);
2719 if (temp_result != result)
2720 {
2721 NX_CRYPTO_HUGE_NUMBER_COPY(result, &temp);
2722 }
2723 }
2724
2725 /**************************************************************************/
2726 /* */
2727 /* FUNCTION RELEASE */
2728 /* */
2729 /* _nx_crypto_huge_number_crt_power_modulus PORTABLE C */
2730 /* 6.1 */
2731 /* AUTHOR */
2732 /* */
2733 /* Timothy Stapko, Microsoft Corporation */
2734 /* */
2735 /* DESCRIPTION */
2736 /* */
2737 /* This function raises a huge number to the power of a second huge */
2738 /* number using a fifth huge number as a modulus. The result is placed */
2739 /* in a sixth huge number. Montgomery reduction and Chinese Remainder */
2740 /* Theorem are used. */
2741 /* */
2742 /* Requirement: */
2743 /* 1. m = p * q */
2744 /* 2. p and q are primes */
2745 /* 3. scratch is required to be no less than 4 times of buffer size */
2746 /* of m plus 24 bytes. */
2747 /* */
2748 /* INPUT */
2749 /* */
2750 /* x Number being exponentiated */
2751 /* e Exponent number */
2752 /* p Prime number p */
2753 /* q Prime number q */
2754 /* m Modulus number */
2755 /* result Result buffer */
2756 /* scratch Buffer used to hold */
2757 /* intermediate data */
2758 /* */
2759 /* OUTPUT */
2760 /* */
2761 /* None */
2762 /* */
2763 /* CALLS */
2764 /* */
2765 /* NX_CRYPTO_HUGE_NUMBER_COPY Copy huge number */
2766 /* NX_CRYPTO_HUGE_NUMBER_INITIALIZE Initialize the buffer of */
2767 /* huge number */
2768 /* NX_CRYPTO_HUGE_NUMBER_SET_DIGIT Set value of huge number */
2769 /* between 0 and (HN_RADIX - 1)*/
2770 /* _nx_crypto_huge_number_add Calculate addition for */
2771 /* huge numbers */
2772 /* _nx_crypto_huge_number_subtract Calculate subtraction for */
2773 /* huge numbers */
2774 /* _nx_crypto_huge_number_multiply Multiply two huge numbers */
2775 /* _nx_crypto_huge_number_modulus Perform a modulus operation */
2776 /* _nx_crypto_huge_number_inverse_modulus_prime */
2777 /* Perform an inverse modulus */
2778 /* operation for prime number */
2779 /* _nx_crypto_huge_number_mont_power_modulus */
2780 /* Raise a huge number for */
2781 /* montgomery reduction */
2782 /* */
2783 /* CALLED BY */
2784 /* */
2785 /* _nx_crypto_rsa_operation Perform an RSA operation */
2786 /* */
2787 /* RELEASE HISTORY */
2788 /* */
2789 /* DATE NAME DESCRIPTION */
2790 /* */
2791 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
2792 /* 09-30-2020 Timothy Stapko Modified comment(s), */
2793 /* resulting in version 6.1 */
2794 /* */
2795 /**************************************************************************/
_nx_crypto_huge_number_crt_power_modulus(NX_CRYPTO_HUGE_NUMBER * x,NX_CRYPTO_HUGE_NUMBER * e,NX_CRYPTO_HUGE_NUMBER * p,NX_CRYPTO_HUGE_NUMBER * q,NX_CRYPTO_HUGE_NUMBER * m,NX_CRYPTO_HUGE_NUMBER * result,HN_UBASE * scratch)2796 NX_CRYPTO_KEEP VOID _nx_crypto_huge_number_crt_power_modulus(NX_CRYPTO_HUGE_NUMBER *x,
2797 NX_CRYPTO_HUGE_NUMBER *e,
2798 NX_CRYPTO_HUGE_NUMBER *p,
2799 NX_CRYPTO_HUGE_NUMBER *q,
2800 NX_CRYPTO_HUGE_NUMBER *m,
2801 NX_CRYPTO_HUGE_NUMBER *result,
2802 HN_UBASE *scratch)
2803 {
2804 NX_CRYPTO_HUGE_NUMBER *ep, *eq, *xp, *xq, *m1, *m2;
2805 NX_CRYPTO_HUGE_NUMBER pi, qi;
2806 NX_CRYPTO_HUGE_NUMBER temp1, temp2, temp3;
2807 NX_CRYPTO_HUGE_NUMBER digit;
2808 HN_UBASE digit_value;
2809
2810 /*****************************************
2811 * ep = e mod (p - 1)
2812 * xp = x mod p
2813 * m1 = xp ^ ep mod p
2814 *
2815 * eq = e mod (q - 1)
2816 * xq = x mod q
2817 * m2 = xq ^ eq mod q
2818 *
2819 * pi = p ^ (-1) mod q
2820 * qi = q ^ (-1) mod p
2821 *
2822 * r = (m1 * qi * q + m2 * pi * p) mod m
2823 ****************************************/
2824
2825 /* Buffer usage: 1 * buffer size of m */
2826 /* temp1 is used to hold the result of pi * p * m2. So twice of m buffer size is used. */
2827 NX_CRYPTO_HUGE_NUMBER_INITIALIZE(&pi, scratch, p -> nx_crypto_huge_buffer_size);
2828 NX_CRYPTO_HUGE_NUMBER_INITIALIZE(&qi, scratch, q -> nx_crypto_huge_buffer_size);
2829
2830 /* qi = q ^ (-1) mod p */
2831 /* pi = p ^ (-1) mod q */
2832 /* Buffer usage: 2 * buffer_size of m + 24 bytes */
2833 _nx_crypto_huge_number_inverse_modulus_prime(q, p, &qi, scratch);
2834 _nx_crypto_huge_number_inverse_modulus_prime(p, q, &pi, scratch);
2835
2836 /* Buffer usage: 2 * buffer size of m */
2837 NX_CRYPTO_HUGE_NUMBER_INITIALIZE(&temp1, scratch, m -> nx_crypto_huge_buffer_size);
2838 NX_CRYPTO_HUGE_NUMBER_INITIALIZE(&temp2, scratch, p -> nx_crypto_huge_buffer_size);
2839 NX_CRYPTO_HUGE_NUMBER_INITIALIZE(&temp3, scratch, p -> nx_crypto_huge_buffer_size);
2840 NX_CRYPTO_HUGE_NUMBER_INITIALIZE_DIGIT(&digit, &digit_value, 1);
2841
2842 /* In the following calculation, buffer of temp3 is used by temp2. */
2843 /* ep = e mod (p - 1) */
2844 ep = &temp2;
2845 NX_CRYPTO_HUGE_NUMBER_COPY(ep, e);
2846 NX_CRYPTO_HUGE_NUMBER_COPY(&temp1, p);
2847 _nx_crypto_huge_number_subtract(&temp1, &digit);
2848 _nx_crypto_huge_number_modulus(ep, &temp1);
2849
2850 /* xp = x mod p */
2851 xp = &temp3;
2852 NX_CRYPTO_HUGE_NUMBER_COPY(xp, x);
2853 _nx_crypto_huge_number_modulus(xp, p);
2854
2855 /* m1 = xp ^ ep mod p */
2856 m1 = &temp1;
2857
2858 /* Buffer usage: 1 * buffer_size of m + 8 bytes */
2859 _nx_crypto_huge_number_mont_power_modulus(xp, ep, p, m1, scratch);
2860
2861 /* m1 * qi * q */
2862 _nx_crypto_huge_number_multiply(&qi, m1, &temp3);
2863 _nx_crypto_huge_number_multiply(&temp3, q, result);
2864
2865
2866 /* In the following calculation, buffer of temp3 is used by temp2. */
2867 /* eq = e mod (q - 1) */
2868 eq = &temp2;
2869 NX_CRYPTO_HUGE_NUMBER_COPY(eq, e);
2870 NX_CRYPTO_HUGE_NUMBER_COPY(&temp1, q);
2871 _nx_crypto_huge_number_subtract(&temp1, &digit);
2872 _nx_crypto_huge_number_modulus(eq, &temp1);
2873
2874 /* xq = x mod q */
2875 xq = &temp3;
2876 NX_CRYPTO_HUGE_NUMBER_COPY(xq, x);
2877 _nx_crypto_huge_number_modulus(xq, q);
2878
2879 /* m2 = xq ^ eq mod q */
2880 m2 = &temp1;
2881
2882 /* Buffer usage: 1 * buffer_size of m + 8 bytes */
2883 _nx_crypto_huge_number_mont_power_modulus(xq, eq, q, m2, scratch);
2884
2885 /* pi * p * m2 */
2886 _nx_crypto_huge_number_multiply(&pi, m2, &temp3);
2887
2888 /* Buffer of temp2 is not used anymore. It is used by temp1.
2889 * So buffer length of temp1 is 1.5 * buffer length of m.
2890 * It is large enough to hold the result of pi * p * m2 */
2891 _nx_crypto_huge_number_multiply(p, &temp3, &temp1);
2892
2893
2894 /* r = (m1 * qi * q + m2 * pi * p) mod m */
2895 _nx_crypto_huge_number_add(result, &temp1);
2896 _nx_crypto_huge_number_modulus(result, m);
2897 }
2898
2899