1*2c956a60SJason A. Donenfeld /* Copyright (C) 2016 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. 2*2c956a60SJason A. Donenfeld * 3*2c956a60SJason A. Donenfeld * This file is provided under a dual BSD/GPLv2 license. 4*2c956a60SJason A. Donenfeld * 5*2c956a60SJason A. Donenfeld * SipHash: a fast short-input PRF 6*2c956a60SJason A. Donenfeld * https://131002.net/siphash/ 7*2c956a60SJason A. Donenfeld * 8*2c956a60SJason A. Donenfeld * This implementation is specifically for SipHash2-4. 9*2c956a60SJason A. Donenfeld */ 10*2c956a60SJason A. Donenfeld 11*2c956a60SJason A. Donenfeld #ifndef _LINUX_SIPHASH_H 12*2c956a60SJason A. Donenfeld #define _LINUX_SIPHASH_H 13*2c956a60SJason A. Donenfeld 14*2c956a60SJason A. Donenfeld #include <linux/types.h> 15*2c956a60SJason A. Donenfeld #include <linux/kernel.h> 16*2c956a60SJason A. Donenfeld 17*2c956a60SJason A. Donenfeld #define SIPHASH_ALIGNMENT __alignof__(u64) 18*2c956a60SJason A. Donenfeld typedef struct { 19*2c956a60SJason A. Donenfeld u64 key[2]; 20*2c956a60SJason A. Donenfeld } siphash_key_t; 21*2c956a60SJason A. Donenfeld 22*2c956a60SJason A. Donenfeld u64 __siphash_aligned(const void *data, size_t len, const siphash_key_t *key); 23*2c956a60SJason A. Donenfeld #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 24*2c956a60SJason A. Donenfeld u64 __siphash_unaligned(const void *data, size_t len, const siphash_key_t *key); 25*2c956a60SJason A. Donenfeld #endif 26*2c956a60SJason A. Donenfeld 27*2c956a60SJason A. Donenfeld u64 siphash_1u64(const u64 a, const siphash_key_t *key); 28*2c956a60SJason A. Donenfeld u64 siphash_2u64(const u64 a, const u64 b, const siphash_key_t *key); 29*2c956a60SJason A. Donenfeld u64 siphash_3u64(const u64 a, const u64 b, const u64 c, 30*2c956a60SJason A. Donenfeld const siphash_key_t *key); 31*2c956a60SJason A. Donenfeld u64 siphash_4u64(const u64 a, const u64 b, const u64 c, const u64 d, 32*2c956a60SJason A. Donenfeld const siphash_key_t *key); 33*2c956a60SJason A. Donenfeld u64 siphash_1u32(const u32 a, const siphash_key_t *key); 34*2c956a60SJason A. Donenfeld u64 siphash_3u32(const u32 a, const u32 b, const u32 c, 35*2c956a60SJason A. Donenfeld const siphash_key_t *key); 36*2c956a60SJason A. Donenfeld 37*2c956a60SJason A. Donenfeld static inline u64 siphash_2u32(const u32 a, const u32 b, 38*2c956a60SJason A. Donenfeld const siphash_key_t *key) 39*2c956a60SJason A. Donenfeld { 40*2c956a60SJason A. Donenfeld return siphash_1u64((u64)b << 32 | a, key); 41*2c956a60SJason A. Donenfeld } 42*2c956a60SJason A. Donenfeld static inline u64 siphash_4u32(const u32 a, const u32 b, const u32 c, 43*2c956a60SJason A. Donenfeld const u32 d, const siphash_key_t *key) 44*2c956a60SJason A. Donenfeld { 45*2c956a60SJason A. Donenfeld return siphash_2u64((u64)b << 32 | a, (u64)d << 32 | c, key); 46*2c956a60SJason A. Donenfeld } 47*2c956a60SJason A. Donenfeld 48*2c956a60SJason A. Donenfeld 49*2c956a60SJason A. Donenfeld static inline u64 ___siphash_aligned(const __le64 *data, size_t len, 50*2c956a60SJason A. Donenfeld const siphash_key_t *key) 51*2c956a60SJason A. Donenfeld { 52*2c956a60SJason A. Donenfeld if (__builtin_constant_p(len) && len == 4) 53*2c956a60SJason A. Donenfeld return siphash_1u32(le32_to_cpup((const __le32 *)data), key); 54*2c956a60SJason A. Donenfeld if (__builtin_constant_p(len) && len == 8) 55*2c956a60SJason A. Donenfeld return siphash_1u64(le64_to_cpu(data[0]), key); 56*2c956a60SJason A. Donenfeld if (__builtin_constant_p(len) && len == 16) 57*2c956a60SJason A. Donenfeld return siphash_2u64(le64_to_cpu(data[0]), le64_to_cpu(data[1]), 58*2c956a60SJason A. Donenfeld key); 59*2c956a60SJason A. Donenfeld if (__builtin_constant_p(len) && len == 24) 60*2c956a60SJason A. Donenfeld return siphash_3u64(le64_to_cpu(data[0]), le64_to_cpu(data[1]), 61*2c956a60SJason A. Donenfeld le64_to_cpu(data[2]), key); 62*2c956a60SJason A. Donenfeld if (__builtin_constant_p(len) && len == 32) 63*2c956a60SJason A. Donenfeld return siphash_4u64(le64_to_cpu(data[0]), le64_to_cpu(data[1]), 64*2c956a60SJason A. Donenfeld le64_to_cpu(data[2]), le64_to_cpu(data[3]), 65*2c956a60SJason A. Donenfeld key); 66*2c956a60SJason A. Donenfeld return __siphash_aligned(data, len, key); 67*2c956a60SJason A. Donenfeld } 68*2c956a60SJason A. Donenfeld 69*2c956a60SJason A. Donenfeld /** 70*2c956a60SJason A. Donenfeld * siphash - compute 64-bit siphash PRF value 71*2c956a60SJason A. Donenfeld * @data: buffer to hash 72*2c956a60SJason A. Donenfeld * @size: size of @data 73*2c956a60SJason A. Donenfeld * @key: the siphash key 74*2c956a60SJason A. Donenfeld */ 75*2c956a60SJason A. Donenfeld static inline u64 siphash(const void *data, size_t len, 76*2c956a60SJason A. Donenfeld const siphash_key_t *key) 77*2c956a60SJason A. Donenfeld { 78*2c956a60SJason A. Donenfeld #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 79*2c956a60SJason A. Donenfeld if (!IS_ALIGNED((unsigned long)data, SIPHASH_ALIGNMENT)) 80*2c956a60SJason A. Donenfeld return __siphash_unaligned(data, len, key); 81*2c956a60SJason A. Donenfeld #endif 82*2c956a60SJason A. Donenfeld return ___siphash_aligned(data, len, key); 83*2c956a60SJason A. Donenfeld } 84*2c956a60SJason A. Donenfeld 85*2c956a60SJason A. Donenfeld #endif /* _LINUX_SIPHASH_H */ 86