using System.Buffers.Binary; namespace AcDream.Core.Net.Cryptography; /// /// Simple 32-bit checksum used by the AC packet header. The algorithm is: /// /// Seed the accumulator with length << 16. /// Sum the input as little-endian uint32s, four bytes at a time. /// Fold any tail bytes (length not divisible by 4) into the top of /// the accumulator with a descending left-shift per byte (24, 16, 8, 0). /// /// Reimplemented from reading ACE's AGPL reference /// (references/ACE/Source/ACE.Common/Cryptography/Hash32.cs). See /// NOTICE.md for the attribution policy. /// public static class Hash32 { public static uint Calculate(ReadOnlySpan data) { int length = data.Length; uint checksum = (uint)length << 16; int wordAligned = length & ~3; for (int i = 0; i < wordAligned; i += 4) { checksum += BinaryPrimitives.ReadUInt32LittleEndian(data.Slice(i)); } // Tail bytes (0, 1, 2, or 3 bytes) with descending shift: first tail // byte goes into bits 24..31, second into 16..23, third into 8..15. int shift = 24; for (int j = wordAligned; j < length; j++) { checksum += (uint)data[j] << shift; shift -= 8; } return checksum; } }