1 /* CC0 license (public domain) - see LICENSE file for details */
2 /* Based on CC0 reference implementation:
3 * https://github.com/veorq/SipHash c03e6bbf6613243bc30788912ad4afbc0b992d47
5 #include <ccan/crypto/siphash24/siphash24.h>
6 #include <ccan/endian/endian.h>
11 /* default: SipHash-2-4 */
15 #define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b))))
20 v[1] = ROTL(v[1], 13); \
22 v[0] = ROTL(v[0], 32); \
24 v[3] = ROTL(v[3], 16); \
27 v[3] = ROTL(v[3], 21); \
30 v[1] = ROTL(v[1], 17); \
32 v[2] = ROTL(v[2], 32); \
35 static void invalidate_siphash24(struct siphash24_ctx *ctx)
40 static void check_siphash24(struct siphash24_ctx *ctx)
42 assert(ctx->bytes != -1ULL);
45 static bool alignment_ok(const void *p, size_t n)
47 #if HAVE_UNALIGNED_ACCESS
51 return ((size_t)p % n == 0);
55 static void add_64bits(uint64_t v[4], uint64_t in)
58 uint64_t m = cpu_to_le64(in);
61 for (i = 0; i < cROUNDS; ++i)
67 static void add(struct siphash24_ctx *ctx, const void *p, size_t len)
69 const unsigned char *data = p;
70 size_t bufsize = ctx->bytes % sizeof(ctx->buf.u8);
72 if (bufsize + len >= sizeof(ctx->buf.u8)) {
73 // Fill the buffer, and process it.
74 memcpy(ctx->buf.u8 + bufsize, data,
75 sizeof(ctx->buf.u8) - bufsize);
76 ctx->bytes += sizeof(ctx->buf.u8) - bufsize;
77 data += sizeof(ctx->buf.u8) - bufsize;
78 len -= sizeof(ctx->buf.u8) - bufsize;
79 add_64bits(ctx->v, ctx->buf.u64);
83 while (len >= sizeof(ctx->buf.u8)) {
84 // Process full chunks directly from the source.
85 if (alignment_ok(data, sizeof(uint64_t)))
86 add_64bits(ctx->v, *(const uint64_t *)data);
88 memcpy(ctx->buf.u8, data, sizeof(ctx->buf));
89 add_64bits(ctx->v, ctx->buf.u64);
91 ctx->bytes += sizeof(ctx->buf.u8);
92 data += sizeof(ctx->buf.u8);
93 len -= sizeof(ctx->buf.u8);
97 // Fill the buffer with what remains.
98 memcpy(ctx->buf.u8 + bufsize, data, len);
103 void siphash24_init(struct siphash24_ctx *ctx, const struct siphash_seed *seed)
105 struct siphash24_ctx init = SIPHASH24_INIT(0, 0);
107 ctx->v[0] ^= seed->u.u64[0];
108 ctx->v[1] ^= seed->u.u64[1];
109 ctx->v[2] ^= seed->u.u64[0];
110 ctx->v[3] ^= seed->u.u64[1];
113 void siphash24_update(struct siphash24_ctx *ctx, const void *p, size_t size)
115 check_siphash24(ctx);
119 uint64_t siphash24_done(struct siphash24_ctx *ctx)
124 b = ctx->bytes << 56;
126 switch (ctx->bytes % 8) {
128 b |= ((uint64_t)ctx->buf.u8[6]) << 48;
130 b |= ((uint64_t)ctx->buf.u8[5]) << 40;
132 b |= ((uint64_t)ctx->buf.u8[4]) << 32;
134 b |= ((uint64_t)ctx->buf.u8[3]) << 24;
136 b |= ((uint64_t)ctx->buf.u8[2]) << 16;
138 b |= ((uint64_t)ctx->buf.u8[1]) << 8;
140 b |= ((uint64_t)ctx->buf.u8[0]);
148 for (i = 0; i < cROUNDS; ++i)
155 for (i = 0; i < dROUNDS; ++i)
158 b = ctx->v[0] ^ ctx->v[1] ^ ctx->v[2] ^ ctx->v[3];
160 invalidate_siphash24(ctx);
161 return cpu_to_le64(b);
164 uint64_t siphash24(const struct siphash_seed *seed, const void *p, size_t size)
166 struct siphash24_ctx ctx;
168 siphash24_init(&ctx, seed);
169 siphash24_update(&ctx, p, size);
170 return siphash24_done(&ctx);
173 void siphash24_u8(struct siphash24_ctx *ctx, uint8_t v)
175 siphash24_update(ctx, &v, sizeof(v));
178 void siphash24_u16(struct siphash24_ctx *ctx, uint16_t v)
180 siphash24_update(ctx, &v, sizeof(v));
183 void siphash24_u32(struct siphash24_ctx *ctx, uint32_t v)
185 siphash24_update(ctx, &v, sizeof(v));
188 void siphash24_u64(struct siphash24_ctx *ctx, uint64_t v)
190 siphash24_update(ctx, &v, sizeof(v));
193 /* Add as little-endian */
194 void siphash24_le16(struct siphash24_ctx *ctx, uint16_t v)
196 leint16_t lev = cpu_to_le16(v);
197 siphash24_update(ctx, &lev, sizeof(lev));
200 void siphash24_le32(struct siphash24_ctx *ctx, uint32_t v)
202 leint32_t lev = cpu_to_le32(v);
203 siphash24_update(ctx, &lev, sizeof(lev));
206 void siphash24_le64(struct siphash24_ctx *ctx, uint64_t v)
208 leint64_t lev = cpu_to_le64(v);
209 siphash24_update(ctx, &lev, sizeof(lev));
212 /* Add as big-endian */
213 void siphash24_be16(struct siphash24_ctx *ctx, uint16_t v)
215 beint16_t bev = cpu_to_be16(v);
216 siphash24_update(ctx, &bev, sizeof(bev));
219 void siphash24_be32(struct siphash24_ctx *ctx, uint32_t v)
221 beint32_t bev = cpu_to_be32(v);
222 siphash24_update(ctx, &bev, sizeof(bev));
225 void siphash24_be64(struct siphash24_ctx *ctx, uint64_t v)
227 beint64_t bev = cpu_to_be64(v);
228 siphash24_update(ctx, &bev, sizeof(bev));