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 {
34 match value {
35 JsonValue::Object(map) => {
36 let mut entries: Vec<(&String, &JsonValue)> = map.iter().collect();
37 entries.sort_by(|a, b| a.0.cmp(b.0));
38 let mut out = serde_json::Map::with_capacity(entries.len());
39 for (key, item) in entries {
40 out.insert(key.clone(), sort(item));
41 }
42 JsonValue::Object(out)
43 },
44 JsonValue::Array(items) => JsonValue::Array(items.iter().map(sort).collect()),
45 other => other.clone(),
46 }
47 }
48 sort(value).to_string()
49}