diff --git a/src/BizHawk.Common/checksums/CRC32Checksum.cs b/src/BizHawk.Common/checksums/CRC32Checksum.cs
index 44c2eafd7c..2da38d834d 100644
--- a/src/BizHawk.Common/checksums/CRC32Checksum.cs
+++ b/src/BizHawk.Common/checksums/CRC32Checksum.cs
@@ -6,6 +6,7 @@ namespace BizHawk.Common
///
///
///
+ ///
public static class CRC32Checksum
{
/// in bits
diff --git a/src/BizHawk.Common/checksums/MD5Checksum.cs b/src/BizHawk.Common/checksums/MD5Checksum.cs
index 20aa7939b5..80de6d4bb1 100644
--- a/src/BizHawk.Common/checksums/MD5Checksum.cs
+++ b/src/BizHawk.Common/checksums/MD5Checksum.cs
@@ -9,6 +9,7 @@ namespace BizHawk.Common
///
///
///
+ ///
public static class MD5Checksum
{
/// in bits
diff --git a/src/BizHawk.Common/checksums/SHA1Checksum.cs b/src/BizHawk.Common/checksums/SHA1Checksum.cs
index 74c1fc5c88..a1131137ef 100644
--- a/src/BizHawk.Common/checksums/SHA1Checksum.cs
+++ b/src/BizHawk.Common/checksums/SHA1Checksum.cs
@@ -11,6 +11,7 @@ namespace BizHawk.Common
///
///
///
+ ///
public static class SHA1Checksum
{
/// in bits
diff --git a/src/BizHawk.Common/checksums/SHA256Checksum.cs b/src/BizHawk.Common/checksums/SHA256Checksum.cs
index b999e02c48..a0e38f7b73 100644
--- a/src/BizHawk.Common/checksums/SHA256Checksum.cs
+++ b/src/BizHawk.Common/checksums/SHA256Checksum.cs
@@ -9,6 +9,7 @@ namespace BizHawk.Common
///
///
///
+ ///
public static class SHA256Checksum
{
/// in bits
diff --git a/src/BizHawk.Common/checksums/SHA512Checksum.cs b/src/BizHawk.Common/checksums/SHA512Checksum.cs
new file mode 100644
index 0000000000..4a84436e34
--- /dev/null
+++ b/src/BizHawk.Common/checksums/SHA512Checksum.cs
@@ -0,0 +1,58 @@
+using System.Diagnostics;
+using System.Security.Cryptography;
+
+using BizHawk.Common.BufferExtensions;
+
+namespace BizHawk.Common
+{
+ /// uses implementation from BCL
+ ///
+ ///
+ ///
+ ///
+ public static class SHA512Checksum
+ {
+ /// in bits
+ internal const int EXPECTED_LENGTH = 512;
+
+ internal const string PREFIX = "SHA512";
+
+#if NET7_0_OR_GREATER
+ public static byte[] Compute(ReadOnlySpan data)
+ => SHA512.HashData(data);
+#else
+ private static SHA512? _sha512Impl;
+
+ private static SHA512 SHA512Impl
+ {
+ get
+ {
+ if (_sha512Impl == null)
+ {
+ _sha512Impl = SHA512.Create();
+ Debug.Assert(_sha512Impl.CanReuseTransform && _sha512Impl.HashSize is EXPECTED_LENGTH, "nonstandard implementation?");
+ }
+ return _sha512Impl;
+ }
+ }
+
+ public static byte[] Compute(byte[] data)
+ => SHA512Impl.ComputeHash(data);
+
+ public static string ComputeDigestHex(byte[] data)
+ => Compute(data).BytesToHexString();
+
+ public static string ComputePrefixedHex(byte[] data)
+ => $"{PREFIX}:{ComputeDigestHex(data)}";
+
+ public static byte[] Compute(ReadOnlySpan data)
+ => Compute(data.ToArray());
+#endif
+
+ public static string ComputeDigestHex(ReadOnlySpan data)
+ => Compute(data).BytesToHexString();
+
+ public static string ComputePrefixedHex(ReadOnlySpan data)
+ => $"{PREFIX}:{ComputeDigestHex(data)}";
+ }
+}