Skip to content

Commit

Permalink
Use Marvin32 instead of xxHash32 in COSE hash codes
Browse files Browse the repository at this point in the history
  • Loading branch information
bartonjs authored and carlossanlop committed Sep 17, 2024
1 parent 5bb9659 commit 750a230
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 35 deletions.
32 changes: 7 additions & 25 deletions src/libraries/Common/src/System/HashCodeRandomization.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Runtime.InteropServices;
using System.Security.Cryptography;

namespace System
{
// Contains helpers for calculating randomized hash codes of common types.
Expand All @@ -21,32 +24,11 @@ public static int GetRandomizedOrdinalHashCode(this string value)

return value.GetHashCode();
#else
// Downlevel, we need to perform randomization ourselves. There's still
// the potential for limited collisions ("Hello!" and "Hello!\0"), but
// this shouldn't be a problem in practice. If we need to address it,
// we can mix the string length into the accumulator before running the
// string contents through.
//
// We'll pull out pairs of chars and write 32 bits at a time.
// Downlevel, we need to perform randomization ourselves.

HashCode hashCode = default;
int pair = 0;
for (int i = 0; i < value.Length; i++)
{
int ch = value[i];
if ((i & 1) == 0)
{
pair = ch << 16; // first member of pair
}
else
{
pair |= ch; // second member of pair
hashCode.Add(pair); // write pair as single unit
pair = 0;
}
}
hashCode.Add(pair); // flush any leftover data (could be 0 or 1 chars)
return hashCode.ToHashCode();
ReadOnlySpan<char> charSpan = value.AsSpan();
ReadOnlySpan<byte> byteSpan = MemoryMarshal.AsBytes(charSpan);
return Marvin.ComputeHash32(byteSpan, Marvin.DefaultSeed);
#endif
}

Expand Down
37 changes: 32 additions & 5 deletions src/libraries/System.Private.CoreLib/src/System/Marvin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

#if SYSTEM_PRIVATE_CORELIB
using static System.Numerics.BitOperations;
#else
using System.Security.Cryptography;
#endif

namespace System
{
internal static partial class Marvin
Expand Down Expand Up @@ -204,7 +210,7 @@ public static int ComputeHash32(ref byte data, uint count, uint p0, uint p1)
else
{
partialResult |= (uint)Unsafe.ReadUnaligned<ushort>(ref data);
partialResult = BitOperations.RotateLeft(partialResult, 16);
partialResult = RotateLeft(partialResult, 16);
}
}

Expand All @@ -221,16 +227,16 @@ private static void Block(ref uint rp0, ref uint rp1)
uint p1 = rp1;

p1 ^= p0;
p0 = BitOperations.RotateLeft(p0, 20);
p0 = RotateLeft(p0, 20);

p0 += p1;
p1 = BitOperations.RotateLeft(p1, 9);
p1 = RotateLeft(p1, 9);

p1 ^= p0;
p0 = BitOperations.RotateLeft(p0, 27);
p0 = RotateLeft(p0, 27);

p0 += p1;
p1 = BitOperations.RotateLeft(p1, 19);
p1 = RotateLeft(p1, 19);

rp0 = p0;
rp1 = p1;
Expand All @@ -241,8 +247,29 @@ private static void Block(ref uint rp0, ref uint rp1)
private static unsafe ulong GenerateSeed()
{
ulong seed;
#if SYSTEM_PRIVATE_CORELIB
Interop.GetRandomBytes((byte*)&seed, sizeof(ulong));
#else
byte[] seedBytes = new byte[sizeof(ulong)];
using (RandomNumberGenerator rng = RandomNumberGenerator.Create())
{
rng.GetBytes(seedBytes);
fixed (byte* b = seedBytes)
{
seed = *(ulong*)b;
}
}
#endif
return seed;
}

#if !SYSTEM_PRIVATE_CORELIB
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static uint RotateLeft(uint value, int shift)
{
// This is expected to be optimized into a single rol (or ror with negated shift value) instruction
return (value << shift) | (value >> (32 - shift));
}
#endif
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,12 @@
<Compile Include="System\Security\Cryptography\Cose\SigStructureContext.cs" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="$(LibrariesProjectRoot)System.Formats.Cbor\src\System.Formats.Cbor.csproj" />
<ItemGroup Condition="'$(TargetFrameworkIdentifier)' != '.NETCoreApp'">
<Compile Include="$(CoreLibSharedDir)System\Marvin.cs" Link="CoreLib\System\Marvin.cs" />
</ItemGroup>

<!-- For System.HashCode -->
<ItemGroup Condition="'$(TargetFrameworkIdentifier)' != '.NETCoreApp'">
<PackageReference Include="Microsoft.Bcl.HashCode" Version="$(MicrosoftBclHashCodeVersion)" />
<ItemGroup>
<ProjectReference Include="$(LibrariesProjectRoot)System.Formats.Cbor\src\System.Formats.Cbor.csproj" />
</ItemGroup>

</Project>

0 comments on commit 750a230

Please sign in to comment.