Files
git.stella-ops.org/src/__Libraries/StellaOps.Canonicalization/Json/CanonicalJsonSerializer.cs

48 lines
1.6 KiB
C#

using System.Security.Cryptography;
using System.Text;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Serialization;
using static StellaOps.Localization.T;
namespace StellaOps.Canonicalization.Json;
/// <summary>
/// Produces canonical JSON output with deterministic ordering.
/// Implements RFC 8785 principles for stable output.
/// </summary>
public static class CanonicalJsonSerializer
{
private static readonly JsonSerializerOptions _options = new()
{
WriteIndented = false,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
DictionaryKeyPolicy = JsonNamingPolicy.CamelCase,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
NumberHandling = JsonNumberHandling.Strict,
Converters =
{
new StableDictionaryConverterFactory(),
new Iso8601DateTimeConverter()
}
};
public static string Serialize<T>(T value)
=> JsonSerializer.Serialize(value, _options);
public static (string Json, string Digest) SerializeWithDigest<T>(T value)
{
var json = Serialize(value);
var hash = SHA256.HashData(Encoding.UTF8.GetBytes(json));
var digest = Convert.ToHexString(hash).ToLowerInvariant();
return (json, digest);
}
public static T Deserialize<T>(string json)
{
return JsonSerializer.Deserialize<T>(json, _options)
?? throw new InvalidOperationException(_t("common.canonicalization.deserialize_failed", typeof(T).Name));
}
}