bn_mp_prime_frobenius_underwood.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. #include "tommath_private.h"
  2. #ifdef BN_MP_PRIME_FROBENIUS_UNDERWOOD_C
  3. /* LibTomMath, multiple-precision integer library -- Tom St Denis */
  4. /* SPDX-License-Identifier: Unlicense */
  5. /*
  6. * See file bn_mp_prime_is_prime.c or the documentation in doc/bn.tex for the details
  7. */
  8. #ifndef LTM_USE_ONLY_MR
  9. #ifdef MP_8BIT
  10. /*
  11. * floor of positive solution of
  12. * (2^16)-1 = (a+4)*(2*a+5)
  13. * TODO: Both values are smaller than N^(1/4), would have to use a bigint
  14. * for a instead but any a biger than about 120 are already so rare that
  15. * it is possible to ignore them and still get enough pseudoprimes.
  16. * But it is still a restriction of the set of available pseudoprimes
  17. * which makes this implementation less secure if used stand-alone.
  18. */
  19. #define LTM_FROBENIUS_UNDERWOOD_A 177
  20. #else
  21. #define LTM_FROBENIUS_UNDERWOOD_A 32764
  22. #endif
  23. mp_err mp_prime_frobenius_underwood(const mp_int *N, mp_bool *result)
  24. {
  25. mp_int T1z, T2z, Np1z, sz, tz;
  26. int a, ap2, length, i, j;
  27. mp_err err;
  28. *result = MP_NO;
  29. if ((err = mp_init_multi(&T1z, &T2z, &Np1z, &sz, &tz, NULL)) != MP_OKAY) {
  30. return err;
  31. }
  32. for (a = 0; a < LTM_FROBENIUS_UNDERWOOD_A; a++) {
  33. /* TODO: That's ugly! No, really, it is! */
  34. if ((a==2) || (a==4) || (a==7) || (a==8) || (a==10) ||
  35. (a==14) || (a==18) || (a==23) || (a==26) || (a==28)) {
  36. continue;
  37. }
  38. /* (32764^2 - 4) < 2^31, no bigint for >MP_8BIT needed) */
  39. mp_set_u32(&T1z, (uint32_t)a);
  40. if ((err = mp_sqr(&T1z, &T1z)) != MP_OKAY) goto LBL_FU_ERR;
  41. if ((err = mp_sub_d(&T1z, 4uL, &T1z)) != MP_OKAY) goto LBL_FU_ERR;
  42. if ((err = mp_kronecker(&T1z, N, &j)) != MP_OKAY) goto LBL_FU_ERR;
  43. if (j == -1) {
  44. break;
  45. }
  46. if (j == 0) {
  47. /* composite */
  48. goto LBL_FU_ERR;
  49. }
  50. }
  51. /* Tell it a composite and set return value accordingly */
  52. if (a >= LTM_FROBENIUS_UNDERWOOD_A) {
  53. err = MP_ITER;
  54. goto LBL_FU_ERR;
  55. }
  56. /* Composite if N and (a+4)*(2*a+5) are not coprime */
  57. mp_set_u32(&T1z, (uint32_t)((a+4)*((2*a)+5)));
  58. if ((err = mp_gcd(N, &T1z, &T1z)) != MP_OKAY) goto LBL_FU_ERR;
  59. if (!((T1z.used == 1) && (T1z.dp[0] == 1u))) goto LBL_FU_ERR;
  60. ap2 = a + 2;
  61. if ((err = mp_add_d(N, 1uL, &Np1z)) != MP_OKAY) goto LBL_FU_ERR;
  62. mp_set(&sz, 1uL);
  63. mp_set(&tz, 2uL);
  64. length = mp_count_bits(&Np1z);
  65. for (i = length - 2; i >= 0; i--) {
  66. /*
  67. * temp = (sz*(a*sz+2*tz))%N;
  68. * tz = ((tz-sz)*(tz+sz))%N;
  69. * sz = temp;
  70. */
  71. if ((err = mp_mul_2(&tz, &T2z)) != MP_OKAY) goto LBL_FU_ERR;
  72. /* a = 0 at about 50% of the cases (non-square and odd input) */
  73. if (a != 0) {
  74. if ((err = mp_mul_d(&sz, (mp_digit)a, &T1z)) != MP_OKAY) goto LBL_FU_ERR;
  75. if ((err = mp_add(&T1z, &T2z, &T2z)) != MP_OKAY) goto LBL_FU_ERR;
  76. }
  77. if ((err = mp_mul(&T2z, &sz, &T1z)) != MP_OKAY) goto LBL_FU_ERR;
  78. if ((err = mp_sub(&tz, &sz, &T2z)) != MP_OKAY) goto LBL_FU_ERR;
  79. if ((err = mp_add(&sz, &tz, &sz)) != MP_OKAY) goto LBL_FU_ERR;
  80. if ((err = mp_mul(&sz, &T2z, &tz)) != MP_OKAY) goto LBL_FU_ERR;
  81. if ((err = mp_mod(&tz, N, &tz)) != MP_OKAY) goto LBL_FU_ERR;
  82. if ((err = mp_mod(&T1z, N, &sz)) != MP_OKAY) goto LBL_FU_ERR;
  83. if (s_mp_get_bit(&Np1z, (unsigned int)i) == MP_YES) {
  84. /*
  85. * temp = (a+2) * sz + tz
  86. * tz = 2 * tz - sz
  87. * sz = temp
  88. */
  89. if (a == 0) {
  90. if ((err = mp_mul_2(&sz, &T1z)) != MP_OKAY) goto LBL_FU_ERR;
  91. } else {
  92. if ((err = mp_mul_d(&sz, (mp_digit)ap2, &T1z)) != MP_OKAY) goto LBL_FU_ERR;
  93. }
  94. if ((err = mp_add(&T1z, &tz, &T1z)) != MP_OKAY) goto LBL_FU_ERR;
  95. if ((err = mp_mul_2(&tz, &T2z)) != MP_OKAY) goto LBL_FU_ERR;
  96. if ((err = mp_sub(&T2z, &sz, &tz)) != MP_OKAY) goto LBL_FU_ERR;
  97. mp_exch(&sz, &T1z);
  98. }
  99. }
  100. mp_set_u32(&T1z, (uint32_t)((2 * a) + 5));
  101. if ((err = mp_mod(&T1z, N, &T1z)) != MP_OKAY) goto LBL_FU_ERR;
  102. if (MP_IS_ZERO(&sz) && (mp_cmp(&tz, &T1z) == MP_EQ)) {
  103. *result = MP_YES;
  104. }
  105. LBL_FU_ERR:
  106. mp_clear_multi(&tz, &sz, &Np1z, &T2z, &T1z, NULL);
  107. return err;
  108. }
  109. #endif
  110. #endif