sovereign-addr / src /lib.rs
SNAPKITTYWEST's picture
push from SNAPKITTYWEST/sovereign-addr
103262d verified
Raw History Blame Contribute Delete
5.05 kB
// snapkitty-sovereign-addr — Non-recursive artifact addressing
//
// Algorithm:
// 1. validate JSON admissibility
// 2. normalize all strings to Unicode NFC
// 3. serialize canonical JSON with sorted keys, no whitespace
// 4. hash canonical bytes with SHA-256
// 5. emit snapaddr:<digest>
// 6. generate WORM receipt
// 7. never recurse in validation rules; use explicit staged traversal
pub mod canonical;
pub mod admissibility;
pub mod datalog;
pub mod receipt;
pub mod worm;
pub mod cli;
use serde::{Deserialize, Serialize};
use sha2::{Sha256, Digest};
use thiserror::Error;
/// Errors from sovereign addressing.
#[derive(Error, Debug, Clone)]
pub enum SnapAddrError {
#[error("not JSON admissible: {0}")]
NotAdmissible(String),
#[error("Unicode NFC normalization failed: {0}")]
NormalizationFailed(String),
#[error("canonical serialization failed: {0}")]
CanonicalFailed(String),
#[error("empty canonical bytes")]
EmptyCanonical,
#[error("address must be exactly 64 hex chars")]
InvalidAddressLength,
}
/// WORM receipt for a sovereign address.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct WormReceipt {
pub standard: String,
pub algorithm: String,
pub canonicalization: String,
pub address: String,
pub status: String,
pub seal: String,
pub governance: String,
}
/// Compute the canonical bytes of a JSON value.
///
/// Algorithm:
/// 1. Normalize all strings to Unicode NFC
/// 2. Sort object keys recursively
/// 3. Serialize with no whitespace
pub fn canonical_bytes(value: &serde_json::Value) -> Result<Vec<u8>, SnapAddrError> {
canonical::to_canonical(value)
}
/// Compute the sovereign address of a JSON value.
///
/// Returns: snapaddr:<64 lowercase hex chars>
pub fn sovereign_address(value: &serde_json::Value) -> Result<String, SnapAddrError> {
let bytes = canonical_bytes(value)?;
Ok(format!("snapaddr:{}", hex::encode(bytes)))
}
/// Compute the sovereign address as raw bytes.
pub fn sovereign_address_bytes(value: &serde_json::Value) -> Result<[u8; 32], SnapAddrError> {
let bytes = canonical_bytes(value)?;
let mut hasher = Sha256::new();
hasher.update(&bytes);
let result = hasher.finalize();
let mut out = [0u8; 32];
out.copy_from_slice(&result);
Ok(out)
}
/// Generate a WORM receipt for a JSON value.
pub fn worm_receipt(value: &serde_json::Value) -> Result<WormReceipt, SnapAddrError> {
worm::generate_receipt(value)
}
/// Verify that an address matches a JSON value.
pub fn verify_address(
value: &serde_json::Value,
expected_addr: &str,
) -> Result<bool, SnapAddrError> {
let addr = sovereign_address(value)?;
Ok(addr == expected_addr)
}
/// Verify a WORM receipt.
pub fn verify_receipt(receipt: &WormReceipt) -> Result<bool, SnapAddrError> {
worm::verify_receipt(receipt)
}
/// Normalize a JSON value to Unicode NFC (used by datalog).
pub fn normalize_value(value: &serde_json::Value) -> Result<serde_json::Value, SnapAddrError> {
canonical::normalize_value(value)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sovereign_address_simple() {
let value = serde_json::json!({"key": "value"});
let addr = sovereign_address(&value).unwrap();
assert!(addr.starts_with("snapaddr:"));
assert_eq!(addr.len(), 64 + "snapaddr:".len());
}
#[test]
fn test_sovereign_address_deterministic() {
let v1 = serde_json::json!({"a": 1, "b": 2});
let v2 = serde_json::json!({"b": 2, "a": 1});
assert_eq!(sovereign_address(&v1).unwrap(), sovereign_address(&v2).unwrap());
}
#[test]
fn test_sovereign_address_bytes() {
let value = serde_json::json!({"test": true});
let bytes = sovereign_address_bytes(&value).unwrap();
assert_eq!(bytes.len(), 32);
}
#[test]
fn test_worm_receipt() {
let value = serde_json::json!({"prime": 42});
let receipt = worm_receipt(&value).unwrap();
assert_eq!(receipt.standard, "SNAPKITTY-SOVEREIGN-ADDR-1");
assert_eq!(receipt.status, "accepted");
assert!(receipt.seal.starts_with("snapaddr:"));
}
#[test]
fn test_verify_address() {
let value = serde_json::json!({"check": "this"});
let addr = sovereign_address(&value).unwrap();
assert!(verify_address(&value, &addr).unwrap());
assert!(!verify_address(&value, "snapaddr:0000000000000000000000000000000000000000000000000000000000000000").unwrap());
}
#[test]
fn test_unicode_nfc_equivalence() {
// "é" can be U+00E9 or U+0065 U+0301 — both should produce same address
let v1 = serde_json::json!({"name": "\u{00e9}"});
let v2 = serde_json::json!({"name": "\u{0065}\u{0301}"});
assert_eq!(sovereign_address(&v1).unwrap(), sovereign_address(&v2).unwrap());
}
}