├── .gitignore ├── Makefile ├── README.md ├── test.c └── csiphash.c /.gitignore: -------------------------------------------------------------------------------- 1 | siphashtest 2 | 3 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | all: 3 | gcc -O3 csiphash.c test.c -g -Wall -Wextra -ggdb -o siphashtest && ./siphashtest 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | SipHash in C 2 | ==== 3 | 4 | A pure C implementation of [SipHash-2-4](https://131002.net/siphash/), 5 | a fast short-input 6 | [PRF](https://en.wikipedia.org/wiki/Pseudorandom_function) with a 7 | 128-bit key and 64-bit output. 8 | 9 | Extract from the description: 10 | 11 | SipHash is a family of pseudorandom functions (a.k.a. keyed hash 12 | functions) optimized for speed on short messages. 13 | 14 | Target applications include network traffic authentication and defense 15 | against hash-flooding DoS attacks. 16 | 17 | SipHash is secure, fast, and simple (for real): 18 | * SipHash is simpler and faster than previous cryptographic algorithms 19 | (e.g. MACs based on universal hashing) 20 | * SipHash is competitive in performance with insecure 21 | non-cryptographic algorithms (e.g. MurmurHash) 22 | * We propose that hash tables switch to SipHash as a hash 23 | function. Users of SipHash already include OpenDNS, Perl 5, Ruby, or 24 | Rust. 25 | 26 | 27 | Introductory blog post: https://idea.popcount.org/2013-01-24-siphash/ 28 | 29 | installation 30 | --- 31 | 32 | Copy `csiphash.c` to your code directory and add the declaration 33 | somewhere: 34 | 35 | ```c 36 | uint64_t siphash24(const void *src, 37 | unsigned long src_sz, 38 | const char k[16]); 39 | ``` 40 | 41 | 42 | usage 43 | --- 44 | 45 | Shortest program: 46 | 47 | ```c 48 | #include 49 | #include 50 | #include 51 | 52 | uint64_t siphash24(const void *src, 53 | unsigned long src_sz, 54 | const char key[16]); 55 | 56 | int main() { 57 | char key[16] = {0,1,2,3,4,5,6,7,8,9,0xa,0xb,0xc,0xd,0xe,0xf}; 58 | char *pt = "hello world!"; 59 | uint64_t hash = siphash24(pt, strlen(pt), key); 60 | printf("plaintext=%s hash=%llu\n", pt, hash); 61 | return 0; 62 | } 63 | ``` 64 | 65 | testing 66 | --- 67 | 68 | Type `make`: 69 | 70 | $ make 71 | 64 tests passed in 0.008ms, 125ns per test 72 | 73 | license 74 | ---- 75 | 76 | This code is released under the MIT License, the full text of which can be found is in the header of [`csiphash.c`](https://github.com/majek/csiphash/blob/master/csiphash.c). 77 | -------------------------------------------------------------------------------- /test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | uint64_t gettime_ns() { 7 | struct timeval tv; 8 | gettimeofday(&tv, NULL); 9 | return (uint64_t)tv.tv_sec * 1000000000ULL + tv.tv_usec * 1000ULL; 10 | } 11 | 12 | 13 | uint64_t siphash24(const char *in, unsigned long inlen, const char k[16]); 14 | 15 | #define REPEATS 1 16 | 17 | uint64_t vectors[64] = { 18 | 0x726fdb47dd0e0e31LLU, 0x74f839c593dc67fdLLU, 0x0d6c8009d9a94f5aLLU, 0x85676696d7fb7e2dLLU, 19 | 0xcf2794e0277187b7LLU, 0x18765564cd99a68dLLU, 0xcbc9466e58fee3ceLLU, 0xab0200f58b01d137LLU, 20 | 0x93f5f5799a932462LLU, 0x9e0082df0ba9e4b0LLU, 0x7a5dbbc594ddb9f3LLU, 0xf4b32f46226bada7LLU, 21 | 0x751e8fbc860ee5fbLLU, 0x14ea5627c0843d90LLU, 0xf723ca908e7af2eeLLU, 0xa129ca6149be45e5LLU, 22 | 0x3f2acc7f57c29bdbLLU, 0x699ae9f52cbe4794LLU, 0x4bc1b3f0968dd39cLLU, 0xbb6dc91da77961bdLLU, 23 | 0xbed65cf21aa2ee98LLU, 0xd0f2cbb02e3b67c7LLU, 0x93536795e3a33e88LLU, 0xa80c038ccd5ccec8LLU, 24 | 0xb8ad50c6f649af94LLU, 0xbce192de8a85b8eaLLU, 0x17d835b85bbb15f3LLU, 0x2f2e6163076bcfadLLU, 25 | 0xde4daaaca71dc9a5LLU, 0xa6a2506687956571LLU, 0xad87a3535c49ef28LLU, 0x32d892fad841c342LLU, 26 | 0x7127512f72f27cceLLU, 0xa7f32346f95978e3LLU, 0x12e0b01abb051238LLU, 0x15e034d40fa197aeLLU, 27 | 0x314dffbe0815a3b4LLU, 0x027990f029623981LLU, 0xcadcd4e59ef40c4dLLU, 0x9abfd8766a33735cLLU, 28 | 0x0e3ea96b5304a7d0LLU, 0xad0c42d6fc585992LLU, 0x187306c89bc215a9LLU, 0xd4a60abcf3792b95LLU, 29 | 0xf935451de4f21df2LLU, 0xa9538f0419755787LLU, 0xdb9acddff56ca510LLU, 0xd06c98cd5c0975ebLLU, 30 | 0xe612a3cb9ecba951LLU, 0xc766e62cfcadaf96LLU, 0xee64435a9752fe72LLU, 0xa192d576b245165aLLU, 31 | 0x0a8787bf8ecb74b2LLU, 0x81b3e73d20b49b6fLLU, 0x7fa8220ba3b2eceaLLU, 0x245731c13ca42499LLU, 32 | 0xb78dbfaf3a8d83bdLLU, 0xea1ad565322a1a0bLLU, 0x60e61c23a3795013LLU, 0x6606d7e446282b93LLU, 33 | 0x6ca4ecb15c5f91e1LLU, 0x9f626da15c9625f3LLU, 0xe51b38608ef25f57LLU, 0x958a324ceb064572LLU, 34 | }; 35 | 36 | 37 | int main() { 38 | int i; 39 | char key[16] = {0,1,2,3,4,5,6,7,8,9,0xa,0xb,0xc,0xd,0xe,0xf}; 40 | char plaintext[64]; 41 | for (i=0; i<64; i++) plaintext[i] = i; 42 | 43 | 44 | int j; 45 | uint64_t t0, t1; 46 | t0 = gettime_ns(); 47 | for (j=0; j 2 | Copyright (c) 2013 Marek Majkowski 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | 22 | 23 | Original location: 24 | https://github.com/majek/csiphash/ 25 | 26 | Solution inspired by code from: 27 | Samuel Neves (supercop/crypto_auth/siphash24/little) 28 | djb (supercop/crypto_auth/siphash24/little2) 29 | Jean-Philippe Aumasson (https://131002.net/siphash/siphash24.c) 30 | */ 31 | 32 | #include 33 | 34 | #if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \ 35 | __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 36 | # define _le64toh(x) ((uint64_t)(x)) 37 | #elif defined(_WIN32) 38 | /* Windows is always little endian, unless you're on xbox360 39 | http://msdn.microsoft.com/en-us/library/b0084kay(v=vs.80).aspx */ 40 | # define _le64toh(x) ((uint64_t)(x)) 41 | #elif defined(__APPLE__) 42 | # include 43 | # define _le64toh(x) OSSwapLittleToHostInt64(x) 44 | #else 45 | 46 | /* See: http://sourceforge.net/p/predef/wiki/Endianness/ */ 47 | # if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) 48 | # include 49 | # else 50 | # include 51 | # endif 52 | # if defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \ 53 | __BYTE_ORDER == __LITTLE_ENDIAN 54 | # define _le64toh(x) ((uint64_t)(x)) 55 | # else 56 | # define _le64toh(x) le64toh(x) 57 | # endif 58 | 59 | #endif 60 | 61 | 62 | #define ROTATE(x, b) (uint64_t)( ((x) << (b)) | ( (x) >> (64 - (b))) ) 63 | 64 | #define HALF_ROUND(a,b,c,d,s,t) \ 65 | a += b; c += d; \ 66 | b = ROTATE(b, s) ^ a; \ 67 | d = ROTATE(d, t) ^ c; \ 68 | a = ROTATE(a, 32); 69 | 70 | #define DOUBLE_ROUND(v0,v1,v2,v3) \ 71 | HALF_ROUND(v0,v1,v2,v3,13,16); \ 72 | HALF_ROUND(v2,v1,v0,v3,17,21); \ 73 | HALF_ROUND(v0,v1,v2,v3,13,16); \ 74 | HALF_ROUND(v2,v1,v0,v3,17,21); 75 | 76 | 77 | uint64_t siphash24(const void *src, unsigned long src_sz, const char key[16]) { 78 | const uint64_t *_key = (uint64_t *)key; 79 | uint64_t k0 = _le64toh(_key[0]); 80 | uint64_t k1 = _le64toh(_key[1]); 81 | uint64_t b = (uint64_t)src_sz << 56; 82 | const uint64_t *in = (uint64_t*)src; 83 | 84 | uint64_t v0 = k0 ^ 0x736f6d6570736575ULL; 85 | uint64_t v1 = k1 ^ 0x646f72616e646f6dULL; 86 | uint64_t v2 = k0 ^ 0x6c7967656e657261ULL; 87 | uint64_t v3 = k1 ^ 0x7465646279746573ULL; 88 | 89 | while (src_sz >= 8) { 90 | uint64_t mi = _le64toh(*in); 91 | in += 1; src_sz -= 8; 92 | v3 ^= mi; 93 | DOUBLE_ROUND(v0,v1,v2,v3); 94 | v0 ^= mi; 95 | } 96 | 97 | uint64_t t = 0; uint8_t *pt = (uint8_t *)&t; uint8_t *m = (uint8_t *)in; 98 | switch (src_sz) { 99 | case 7: pt[6] = m[6]; 100 | case 6: pt[5] = m[5]; 101 | case 5: pt[4] = m[4]; 102 | case 4: *((uint32_t*)&pt[0]) = *((uint32_t*)&m[0]); break; 103 | case 3: pt[2] = m[2]; 104 | case 2: pt[1] = m[1]; 105 | case 1: pt[0] = m[0]; 106 | } 107 | b |= _le64toh(t); 108 | 109 | v3 ^= b; 110 | DOUBLE_ROUND(v0,v1,v2,v3); 111 | v0 ^= b; v2 ^= 0xff; 112 | DOUBLE_ROUND(v0,v1,v2,v3); 113 | DOUBLE_ROUND(v0,v1,v2,v3); 114 | return (v0 ^ v1) ^ (v2 ^ v3); 115 | } 116 | --------------------------------------------------------------------------------