Skip to main content

rns_core/
receipt.rs

1use rns_crypto::identity::Identity;
2
3use crate::constants;
4
5/// Result of proof validation.
6#[derive(Debug, PartialEq, Eq)]
7pub enum ProofResult {
8    Valid,
9    InvalidHash,
10    InvalidSignature,
11    InvalidLength,
12}
13
14/// Validate an explicit or implicit proof against a packet hash.
15///
16/// Explicit proof (96 bytes): `[proof_hash:32][signature:64]`
17/// - Verify: proof_hash == packet_hash AND identity.verify(signature, packet_hash)
18///
19/// Implicit proof (64 bytes): `[signature:64]`
20/// - Verify: identity.verify(signature, packet_hash)
21pub fn validate_proof(
22    proof: &[u8],
23    packet_hash: &[u8; 32],
24    identity: &Identity,
25) -> ProofResult {
26    if proof.len() == constants::EXPL_LENGTH {
27        // Explicit proof: [proof_hash:32][signature:64]
28        let proof_hash = &proof[..constants::HASHLENGTH / 8];
29        if proof_hash != packet_hash.as_slice() {
30            return ProofResult::InvalidHash;
31        }
32
33        let signature: &[u8; 64] = proof[constants::HASHLENGTH / 8..constants::HASHLENGTH / 8 + constants::SIGLENGTH / 8]
34            .try_into()
35            .unwrap();
36
37        if identity.verify(signature, packet_hash) {
38            ProofResult::Valid
39        } else {
40            ProofResult::InvalidSignature
41        }
42    } else if proof.len() == constants::IMPL_LENGTH {
43        // Implicit proof: [signature:64]
44        let signature: &[u8; 64] = proof[..constants::SIGLENGTH / 8]
45            .try_into()
46            .unwrap();
47
48        if identity.verify(signature, packet_hash) {
49            ProofResult::Valid
50        } else {
51            ProofResult::InvalidSignature
52        }
53    } else {
54        ProofResult::InvalidLength
55    }
56}
57
58#[cfg(test)]
59mod tests {
60    use super::*;
61
62    fn make_test_identity() -> Identity {
63        Identity::from_private_key(&[0x42; 64])
64    }
65
66    #[test]
67    fn test_explicit_proof_valid() {
68        let identity = make_test_identity();
69        let packet_hash = crate::hash::full_hash(b"test packet data");
70
71        let signature = identity.sign(&packet_hash).unwrap();
72
73        let mut proof = Vec::new();
74        proof.extend_from_slice(&packet_hash);
75        proof.extend_from_slice(&signature);
76
77        assert_eq!(proof.len(), constants::EXPL_LENGTH);
78        assert_eq!(validate_proof(&proof, &packet_hash, &identity), ProofResult::Valid);
79    }
80
81    #[test]
82    fn test_explicit_proof_wrong_hash() {
83        let identity = make_test_identity();
84        let packet_hash = crate::hash::full_hash(b"test packet data");
85        let wrong_hash = crate::hash::full_hash(b"wrong data");
86
87        let signature = identity.sign(&packet_hash).unwrap();
88
89        let mut proof = Vec::new();
90        proof.extend_from_slice(&wrong_hash); // wrong hash in proof
91        proof.extend_from_slice(&signature);
92
93        assert_eq!(validate_proof(&proof, &packet_hash, &identity), ProofResult::InvalidHash);
94    }
95
96    #[test]
97    fn test_explicit_proof_bad_signature() {
98        let identity = make_test_identity();
99        let packet_hash = crate::hash::full_hash(b"test packet data");
100
101        let mut bad_sig = [0u8; 64];
102        bad_sig[0] = 0xFF;
103
104        let mut proof = Vec::new();
105        proof.extend_from_slice(&packet_hash);
106        proof.extend_from_slice(&bad_sig);
107
108        assert_eq!(validate_proof(&proof, &packet_hash, &identity), ProofResult::InvalidSignature);
109    }
110
111    #[test]
112    fn test_implicit_proof_valid() {
113        let identity = make_test_identity();
114        let packet_hash = crate::hash::full_hash(b"test packet data");
115
116        let signature = identity.sign(&packet_hash).unwrap();
117
118        assert_eq!(signature.len(), constants::IMPL_LENGTH);
119        assert_eq!(validate_proof(&signature, &packet_hash, &identity), ProofResult::Valid);
120    }
121
122    #[test]
123    fn test_implicit_proof_bad_signature() {
124        let identity = make_test_identity();
125        let packet_hash = crate::hash::full_hash(b"test packet data");
126
127        let bad_sig = [0u8; 64];
128        assert_eq!(validate_proof(&bad_sig, &packet_hash, &identity), ProofResult::InvalidSignature);
129    }
130
131    #[test]
132    fn test_wrong_length_proof() {
133        let identity = make_test_identity();
134        let packet_hash = crate::hash::full_hash(b"test packet data");
135
136        let proof = [0u8; 50]; // wrong length
137        assert_eq!(validate_proof(&proof, &packet_hash, &identity), ProofResult::InvalidLength);
138    }
139}