Path: blob/main/sys/compat/linuxkpi/common/src/linux_siphash.c
96339 views
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)1/* Copyright (C) 2016-2022 Jason A. Donenfeld <[email protected]>. All Rights Reserved.2*3* SipHash: a fast short-input PRF4* https://131002.net/siphash/5*6* This implementation is specifically for SipHash2-4 for a secure PRF7* and HalfSipHash1-3/SipHash1-3 for an insecure PRF only suitable for8* hashtables.9*/1011#include <linux/siphash.h>12#include <asm/unaligned.h>1314#if defined(CONFIG_DCACHE_WORD_ACCESS) && BITS_PER_LONG == 6415#include <linux/dcache.h>16#include <asm/word-at-a-time.h>17#endif1819#define EXPORT_SYMBOL(name)2021#define SIPROUND SIPHASH_PERMUTATION(v0, v1, v2, v3)2223#define PREAMBLE(len) \24u64 v0 = SIPHASH_CONST_0; \25u64 v1 = SIPHASH_CONST_1; \26u64 v2 = SIPHASH_CONST_2; \27u64 v3 = SIPHASH_CONST_3; \28u64 b = ((u64)(len)) << 56; \29v3 ^= key->key[1]; \30v2 ^= key->key[0]; \31v1 ^= key->key[1]; \32v0 ^= key->key[0];3334#define POSTAMBLE \35v3 ^= b; \36SIPROUND; \37SIPROUND; \38v0 ^= b; \39v2 ^= 0xff; \40SIPROUND; \41SIPROUND; \42SIPROUND; \43SIPROUND; \44return (v0 ^ v1) ^ (v2 ^ v3);4546#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS47u64 __siphash_aligned(const void *_data, size_t len, const siphash_key_t *key)48{49const u8 *data = _data;50const u8 *end = data + len - (len % sizeof(u64));51const u8 left = len & (sizeof(u64) - 1);52u64 m;53PREAMBLE(len)54for (; data != end; data += sizeof(u64)) {55m = le64_to_cpup(data);56v3 ^= m;57SIPROUND;58SIPROUND;59v0 ^= m;60}61#if defined(CONFIG_DCACHE_WORD_ACCESS) && BITS_PER_LONG == 6462if (left)63b |= le64_to_cpu((__force __le64)(load_unaligned_zeropad(data) &64bytemask_from_count(left)));65#else66switch (left) {67case 7: b |= ((u64)end[6]) << 48; fallthrough;68case 6: b |= ((u64)end[5]) << 40; fallthrough;69case 5: b |= ((u64)end[4]) << 32; fallthrough;70case 4: b |= le32_to_cpup(data); break;71case 3: b |= ((u64)end[2]) << 16; fallthrough;72case 2: b |= le16_to_cpup(data); break;73case 1: b |= end[0];74}75#endif76POSTAMBLE77}78EXPORT_SYMBOL(__siphash_aligned);79#endif8081u64 __siphash_unaligned(const void *_data, size_t len, const siphash_key_t *key)82{83const u8 *data = _data;84const u8 *end = data + len - (len % sizeof(u64));85const u8 left = len & (sizeof(u64) - 1);86u64 m;87PREAMBLE(len)88for (; data != end; data += sizeof(u64)) {89m = get_unaligned_le64(data);90v3 ^= m;91SIPROUND;92SIPROUND;93v0 ^= m;94}95#if defined(CONFIG_DCACHE_WORD_ACCESS) && BITS_PER_LONG == 6496if (left)97b |= le64_to_cpu((__force __le64)(load_unaligned_zeropad(data) &98bytemask_from_count(left)));99#else100switch (left) {101case 7: b |= ((u64)end[6]) << 48; fallthrough;102case 6: b |= ((u64)end[5]) << 40; fallthrough;103case 5: b |= ((u64)end[4]) << 32; fallthrough;104case 4: b |= get_unaligned_le32(end); break;105case 3: b |= ((u64)end[2]) << 16; fallthrough;106case 2: b |= get_unaligned_le16(end); break;107case 1: b |= end[0];108}109#endif110POSTAMBLE111}112EXPORT_SYMBOL(__siphash_unaligned);113114/**115* siphash_1u64 - compute 64-bit siphash PRF value of a u64116* @first: first u64117* @key: the siphash key118*/119u64 siphash_1u64(const u64 first, const siphash_key_t *key)120{121PREAMBLE(8)122v3 ^= first;123SIPROUND;124SIPROUND;125v0 ^= first;126POSTAMBLE127}128EXPORT_SYMBOL(siphash_1u64);129130/**131* siphash_2u64 - compute 64-bit siphash PRF value of 2 u64132* @first: first u64133* @second: second u64134* @key: the siphash key135*/136u64 siphash_2u64(const u64 first, const u64 second, const siphash_key_t *key)137{138PREAMBLE(16)139v3 ^= first;140SIPROUND;141SIPROUND;142v0 ^= first;143v3 ^= second;144SIPROUND;145SIPROUND;146v0 ^= second;147POSTAMBLE148}149EXPORT_SYMBOL(siphash_2u64);150151/**152* siphash_3u64 - compute 64-bit siphash PRF value of 3 u64153* @first: first u64154* @second: second u64155* @third: third u64156* @key: the siphash key157*/158u64 siphash_3u64(const u64 first, const u64 second, const u64 third,159const siphash_key_t *key)160{161PREAMBLE(24)162v3 ^= first;163SIPROUND;164SIPROUND;165v0 ^= first;166v3 ^= second;167SIPROUND;168SIPROUND;169v0 ^= second;170v3 ^= third;171SIPROUND;172SIPROUND;173v0 ^= third;174POSTAMBLE175}176EXPORT_SYMBOL(siphash_3u64);177178/**179* siphash_4u64 - compute 64-bit siphash PRF value of 4 u64180* @first: first u64181* @second: second u64182* @third: third u64183* @forth: forth u64184* @key: the siphash key185*/186u64 siphash_4u64(const u64 first, const u64 second, const u64 third,187const u64 forth, const siphash_key_t *key)188{189PREAMBLE(32)190v3 ^= first;191SIPROUND;192SIPROUND;193v0 ^= first;194v3 ^= second;195SIPROUND;196SIPROUND;197v0 ^= second;198v3 ^= third;199SIPROUND;200SIPROUND;201v0 ^= third;202v3 ^= forth;203SIPROUND;204SIPROUND;205v0 ^= forth;206POSTAMBLE207}208EXPORT_SYMBOL(siphash_4u64);209210u64 siphash_1u32(const u32 first, const siphash_key_t *key)211{212PREAMBLE(4)213b |= first;214POSTAMBLE215}216EXPORT_SYMBOL(siphash_1u32);217218u64 siphash_3u32(const u32 first, const u32 second, const u32 third,219const siphash_key_t *key)220{221u64 combined = (u64)second << 32 | first;222PREAMBLE(12)223v3 ^= combined;224SIPROUND;225SIPROUND;226v0 ^= combined;227b |= third;228POSTAMBLE229}230EXPORT_SYMBOL(siphash_3u32);231232#if BITS_PER_LONG == 64233/* Note that on 64-bit, we make HalfSipHash1-3 actually be SipHash1-3, for234* performance reasons. On 32-bit, below, we actually implement HalfSipHash1-3.235*/236237#define HSIPROUND SIPROUND238#define HPREAMBLE(len) PREAMBLE(len)239#define HPOSTAMBLE \240v3 ^= b; \241HSIPROUND; \242v0 ^= b; \243v2 ^= 0xff; \244HSIPROUND; \245HSIPROUND; \246HSIPROUND; \247return (v0 ^ v1) ^ (v2 ^ v3);248249#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS250u32 __hsiphash_aligned(const void *_data, size_t len, const hsiphash_key_t *key)251{252const u8 *data = _data;253const u8 *end = data + len - (len % sizeof(u64));254const u8 left = len & (sizeof(u64) - 1);255u64 m;256HPREAMBLE(len)257for (; data != end; data += sizeof(u64)) {258m = le64_to_cpup(data);259v3 ^= m;260HSIPROUND;261v0 ^= m;262}263#if defined(CONFIG_DCACHE_WORD_ACCESS) && BITS_PER_LONG == 64264if (left)265b |= le64_to_cpu((__force __le64)(load_unaligned_zeropad(data) &266bytemask_from_count(left)));267#else268switch (left) {269case 7: b |= ((u64)end[6]) << 48; fallthrough;270case 6: b |= ((u64)end[5]) << 40; fallthrough;271case 5: b |= ((u64)end[4]) << 32; fallthrough;272case 4: b |= le32_to_cpup(data); break;273case 3: b |= ((u64)end[2]) << 16; fallthrough;274case 2: b |= le16_to_cpup(data); break;275case 1: b |= end[0];276}277#endif278HPOSTAMBLE279}280EXPORT_SYMBOL(__hsiphash_aligned);281#endif282283u32 __hsiphash_unaligned(const void *_data, size_t len,284const hsiphash_key_t *key)285{286const u8 *data = _data;287const u8 *end = data + len - (len % sizeof(u64));288const u8 left = len & (sizeof(u64) - 1);289u64 m;290HPREAMBLE(len)291for (; data != end; data += sizeof(u64)) {292m = get_unaligned_le64(data);293v3 ^= m;294HSIPROUND;295v0 ^= m;296}297#if defined(CONFIG_DCACHE_WORD_ACCESS) && BITS_PER_LONG == 64298if (left)299b |= le64_to_cpu((__force __le64)(load_unaligned_zeropad(data) &300bytemask_from_count(left)));301#else302switch (left) {303case 7: b |= ((u64)end[6]) << 48; fallthrough;304case 6: b |= ((u64)end[5]) << 40; fallthrough;305case 5: b |= ((u64)end[4]) << 32; fallthrough;306case 4: b |= get_unaligned_le32(end); break;307case 3: b |= ((u64)end[2]) << 16; fallthrough;308case 2: b |= get_unaligned_le16(end); break;309case 1: b |= end[0];310}311#endif312HPOSTAMBLE313}314EXPORT_SYMBOL(__hsiphash_unaligned);315316/**317* hsiphash_1u32 - compute 64-bit hsiphash PRF value of a u32318* @first: first u32319* @key: the hsiphash key320*/321u32 hsiphash_1u32(const u32 first, const hsiphash_key_t *key)322{323HPREAMBLE(4)324b |= first;325HPOSTAMBLE326}327EXPORT_SYMBOL(hsiphash_1u32);328329/**330* hsiphash_2u32 - compute 32-bit hsiphash PRF value of 2 u32331* @first: first u32332* @second: second u32333* @key: the hsiphash key334*/335u32 hsiphash_2u32(const u32 first, const u32 second, const hsiphash_key_t *key)336{337u64 combined = (u64)second << 32 | first;338HPREAMBLE(8)339v3 ^= combined;340HSIPROUND;341v0 ^= combined;342HPOSTAMBLE343}344EXPORT_SYMBOL(hsiphash_2u32);345346/**347* hsiphash_3u32 - compute 32-bit hsiphash PRF value of 3 u32348* @first: first u32349* @second: second u32350* @third: third u32351* @key: the hsiphash key352*/353u32 hsiphash_3u32(const u32 first, const u32 second, const u32 third,354const hsiphash_key_t *key)355{356u64 combined = (u64)second << 32 | first;357HPREAMBLE(12)358v3 ^= combined;359HSIPROUND;360v0 ^= combined;361b |= third;362HPOSTAMBLE363}364EXPORT_SYMBOL(hsiphash_3u32);365366/**367* hsiphash_4u32 - compute 32-bit hsiphash PRF value of 4 u32368* @first: first u32369* @second: second u32370* @third: third u32371* @forth: forth u32372* @key: the hsiphash key373*/374u32 hsiphash_4u32(const u32 first, const u32 second, const u32 third,375const u32 forth, const hsiphash_key_t *key)376{377u64 combined = (u64)second << 32 | first;378HPREAMBLE(16)379v3 ^= combined;380HSIPROUND;381v0 ^= combined;382combined = (u64)forth << 32 | third;383v3 ^= combined;384HSIPROUND;385v0 ^= combined;386HPOSTAMBLE387}388EXPORT_SYMBOL(hsiphash_4u32);389#else390#define HSIPROUND HSIPHASH_PERMUTATION(v0, v1, v2, v3)391392#define HPREAMBLE(len) \393u32 v0 = HSIPHASH_CONST_0; \394u32 v1 = HSIPHASH_CONST_1; \395u32 v2 = HSIPHASH_CONST_2; \396u32 v3 = HSIPHASH_CONST_3; \397u32 b = ((u32)(len)) << 24; \398v3 ^= key->key[1]; \399v2 ^= key->key[0]; \400v1 ^= key->key[1]; \401v0 ^= key->key[0];402403#define HPOSTAMBLE \404v3 ^= b; \405HSIPROUND; \406v0 ^= b; \407v2 ^= 0xff; \408HSIPROUND; \409HSIPROUND; \410HSIPROUND; \411return v1 ^ v3;412413#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS414u32 __hsiphash_aligned(const void *_data, size_t len, const hsiphash_key_t *key)415{416const u8 *data = _data;417const u8 *end = data + len - (len % sizeof(u32));418const u8 left = len & (sizeof(u32) - 1);419u32 m;420HPREAMBLE(len)421for (; data != end; data += sizeof(u32)) {422m = le32_to_cpup(data);423v3 ^= m;424HSIPROUND;425v0 ^= m;426}427switch (left) {428case 3: b |= ((u32)end[2]) << 16; fallthrough;429case 2: b |= le16_to_cpup(data); break;430case 1: b |= end[0];431}432HPOSTAMBLE433}434EXPORT_SYMBOL(__hsiphash_aligned);435#endif436437u32 __hsiphash_unaligned(const void *_data, size_t len,438const hsiphash_key_t *key)439{440const u8 *data = _data;441const u8 *end = data + len - (len % sizeof(u32));442const u8 left = len & (sizeof(u32) - 1);443u32 m;444HPREAMBLE(len)445for (; data != end; data += sizeof(u32)) {446m = get_unaligned_le32(data);447v3 ^= m;448HSIPROUND;449v0 ^= m;450}451switch (left) {452case 3: b |= ((u32)end[2]) << 16; fallthrough;453case 2: b |= get_unaligned_le16(end); break;454case 1: b |= end[0];455}456HPOSTAMBLE457}458EXPORT_SYMBOL(__hsiphash_unaligned);459460/**461* hsiphash_1u32 - compute 32-bit hsiphash PRF value of a u32462* @first: first u32463* @key: the hsiphash key464*/465u32 hsiphash_1u32(const u32 first, const hsiphash_key_t *key)466{467HPREAMBLE(4)468v3 ^= first;469HSIPROUND;470v0 ^= first;471HPOSTAMBLE472}473EXPORT_SYMBOL(hsiphash_1u32);474475/**476* hsiphash_2u32 - compute 32-bit hsiphash PRF value of 2 u32477* @first: first u32478* @second: second u32479* @key: the hsiphash key480*/481u32 hsiphash_2u32(const u32 first, const u32 second, const hsiphash_key_t *key)482{483HPREAMBLE(8)484v3 ^= first;485HSIPROUND;486v0 ^= first;487v3 ^= second;488HSIPROUND;489v0 ^= second;490HPOSTAMBLE491}492EXPORT_SYMBOL(hsiphash_2u32);493494/**495* hsiphash_3u32 - compute 32-bit hsiphash PRF value of 3 u32496* @first: first u32497* @second: second u32498* @third: third u32499* @key: the hsiphash key500*/501u32 hsiphash_3u32(const u32 first, const u32 second, const u32 third,502const hsiphash_key_t *key)503{504HPREAMBLE(12)505v3 ^= first;506HSIPROUND;507v0 ^= first;508v3 ^= second;509HSIPROUND;510v0 ^= second;511v3 ^= third;512HSIPROUND;513v0 ^= third;514HPOSTAMBLE515}516EXPORT_SYMBOL(hsiphash_3u32);517518/**519* hsiphash_4u32 - compute 32-bit hsiphash PRF value of 4 u32520* @first: first u32521* @second: second u32522* @third: third u32523* @forth: forth u32524* @key: the hsiphash key525*/526u32 hsiphash_4u32(const u32 first, const u32 second, const u32 third,527const u32 forth, const hsiphash_key_t *key)528{529HPREAMBLE(16)530v3 ^= first;531HSIPROUND;532v0 ^= first;533v3 ^= second;534HSIPROUND;535v0 ^= second;536v3 ^= third;537HSIPROUND;538v0 ^= third;539v3 ^= forth;540HSIPROUND;541v0 ^= forth;542HPOSTAMBLE543}544EXPORT_SYMBOL(hsiphash_4u32);545#endif546547548