2
0

Speck128.hpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. /*
  2. * Copyright (c)2013-2020 ZeroTier, Inc.
  3. *
  4. * Use of this software is governed by the Business Source License included
  5. * in the LICENSE.TXT file in the project's root directory.
  6. *
  7. * Change Date: 2024-01-01
  8. *
  9. * On the date above, in accordance with the Business Source License, use
  10. * of this software will be governed by version 2.0 of the Apache License.
  11. */
  12. /****/
  13. #ifndef ZT_SPECK128_HPP
  14. #define ZT_SPECK128_HPP
  15. #include "Constants.hpp"
  16. #include "Utils.hpp"
  17. namespace ZeroTier {
  18. /**
  19. * Tiny and simple 128-bit ARX block cipher
  20. *
  21. * Speck does not specify a mandatory endian-ness. This implementation is
  22. * little-endian for higher performance on the majority of platforms.
  23. *
  24. * @tparam R Number of rounds (default: 32)
  25. */
  26. template<int R = 32>
  27. class Speck128
  28. {
  29. public:
  30. /**
  31. * Create an uninitialized instance, init() must be called to set up.
  32. */
  33. ZT_INLINE Speck128() noexcept {}
  34. /**
  35. * Initialize Speck from a 128-bit key
  36. *
  37. * @param k 128-bit / 16 byte key
  38. */
  39. ZT_INLINE Speck128(const void *k) noexcept { this->init(k); }
  40. ZT_INLINE ~Speck128() { Utils::burn(_k,sizeof(_k)); }
  41. /**
  42. * Initialize Speck from a 128-bit key
  43. *
  44. * @param k 128-bit / 16 byte key
  45. */
  46. ZT_INLINE void init(const void *k) noexcept
  47. {
  48. initXY(Utils::loadLittleEndian<uint64_t>(k),Utils::loadLittleEndian<uint64_t>(reinterpret_cast<const uint8_t *>(k) + 8));
  49. }
  50. /**
  51. * Initialize Speck from a 128-bit key in two 64-bit words
  52. *
  53. * @param x Least significant 64 bits
  54. * @param y Most significant 64 bits
  55. */
  56. ZT_INLINE void initXY(uint64_t x,uint64_t y) noexcept
  57. {
  58. _k[0] = x;
  59. for(uint64_t i=0;i<(R-1);++i) {
  60. x = x >> 8U | x << 56U;
  61. x += y;
  62. x ^= i;
  63. y = y << 3U | y >> 61U;
  64. y ^= x;
  65. _k[i + 1] = y;
  66. }
  67. }
  68. /**
  69. * Encrypt a 128-bit block as two 64-bit words
  70. *
  71. * These should be in host byte order. If read or written to/from data
  72. * they should be stored in little-endian byte order.
  73. *
  74. * @param x Least significant 64 bits
  75. * @param y Most significant 64 bits
  76. */
  77. ZT_INLINE void encryptXY(uint64_t &x,uint64_t &y) const noexcept
  78. {
  79. for (int i=0;i<R;++i) {
  80. const uint64_t kk = _k[i];
  81. x = x >> 8U | x << 56U;
  82. x += y;
  83. x ^= kk;
  84. y = y << 3U | y >> 61U;
  85. y ^= x;
  86. }
  87. }
  88. /**
  89. * Encrypt 512 bits in parallel with the same key
  90. */
  91. ZT_INLINE void encryptXYXYXYXY(uint64_t &x0,uint64_t &y0,uint64_t &x1,uint64_t &y1,uint64_t &x2,uint64_t &y2,uint64_t &x3,uint64_t &y3) const noexcept
  92. {
  93. for (int i=0;i<R;++i) {
  94. const uint64_t kk = _k[i];
  95. x0 = x0 >> 8U | x0 << 56U;
  96. x1 = x1 >> 8U | x1 << 56U;
  97. x2 = x2 >> 8U | x2 << 56U;
  98. x3 = x3 >> 8U | x3 << 56U;
  99. x0 += y0;
  100. x1 += y1;
  101. x2 += y2;
  102. x3 += y3;
  103. x0 ^= kk;
  104. x1 ^= kk;
  105. x2 ^= kk;
  106. x3 ^= kk;
  107. y0 = y0 << 3U | y0 >> 61U;
  108. y1 = y1 << 3U | y1 >> 61U;
  109. y2 = y2 << 3U | y2 >> 61U;
  110. y3 = y3 << 3U | y3 >> 61U;
  111. y0 ^= x0;
  112. y1 ^= x1;
  113. y2 ^= x2;
  114. y3 ^= x3;
  115. }
  116. }
  117. /**
  118. * Decrypt a 128-bit block as two 64-bit words
  119. *
  120. * These should be in host byte order. If read or written to/from data
  121. * they should be stored in little-endian byte order.
  122. *
  123. * @param x Least significant 64 bits
  124. * @param y Most significant 64 bits
  125. */
  126. ZT_INLINE void decryptXY(uint64_t &x,uint64_t &y) const noexcept
  127. {
  128. for (int i=(R-1);i>=0;--i) {
  129. const uint64_t kk = _k[i];
  130. y ^= x;
  131. y = y >> 3U | y << 61U;
  132. x ^= kk;
  133. x -= y;
  134. x = x << 8U | x >> 56U;
  135. }
  136. }
  137. /**
  138. * Encrypt a block
  139. *
  140. * @param in 128-bit / 16 byte input
  141. * @param out 128-bit / 16 byte output
  142. */
  143. ZT_INLINE void encrypt(const void *const in,void *const out) const noexcept
  144. {
  145. uint64_t x = Utils::loadLittleEndian<uint64_t>(in);
  146. uint64_t y = Utils::loadLittleEndian<uint64_t>(reinterpret_cast<const uint8_t *>(in) + 8);
  147. encryptXY(x,y);
  148. Utils::storeLittleEndian<uint64_t>(out,x);
  149. Utils::storeLittleEndian<uint64_t>(reinterpret_cast<uint8_t *>(out) + 8,y);
  150. }
  151. /**
  152. * Decrypt a block
  153. *
  154. * @param in 128-bit / 16 byte input
  155. * @param out 128-bit / 16 byte output
  156. */
  157. ZT_INLINE void decrypt(const void *const in,void *const out) const noexcept
  158. {
  159. uint64_t x = Utils::loadLittleEndian<uint64_t>(in);
  160. uint64_t y = Utils::loadLittleEndian<uint64_t>(reinterpret_cast<const uint8_t *>(in) + 8);
  161. decryptXY(x,y);
  162. Utils::storeLittleEndian<uint64_t>(out,x);
  163. Utils::storeLittleEndian<uint64_t>(reinterpret_cast<uint8_t *>(out) + 8,y);
  164. }
  165. private:
  166. uint64_t _k[R];
  167. };
  168. } // namespace ZeroTier
  169. #endif