endian: add constant versions.
[ccan] / ccan / siphash / siphash.c
1 /* Licensed under GPL v2+ - see LICENSE file for details */
2
3 #include <ccan/endian/endian.h>
4
5 #include <string.h>
6
7 #include "siphash.h"
8
9 enum sip_index { A=0, B=2, C=1, D=3, E=4 };
10
11 #define rol(x,l) (((x) << (l)) | ((x) >> (64-(l))))
12
13 #define SIP_HALF_ROUND(a,b,c,d,L1,L2) \
14     (a) += (b); \
15     (c) += (d); \
16     (b)  = (a) ^ rol((b),L1); \
17     (d)  = (c) ^ rol((d),L2); \
18     (a)  = rol((a),32);
19
20 #define SIP_ROUND(W) \
21     do  { \
22         SIP_HALF_ROUND((W)[A], (W)[B], (W)[C], (W)[D], 13, 16); \
23         SIP_HALF_ROUND((W)[C], (W)[B], (W)[A], (W)[D], 17, 21); \
24     } while(0)
25
26
27 static inline uint64_t W64(const unsigned char *p, size_t j)
28 {
29     uint64_t x;
30     memcpy(&x, p + j*sizeof(x), sizeof(x));
31     return le64_to_cpu(x);
32 }
33
34 static void siphash_init(uint64_t v[5], const unsigned char key[16])
35 {
36     v[A] = W64(key, 0) ^ UINT64_C(0x736f6d6570736575);
37     v[B] = W64(key, 1) ^ UINT64_C(0x646f72616e646f6d);
38     v[C] = W64(key, 0) ^ UINT64_C(0x6c7967656e657261);
39     v[D] = W64(key, 1) ^ UINT64_C(0x7465646279746573);
40     v[E] = 0;  /* message continuation */
41 }
42
43 /* Load the last 0-7 bytes of `in` and put in len & 255 */
44 static void siphash_epilogue(uint64_t *m, const unsigned char *in, size_t len)
45 {
46     in += len & ~(size_t)7;
47     *m = (uint64_t)(len & 255) << 56;
48     switch (len & 7) {
49         case 7: *m |= (uint64_t) in[6] << 48;
50         case 6: *m |= (uint64_t) in[5] << 40;
51         case 5: *m |= (uint64_t) in[4] << 32;
52         case 4: *m |= (uint64_t) in[3] << 24;
53         case 3: *m |= (uint64_t) in[2] << 16;
54         case 2: *m |= (uint64_t) in[1] << 8;
55         case 1: *m |= (uint64_t) in[0];
56         case 0: ;
57     }
58 }
59
60 uint64_t siphash_2_4(const void *in, size_t len, const unsigned char key[16])
61 {
62     uint64_t v[5];
63     size_t j;
64
65     siphash_init(v, key);
66
67     for (j = 0; j < len/8; j++) {
68         v[E] = W64(in, j);
69         v[D] ^= v[E];
70         SIP_ROUND(v);
71         SIP_ROUND(v);
72         v[A] ^= v[E];
73     }
74     siphash_epilogue(&v[E], in, len);
75
76     v[D] ^= v[E];
77     SIP_ROUND(v);
78     SIP_ROUND(v);
79     v[A] ^= v[E];
80
81     /* Finalize */
82     v[C] ^= 0xff;
83     SIP_ROUND(v);
84     SIP_ROUND(v);
85     SIP_ROUND(v);
86     SIP_ROUND(v);
87
88     return v[A]^v[B]^v[C]^v[D];
89 }
90