bn_mp_sqrtmod_prime.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. #include "tommath_private.h"
  2. #ifdef BN_MP_SQRTMOD_PRIME_C
  3. /* LibTomMath, multiple-precision integer library -- Tom St Denis */
  4. /* SPDX-License-Identifier: Unlicense */
  5. /* Tonelli-Shanks algorithm
  6. * https://en.wikipedia.org/wiki/Tonelli%E2%80%93Shanks_algorithm
  7. * https://gmplib.org/list-archives/gmp-discuss/2013-April/005300.html
  8. *
  9. */
  10. mp_err mp_sqrtmod_prime(const mp_int *n, const mp_int *prime, mp_int *ret)
  11. {
  12. mp_err err;
  13. int legendre;
  14. mp_int t1, C, Q, S, Z, M, T, R, two;
  15. mp_digit i;
  16. /* first handle the simple cases */
  17. if (mp_cmp_d(n, 0uL) == MP_EQ) {
  18. mp_zero(ret);
  19. return MP_OKAY;
  20. }
  21. if (mp_cmp_d(prime, 2uL) == MP_EQ) return MP_VAL; /* prime must be odd */
  22. if ((err = mp_kronecker(n, prime, &legendre)) != MP_OKAY) return err;
  23. if (legendre == -1) return MP_VAL; /* quadratic non-residue mod prime */
  24. if ((err = mp_init_multi(&t1, &C, &Q, &S, &Z, &M, &T, &R, &two, NULL)) != MP_OKAY) {
  25. return err;
  26. }
  27. /* SPECIAL CASE: if prime mod 4 == 3
  28. * compute directly: err = n^(prime+1)/4 mod prime
  29. * Handbook of Applied Cryptography algorithm 3.36
  30. */
  31. if ((err = mp_mod_d(prime, 4uL, &i)) != MP_OKAY) goto cleanup;
  32. if (i == 3u) {
  33. if ((err = mp_add_d(prime, 1uL, &t1)) != MP_OKAY) goto cleanup;
  34. if ((err = mp_div_2(&t1, &t1)) != MP_OKAY) goto cleanup;
  35. if ((err = mp_div_2(&t1, &t1)) != MP_OKAY) goto cleanup;
  36. if ((err = mp_exptmod(n, &t1, prime, ret)) != MP_OKAY) goto cleanup;
  37. err = MP_OKAY;
  38. goto cleanup;
  39. }
  40. /* NOW: Tonelli-Shanks algorithm */
  41. /* factor out powers of 2 from prime-1, defining Q and S as: prime-1 = Q*2^S */
  42. if ((err = mp_copy(prime, &Q)) != MP_OKAY) goto cleanup;
  43. if ((err = mp_sub_d(&Q, 1uL, &Q)) != MP_OKAY) goto cleanup;
  44. /* Q = prime - 1 */
  45. mp_zero(&S);
  46. /* S = 0 */
  47. while (MP_IS_EVEN(&Q)) {
  48. if ((err = mp_div_2(&Q, &Q)) != MP_OKAY) goto cleanup;
  49. /* Q = Q / 2 */
  50. if ((err = mp_add_d(&S, 1uL, &S)) != MP_OKAY) goto cleanup;
  51. /* S = S + 1 */
  52. }
  53. /* find a Z such that the Legendre symbol (Z|prime) == -1 */
  54. mp_set_u32(&Z, 2u);
  55. /* Z = 2 */
  56. for (;;) {
  57. if ((err = mp_kronecker(&Z, prime, &legendre)) != MP_OKAY) goto cleanup;
  58. if (legendre == -1) break;
  59. if ((err = mp_add_d(&Z, 1uL, &Z)) != MP_OKAY) goto cleanup;
  60. /* Z = Z + 1 */
  61. }
  62. if ((err = mp_exptmod(&Z, &Q, prime, &C)) != MP_OKAY) goto cleanup;
  63. /* C = Z ^ Q mod prime */
  64. if ((err = mp_add_d(&Q, 1uL, &t1)) != MP_OKAY) goto cleanup;
  65. if ((err = mp_div_2(&t1, &t1)) != MP_OKAY) goto cleanup;
  66. /* t1 = (Q + 1) / 2 */
  67. if ((err = mp_exptmod(n, &t1, prime, &R)) != MP_OKAY) goto cleanup;
  68. /* R = n ^ ((Q + 1) / 2) mod prime */
  69. if ((err = mp_exptmod(n, &Q, prime, &T)) != MP_OKAY) goto cleanup;
  70. /* T = n ^ Q mod prime */
  71. if ((err = mp_copy(&S, &M)) != MP_OKAY) goto cleanup;
  72. /* M = S */
  73. mp_set_u32(&two, 2u);
  74. for (;;) {
  75. if ((err = mp_copy(&T, &t1)) != MP_OKAY) goto cleanup;
  76. i = 0;
  77. for (;;) {
  78. if (mp_cmp_d(&t1, 1uL) == MP_EQ) break;
  79. if ((err = mp_exptmod(&t1, &two, prime, &t1)) != MP_OKAY) goto cleanup;
  80. i++;
  81. }
  82. if (i == 0u) {
  83. if ((err = mp_copy(&R, ret)) != MP_OKAY) goto cleanup;
  84. err = MP_OKAY;
  85. goto cleanup;
  86. }
  87. if ((err = mp_sub_d(&M, i, &t1)) != MP_OKAY) goto cleanup;
  88. if ((err = mp_sub_d(&t1, 1uL, &t1)) != MP_OKAY) goto cleanup;
  89. if ((err = mp_exptmod(&two, &t1, prime, &t1)) != MP_OKAY) goto cleanup;
  90. /* t1 = 2 ^ (M - i - 1) */
  91. if ((err = mp_exptmod(&C, &t1, prime, &t1)) != MP_OKAY) goto cleanup;
  92. /* t1 = C ^ (2 ^ (M - i - 1)) mod prime */
  93. if ((err = mp_sqrmod(&t1, prime, &C)) != MP_OKAY) goto cleanup;
  94. /* C = (t1 * t1) mod prime */
  95. if ((err = mp_mulmod(&R, &t1, prime, &R)) != MP_OKAY) goto cleanup;
  96. /* R = (R * t1) mod prime */
  97. if ((err = mp_mulmod(&T, &C, prime, &T)) != MP_OKAY) goto cleanup;
  98. /* T = (T * C) mod prime */
  99. mp_set(&M, i);
  100. /* M = i */
  101. }
  102. cleanup:
  103. mp_clear_multi(&t1, &C, &Q, &S, &Z, &M, &T, &R, &two, NULL);
  104. return err;
  105. }
  106. #endif