はなちるのマイノート

Unityをメインとした技術ブログ。自分らしくまったりやっていきたいと思いますー!

【Unity】Unity公式のハッシュアルゴリズムxxHash3がCollectionsパッケージに入っているので使ってみる

はじめに

今回はUnity公式のxxHash3について紹介をしたいと思います。

public void Start()
{
    // unmanagedなHeap確保
    NativeArray<byte> input = new NativeArray<byte>(10000, Allocator.Temp, NativeArrayOptions.UninitializedMemory);
    for (var i = 0; i < input.Length; i++)
    {
        input[i] = (byte)(i % 255);
    }
        
    unsafe
    {
        // Hash値計算
        uint4 hash128 = xxHash3.Hash128(input.GetUnsafePtr(), input.Length);
            
        // uint4(218708217, 638813917, 1325193794, 1873747569)
        Debug.Log(hash128);

        // Hash値計算
        var hash64 = xxHash3.Hash64(input.GetUnsafePtr(), input.Length);

        // uint2(218708217, 638813917)
        Debug.Log(hash64);
    }

    // NativeArray破棄
    input.Dispose();
}

概要

xxHashとはハッシュ値を算出するハッシュアルゴリズムで、C#の場合は以下のライブラリなんかが使われるケースがあるようです。
GitHub - uranium62/xxHash: A pure C# implementation of xxhash algorithm

xxHash is an Extremely fast Hash algorithm, processing at RAM speed limits. Code is highly portable, and produces hashes identical across all platforms (little / big endian). The library includes the following algorithms :

XXH32 : generates 32-bit hashes, using 32-bit arithmetic
XXH64 : generates 64-bit hashes, using 64-bit arithmetic
XXH3 (since v0.8.0): generates 64 or 128-bit hashes, using vectorized arithmetic. The 128-bit variant is called XXH128.
All variants successfully complete the SMHasher test suite which evaluates the quality of hash functions (collision, dispersion and randomness). Additional tests, which evaluate more thoroughly speed and collision properties of 64-bit hashes, are also provided.

// DeepL翻訳
xxHash は非常に高速なハッシュアルゴリズムで、RAM 速度の限界で処理します。コードの移植性が高く、すべてのプラットフォーム(リトル/ビッグエンディアン)で同一のハッシュを生成します。ライブラリには以下のアルゴリズムが含まれています:

  • XXH32 : 32 ビット演算を使用して 32 ビットハッシュを生成します。
  • XXH64 : 64 ビット演算を使用して 64 ビットハッシュを生成する。
  • XXH3 (v0.8.0以降): ベクトル化された算術を用いて64ビットまたは128ビットのハッシュを生成する。128ビットハッシュはXXH128と呼ばれる。


ハッシュ関数の品質(衝突、分散、ランダム性)を評価するSMHasherテストスイートを、すべての亜種が成功裏に完了しています。64ビットハッシュの速度と衝突の特性をより詳細に評価する追加テストも提供される。

GitHub - Cyan4973/xxHash: Extremely fast non-cryptographic hash algorithm

公式のCollectionsパッケージの中にxxHash3の実装がpublicで公開されています。
docs.unity3d.com

public static uint2 Hash64(void *input, long length)
public static uint2 Hash64(void *input, long length, ulong seed)
public static uint2 Hash64<T>(in T input) where T : struct
public static uint4 Hash128(void *input, long length)
public static uint4 Hash128(void *input, long length, ulong seed)
public static uint4 Hash128(void *input, void *destination, long length)
public static uint4 Hash128(void *input, void *destination, long length, ulong seed)
public static uint4 Hash128<T>(in T input) where T : struct

またxxHash3の中身はBurstにより最適化されており、返り値もMathematicsuint4が利用されています。ここからもSIMDを活用した最適化がなされていそうな雰囲気が伺えます。

インストール方法

PackageManagerよりCollectionsパッケージがインストールされているか確認してください。されていない場合はインストールします。

Collectionsパッケージ

使い方

NativeArray利用例

public void Start()
{
    // unmanagedなHeap確保
    NativeArray<byte> input = new NativeArray<byte>(10000, Allocator.Temp, NativeArrayOptions.UninitializedMemory);
    for (var i = 0; i < input.Length; i++)
    {
        input[i] = (byte)(i % 255);
    }
        
    unsafe
    {
        // Hash値計算
        uint4 hash128 = xxHash3.Hash128(input.GetUnsafePtr(), input.Length);
            
        // uint4(218708217, 638813917, 1325193794, 1873747569)
        Debug.Log(hash128);

        // Hash値計算
        var hash64 = xxHash3.Hash64(input.GetUnsafePtr(), input.Length);

        // uint2(218708217, 638813917)
        Debug.Log(hash64);
    }

    // NativeArray破棄
    input.Dispose();
}

ManagedHeapの例

public void Start()
{
    var input = Enumerable.Range(0, 100000).Select(x => (byte)x).ToArray();
        
    unsafe
    {
        fixed (byte* p = input)
        {
            // Hash値計算
            uint4 hash128 = xxHash3.Hash128(p, input.Length);
            
            // uint4(1566616920, 969907459, 2787069300, 125799814)
            Debug.Log(hash128);

            // Hash値計算
            var hash64 = xxHash3.Hash64(p, input.Length);

            // uint2(1566616920, 969907459)
            Debug.Log(hash64);   
        }
    }
}

さいごに

xxHash3.StreamingStateという複数のデータからハッシュ計算をしてくれる構造体があるので、また別の記事で紹介しようと思ってます。
docs.unity3d.com