1 /* 2 SipHash reference C implementation 3 4 Copyright (c) 2012-2016 Jean-Philippe Aumasson 5 <jeanphilippe.aumasson@gmail.com> 6 Copyright (c) 2012-2014 Daniel J. Bernstein <djb@cr.yp.to> 7 8 To the extent possible under law, the author(s) have dedicated all copyright 9 and related and neighboring rights to this software to the public domain 10 worldwide. This software is distributed without any warranty. 11 12 You should have received a copy of the CC0 Public Domain Dedication along 13 with 14 this software. If not, see 15 <http://creativecommons.org/publicdomain/zero/1.0/>. 16 */ 17 #include <assert.h> 18 #include <stdint.h> 19 #include <stdio.h> 20 #include <string.h> 21 22 /* default: SipHash-2-4 */ 23 #define cROUNDS 2 24 #define dROUNDS 4 25 26 #define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b)))) 27 28 #define U32TO8_LE(p, v) \ 29 (p)[0] = (uint8_t)((v)); \ 30 (p)[1] = (uint8_t)((v) >> 8); \ 31 (p)[2] = (uint8_t)((v) >> 16); \ 32 (p)[3] = (uint8_t)((v) >> 24); 33 34 #define U64TO8_LE(p, v) \ 35 U32TO8_LE((p), (uint32_t)((v))); \ 36 U32TO8_LE((p) + 4, (uint32_t)((v) >> 32)); 37 38 #define U8TO64_LE(p) \ 39 (((uint64_t)((p)[0])) | ((uint64_t)((p)[1]) << 8) | \ 40 ((uint64_t)((p)[2]) << 16) | ((uint64_t)((p)[3]) << 24) | \ 41 ((uint64_t)((p)[4]) << 32) | ((uint64_t)((p)[5]) << 40) | \ 42 ((uint64_t)((p)[6]) << 48) | ((uint64_t)((p)[7]) << 56)) 43 44 #define SIPROUND \ 45 do { \ 46 v0 += v1; \ 47 v1 = ROTL(v1, 13); \ 48 v1 ^= v0; \ 49 v0 = ROTL(v0, 32); \ 50 v2 += v3; \ 51 v3 = ROTL(v3, 16); \ 52 v3 ^= v2; \ 53 v0 += v3; \ 54 v3 = ROTL(v3, 21); \ 55 v3 ^= v0; \ 56 v2 += v1; \ 57 v1 = ROTL(v1, 17); \ 58 v1 ^= v2; \ 59 v2 = ROTL(v2, 32); \ 60 } while (0) 61 62 #ifdef DEBUG 63 #define TRACE \ 64 do { \ 65 printf("(%3d) v0 %08x %08x\n", (int)inlen, (uint32_t)(v0 >> 32), \ 66 (uint32_t)v0); \ 67 printf("(%3d) v1 %08x %08x\n", (int)inlen, (uint32_t)(v1 >> 32), \ 68 (uint32_t)v1); \ 69 printf("(%3d) v2 %08x %08x\n", (int)inlen, (uint32_t)(v2 >> 32), \ 70 (uint32_t)v2); \ 71 printf("(%3d) v3 %08x %08x\n", (int)inlen, (uint32_t)(v3 >> 32), \ 72 (uint32_t)v3); \ 73 } while (0) 74 #else 75 #define TRACE 76 #endif 77 78 int siphash(const uint8_t *in, const size_t inlen, const uint8_t *k, 79 uint8_t *out, const size_t outlen) { 80 uint64_t v0 = 0x736f6d6570736575ULL; 81 uint64_t v1 = 0x646f72616e646f6dULL; 82 uint64_t v2 = 0x6c7967656e657261ULL; 83 uint64_t v3 = 0x7465646279746573ULL; 84 uint64_t k0 = U8TO64_LE(k); 85 uint64_t k1 = U8TO64_LE(k + 8); 86 uint64_t m; 87 int i; 88 const uint8_t *end = in + inlen - (inlen % sizeof(uint64_t)); 89 const int left = inlen & 7; 90 uint64_t b = ((uint64_t)inlen) << 56; 91 v3 ^= k1; 92 v2 ^= k0; 93 v1 ^= k1; 94 v0 ^= k0; 95 96 assert((outlen == 8) || (outlen == 16)); 97 if (outlen == 16) 98 v1 ^= 0xee; 99 100 for (; in != end; in += 8) { 101 m = U8TO64_LE(in); 102 v3 ^= m; 103 104 TRACE; 105 for (i = 0; i < cROUNDS; ++i) 106 SIPROUND; 107 108 v0 ^= m; 109 } 110 111 switch (left) { 112 case 7: 113 b |= ((uint64_t)in[6]) << 48; 114 /* fallthrough */ 115 case 6: 116 b |= ((uint64_t)in[5]) << 40; 117 /* fallthrough */ 118 case 5: 119 b |= ((uint64_t)in[4]) << 32; 120 /* fallthrough */ 121 case 4: 122 b |= ((uint64_t)in[3]) << 24; 123 /* fallthrough */ 124 case 3: 125 b |= ((uint64_t)in[2]) << 16; 126 /* fallthrough */ 127 case 2: 128 b |= ((uint64_t)in[1]) << 8; 129 /* fallthrough */ 130 case 1: 131 b |= ((uint64_t)in[0]); 132 break; 133 case 0: 134 break; 135 } 136 137 v3 ^= b; 138 139 TRACE; 140 for (i = 0; i < cROUNDS; ++i) 141 SIPROUND; 142 143 v0 ^= b; 144 145 if (outlen == 16) 146 v2 ^= 0xee; 147 else 148 v2 ^= 0xff; 149 150 TRACE; 151 for (i = 0; i < dROUNDS; ++i) 152 SIPROUND; 153 154 b = v0 ^ v1 ^ v2 ^ v3; 155 U64TO8_LE(out, b); 156 157 if (outlen == 8) 158 return 0; 159 160 v1 ^= 0xdd; 161 162 TRACE; 163 for (i = 0; i < dROUNDS; ++i) 164 SIPROUND; 165 166 b = v0 ^ v1 ^ v2 ^ v3; 167 U64TO8_LE(out + 8, b); 168 169 return 0; 170 } 171