crypto_endian.h 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. /* Any copyright is dedicated to the Public Domain.
  2. * http://creativecommons.org/publicdomain/zero/1.0/ */
  3. // Written in 2014 by Nils Maier
  4. #ifndef CRYPTO_ENDIAN_H
  5. #define CRYPTO_ENDIAN_H
  6. #include <cstdint>
  7. #include "config.h"
  8. namespace crypto {
  9. #if defined(__GNUG__)
  10. #define forceinline __attribute__((always_inline)) inline
  11. #elif defined(_MSC_VER)
  12. #define forceinline __forceinline
  13. #else // ! _MSC_VER
  14. #define forceinline inline
  15. #endif // ! _MSC_VER
  16. /* In order for this implementation to work your system (or you yourself) must
  17. * define after including <sys/param.h>
  18. * - LITTLE_ENDIAN
  19. * - BIG_ENDIAN
  20. * - BYTE_ORDER
  21. * - where BYTE_ORDER == LITTLE_ENDIAN or BYTE_ORDER == BIG_ENDIAN
  22. * Failing to conform will render this implementation utterly incorrect.
  23. */
  24. #if defined(_WIN32) || defined(__INTEL_COMPILER) || defined(_MSC_VER)
  25. // Itanium is dead!
  26. #define LITTLE_ENDIAN 1234
  27. #define BIG_ENDIAN 4321
  28. #define BYTE_ORDER LITTLE_ENDIAN
  29. #else // ! defined(_WIN32) || defined(__INTEL_COMPILER) || defined (_MSC_VER)
  30. #ifdef HAVE_SYS_PARAM_H
  31. #include <sys/param.h>
  32. #endif // HAVE_SYS_PARAM_H
  33. #endif // ! defined(_WIN32) || defined(__INTEL_COMPILER) || defined (_MSC_VER)
  34. #if !defined(LITTLE_ENDIAN) || !defined(BIG_ENDIAN) || !defined(BYTE_ORDER) || \
  35. (LITTLE_ENDIAN != BYTE_ORDER && BIG_ENDIAN != BYTE_ORDER)
  36. #error Unsupported byte order/endianness
  37. #endif
  38. // Lets spend some quality time mucking around with byte swap and endian-ness.
  39. // First bswap32:
  40. #if (defined(__i386__) || defined(__x86_64__)) && defined(__GNUG__)
  41. forceinline uint32_t __crypto_bswap32(uint32_t p)
  42. {
  43. __asm__ __volatile__("bswap %0" : "=r"(p) : "0"(p));
  44. return p;
  45. }
  46. #elif defined(__GNUG__)
  47. #define __crypto_bswap32 __builtin_bswap32
  48. #else // defined(__GNUG__)
  49. forceinline uint32_t __crypto_bswap32(uint32_t n)
  50. {
  51. n = ((n << 8) & 0xff00ff00) | ((n >> 8) & 0xff00ff);
  52. return (n << 16) | (n >> 16);
  53. }
  54. #endif // defined(__GNUG__)
  55. // Next up: bswap64
  56. #if defined(__x86_64__) && defined(__GNUG__)
  57. forceinline uint64_t __crypto_bswap64(uint64_t p)
  58. {
  59. __asm__ __volatile__("bswapq %q0" : "=r"(p) : "0"(p));
  60. return p;
  61. }
  62. #elif defined(__GNUG__)
  63. #define __crypto_bswap64 __builtin_bswap64
  64. #else // defined(__GNUG__)
  65. forceinline uint64_t __crypto_bswap64(uint64_t n)
  66. {
  67. n = ((n << 8) & 0xff00ff00ff00ff00) | ((n >> 8) & 0x00ff00ff00ff00ff);
  68. n = ((n << 16) & 0xffff0000ffff0000) | ((n >> 16) & 0x0000ffff0000ffff);
  69. return (n << 32) | (n >> 32);
  70. }
  71. #endif // defined(__GNUG__)
  72. // Time for an implementation that makes reuse easier.
  73. namespace {
  74. template <typename T> inline T __crypto_bswap(T n)
  75. {
  76. static_assert(sizeof(T) != sizeof(T), "Not implemented");
  77. }
  78. template <> inline uint32_t __crypto_bswap(uint32_t n)
  79. {
  80. return __crypto_bswap32(n);
  81. }
  82. template <> inline uint64_t __crypto_bswap(uint64_t n)
  83. {
  84. return __crypto_bswap64(n);
  85. }
  86. } // namespace
  87. // __crypto_le and __crypto_be depending on byte order
  88. #if LITTLE_ENDIAN == BYTE_ORDER
  89. #define __crypto_be(n) __crypto_bswap(n)
  90. #define __crypto_le(n) (n)
  91. #else // LITTLE_ENDIAN != WORD_ORDER
  92. #define __crypto_be(n) (n)
  93. #define __crypto_le(n) __crypto_bswap(n)
  94. #endif // LITTLE_ENDIAN != WORD_ORDER
  95. } // namespace crypto
  96. #endif // CRYPTO_ENDIAN_H