bn_fast_mp_invmod.c revision f7fc46c63fdc8f39234fea409b8dbe116d73ebf8
1f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project#include <tommath.h> 2f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project#ifdef BN_FAST_MP_INVMOD_C 3f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project/* LibTomMath, multiple-precision integer library -- Tom St Denis 4f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * 5f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * LibTomMath is a library that provides multiple-precision 6f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * integer arithmetic as well as number theoretic functionality. 7f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * 8f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * The library was designed directly after the MPI library by 9f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * Michael Fromberger but has been written from scratch with 10f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * additional optimizations in place. 11f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * 12f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * The library is free for all purposes without any express 13f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * guarantee it works. 14f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * 15f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com 16f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project */ 17f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project 18f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project/* computes the modular inverse via binary extended euclidean algorithm, 19f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * that is c = 1/a mod b 20f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * 21f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * Based on slow invmod except this is optimized for the case where b is 22f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * odd as per HAC Note 14.64 on pp. 610 23f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project */ 24f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Projectint fast_mp_invmod (mp_int * a, mp_int * b, mp_int * c) 25f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project{ 26f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project mp_int x, y, u, v, B, D; 27f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project int res, neg; 28f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project 29f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project /* 2. [modified] b must be odd */ 30f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project if (mp_iseven (b) == 1) { 31f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project return MP_VAL; 32f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project } 33f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project 34f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project /* init all our temps */ 35f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project if ((res = mp_init_multi(&x, &y, &u, &v, &B, &D, NULL)) != MP_OKAY) { 36f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project return res; 37f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project } 38f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project 39f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project /* x == modulus, y == value to invert */ 40f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project if ((res = mp_copy (b, &x)) != MP_OKAY) { 41f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project goto LBL_ERR; 42f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project } 43f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project 44f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project /* we need y = |a| */ 45f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project if ((res = mp_mod (a, b, &y)) != MP_OKAY) { 46f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project goto LBL_ERR; 47f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project } 48f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project 49f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */ 50f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project if ((res = mp_copy (&x, &u)) != MP_OKAY) { 51f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project goto LBL_ERR; 52f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project } 53f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project if ((res = mp_copy (&y, &v)) != MP_OKAY) { 54f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project goto LBL_ERR; 55f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project } 56f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project mp_set (&D, 1); 57f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project 58f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Projecttop: 59f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project /* 4. while u is even do */ 60f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project while (mp_iseven (&u) == 1) { 61f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project /* 4.1 u = u/2 */ 62f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project if ((res = mp_div_2 (&u, &u)) != MP_OKAY) { 63f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project goto LBL_ERR; 64f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project } 65f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project /* 4.2 if B is odd then */ 66f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project if (mp_isodd (&B) == 1) { 67f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) { 68f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project goto LBL_ERR; 69f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project } 70f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project } 71f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project /* B = B/2 */ 72f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project if ((res = mp_div_2 (&B, &B)) != MP_OKAY) { 73f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project goto LBL_ERR; 74f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project } 75f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project } 76f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project 77f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project /* 5. while v is even do */ 78f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project while (mp_iseven (&v) == 1) { 79f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project /* 5.1 v = v/2 */ 80f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project if ((res = mp_div_2 (&v, &v)) != MP_OKAY) { 81f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project goto LBL_ERR; 82f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project } 83f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project /* 5.2 if D is odd then */ 84f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project if (mp_isodd (&D) == 1) { 85f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project /* D = (D-x)/2 */ 86f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) { 87f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project goto LBL_ERR; 88f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project } 89f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project } 90f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project /* D = D/2 */ 91f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project if ((res = mp_div_2 (&D, &D)) != MP_OKAY) { 92f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project goto LBL_ERR; 93f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project } 94f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project } 95f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project 96f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project /* 6. if u >= v then */ 97f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project if (mp_cmp (&u, &v) != MP_LT) { 98f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project /* u = u - v, B = B - D */ 99f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project if ((res = mp_sub (&u, &v, &u)) != MP_OKAY) { 100f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project goto LBL_ERR; 101f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project } 102f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project 103f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) { 104f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project goto LBL_ERR; 105f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project } 106f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project } else { 107f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project /* v - v - u, D = D - B */ 108f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) { 109f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project goto LBL_ERR; 110f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project } 111f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project 112f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) { 113f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project goto LBL_ERR; 114f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project } 115f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project } 116f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project 117f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project /* if not zero goto step 4 */ 118f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project if (mp_iszero (&u) == 0) { 119f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project goto top; 120f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project } 121f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project 122f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project /* now a = C, b = D, gcd == g*v */ 123f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project 124f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project /* if v != 1 then there is no inverse */ 125f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project if (mp_cmp_d (&v, 1) != MP_EQ) { 126f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project res = MP_VAL; 127f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project goto LBL_ERR; 128f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project } 129f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project 130f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project /* b is now the inverse */ 131f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project neg = a->sign; 132f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project while (D.sign == MP_NEG) { 133f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project if ((res = mp_add (&D, b, &D)) != MP_OKAY) { 134f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project goto LBL_ERR; 135f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project } 136f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project } 137f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project mp_exch (&D, c); 138f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project c->sign = neg; 139f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project res = MP_OKAY; 140f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project 141f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source ProjectLBL_ERR:mp_clear_multi (&x, &y, &u, &v, &B, &D, NULL); 142f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project return res; 143f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project} 144f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project#endif 145f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project 146f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project/* $Source: /cvs/libtom/libtommath/bn_fast_mp_invmod.c,v $ */ 147f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project/* $Revision: 1.3 $ */ 148f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project/* $Date: 2006/03/31 14:18:44 $ */ 149