bn_mp_div_d.c 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. #include "tommath_private.h"
  2. #ifdef BN_MP_DIV_D_C
  3. /* LibTomMath, multiple-precision integer library -- Tom St Denis */
  4. /* SPDX-License-Identifier: Unlicense */
  5. /* single digit division (based on routine from MPI) */
  6. mp_err mp_div_d(const mp_int *a, mp_digit b, mp_int *c, mp_digit *d)
  7. {
  8. mp_int q;
  9. mp_word w;
  10. mp_digit t;
  11. mp_err err;
  12. int ix;
  13. /* cannot divide by zero */
  14. if (b == 0u) {
  15. return MP_VAL;
  16. }
  17. /* quick outs */
  18. if ((b == 1u) || MP_IS_ZERO(a)) {
  19. if (d != NULL) {
  20. *d = 0;
  21. }
  22. if (c != NULL) {
  23. return mp_copy(a, c);
  24. }
  25. return MP_OKAY;
  26. }
  27. /* power of two ? */
  28. if ((b & (b - 1u)) == 0u) {
  29. ix = 1;
  30. while ((ix < MP_DIGIT_BIT) && (b != (((mp_digit)1)<<ix))) {
  31. ix++;
  32. }
  33. if (d != NULL) {
  34. *d = a->dp[0] & (((mp_digit)1<<(mp_digit)ix) - 1uL);
  35. }
  36. if (c != NULL) {
  37. return mp_div_2d(a, ix, c, NULL);
  38. }
  39. return MP_OKAY;
  40. }
  41. /* three? */
  42. if (MP_HAS(MP_DIV_3) && (b == 3u)) {
  43. return mp_div_3(a, c, d);
  44. }
  45. /* no easy answer [c'est la vie]. Just division */
  46. if ((err = mp_init_size(&q, a->used)) != MP_OKAY) {
  47. return err;
  48. }
  49. q.used = a->used;
  50. q.sign = a->sign;
  51. w = 0;
  52. for (ix = a->used - 1; ix >= 0; ix--) {
  53. w = (w << (mp_word)MP_DIGIT_BIT) | (mp_word)a->dp[ix];
  54. if (w >= b) {
  55. t = (mp_digit)(w / b);
  56. w -= (mp_word)t * (mp_word)b;
  57. } else {
  58. t = 0;
  59. }
  60. q.dp[ix] = t;
  61. }
  62. if (d != NULL) {
  63. *d = (mp_digit)w;
  64. }
  65. if (c != NULL) {
  66. mp_clamp(&q);
  67. mp_exch(&q, c);
  68. }
  69. mp_clear(&q);
  70. return err;
  71. }
  72. #endif