/src/dropbear/libtommath/bn_s_mp_invmod_fast.c
Line | Count | Source |
1 | | #include "tommath_private.h" |
2 | | #ifdef BN_S_MP_INVMOD_FAST_C |
3 | | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ |
4 | | /* SPDX-License-Identifier: Unlicense */ |
5 | | |
6 | | /* computes the modular inverse via binary extended euclidean algorithm, |
7 | | * that is c = 1/a mod b |
8 | | * |
9 | | * Based on slow invmod except this is optimized for the case where b is |
10 | | * odd as per HAC Note 14.64 on pp. 610 |
11 | | */ |
12 | | mp_err s_mp_invmod_fast(const mp_int *a, const mp_int *b, mp_int *c) |
13 | 9.98k | { |
14 | 9.98k | mp_int x, y, u, v, B, D; |
15 | 9.98k | mp_sign neg; |
16 | 9.98k | mp_err err; |
17 | | |
18 | | /* 2. [modified] b must be odd */ |
19 | 9.98k | if (MP_IS_EVEN(b)) { |
20 | 0 | return MP_VAL; |
21 | 0 | } |
22 | | |
23 | | /* init all our temps */ |
24 | 9.98k | if ((err = mp_init_multi(&x, &y, &u, &v, &B, &D, NULL)) != MP_OKAY) { |
25 | 0 | return err; |
26 | 0 | } |
27 | | |
28 | | /* x == modulus, y == value to invert */ |
29 | 9.98k | if ((err = mp_copy(b, &x)) != MP_OKAY) goto LBL_ERR; |
30 | | |
31 | | /* we need y = |a| */ |
32 | 9.98k | if ((err = mp_mod(a, b, &y)) != MP_OKAY) goto LBL_ERR; |
33 | | |
34 | | /* if one of x,y is zero return an error! */ |
35 | 9.98k | if (MP_IS_ZERO(&x) || MP_IS_ZERO(&y)) { |
36 | 0 | err = MP_VAL; |
37 | 0 | goto LBL_ERR; |
38 | 0 | } |
39 | | |
40 | | /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */ |
41 | 9.98k | if ((err = mp_copy(&x, &u)) != MP_OKAY) goto LBL_ERR; |
42 | 9.98k | if ((err = mp_copy(&y, &v)) != MP_OKAY) goto LBL_ERR; |
43 | 9.98k | mp_set(&D, 1uL); |
44 | | |
45 | 11.8M | top: |
46 | | /* 4. while u is even do */ |
47 | 23.7M | while (MP_IS_EVEN(&u)) { |
48 | | /* 4.1 u = u/2 */ |
49 | 11.9M | if ((err = mp_div_2(&u, &u)) != MP_OKAY) goto LBL_ERR; |
50 | | |
51 | | /* 4.2 if B is odd then */ |
52 | 11.9M | if (MP_IS_ODD(&B)) { |
53 | 5.98M | if ((err = mp_sub(&B, &x, &B)) != MP_OKAY) goto LBL_ERR; |
54 | 5.98M | } |
55 | | /* B = B/2 */ |
56 | 11.9M | if ((err = mp_div_2(&B, &B)) != MP_OKAY) goto LBL_ERR; |
57 | 11.9M | } |
58 | | |
59 | | /* 5. while v is even do */ |
60 | 23.6M | while (MP_IS_EVEN(&v)) { |
61 | | /* 5.1 v = v/2 */ |
62 | 11.8M | if ((err = mp_div_2(&v, &v)) != MP_OKAY) goto LBL_ERR; |
63 | | |
64 | | /* 5.2 if D is odd then */ |
65 | 11.8M | if (MP_IS_ODD(&D)) { |
66 | | /* D = (D-x)/2 */ |
67 | 6.08M | if ((err = mp_sub(&D, &x, &D)) != MP_OKAY) goto LBL_ERR; |
68 | 6.08M | } |
69 | | /* D = D/2 */ |
70 | 11.8M | if ((err = mp_div_2(&D, &D)) != MP_OKAY) goto LBL_ERR; |
71 | 11.8M | } |
72 | | |
73 | | /* 6. if u >= v then */ |
74 | 11.8M | if (mp_cmp(&u, &v) != MP_LT) { |
75 | | /* u = u - v, B = B - D */ |
76 | 5.95M | if ((err = mp_sub(&u, &v, &u)) != MP_OKAY) goto LBL_ERR; |
77 | | |
78 | 5.95M | if ((err = mp_sub(&B, &D, &B)) != MP_OKAY) goto LBL_ERR; |
79 | 5.95M | } else { |
80 | | /* v - v - u, D = D - B */ |
81 | 5.88M | if ((err = mp_sub(&v, &u, &v)) != MP_OKAY) goto LBL_ERR; |
82 | | |
83 | 5.88M | if ((err = mp_sub(&D, &B, &D)) != MP_OKAY) goto LBL_ERR; |
84 | 5.88M | } |
85 | | |
86 | | /* if not zero goto step 4 */ |
87 | 11.8M | if (!MP_IS_ZERO(&u)) { |
88 | 11.8M | goto top; |
89 | 11.8M | } |
90 | | |
91 | | /* now a = C, b = D, gcd == g*v */ |
92 | | |
93 | | /* if v != 1 then there is no inverse */ |
94 | 9.98k | if (mp_cmp_d(&v, 1uL) != MP_EQ) { |
95 | 5 | err = MP_VAL; |
96 | 5 | goto LBL_ERR; |
97 | 5 | } |
98 | | |
99 | | /* b is now the inverse */ |
100 | 9.98k | neg = a->sign; |
101 | 18.5k | while (D.sign == MP_NEG) { |
102 | 8.54k | if ((err = mp_add(&D, b, &D)) != MP_OKAY) goto LBL_ERR; |
103 | 8.54k | } |
104 | | |
105 | | /* too big */ |
106 | 10.0k | while (mp_cmp_mag(&D, b) != MP_LT) { |
107 | 50 | if ((err = mp_sub(&D, b, &D)) != MP_OKAY) goto LBL_ERR; |
108 | 50 | } |
109 | | |
110 | 9.98k | mp_exch(&D, c); |
111 | 9.98k | c->sign = neg; |
112 | 9.98k | err = MP_OKAY; |
113 | | |
114 | 9.98k | LBL_ERR: |
115 | | mp_clear_multi(&x, &y, &u, &v, &B, &D, NULL); |
116 | 9.98k | return err; |
117 | 9.98k | } |
118 | | #endif |