systemprompt_models/artifacts/
digest.rs1use serde_json::Value as JsonValue;
12use sha2::{Digest, Sha256};
13
14#[derive(Debug, Clone, PartialEq, Eq)]
15pub struct PayloadDigest {
16 pub sha256: String,
17 pub byte_len: usize,
18}
19
20#[must_use]
22pub fn payload_digest(body: &JsonValue) -> PayloadDigest {
23 let canonical = canonical_json(body);
24 PayloadDigest {
25 sha256: hex::encode(Sha256::digest(canonical.as_bytes())),
26 byte_len: canonical.len(),
27 }
28}
29
30fn canonical_json(value: &JsonValue) -> String {
32 fn sort(value: &JsonValue) -> JsonValue {
33 match value {
34 JsonValue::Object(map) => {
35 let mut entries: Vec<(&String, &JsonValue)> = map.iter().collect();
36 entries.sort_by(|a, b| a.0.cmp(b.0));
37 let mut out = serde_json::Map::with_capacity(entries.len());
38 for (key, item) in entries {
39 out.insert(key.clone(), sort(item));
40 }
41 JsonValue::Object(out)
42 },
43 JsonValue::Array(items) => JsonValue::Array(items.iter().map(sort).collect()),
44 other => other.clone(),
45 }
46 }
47 sort(value).to_string()
48}