mpi-inv.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. /* mpi-inv.c - MPI functions
  2. * Copyright (C) 1998, 2001, 2002, 2003 Free Software Foundation, Inc.
  3. *
  4. * This file is part of Libgcrypt.
  5. *
  6. * Libgcrypt is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU Lesser General Public License as
  8. * published by the Free Software Foundation; either version 2.1 of
  9. * the License, or (at your option) any later version.
  10. *
  11. * Libgcrypt is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this program; if not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include "mpi-internal.h"
  20. /****************
  21. * Calculate the multiplicative inverse X of A mod N
  22. * That is: Find the solution x for
  23. * 1 = (a*x) mod n
  24. */
  25. int mpi_invm(MPI x, MPI a, MPI n)
  26. {
  27. /* Extended Euclid's algorithm (See TAOCP Vol II, 4.5.2, Alg X)
  28. * modified according to Michael Penk's solution for Exercise 35
  29. * with further enhancement
  30. */
  31. MPI u, v, u1, u2 = NULL, u3, v1, v2 = NULL, v3, t1, t2 = NULL, t3;
  32. unsigned int k;
  33. int sign;
  34. int odd;
  35. if (!mpi_cmp_ui(a, 0))
  36. return 0; /* Inverse does not exists. */
  37. if (!mpi_cmp_ui(n, 1))
  38. return 0; /* Inverse does not exists. */
  39. u = mpi_copy(a);
  40. v = mpi_copy(n);
  41. for (k = 0; !mpi_test_bit(u, 0) && !mpi_test_bit(v, 0); k++) {
  42. mpi_rshift(u, u, 1);
  43. mpi_rshift(v, v, 1);
  44. }
  45. odd = mpi_test_bit(v, 0);
  46. u1 = mpi_alloc_set_ui(1);
  47. if (!odd)
  48. u2 = mpi_alloc_set_ui(0);
  49. u3 = mpi_copy(u);
  50. v1 = mpi_copy(v);
  51. if (!odd) {
  52. v2 = mpi_alloc(mpi_get_nlimbs(u));
  53. mpi_sub(v2, u1, u); /* U is used as const 1 */
  54. }
  55. v3 = mpi_copy(v);
  56. if (mpi_test_bit(u, 0)) { /* u is odd */
  57. t1 = mpi_alloc_set_ui(0);
  58. if (!odd) {
  59. t2 = mpi_alloc_set_ui(1);
  60. t2->sign = 1;
  61. }
  62. t3 = mpi_copy(v);
  63. t3->sign = !t3->sign;
  64. goto Y4;
  65. } else {
  66. t1 = mpi_alloc_set_ui(1);
  67. if (!odd)
  68. t2 = mpi_alloc_set_ui(0);
  69. t3 = mpi_copy(u);
  70. }
  71. do {
  72. do {
  73. if (!odd) {
  74. if (mpi_test_bit(t1, 0) || mpi_test_bit(t2, 0)) {
  75. /* one is odd */
  76. mpi_add(t1, t1, v);
  77. mpi_sub(t2, t2, u);
  78. }
  79. mpi_rshift(t1, t1, 1);
  80. mpi_rshift(t2, t2, 1);
  81. mpi_rshift(t3, t3, 1);
  82. } else {
  83. if (mpi_test_bit(t1, 0))
  84. mpi_add(t1, t1, v);
  85. mpi_rshift(t1, t1, 1);
  86. mpi_rshift(t3, t3, 1);
  87. }
  88. Y4:
  89. ;
  90. } while (!mpi_test_bit(t3, 0)); /* while t3 is even */
  91. if (!t3->sign) {
  92. mpi_set(u1, t1);
  93. if (!odd)
  94. mpi_set(u2, t2);
  95. mpi_set(u3, t3);
  96. } else {
  97. mpi_sub(v1, v, t1);
  98. sign = u->sign; u->sign = !u->sign;
  99. if (!odd)
  100. mpi_sub(v2, u, t2);
  101. u->sign = sign;
  102. sign = t3->sign; t3->sign = !t3->sign;
  103. mpi_set(v3, t3);
  104. t3->sign = sign;
  105. }
  106. mpi_sub(t1, u1, v1);
  107. if (!odd)
  108. mpi_sub(t2, u2, v2);
  109. mpi_sub(t3, u3, v3);
  110. if (t1->sign) {
  111. mpi_add(t1, t1, v);
  112. if (!odd)
  113. mpi_sub(t2, t2, u);
  114. }
  115. } while (mpi_cmp_ui(t3, 0)); /* while t3 != 0 */
  116. /* mpi_lshift( u3, k ); */
  117. mpi_set(x, u1);
  118. mpi_free(u1);
  119. mpi_free(v1);
  120. mpi_free(t1);
  121. if (!odd) {
  122. mpi_free(u2);
  123. mpi_free(v2);
  124. mpi_free(t2);
  125. }
  126. mpi_free(u3);
  127. mpi_free(v3);
  128. mpi_free(t3);
  129. mpi_free(u);
  130. mpi_free(v);
  131. return 1;
  132. }
  133. EXPORT_SYMBOL_GPL(mpi_invm);