/ccan/crypto/siphash24/siphash24.c

https://github.com/rustyrussell/ccan · C · 229 lines · 182 code · 37 blank · 10 comment · 12 complexity · 92e891a9841e521f4ef6f4826f4d399a MD5 · raw file

  1. /* CC0 license (public domain) - see LICENSE file for details */
  2. /* Based on CC0 reference implementation:
  3. * https://github.com/veorq/SipHash c03e6bbf6613243bc30788912ad4afbc0b992d47
  4. */
  5. #include <ccan/crypto/siphash24/siphash24.h>
  6. #include <ccan/endian/endian.h>
  7. #include <stdbool.h>
  8. #include <assert.h>
  9. #include <string.h>
  10. /* default: SipHash-2-4 */
  11. #define cROUNDS 2
  12. #define dROUNDS 4
  13. #define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b))))
  14. #define SIPROUND(v) \
  15. do { \
  16. v[0] += v[1]; \
  17. v[1] = ROTL(v[1], 13); \
  18. v[1] ^= v[0]; \
  19. v[0] = ROTL(v[0], 32); \
  20. v[2] += v[3]; \
  21. v[3] = ROTL(v[3], 16); \
  22. v[3] ^= v[2]; \
  23. v[0] += v[3]; \
  24. v[3] = ROTL(v[3], 21); \
  25. v[3] ^= v[0]; \
  26. v[2] += v[1]; \
  27. v[1] = ROTL(v[1], 17); \
  28. v[1] ^= v[2]; \
  29. v[2] = ROTL(v[2], 32); \
  30. } while (0)
  31. static void invalidate_siphash24(struct siphash24_ctx *ctx)
  32. {
  33. ctx->bytes = -1ULL;
  34. }
  35. static void check_siphash24(struct siphash24_ctx *ctx)
  36. {
  37. assert(ctx->bytes != -1ULL);
  38. }
  39. static bool alignment_ok(const void *p, size_t n)
  40. {
  41. #if HAVE_UNALIGNED_ACCESS
  42. (void)p; (void)n;
  43. return true;
  44. #else
  45. return ((size_t)p % n == 0);
  46. #endif
  47. }
  48. static void add_64bits(uint64_t v[4], uint64_t in)
  49. {
  50. int i;
  51. uint64_t m = cpu_to_le64(in);
  52. v[3] ^= m;
  53. for (i = 0; i < cROUNDS; ++i)
  54. SIPROUND(v);
  55. v[0] ^= m;
  56. }
  57. static void add(struct siphash24_ctx *ctx, const void *p, size_t len)
  58. {
  59. const unsigned char *data = p;
  60. size_t bufsize = ctx->bytes % sizeof(ctx->buf.u8);
  61. if (bufsize + len >= sizeof(ctx->buf.u8)) {
  62. // Fill the buffer, and process it.
  63. memcpy(ctx->buf.u8 + bufsize, data,
  64. sizeof(ctx->buf.u8) - bufsize);
  65. ctx->bytes += sizeof(ctx->buf.u8) - bufsize;
  66. data += sizeof(ctx->buf.u8) - bufsize;
  67. len -= sizeof(ctx->buf.u8) - bufsize;
  68. add_64bits(ctx->v, ctx->buf.u64);
  69. bufsize = 0;
  70. }
  71. while (len >= sizeof(ctx->buf.u8)) {
  72. // Process full chunks directly from the source.
  73. if (alignment_ok(data, sizeof(uint64_t)))
  74. add_64bits(ctx->v, *(const uint64_t *)data);
  75. else {
  76. memcpy(ctx->buf.u8, data, sizeof(ctx->buf));
  77. add_64bits(ctx->v, ctx->buf.u64);
  78. }
  79. ctx->bytes += sizeof(ctx->buf.u8);
  80. data += sizeof(ctx->buf.u8);
  81. len -= sizeof(ctx->buf.u8);
  82. }
  83. if (len) {
  84. // Fill the buffer with what remains.
  85. memcpy(ctx->buf.u8 + bufsize, data, len);
  86. ctx->bytes += len;
  87. }
  88. }
  89. void siphash24_init(struct siphash24_ctx *ctx, const struct siphash_seed *seed)
  90. {
  91. struct siphash24_ctx init = SIPHASH24_INIT(0, 0);
  92. *ctx = init;
  93. ctx->v[0] ^= seed->u.u64[0];
  94. ctx->v[1] ^= seed->u.u64[1];
  95. ctx->v[2] ^= seed->u.u64[0];
  96. ctx->v[3] ^= seed->u.u64[1];
  97. }
  98. void siphash24_update(struct siphash24_ctx *ctx, const void *p, size_t size)
  99. {
  100. check_siphash24(ctx);
  101. add(ctx, p, size);
  102. }
  103. uint64_t siphash24_done(struct siphash24_ctx *ctx)
  104. {
  105. uint64_t b;
  106. int i;
  107. b = ctx->bytes << 56;
  108. switch (ctx->bytes % 8) {
  109. case 7:
  110. b |= ((uint64_t)ctx->buf.u8[6]) << 48;
  111. case 6:
  112. b |= ((uint64_t)ctx->buf.u8[5]) << 40;
  113. case 5:
  114. b |= ((uint64_t)ctx->buf.u8[4]) << 32;
  115. case 4:
  116. b |= ((uint64_t)ctx->buf.u8[3]) << 24;
  117. case 3:
  118. b |= ((uint64_t)ctx->buf.u8[2]) << 16;
  119. case 2:
  120. b |= ((uint64_t)ctx->buf.u8[1]) << 8;
  121. case 1:
  122. b |= ((uint64_t)ctx->buf.u8[0]);
  123. break;
  124. case 0:
  125. break;
  126. }
  127. ctx->v[3] ^= b;
  128. for (i = 0; i < cROUNDS; ++i)
  129. SIPROUND(ctx->v);
  130. ctx->v[0] ^= b;
  131. ctx->v[2] ^= 0xff;
  132. for (i = 0; i < dROUNDS; ++i)
  133. SIPROUND(ctx->v);
  134. b = ctx->v[0] ^ ctx->v[1] ^ ctx->v[2] ^ ctx->v[3];
  135. invalidate_siphash24(ctx);
  136. return cpu_to_le64(b);
  137. }
  138. uint64_t siphash24(const struct siphash_seed *seed, const void *p, size_t size)
  139. {
  140. struct siphash24_ctx ctx;
  141. siphash24_init(&ctx, seed);
  142. siphash24_update(&ctx, p, size);
  143. return siphash24_done(&ctx);
  144. }
  145. void siphash24_u8(struct siphash24_ctx *ctx, uint8_t v)
  146. {
  147. siphash24_update(ctx, &v, sizeof(v));
  148. }
  149. void siphash24_u16(struct siphash24_ctx *ctx, uint16_t v)
  150. {
  151. siphash24_update(ctx, &v, sizeof(v));
  152. }
  153. void siphash24_u32(struct siphash24_ctx *ctx, uint32_t v)
  154. {
  155. siphash24_update(ctx, &v, sizeof(v));
  156. }
  157. void siphash24_u64(struct siphash24_ctx *ctx, uint64_t v)
  158. {
  159. siphash24_update(ctx, &v, sizeof(v));
  160. }
  161. /* Add as little-endian */
  162. void siphash24_le16(struct siphash24_ctx *ctx, uint16_t v)
  163. {
  164. leint16_t lev = cpu_to_le16(v);
  165. siphash24_update(ctx, &lev, sizeof(lev));
  166. }
  167. void siphash24_le32(struct siphash24_ctx *ctx, uint32_t v)
  168. {
  169. leint32_t lev = cpu_to_le32(v);
  170. siphash24_update(ctx, &lev, sizeof(lev));
  171. }
  172. void siphash24_le64(struct siphash24_ctx *ctx, uint64_t v)
  173. {
  174. leint64_t lev = cpu_to_le64(v);
  175. siphash24_update(ctx, &lev, sizeof(lev));
  176. }
  177. /* Add as big-endian */
  178. void siphash24_be16(struct siphash24_ctx *ctx, uint16_t v)
  179. {
  180. beint16_t bev = cpu_to_be16(v);
  181. siphash24_update(ctx, &bev, sizeof(bev));
  182. }
  183. void siphash24_be32(struct siphash24_ctx *ctx, uint32_t v)
  184. {
  185. beint32_t bev = cpu_to_be32(v);
  186. siphash24_update(ctx, &bev, sizeof(bev));
  187. }
  188. void siphash24_be64(struct siphash24_ctx *ctx, uint64_t v)
  189. {
  190. beint64_t bev = cpu_to_be64(v);
  191. siphash24_update(ctx, &bev, sizeof(bev));
  192. }