From 37998895d85b4acecc26689cc98009a02795ea58 Mon Sep 17 00:00:00 2001 From: rmg-x Date: Sat, 5 Apr 2025 17:48:12 -0500 Subject: [PATCH] AK+Meta+LibCore+Tests: Remove unused `SipHash` implementation This is a homegrown implementation that wasn't actually used in dependent classes. If this is needed in the future, using OpenSSL would probably be a better option. --- AK/CMakeLists.txt | 1 - AK/IPv4Address.h | 6 - AK/IPv6Address.h | 6 - AK/SipHash.cpp | 176 ------------------------------ AK/SipHash.h | 29 ----- Libraries/LibCore/SocketAddress.h | 8 -- Meta/gn/secondary/AK/BUILD.gn | 2 - Tests/AK/TestHashFunctions.cpp | 33 ------ 8 files changed, 261 deletions(-) delete mode 100644 AK/SipHash.cpp delete mode 100644 AK/SipHash.h diff --git a/AK/CMakeLists.txt b/AK/CMakeLists.txt index 475f46e6253..874f6adeed5 100644 --- a/AK/CMakeLists.txt +++ b/AK/CMakeLists.txt @@ -20,7 +20,6 @@ set(SOURCES NumberFormat.cpp OptionParser.cpp Random.cpp - SipHash.cpp StackInfo.cpp Stream.cpp String.cpp diff --git a/AK/IPv4Address.h b/AK/IPv4Address.h index a6dcf0777f0..1e27414c3cd 100644 --- a/AK/IPv4Address.h +++ b/AK/IPv4Address.h @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -144,11 +143,6 @@ private: static_assert(sizeof(IPv4Address) == 4); -template<> -struct Traits : public DefaultTraits { - static unsigned hash(IPv4Address const& address) { return secure_sip_hash(static_cast(address.to_u32())); } -}; - template<> struct Formatter : Formatter { ErrorOr format(FormatBuilder& builder, IPv4Address value) diff --git a/AK/IPv6Address.h b/AK/IPv6Address.h index fc5c708c7f4..a2b6e93abdd 100644 --- a/AK/IPv6Address.h +++ b/AK/IPv6Address.h @@ -267,12 +267,6 @@ private: static_assert(sizeof(IPv6Address) == 16); -template<> -struct Traits : public DefaultTraits { - // SipHash-4-8 is considered conservatively secure, even if not cryptographically secure. - static unsigned hash(IPv6Address const& address) { return sip_hash_bytes<4, 8>({ &address.to_in6_addr_t(), sizeof(address.to_in6_addr_t()) }); } -}; - template<> struct Formatter : Formatter { ErrorOr format(FormatBuilder& builder, IPv6Address const& value) diff --git a/AK/SipHash.cpp b/AK/SipHash.cpp deleted file mode 100644 index 1ca6bdc8bb6..00000000000 --- a/AK/SipHash.cpp +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright (c) 2023, kleines Filmröllchen - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include -#include -#include - -namespace AK { - -ALWAYS_INLINE constexpr u64 rotate_left(u64 x, u64 bits) -{ - return static_cast(((x) << (bits)) | ((x) >> (64 - (bits)))); -} - -ALWAYS_INLINE constexpr void sipround(u64& v0, u64& v1, u64& v2, u64& v3) -{ - v0 += v1; - v1 = rotate_left(v1, 13); - v1 ^= v0; - v0 = rotate_left(v0, 32); - v2 += v3; - v3 = rotate_left(v3, 16); - v3 ^= v2; - v0 += v3; - v3 = rotate_left(v3, 21); - v3 ^= v0; - v2 += v1; - v1 = rotate_left(v1, 17); - v1 ^= v2; - v2 = rotate_left(v2, 32); -} - -// Can handle u64 or u128 output as per reference implementation. -// We currenly only use u64 and further fold it to u32 (unsigned) for use in Traits. -template -static void do_siphash(ReadonlyBytes input, u128 key, Bytes output) -{ - VERIFY((output.size() == 8) || (output.size() == 16)); - - u64 v0 = 0x736f6d6570736575ull; - u64 v1 = 0x646f72616e646f6dull; - u64 v2 = 0x6c7967656e657261ull; - u64 v3 = 0x7465646279746573ull; - u64 const length = input.size(); - auto const left = length & 7; - // The end of 64-bit blocks. - auto const block_end = length - (length % sizeof(u64)); - u64 b = length << 56; - v3 ^= key.high(); - v2 ^= key.low(); - v1 ^= key.high(); - v0 ^= key.low(); - - if (output.size() == 16) - v1 ^= 0xee; - - for (size_t input_index = 0; input_index < block_end; input_index += 8) { - u64 const m = bit_cast>(ByteReader::load64(input.slice(input_index, sizeof(u64)).data())); - v3 ^= m; - - for (size_t i = 0; i < message_block_rounds; ++i) - sipround(v0, v1, v2, v3); - - v0 ^= m; - } - - switch (left) { - case 7: - b |= (static_cast(input[block_end + 6])) << 48; - [[fallthrough]]; - case 6: - b |= (static_cast(input[block_end + 5])) << 40; - [[fallthrough]]; - case 5: - b |= (static_cast(input[block_end + 4])) << 32; - [[fallthrough]]; - case 4: - b |= (static_cast(input[block_end + 3])) << 24; - [[fallthrough]]; - case 3: - b |= (static_cast(input[block_end + 2])) << 16; - [[fallthrough]]; - case 2: - b |= (static_cast(input[block_end + 1])) << 8; - [[fallthrough]]; - case 1: - b |= (static_cast(input[block_end + 0])); - break; - case 0: - break; - } - - v3 ^= b; - - for (size_t i = 0; i < message_block_rounds; ++i) - sipround(v0, v1, v2, v3); - - v0 ^= b; - - if (output.size() == 16) - v2 ^= 0xee; - else - v2 ^= 0xff; - - for (size_t i = 0; i < finalization_rounds; ++i) - sipround(v0, v1, v2, v3); - - b = v0 ^ v1 ^ v2 ^ v3; - - LittleEndian b_le { b }; - output.overwrite(0, &b_le, sizeof(b_le)); - - if (output.size() == 8) - return; - - v1 ^= 0xdd; - - for (size_t i = 0; i < finalization_rounds; ++i) - sipround(v0, v1, v2, v3); - - b = v0 ^ v1 ^ v2 ^ v3; - b_le = b; - output.overwrite(sizeof(b_le), &b_le, sizeof(b_le)); -} - -struct SipHashKey { - SipHashKey() - { - // get_random is assumed to be secure, otherwise SipHash doesn't deliver on its promises! - key = get_random(); - } - constexpr u128 operator*() const { return key; } - u128 key; -}; -// Using a singleton is a little heavier than a plain static, but avoids an initialization order fiasco. -static Singleton static_sip_hash_key; - -template -unsigned sip_hash_u64(u64 input) -{ - ReadonlyBytes input_bytes { &input, sizeof(input) }; - u64 const output_u64 = sip_hash_bytes(input_bytes); - return static_cast(output_u64 ^ (output_u64 >> 32)); -} - -unsigned standard_sip_hash(u64 input) -{ - return sip_hash_u64<1, 3>(input); -} - -unsigned secure_sip_hash(u64 input) -{ - return sip_hash_u64<4, 8>(input); -} - -template -u64 sip_hash_bytes(ReadonlyBytes input) -{ - auto sip_hash_key = **static_sip_hash_key; - u64 output = 0; - Bytes output_bytes { &output, sizeof(output) }; - do_siphash(input, sip_hash_key, output_bytes); - return output; -} - -// Instantiate all used SipHash variants here: -template u64 sip_hash_bytes<1, 3>(ReadonlyBytes); -template u64 sip_hash_bytes<4, 8>(ReadonlyBytes); - -} diff --git a/AK/SipHash.h b/AK/SipHash.h deleted file mode 100644 index 3c159362aeb..00000000000 --- a/AK/SipHash.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2023, kleines Filmröllchen - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include - -namespace AK { - -// Ported from the SipHash reference implementation, released to the public domain: -// https://github.com/veorq/SipHash/blob/eee7d0d84dc7731df2359b243aa5e75d85f6eaef/siphash.c -// The standard is SipHash-2-4, but we use 1-3 for a little more speed. -// Cryptography should use 4-8 for (relative) conservative security, -// though SipHash itself is NOT a cryptographically secure hash algorithm. -template -u64 sip_hash_bytes(ReadonlyBytes input); -unsigned standard_sip_hash(u64 input); -unsigned secure_sip_hash(u64 input); - -} - -#ifdef USING_AK_GLOBALLY -using AK::secure_sip_hash; -using AK::sip_hash_bytes; -using AK::standard_sip_hash; -#endif diff --git a/Libraries/LibCore/SocketAddress.h b/Libraries/LibCore/SocketAddress.h index ac9403fe747..828381126c5 100644 --- a/Libraries/LibCore/SocketAddress.h +++ b/Libraries/LibCore/SocketAddress.h @@ -140,11 +140,3 @@ struct AK::Formatter : Formatter { return Formatter::format(builder, value.to_byte_string()); } }; - -template<> -struct AK::Traits : public DefaultTraits { - static unsigned hash(Core::SocketAddress const& socket_address) - { - return pair_int_hash(Traits::hash(socket_address.ipv4_address()), Traits::hash(socket_address.port())); - } -}; diff --git a/Meta/gn/secondary/AK/BUILD.gn b/Meta/gn/secondary/AK/BUILD.gn index 6ad7ee677e4..6dc7eda568e 100644 --- a/Meta/gn/secondary/AK/BUILD.gn +++ b/Meta/gn/secondary/AK/BUILD.gn @@ -154,8 +154,6 @@ shared_library("AK") { "Singleton.h", "SinglyLinkedList.h", "SinglyLinkedListSizePolicy.h", - "SipHash.cpp", - "SipHash.h", "SourceGenerator.h", "SourceLocation.h", "Span.h", diff --git a/Tests/AK/TestHashFunctions.cpp b/Tests/AK/TestHashFunctions.cpp index 1baf577fb23..96610533d60 100644 --- a/Tests/AK/TestHashFunctions.cpp +++ b/Tests/AK/TestHashFunctions.cpp @@ -7,7 +7,6 @@ #include #include -#include #include TEST_CASE(int_hash) @@ -55,28 +54,6 @@ TEST_CASE(constexpr_ptr_hash) static_assert(ptr_hash(FlatPtr(42))); } -// Testing concrete hash results is not possible due to SipHash's non-determinism. -// We instead perform some sanity checks and try to hit any asserts caused by programming errors. -TEST_CASE(sip_hash) -{ - EXPECT_EQ(standard_sip_hash(42), standard_sip_hash(42)); - EXPECT_EQ(secure_sip_hash(42), secure_sip_hash(42)); - EXPECT_NE(standard_sip_hash(42), secure_sip_hash(42)); -} - -TEST_CASE(sip_hash_bytes) -{ - constexpr Array short_test_array { 1, 2, 3, 4, 5, 6, 7, 8 }; - constexpr Array common_prefix_array { 1, 2, 3, 4, 5, 6, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0 }; - EXPECT_EQ((sip_hash_bytes<1, 3>(short_test_array.span())), (sip_hash_bytes<1, 3>(short_test_array.span()))); - EXPECT_NE((sip_hash_bytes<1, 3>(short_test_array.span())), (sip_hash_bytes<1, 3>(common_prefix_array.span()))); - - for (size_t prefix_length = 1; prefix_length < 8; ++prefix_length) { - EXPECT_NE((sip_hash_bytes<1, 3>(short_test_array.span().trim(prefix_length))), (sip_hash_bytes<1, 3>(short_test_array.span()))); - EXPECT_EQ((sip_hash_bytes<1, 3>(short_test_array.span().trim(prefix_length))), (sip_hash_bytes<1, 3>(common_prefix_array.span().trim(prefix_length)))); - } -} - template requires(IsCallableWithArguments) static void run_benchmark(HashFunction hash_function) @@ -94,13 +71,3 @@ BENCHMARK_CASE(deterministic_hash) { run_benchmark(u64_hash); } - -BENCHMARK_CASE(fast_sip_hash) -{ - run_benchmark(standard_sip_hash); -} - -BENCHMARK_CASE(secure_sip_hash) -{ - run_benchmark(secure_sip_hash); -}