sshbn.h 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. /*
  2. * sshbn.h: the assorted conditional definitions of BignumInt and
  3. * multiply macros used throughout the bignum code to treat numbers as
  4. * arrays of the most conveniently sized word for the target machine.
  5. * Exported so that other code (e.g. poly1305) can use it too.
  6. *
  7. * This file must export, in whatever ifdef branch it ends up in:
  8. *
  9. * - two types: 'BignumInt' and 'BignumCarry'. BignumInt is an
  10. * unsigned integer type which will be used as the base word size
  11. * for all bignum operations. BignumCarry is an unsigned integer
  12. * type used to hold the carry flag taken as input and output by
  13. * the BignumADC macro (see below).
  14. *
  15. * - four constant macros: BIGNUM_INT_BITS, BIGNUM_INT_BYTES,
  16. * BIGNUM_TOP_BIT, BIGNUM_INT_MASK. These should be more or less
  17. * self-explanatory, but just in case, they give the number of bits
  18. * in BignumInt, the number of bytes that works out to, the
  19. * BignumInt value consisting of only the top bit, and the
  20. * BignumInt value with all bits set.
  21. *
  22. * - four statement macros: BignumADC, BignumMUL, BignumMULADD,
  23. * BignumMULADD2. These do various kinds of multi-word arithmetic,
  24. * and all produce two output values.
  25. * * BignumADC(ret,retc,a,b,c) takes input BignumInt values a,b
  26. * and a BignumCarry c, and outputs a BignumInt ret = a+b+c and
  27. * a BignumCarry retc which is the carry off the top of that
  28. * addition.
  29. * * BignumMUL(rh,rl,a,b) returns the two halves of the
  30. * double-width product a*b.
  31. * * BignumMULADD(rh,rl,a,b,addend) returns the two halves of the
  32. * double-width value a*b + addend.
  33. * * BignumMULADD2(rh,rl,a,b,addend1,addend2) returns the two
  34. * halves of the double-width value a*b + addend1 + addend2.
  35. *
  36. * Every branch of the main ifdef below defines the type BignumInt and
  37. * the value BIGNUM_INT_BITS. The other three constant macros are
  38. * filled in by common code further down.
  39. *
  40. * Most branches also define a macro DEFINE_BIGNUMDBLINT containing a
  41. * typedef statement which declares a type _twice_ the length of a
  42. * BignumInt. This causes the common code further down to produce a
  43. * default implementation of the four statement macros in terms of
  44. * that double-width type, and also to defined BignumCarry to be
  45. * BignumInt.
  46. *
  47. * However, if a particular compile target does not have a type twice
  48. * the length of the BignumInt you want to use but it does provide
  49. * some alternative means of doing add-with-carry and double-word
  50. * multiply, then the ifdef branch in question can just define
  51. * BignumCarry and the four statement macros itself, and that's fine
  52. * too.
  53. */
  54. #if defined __SIZEOF_INT128__
  55. /*
  56. * 64-bit BignumInt using gcc/clang style 128-bit BignumDblInt.
  57. *
  58. * gcc and clang both provide a __uint128_t type on 64-bit targets
  59. * (and, when they do, indicate its presence by the above macro),
  60. * using the same 'two machine registers' kind of code generation
  61. * that 32-bit targets use for 64-bit ints.
  62. */
  63. typedef unsigned long long BignumInt;
  64. #define BIGNUM_INT_BITS 64
  65. #define DEFINE_BIGNUMDBLINT typedef __uint128_t BignumDblInt
  66. #elif defined _MSC_VER && defined _M_AMD64
  67. /*
  68. * 64-bit BignumInt, using Visual Studio x86-64 compiler intrinsics.
  69. *
  70. * 64-bit Visual Studio doesn't provide very much in the way of help
  71. * here: there's no int128 type, and also no inline assembler giving
  72. * us direct access to the x86-64 MUL or ADC instructions. However,
  73. * there are compiler intrinsics giving us that access, so we can
  74. * use those - though it turns out we have to be a little careful,
  75. * since they seem to generate wrong code if their pointer-typed
  76. * output parameters alias their inputs. Hence all the internal temp
  77. * variables inside the macros.
  78. */
  79. #include <intrin.h>
  80. typedef unsigned char BignumCarry; /* the type _addcarry_u64 likes to use */
  81. typedef unsigned __int64 BignumInt;
  82. #define BIGNUM_INT_BITS 64
  83. #define BignumADC(ret, retc, a, b, c) do \
  84. { \
  85. BignumInt ADC_tmp; \
  86. (retc) = _addcarry_u64(c, a, b, &ADC_tmp); \
  87. (ret) = ADC_tmp; \
  88. } while (0)
  89. #define BignumMUL(rh, rl, a, b) do \
  90. { \
  91. BignumInt MULADD_hi; \
  92. (rl) = _umul128(a, b, &MULADD_hi); \
  93. (rh) = MULADD_hi; \
  94. } while (0)
  95. #define BignumMULADD(rh, rl, a, b, addend) do \
  96. { \
  97. BignumInt MULADD_lo, MULADD_hi; \
  98. MULADD_lo = _umul128(a, b, &MULADD_hi); \
  99. MULADD_hi += _addcarry_u64(0, MULADD_lo, (addend), &(rl)); \
  100. (rh) = MULADD_hi; \
  101. } while (0)
  102. #define BignumMULADD2(rh, rl, a, b, addend1, addend2) do \
  103. { \
  104. BignumInt MULADD_lo1, MULADD_lo2, MULADD_hi; \
  105. MULADD_lo1 = _umul128(a, b, &MULADD_hi); \
  106. MULADD_hi += _addcarry_u64(0, MULADD_lo1, (addend1), &MULADD_lo2); \
  107. MULADD_hi += _addcarry_u64(0, MULADD_lo2, (addend2), &(rl)); \
  108. (rh) = MULADD_hi; \
  109. } while (0)
  110. #elif defined __GNUC__ || defined _LLP64 || __STDC__ >= 199901L
  111. /* 32-bit BignumInt, using C99 unsigned long long as BignumDblInt */
  112. typedef unsigned int BignumInt;
  113. #define BIGNUM_INT_BITS 32
  114. #define DEFINE_BIGNUMDBLINT typedef unsigned long long BignumDblInt
  115. #elif defined _MSC_VER && defined _M_IX86
  116. /* 32-bit BignumInt, using Visual Studio __int64 as BignumDblInt */
  117. typedef unsigned int BignumInt;
  118. #define BIGNUM_INT_BITS 32
  119. #define DEFINE_BIGNUMDBLINT typedef unsigned __int64 BignumDblInt
  120. #elif defined _LP64
  121. /*
  122. * 32-bit BignumInt, using unsigned long itself as BignumDblInt.
  123. *
  124. * Only for platforms where long is 64 bits, of course.
  125. */
  126. typedef unsigned int BignumInt;
  127. #define BIGNUM_INT_BITS 32
  128. #define DEFINE_BIGNUMDBLINT typedef unsigned long BignumDblInt
  129. #else
  130. /*
  131. * 16-bit BignumInt, using unsigned long as BignumDblInt.
  132. *
  133. * This is the final fallback for real emergencies: C89 guarantees
  134. * unsigned short/long to be at least the required sizes, so this
  135. * should work on any C implementation at all. But it'll be
  136. * noticeably slow, so if you find yourself in this case you
  137. * probably want to move heaven and earth to find an alternative!
  138. */
  139. typedef unsigned short BignumInt;
  140. #define BIGNUM_INT_BITS 16
  141. #define DEFINE_BIGNUMDBLINT typedef unsigned long BignumDblInt
  142. #endif
  143. /*
  144. * Common code across all branches of that ifdef: define the three
  145. * easy constant macros in terms of BIGNUM_INT_BITS.
  146. */
  147. #define BIGNUM_INT_BYTES (BIGNUM_INT_BITS / 8)
  148. #define BIGNUM_TOP_BIT (((BignumInt)1) << (BIGNUM_INT_BITS-1))
  149. #define BIGNUM_INT_MASK (BIGNUM_TOP_BIT | (BIGNUM_TOP_BIT-1))
  150. /*
  151. * Common code across _most_ branches of the ifdef: define a set of
  152. * statement macros in terms of the BignumDblInt type provided. In
  153. * this case, we also define BignumCarry to be the same thing as
  154. * BignumInt, for simplicity.
  155. */
  156. #ifdef DEFINE_BIGNUMDBLINT
  157. typedef BignumInt BignumCarry;
  158. #define BignumADC(ret, retc, a, b, c) do \
  159. { \
  160. DEFINE_BIGNUMDBLINT; \
  161. BignumDblInt ADC_temp = (BignumInt)(a); \
  162. ADC_temp += (BignumInt)(b); \
  163. ADC_temp += (c); \
  164. (ret) = (BignumInt)ADC_temp; \
  165. (retc) = (BignumCarry)(ADC_temp >> BIGNUM_INT_BITS); \
  166. } while (0)
  167. #define BignumMUL(rh, rl, a, b) do \
  168. { \
  169. DEFINE_BIGNUMDBLINT; \
  170. BignumDblInt MUL_temp = (BignumInt)(a); \
  171. MUL_temp *= (BignumInt)(b); \
  172. (rh) = (BignumInt)(MUL_temp >> BIGNUM_INT_BITS); \
  173. (rl) = (BignumInt)(MUL_temp); \
  174. } while (0)
  175. #define BignumMULADD(rh, rl, a, b, addend) do \
  176. { \
  177. DEFINE_BIGNUMDBLINT; \
  178. BignumDblInt MUL_temp = (BignumInt)(a); \
  179. MUL_temp *= (BignumInt)(b); \
  180. MUL_temp += (BignumInt)(addend); \
  181. (rh) = (BignumInt)(MUL_temp >> BIGNUM_INT_BITS); \
  182. (rl) = (BignumInt)(MUL_temp); \
  183. } while (0)
  184. #define BignumMULADD2(rh, rl, a, b, addend1, addend2) do \
  185. { \
  186. DEFINE_BIGNUMDBLINT; \
  187. BignumDblInt MUL_temp = (BignumInt)(a); \
  188. MUL_temp *= (BignumInt)(b); \
  189. MUL_temp += (BignumInt)(addend1); \
  190. MUL_temp += (BignumInt)(addend2); \
  191. (rh) = (BignumInt)(MUL_temp >> BIGNUM_INT_BITS); \
  192. (rl) = (BignumInt)(MUL_temp); \
  193. } while (0)
  194. #endif /* DEFINE_BIGNUMDBLINT */