From 7ae990d2e5eeb17b461482e3db19c1d1d3c2594c Mon Sep 17 00:00:00 2001 From: Dan Klishch Date: Sun, 19 May 2024 13:43:37 -0400 Subject: [PATCH] LibCrypto: Don't compute 2*N remainders in Adler32 Otherwise Zlib decompression spends half of the time computing the checksum. --- .../Libraries/LibCrypto/Checksum/Adler32.cpp | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/Userland/Libraries/LibCrypto/Checksum/Adler32.cpp b/Userland/Libraries/LibCrypto/Checksum/Adler32.cpp index 93406c10e38..eaff83f7d3c 100644 --- a/Userland/Libraries/LibCrypto/Checksum/Adler32.cpp +++ b/Userland/Libraries/LibCrypto/Checksum/Adler32.cpp @@ -12,10 +12,32 @@ namespace Crypto::Checksum { void Adler32::update(ReadonlyBytes data) { - for (size_t i = 0; i < data.size(); i++) { - m_state_a = (m_state_a + data.at(i)) % 65521; - m_state_b = (m_state_b + m_state_a) % 65521; + // See https://github.com/SerenityOS/serenity/pull/24408#discussion_r1609051678 + constexpr size_t iterations_without_overflow = 380368439; + + u64 state_a = m_state_a; + u64 state_b = m_state_b; + while (data.size()) { + // You can verify that no overflow will happen here during at least + // `iterations_without_overflow` iterations using the following Python script: + // + // state_a = 65520 + // state_b = 65520 + // for i in range(380368439): + // state_a += 255 + // state_b += state_a + // print(state_b < 2 ** 64) + auto chunk = data.slice(0, min(data.size(), iterations_without_overflow)); + for (u8 byte : chunk) { + state_a += byte; + state_b += state_a; + } + state_a %= 65521; + state_b %= 65521; + data = data.slice(chunk.size()); } + m_state_a = state_a; + m_state_b = state_b; } u32 Adler32::digest()