Skip to content

Commit 7dc1560

Browse files
bartonjscarlossanlop
authored andcommitted
Merged PR 41316: Use Marvin32 instead of xxHash32 in COSE hash codes
1 parent 132fb31 commit 7dc1560

File tree

3 files changed

+44
-37
lines changed

3 files changed

+44
-37
lines changed

src/libraries/Common/src/System/HashCodeRandomization.cs

Lines changed: 23 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System.Runtime.InteropServices;
5+
using System.Security.Cryptography;
6+
47
namespace System
58
{
69
// Contains helpers for calculating randomized hash codes of common types.
@@ -14,39 +17,33 @@ namespace System
1417
// rather than a global seed for the entire AppDomain.
1518
internal static class HashCodeRandomization
1619
{
20+
#if !NET
21+
private static readonly ulong s_seed = GenerateSeed();
22+
23+
private static ulong GenerateSeed()
24+
{
25+
using (RandomNumberGenerator rng = RandomNumberGenerator.Create())
26+
{
27+
byte[] rand = new byte[sizeof(ulong)];
28+
rng.GetBytes(rand);
29+
30+
return BitConverter.ToUInt64(rand, 0);
31+
}
32+
}
33+
#endif
34+
1735
public static int GetRandomizedOrdinalHashCode(this string value)
1836
{
1937
#if NETCOREAPP
2038
// In .NET Core, string hash codes are already randomized.
2139

2240
return value.GetHashCode();
2341
#else
24-
// Downlevel, we need to perform randomization ourselves. There's still
25-
// the potential for limited collisions ("Hello!" and "Hello!\0"), but
26-
// this shouldn't be a problem in practice. If we need to address it,
27-
// we can mix the string length into the accumulator before running the
28-
// string contents through.
29-
//
30-
// We'll pull out pairs of chars and write 32 bits at a time.
31-
32-
HashCode hashCode = default;
33-
int pair = 0;
34-
for (int i = 0; i < value.Length; i++)
35-
{
36-
int ch = value[i];
37-
if ((i & 1) == 0)
38-
{
39-
pair = ch << 16; // first member of pair
40-
}
41-
else
42-
{
43-
pair |= ch; // second member of pair
44-
hashCode.Add(pair); // write pair as single unit
45-
pair = 0;
46-
}
47-
}
48-
hashCode.Add(pair); // flush any leftover data (could be 0 or 1 chars)
49-
return hashCode.ToHashCode();
42+
// Downlevel, we need to perform randomization ourselves.
43+
44+
ReadOnlySpan<char> charSpan = value.AsSpan();
45+
ReadOnlySpan<byte> byteSpan = MemoryMarshal.AsBytes(charSpan);
46+
return Marvin.ComputeHash32(byteSpan, s_seed);
5047
#endif
5148
}
5249

src/libraries/System.Private.CoreLib/src/System/Marvin.cs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System.Diagnostics;
5-
using System.Numerics;
65
using System.Runtime.CompilerServices;
76
using System.Runtime.InteropServices;
87

@@ -204,7 +203,7 @@ public static int ComputeHash32(ref byte data, uint count, uint p0, uint p1)
204203
else
205204
{
206205
partialResult |= (uint)Unsafe.ReadUnaligned<ushort>(ref data);
207-
partialResult = BitOperations.RotateLeft(partialResult, 16);
206+
partialResult = RotateLeft(partialResult, 16);
208207
}
209208
}
210209

@@ -221,21 +220,26 @@ private static void Block(ref uint rp0, ref uint rp1)
221220
uint p1 = rp1;
222221

223222
p1 ^= p0;
224-
p0 = BitOperations.RotateLeft(p0, 20);
223+
p0 = RotateLeft(p0, 20);
225224

226225
p0 += p1;
227-
p1 = BitOperations.RotateLeft(p1, 9);
226+
p1 = RotateLeft(p1, 9);
228227

229228
p1 ^= p0;
230-
p0 = BitOperations.RotateLeft(p0, 27);
229+
p0 = RotateLeft(p0, 27);
231230

232231
p0 += p1;
233-
p1 = BitOperations.RotateLeft(p1, 19);
232+
p1 = RotateLeft(p1, 19);
234233

235234
rp0 = p0;
236235
rp1 = p1;
237236
}
238237

238+
#if SYSTEM_PRIVATE_CORELIB
239+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
240+
private static uint RotateLeft(uint value, int offset) =>
241+
System.Numerics.BitOperations.RotateLeft(value, offset);
242+
239243
public static ulong DefaultSeed { get; } = GenerateSeed();
240244

241245
private static unsafe ulong GenerateSeed()
@@ -244,5 +248,10 @@ private static unsafe ulong GenerateSeed()
244248
Interop.GetRandomBytes((byte*)&seed, sizeof(ulong));
245249
return seed;
246250
}
251+
#else
252+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
253+
private static uint RotateLeft(uint value, int offset) =>
254+
(value << offset) | (value >> (32 - offset));
255+
#endif
247256
}
248257
}

src/libraries/System.Security.Cryptography.Cose/src/System.Security.Cryptography.Cose.csproj

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
<TargetFrameworks>$(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum)</TargetFrameworks>
55
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
66
<IsPackable>true</IsPackable>
7+
<ServicingVersion>1</ServicingVersion>
8+
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
79
<PackageDescription>Provides support for CBOR Object Signing and Encryption (COSE).</PackageDescription>
810
</PropertyGroup>
911

@@ -33,13 +35,12 @@
3335
<Compile Include="System\Security\Cryptography\Cose\SigStructureContext.cs" />
3436
</ItemGroup>
3537

36-
<ItemGroup>
37-
<ProjectReference Include="$(LibrariesProjectRoot)System.Formats.Cbor\src\System.Formats.Cbor.csproj" />
38+
<ItemGroup Condition="'$(TargetFrameworkIdentifier)' != '.NETCoreApp'">
39+
<Compile Include="$(CoreLibSharedDir)System\Marvin.cs" Link="CoreLib\System\Marvin.cs" />
3840
</ItemGroup>
3941

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

4546
</Project>

0 commit comments

Comments
 (0)