55 lines
1.6 KiB
C#
55 lines
1.6 KiB
C#
// SPDX-License-Identifier: BUSL-1.1
|
|
// Copyright (c) 2026 StellaOps
|
|
// Sprint: SPRINT_20260118_028_LIB_scoring_manifest_jcs_integration
|
|
// Task: TASK-028-003 - ICanonicalizable interface
|
|
|
|
namespace StellaOps.Canonical.Json;
|
|
|
|
/// <summary>
|
|
/// Interface for types that support canonical JSON serialization.
|
|
/// Enables deterministic serialization and content-addressed hashing.
|
|
/// </summary>
|
|
public interface ICanonicalizable
|
|
{
|
|
/// <summary>
|
|
/// Gets the canonical JSON representation of this object.
|
|
/// Output is deterministic: same input produces identical bytes.
|
|
/// </summary>
|
|
/// <returns>Canonical JSON string.</returns>
|
|
string GetCanonicalJson();
|
|
|
|
/// <summary>
|
|
/// Computes the SHA-256 digest of the canonical JSON representation.
|
|
/// </summary>
|
|
/// <returns>64-character lowercase hex string.</returns>
|
|
string ComputeDigest();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Extension methods for canonical JSON operations.
|
|
/// </summary>
|
|
public static class CanonJsonExtensions
|
|
{
|
|
/// <summary>
|
|
/// Computes the canonical digest if the object implements ICanonicalizable,
|
|
/// otherwise falls back to CanonJson.Hash().
|
|
/// </summary>
|
|
public static string GetDigest<T>(T obj) where T : notnull
|
|
{
|
|
if (obj is ICanonicalizable canonicalizable)
|
|
{
|
|
return canonicalizable.ComputeDigest();
|
|
}
|
|
|
|
return CanonJson.Hash(obj);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Computes the prefixed canonical digest (sha256:...).
|
|
/// </summary>
|
|
public static string GetPrefixedDigest<T>(T obj) where T : notnull
|
|
{
|
|
return "sha256:" + GetDigest(obj);
|
|
}
|
|
}
|