comparison libtommath/bn_mp_sqrtmod_prime.c @ 1739:13d834efc376 fuzz

merge from main
author Matt Johnston <matt@ucc.asn.au>
date Thu, 15 Oct 2020 19:55:15 +0800
parents 1051e4eea25a
children
comparison
equal deleted inserted replaced
1562:768ebf737aa0 1739:13d834efc376
1 #include <tommath_private.h> 1 #include "tommath_private.h"
2 #ifdef BN_MP_SQRTMOD_PRIME_C 2 #ifdef BN_MP_SQRTMOD_PRIME_C
3 /* LibTomMath, multiple-precision integer library -- Tom St Denis 3 /* LibTomMath, multiple-precision integer library -- Tom St Denis */
4 * 4 /* SPDX-License-Identifier: Unlicense */
5 * LibTomMath is a library that provides multiple-precision
6 * integer arithmetic as well as number theoretic functionality.
7 *
8 * The library is free for all purposes without any express
9 * guarantee it works.
10 */
11 5
12 /* Tonelli-Shanks algorithm 6 /* Tonelli-Shanks algorithm
13 * https://en.wikipedia.org/wiki/Tonelli%E2%80%93Shanks_algorithm 7 * https://en.wikipedia.org/wiki/Tonelli%E2%80%93Shanks_algorithm
14 * https://gmplib.org/list-archives/gmp-discuss/2013-April/005300.html 8 * https://gmplib.org/list-archives/gmp-discuss/2013-April/005300.html
15 * 9 *
16 */ 10 */
17 11
18 int mp_sqrtmod_prime(mp_int *n, mp_int *prime, mp_int *ret) 12 mp_err mp_sqrtmod_prime(const mp_int *n, const mp_int *prime, mp_int *ret)
19 { 13 {
20 int res, legendre; 14 mp_err err;
21 mp_int t1, C, Q, S, Z, M, T, R, two; 15 int legendre;
22 mp_digit i; 16 mp_int t1, C, Q, S, Z, M, T, R, two;
17 mp_digit i;
23 18
24 /* first handle the simple cases */ 19 /* first handle the simple cases */
25 if (mp_cmp_d(n, 0) == MP_EQ) { 20 if (mp_cmp_d(n, 0uL) == MP_EQ) {
26 mp_zero(ret); 21 mp_zero(ret);
27 return MP_OKAY; 22 return MP_OKAY;
28 } 23 }
29 if (mp_cmp_d(prime, 2) == MP_EQ) return MP_VAL; /* prime must be odd */ 24 if (mp_cmp_d(prime, 2uL) == MP_EQ) return MP_VAL; /* prime must be odd */
30 if ((res = mp_jacobi(n, prime, &legendre)) != MP_OKAY) return res; 25 if ((err = mp_kronecker(n, prime, &legendre)) != MP_OKAY) return err;
31 if (legendre == -1) return MP_VAL; /* quadratic non-residue mod prime */ 26 if (legendre == -1) return MP_VAL; /* quadratic non-residue mod prime */
32 27
33 if ((res = mp_init_multi(&t1, &C, &Q, &S, &Z, &M, &T, &R, &two, NULL)) != MP_OKAY) { 28 if ((err = mp_init_multi(&t1, &C, &Q, &S, &Z, &M, &T, &R, &two, NULL)) != MP_OKAY) {
34 return res; 29 return err;
35 } 30 }
36 31
37 /* SPECIAL CASE: if prime mod 4 == 3 32 /* SPECIAL CASE: if prime mod 4 == 3
38 * compute directly: res = n^(prime+1)/4 mod prime 33 * compute directly: err = n^(prime+1)/4 mod prime
39 * Handbook of Applied Cryptography algorithm 3.36 34 * Handbook of Applied Cryptography algorithm 3.36
40 */ 35 */
41 if ((res = mp_mod_d(prime, 4, &i)) != MP_OKAY) goto cleanup; 36 if ((err = mp_mod_d(prime, 4uL, &i)) != MP_OKAY) goto cleanup;
42 if (i == 3) { 37 if (i == 3u) {
43 if ((res = mp_add_d(prime, 1, &t1)) != MP_OKAY) goto cleanup; 38 if ((err = mp_add_d(prime, 1uL, &t1)) != MP_OKAY) goto cleanup;
44 if ((res = mp_div_2(&t1, &t1)) != MP_OKAY) goto cleanup; 39 if ((err = mp_div_2(&t1, &t1)) != MP_OKAY) goto cleanup;
45 if ((res = mp_div_2(&t1, &t1)) != MP_OKAY) goto cleanup; 40 if ((err = mp_div_2(&t1, &t1)) != MP_OKAY) goto cleanup;
46 if ((res = mp_exptmod(n, &t1, prime, ret)) != MP_OKAY) goto cleanup; 41 if ((err = mp_exptmod(n, &t1, prime, ret)) != MP_OKAY) goto cleanup;
47 res = MP_OKAY; 42 err = MP_OKAY;
48 goto cleanup; 43 goto cleanup;
49 } 44 }
50 45
51 /* NOW: Tonelli-Shanks algorithm */ 46 /* NOW: Tonelli-Shanks algorithm */
52 47
53 /* factor out powers of 2 from prime-1, defining Q and S as: prime-1 = Q*2^S */ 48 /* factor out powers of 2 from prime-1, defining Q and S as: prime-1 = Q*2^S */
54 if ((res = mp_copy(prime, &Q)) != MP_OKAY) goto cleanup; 49 if ((err = mp_copy(prime, &Q)) != MP_OKAY) goto cleanup;
55 if ((res = mp_sub_d(&Q, 1, &Q)) != MP_OKAY) goto cleanup; 50 if ((err = mp_sub_d(&Q, 1uL, &Q)) != MP_OKAY) goto cleanup;
56 /* Q = prime - 1 */ 51 /* Q = prime - 1 */
57 mp_zero(&S); 52 mp_zero(&S);
58 /* S = 0 */ 53 /* S = 0 */
59 while (mp_iseven(&Q) != MP_NO) { 54 while (MP_IS_EVEN(&Q)) {
60 if ((res = mp_div_2(&Q, &Q)) != MP_OKAY) goto cleanup; 55 if ((err = mp_div_2(&Q, &Q)) != MP_OKAY) goto cleanup;
61 /* Q = Q / 2 */ 56 /* Q = Q / 2 */
62 if ((res = mp_add_d(&S, 1, &S)) != MP_OKAY) goto cleanup; 57 if ((err = mp_add_d(&S, 1uL, &S)) != MP_OKAY) goto cleanup;
63 /* S = S + 1 */ 58 /* S = S + 1 */
64 } 59 }
65 60
66 /* find a Z such that the Legendre symbol (Z|prime) == -1 */ 61 /* find a Z such that the Legendre symbol (Z|prime) == -1 */
67 if ((res = mp_set_int(&Z, 2)) != MP_OKAY) goto cleanup; 62 mp_set_u32(&Z, 2u);
68 /* Z = 2 */ 63 /* Z = 2 */
69 while(1) { 64 for (;;) {
70 if ((res = mp_jacobi(&Z, prime, &legendre)) != MP_OKAY) goto cleanup; 65 if ((err = mp_kronecker(&Z, prime, &legendre)) != MP_OKAY) goto cleanup;
71 if (legendre == -1) break; 66 if (legendre == -1) break;
72 if ((res = mp_add_d(&Z, 1, &Z)) != MP_OKAY) goto cleanup; 67 if ((err = mp_add_d(&Z, 1uL, &Z)) != MP_OKAY) goto cleanup;
73 /* Z = Z + 1 */ 68 /* Z = Z + 1 */
74 } 69 }
75 70
76 if ((res = mp_exptmod(&Z, &Q, prime, &C)) != MP_OKAY) goto cleanup; 71 if ((err = mp_exptmod(&Z, &Q, prime, &C)) != MP_OKAY) goto cleanup;
77 /* C = Z ^ Q mod prime */ 72 /* C = Z ^ Q mod prime */
78 if ((res = mp_add_d(&Q, 1, &t1)) != MP_OKAY) goto cleanup; 73 if ((err = mp_add_d(&Q, 1uL, &t1)) != MP_OKAY) goto cleanup;
79 if ((res = mp_div_2(&t1, &t1)) != MP_OKAY) goto cleanup; 74 if ((err = mp_div_2(&t1, &t1)) != MP_OKAY) goto cleanup;
80 /* t1 = (Q + 1) / 2 */ 75 /* t1 = (Q + 1) / 2 */
81 if ((res = mp_exptmod(n, &t1, prime, &R)) != MP_OKAY) goto cleanup; 76 if ((err = mp_exptmod(n, &t1, prime, &R)) != MP_OKAY) goto cleanup;
82 /* R = n ^ ((Q + 1) / 2) mod prime */ 77 /* R = n ^ ((Q + 1) / 2) mod prime */
83 if ((res = mp_exptmod(n, &Q, prime, &T)) != MP_OKAY) goto cleanup; 78 if ((err = mp_exptmod(n, &Q, prime, &T)) != MP_OKAY) goto cleanup;
84 /* T = n ^ Q mod prime */ 79 /* T = n ^ Q mod prime */
85 if ((res = mp_copy(&S, &M)) != MP_OKAY) goto cleanup; 80 if ((err = mp_copy(&S, &M)) != MP_OKAY) goto cleanup;
86 /* M = S */ 81 /* M = S */
87 if ((res = mp_set_int(&two, 2)) != MP_OKAY) goto cleanup; 82 mp_set_u32(&two, 2u);
88 83
89 res = MP_VAL; 84 for (;;) {
90 while (1) { 85 if ((err = mp_copy(&T, &t1)) != MP_OKAY) goto cleanup;
91 if ((res = mp_copy(&T, &t1)) != MP_OKAY) goto cleanup; 86 i = 0;
92 i = 0; 87 for (;;) {
93 while (1) { 88 if (mp_cmp_d(&t1, 1uL) == MP_EQ) break;
94 if (mp_cmp_d(&t1, 1) == MP_EQ) break; 89 if ((err = mp_exptmod(&t1, &two, prime, &t1)) != MP_OKAY) goto cleanup;
95 if ((res = mp_exptmod(&t1, &two, prime, &t1)) != MP_OKAY) goto cleanup; 90 i++;
96 i++; 91 }
97 } 92 if (i == 0u) {
98 if (i == 0) { 93 if ((err = mp_copy(&R, ret)) != MP_OKAY) goto cleanup;
99 if ((res = mp_copy(&R, ret)) != MP_OKAY) goto cleanup; 94 err = MP_OKAY;
100 res = MP_OKAY; 95 goto cleanup;
101 goto cleanup; 96 }
102 } 97 if ((err = mp_sub_d(&M, i, &t1)) != MP_OKAY) goto cleanup;
103 if ((res = mp_sub_d(&M, i, &t1)) != MP_OKAY) goto cleanup; 98 if ((err = mp_sub_d(&t1, 1uL, &t1)) != MP_OKAY) goto cleanup;
104 if ((res = mp_sub_d(&t1, 1, &t1)) != MP_OKAY) goto cleanup; 99 if ((err = mp_exptmod(&two, &t1, prime, &t1)) != MP_OKAY) goto cleanup;
105 if ((res = mp_exptmod(&two, &t1, prime, &t1)) != MP_OKAY) goto cleanup; 100 /* t1 = 2 ^ (M - i - 1) */
106 /* t1 = 2 ^ (M - i - 1) */ 101 if ((err = mp_exptmod(&C, &t1, prime, &t1)) != MP_OKAY) goto cleanup;
107 if ((res = mp_exptmod(&C, &t1, prime, &t1)) != MP_OKAY) goto cleanup; 102 /* t1 = C ^ (2 ^ (M - i - 1)) mod prime */
108 /* t1 = C ^ (2 ^ (M - i - 1)) mod prime */ 103 if ((err = mp_sqrmod(&t1, prime, &C)) != MP_OKAY) goto cleanup;
109 if ((res = mp_sqrmod(&t1, prime, &C)) != MP_OKAY) goto cleanup; 104 /* C = (t1 * t1) mod prime */
110 /* C = (t1 * t1) mod prime */ 105 if ((err = mp_mulmod(&R, &t1, prime, &R)) != MP_OKAY) goto cleanup;
111 if ((res = mp_mulmod(&R, &t1, prime, &R)) != MP_OKAY) goto cleanup; 106 /* R = (R * t1) mod prime */
112 /* R = (R * t1) mod prime */ 107 if ((err = mp_mulmod(&T, &C, prime, &T)) != MP_OKAY) goto cleanup;
113 if ((res = mp_mulmod(&T, &C, prime, &T)) != MP_OKAY) goto cleanup; 108 /* T = (T * C) mod prime */
114 /* T = (T * C) mod prime */ 109 mp_set(&M, i);
115 mp_set(&M, i); 110 /* M = i */
116 /* M = i */ 111 }
117 }
118 112
119 cleanup: 113 cleanup:
120 mp_clear_multi(&t1, &C, &Q, &S, &Z, &M, &T, &R, &two, NULL); 114 mp_clear_multi(&t1, &C, &Q, &S, &Z, &M, &T, &R, &two, NULL);
121 return res; 115 return err;
122 } 116 }
123 117
124 #endif 118 #endif