Skip to content

[API Proposal]: CRC-32C non-cryptographic hashing API #85222

@brantburnett

Description

@brantburnett

Background and motivation

#24328 and subsequent changes have added support for CRC-32, CRC-64, XxHash32, XxHash64, and XxHash128 non-cryptographic hash algorithms to the System.IO.Hashing library. The CRC-32 implementation follows the ITU-T V.42 and IEEE 802.3 specifications.

However, another common CRC-32 implementation is CRC-32C (Castagnoli), which uses a different polynomial. This algorithm is used by iSCSI, SCTP, G.hn payload, Btrfs, ext4, Ceph, and Snappy. It is also supported by hardware intrinsics on both ARM and Intel processors (with recently added support in BitConverter to simplify use of the intrinsics #61558).

Adding high-performance built-in support for this variant could be beneficial to library and application authors. For example, this case in the Snappier implementation of Snappy compression could benefit from a higher performance implementation being generally available.

The implementation of the algorithm should make use of vectorization and intrinsics (when available) to gain the best possible performance.

API Proposal

namespace System.IO.Hashing;

public sealed class Crc32C : NonCryptographicHashAlgorithm
{
    public Crc32C() : base(32) { }
    public override void Append(ReadOnlySpan<byte> source) { }
    public override void Reset() { }
    protected override GetCurrentHashCore(Span<byte> destination) { }
    protected override void GetHashAndResetCore(Span<byte> destination) { }
    [CLSCompliant(false)] public uint GetCurrentHashAsUInt32() => throw null;

    public static byte[] Hash(byte[] source) => throw null;
    public static byte[] Hash(ReadOnlySpan<byte> source) => throw null;
    public static bool TryHash(ReadOnlySpan<byte> source, Span<byte> destination, out int bytesWritten) => throw null;
    public static int Hash(ReadOnlySpan<byte> source, Span<byte> destination) => throw null;
}

API Usage

// Compute a CRC-32C
var crc32c = new Crc32C();
crc32c.Append(sourceBytes);
Console.WriteLine(crc32c.GetcurrenthashAsUInt32());

// Compute and output to span
Span<byte> dest = stackalloc byte[4];
var bytesWritten = Crc32C.Hash(sourceBytes, dest);

Alternative Designs

An alternative design is to unseal Crc32 and inherit from it to gain some code reuse. However, this could reduce the performance of Crc32 and was previously dismissed in another discussion: #24328 (comment)

Risks

The only risk I see is adding more code to be maintained.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions