newton-core 0.4.16

newton protocol core sdk
//! IPFS content caching and integrity verification.
//!
//! This module provides:
//! - **Two-tier caching**: L1 (moka in-memory LRU) + L2 (Redis distributed)
//! - **CID integrity verification**: SHA2-256 multihash validation against downloaded bytes
//!
//! IPFS content is immutable by CID, making it ideal for aggressive caching.

mod cache;

pub use cache::IpfsCacheService;

/// Verify that downloaded bytes match the SHA2-256 multihash embedded in a CID.
///
/// IPFS CIDs (v0 and v1) embed a content hash. This function re-hashes the
/// downloaded data and compares against the CID's digest, catching malicious
/// or buggy IPFS gateways that serve wrong content.
///
/// Only SHA2-256 (multihash code 0x12) is supported — this covers all standard
/// IPFS content (CIDv0 always uses SHA2-256; CIDv1 typically does).
pub fn verify_cid_multihash(cid_str: &str, data: &[u8]) -> Result<(), String> {
    use cid::Cid;
    use sha2::{Digest, Sha256};

    let parsed_cid = Cid::try_from(cid_str).map_err(|e| format!("invalid CID '{}': {}", cid_str, e))?;

    let expected_hash = parsed_cid.hash();
    let hash_code = expected_hash.code();

    // Standard IPFS uses SHA2-256 (code 0x12)
    if hash_code != 0x12 {
        return Err(format!(
            "unsupported multihash algorithm code 0x{:x} for CID {}; only SHA2-256 (0x12) is supported",
            hash_code, cid_str
        ));
    }

    let actual_digest = Sha256::digest(data);
    let expected_digest = expected_hash.digest();

    if actual_digest.as_slice() != expected_digest {
        return Err(format!(
            "CID multihash mismatch: downloaded data hash does not match CID '{}'",
            cid_str
        ));
    }

    Ok(())
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_verify_cid_multihash_invalid_cid() {
        let result = verify_cid_multihash("not-a-valid-cid!!!", b"some data");
        assert!(result.is_err());
        assert!(result.unwrap_err().contains("invalid CID"));
    }

    #[test]
    fn test_verify_cid_multihash_correct_data() {
        // CIDv0 for the SHA2-256 hash of b"hello world"
        // echo -n "hello world" | ipfs add --only-hash -Q
        let data = b"hello world";
        let cid = "QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4";
        let result = verify_cid_multihash(cid, data);
        assert!(result.is_ok());
    }

    #[test]
    fn test_verify_cid_multihash_mismatched_data() {
        let data = b"hello world\n";
        let cid = "QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4";
        let result = verify_cid_multihash(cid, data);
        assert!(result.is_err());
    }
}