sshbn.h 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. /*
  2. * sshbn.h: the assorted conditional definitions of BignumInt and
  3. * multiply/divide macros used throughout the bignum code to treat
  4. * numbers as arrays of the most conveniently sized word for the
  5. * target machine. Exported so that other code (e.g. poly1305) can use
  6. * it too.
  7. */
  8. /*
  9. * Usage notes:
  10. * * Do not call the DIVMOD_WORD macro with expressions such as array
  11. * subscripts, as some implementations object to this (see below).
  12. * * Note that none of the division methods below will cope if the
  13. * quotient won't fit into BIGNUM_INT_BITS. Callers should be careful
  14. * to avoid this case.
  15. * If this condition occurs, in the case of the x86 DIV instruction,
  16. * an overflow exception will occur, which (according to a correspondent)
  17. * will manifest on Windows as something like
  18. * 0xC0000095: Integer overflow
  19. * The C variant won't give the right answer, either.
  20. */
  21. #if defined __SIZEOF_INT128__
  22. /* gcc and clang both provide a __uint128_t type on 64-bit targets
  23. * (and, when they do, indicate its presence by the above macro),
  24. * using the same 'two machine registers' kind of code generation that
  25. * 32-bit targets use for 64-bit ints. If we have one of these, we can
  26. * use a 64-bit BignumInt and a 128-bit BignumDblInt. */
  27. typedef __uint64_t BignumInt;
  28. typedef __uint128_t BignumDblInt;
  29. #define BIGNUM_INT_MASK 0xFFFFFFFFFFFFFFFFULL
  30. #define BIGNUM_TOP_BIT 0x8000000000000000ULL
  31. #define BIGNUM_INT_BITS 64
  32. #define MUL_WORD(w1, w2) ((BignumDblInt)w1 * w2)
  33. #define DIVMOD_WORD(q, r, hi, lo, w) do { \
  34. BignumDblInt n = (((BignumDblInt)hi) << BIGNUM_INT_BITS) | lo; \
  35. q = n / w; \
  36. r = n % w; \
  37. } while (0)
  38. #elif defined __GNUC__ && defined __i386__
  39. typedef unsigned long BignumInt;
  40. typedef unsigned long long BignumDblInt;
  41. #define BIGNUM_INT_MASK 0xFFFFFFFFUL
  42. #define BIGNUM_TOP_BIT 0x80000000UL
  43. #define BIGNUM_INT_BITS 32
  44. #define MUL_WORD(w1, w2) ((BignumDblInt)w1 * w2)
  45. #define DIVMOD_WORD(q, r, hi, lo, w) \
  46. __asm__("div %2" : \
  47. "=d" (r), "=a" (q) : \
  48. "r" (w), "d" (hi), "a" (lo))
  49. #elif (defined _MSC_VER && defined _M_IX86) || defined(MPEXT)
  50. typedef unsigned __int32 BignumInt;
  51. typedef unsigned __int64 BignumDblInt;
  52. #define BIGNUM_INT_MASK 0xFFFFFFFFUL
  53. #define BIGNUM_TOP_BIT 0x80000000UL
  54. #define BIGNUM_INT_BITS 32
  55. #define MUL_WORD(w1, w2) ((BignumDblInt)w1 * w2)
  56. /* Note: MASM interprets array subscripts in the macro arguments as
  57. * assembler syntax, which gives the wrong answer. Don't supply them.
  58. * <http://msdn2.microsoft.com/en-us/library/bf1dw62z.aspx> */
  59. #ifdef MPEXT
  60. // BCC requires semicolons
  61. #define DIVMOD_WORD(q, r, hi, lo, w) do { \
  62. __asm mov edx, hi; \
  63. __asm mov eax, lo; \
  64. __asm div w; \
  65. __asm mov r, edx; \
  66. __asm mov q, eax; \
  67. } while(0)
  68. #else
  69. #define DIVMOD_WORD(q, r, hi, lo, w) do { \
  70. __asm mov edx, hi \
  71. __asm mov eax, lo \
  72. __asm div w \
  73. __asm mov r, edx \
  74. __asm mov q, eax \
  75. } while(0)
  76. #endif
  77. #elif defined _LP64
  78. /* 64-bit architectures can do 32x32->64 chunks at a time */
  79. typedef unsigned int BignumInt;
  80. typedef unsigned long BignumDblInt;
  81. #define BIGNUM_INT_MASK 0xFFFFFFFFU
  82. #define BIGNUM_TOP_BIT 0x80000000U
  83. #define BIGNUM_INT_BITS 32
  84. #define MUL_WORD(w1, w2) ((BignumDblInt)w1 * w2)
  85. #define DIVMOD_WORD(q, r, hi, lo, w) do { \
  86. BignumDblInt n = (((BignumDblInt)hi) << BIGNUM_INT_BITS) | lo; \
  87. q = n / w; \
  88. r = n % w; \
  89. } while (0)
  90. #elif defined _LLP64
  91. /* 64-bit architectures in which unsigned long is 32 bits, not 64 */
  92. typedef unsigned long BignumInt;
  93. typedef unsigned long long BignumDblInt;
  94. #define BIGNUM_INT_MASK 0xFFFFFFFFUL
  95. #define BIGNUM_TOP_BIT 0x80000000UL
  96. #define BIGNUM_INT_BITS 32
  97. #define MUL_WORD(w1, w2) ((BignumDblInt)w1 * w2)
  98. #define DIVMOD_WORD(q, r, hi, lo, w) do { \
  99. BignumDblInt n = (((BignumDblInt)hi) << BIGNUM_INT_BITS) | lo; \
  100. q = n / w; \
  101. r = n % w; \
  102. } while (0)
  103. #else
  104. /* Fallback for all other cases */
  105. typedef unsigned short BignumInt;
  106. typedef unsigned long BignumDblInt;
  107. #define BIGNUM_INT_MASK 0xFFFFU
  108. #define BIGNUM_TOP_BIT 0x8000U
  109. #define BIGNUM_INT_BITS 16
  110. #define MUL_WORD(w1, w2) ((BignumDblInt)w1 * w2)
  111. #define DIVMOD_WORD(q, r, hi, lo, w) do { \
  112. BignumDblInt n = (((BignumDblInt)hi) << BIGNUM_INT_BITS) | lo; \
  113. q = n / w; \
  114. r = n % w; \
  115. } while (0)
  116. #endif
  117. #define BIGNUM_INT_BYTES (BIGNUM_INT_BITS / 8)