sovereign-addr / src /worm.rs
SNAPKITTYWEST's picture
push from SNAPKITTYWEST/sovereign-addr
103262d verified
Raw History Blame Contribute Delete
2.85 kB
// worm.rs — WORM (Write-Once-Read-Many) artifact sealing
//
// Non-recursive. Every artifact is sealed with SHA-256.
use sha2::{Sha256, Digest};
use crate::WormReceipt;
use crate::SnapAddrError;
/// WORM seal for an artifact.
#[derive(Debug, Clone)]
pub struct WormSeal {
pub hash: String,
pub content_hash: String,
pub receipt_hash: String,
}
/// Seal an artifact with WORM.
pub fn seal_artifact(content: &[u8]) -> WormSeal {
let mut hasher = Sha256::new();
hasher.update(content);
let content_hash = hex::encode(hasher.finalize());
WormSeal {
hash: content_hash.clone(),
content_hash,
receipt_hash: String::new(),
}
}
/// Seal a receipt.
pub fn seal_receipt(receipt: &WormReceipt) -> Result<WormSeal, SnapAddrError> {
let receipt_json = serde_json::to_string(receipt)
.map_err(|e| SnapAddrError::CanonicalFailed(e.to_string()))?;
let content_seal = seal_artifact(receipt_json.as_bytes());
let mut hasher = Sha256::new();
hasher.update(receipt_json.as_bytes());
let receipt_hash = hex::encode(hasher.finalize());
Ok(WormSeal {
hash: content_seal.hash.clone(),
content_hash: content_seal.content_hash,
receipt_hash,
})
}
/// Verify a WORM seal against content.
pub fn verify_seal(content: &[u8], seal: &WormSeal) -> bool {
let mut hasher = Sha256::new();
hasher.update(content);
let computed = hex::encode(hasher.finalize());
computed == seal.content_hash
}
/// Generate a WORM receipt for a JSON value.
pub fn generate_receipt(value: &serde_json::Value) -> Result<WormReceipt, SnapAddrError> {
crate::receipt::generate_receipt(value)
}
/// Verify a WORM receipt.
pub fn verify_receipt(receipt: &WormReceipt) -> Result<bool, SnapAddrError> {
crate::receipt::verify_receipt(receipt)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_seal_artifact() {
let content = b"test content";
let seal = seal_artifact(content);
assert_eq!(seal.content_hash.len(), 64);
assert!(verify_seal(content, &seal));
}
#[test]
fn test_seal_tampered() {
let content = b"test content";
let seal = seal_artifact(content);
assert!(!verify_seal(b"tampered content", &seal));
}
#[test]
fn test_seal_receipt() {
let v = serde_json::json!({"test": 42});
let receipt = generate_receipt(&v).unwrap();
let seal = seal_receipt(&receipt).unwrap();
assert_eq!(seal.receipt_hash.len(), 64);
}
#[test]
fn test_verify_receipt() {
let v = serde_json::json!({"test": 42});
let receipt = generate_receipt(&v).unwrap();
assert!(verify_receipt(&receipt).unwrap());
}
}