agent_pay/jcs.rs
1//! RFC 8785 JSON Canonicalization Scheme + SHA-256 hash.
2//!
3//! NOTE: serde_jcs preserves u64 integers; the TS reference uses ECMAScript JSON
4//! semantics (all numbers are f64). agent-pay's envelope payloads use `price_msat`
5//! as a STRING and other large numbers are strings too, so we do not need the
6//! `normalize_numbers` walker here.
7
8use serde_json::Value;
9use sha2::{Digest, Sha256};
10
11use crate::error::Error;
12
13pub fn canonical_json(value: &Value) -> Result<Vec<u8>, Error> {
14 let s = serde_jcs::to_string(value).map_err(|e| Error::Other(format!("jcs: {e}")))?;
15 Ok(s.into_bytes())
16}
17
18pub fn jcs_hash(value: &Value) -> Result<[u8; 32], Error> {
19 let canonical = canonical_json(value)?;
20 let mut hasher = Sha256::new();
21 hasher.update(&canonical);
22 Ok(hasher.finalize().into())
23}