crypto_endian.h 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  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) || (LITTLE_ENDIAN != BYTE_ORDER && BIG_ENDIAN != BYTE_ORDER)
  35. #error Unsupported byte order/endianess
  36. #endif
  37. // Lets spend some quality time mucking around with byte swap and endian-ness.
  38. // First bswap32:
  39. #if (defined(__i386__) || defined(__x86_64__)) && defined(__GNUG__)
  40. forceinline uint32_t __crypto_bswap32(uint32_t p)
  41. {
  42. __asm__ __volatile__("bswap %0" : "=r"(p) : "0"(p));
  43. return p;
  44. }
  45. #elif defined(__GNUG__)
  46. #define __crypto_bswap32 __builtin_bswap32
  47. #else // defined(__GNUG__)
  48. forceinline uint32_t __crypto_bswap32(uint32_t n)
  49. {
  50. n = ((n << 8) & 0xff00ff00) | ((n >> 8) & 0xff00ff);
  51. return (n << 16) | (n >> 16);
  52. }
  53. #endif // defined(__GNUG__)
  54. // Next up: bswap64
  55. #if defined(__x86_64__) && defined(__GNUG__)
  56. forceinline uint64_t __crypto_bswap64(uint64_t p)
  57. {
  58. __asm__ __volatile__("bswapq %q0" : "=r"(p) : "0"(p));
  59. return p;
  60. }
  61. #elif defined(__GNUG__)
  62. #define __crypto_bswap64 __builtin_bswap64
  63. #else // defined(__GNUG__)
  64. forceinline uint64_t __crypto_bswap64(uint64_t n)
  65. {
  66. n = ((n << 8) & 0xff00ff00ff00ff00) | ((n >> 8) & 0x00ff00ff00ff00ff);
  67. n = ((n << 16) & 0xffff0000ffff0000) | ((n >> 16) & 0x0000ffff0000ffff);
  68. return (n << 32) | (n >> 32);
  69. }
  70. #endif // defined(__GNUG__)
  71. // Time for an implementation that makes reuse easier.
  72. namespace {
  73. template<typename T>
  74. inline T __crypto_bswap(T n)
  75. {
  76. static_assert(sizeof(T) != sizeof(T), "Not implemented");
  77. }
  78. template<>
  79. inline uint32_t __crypto_bswap(uint32_t n)
  80. {
  81. return __crypto_bswap32(n);
  82. }
  83. template<>
  84. inline uint64_t __crypto_bswap(uint64_t n)
  85. {
  86. return __crypto_bswap64(n);
  87. }
  88. } // namespace
  89. // __crypto_le and __crypto_be depending on byte order
  90. #if LITTLE_ENDIAN == BYTE_ORDER
  91. #define __crypto_be(n) __crypto_bswap(n)
  92. #define __crypto_le(n) (n)
  93. #else // LITTLE_ENDIAN != WORD_ORDER
  94. #define __crypto_be(n) (n)
  95. #define __crypto_le(n) __crypto_bswap(n)
  96. #endif // LITTLE_ENDIAN != WORD_ORDER
  97. } // namespace crypto
  98. #endif // CRYPTO_ENDIAN_H