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