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(proof: &[u8], packet_hash: &[u8; 32], identity: &Identity) -> ProofResult {
22    if proof.len() == constants::EXPL_LENGTH {
23        // Explicit proof: [proof_hash:32][signature:64]
24        let proof_hash = &proof[..constants::HASHLENGTH / 8];
25        if proof_hash != packet_hash.as_slice() {
26            return ProofResult::InvalidHash;
27        }
28
29        let mut signature = [0u8; 64];
30        signature.copy_from_slice(
31            &proof[constants::HASHLENGTH / 8..constants::HASHLENGTH / 8 + constants::SIGLENGTH / 8],
32        );
33
34        if identity.verify(&signature, packet_hash) {
35            ProofResult::Valid
36        } else {
37            ProofResult::InvalidSignature
38        }
39    } else if proof.len() == constants::IMPL_LENGTH {
40        // Implicit proof: [signature:64]
41        let mut signature = [0u8; 64];
42        signature.copy_from_slice(&proof[..constants::SIGLENGTH / 8]);
43
44        if identity.verify(&signature, packet_hash) {
45            ProofResult::Valid
46        } else {
47            ProofResult::InvalidSignature
48        }
49    } else {
50        ProofResult::InvalidLength
51    }
52}
53
54#[cfg(test)]
55mod tests {
56    use super::*;
57
58    fn make_test_identity() -> Identity {
59        Identity::from_private_key(&[0x42; 64])
60    }
61
62    #[test]
63    fn test_explicit_proof_valid() {
64        let identity = make_test_identity();
65        let packet_hash = crate::hash::full_hash(b"test packet data");
66
67        let signature = identity.sign(&packet_hash).unwrap();
68
69        let mut proof = Vec::new();
70        proof.extend_from_slice(&packet_hash);
71        proof.extend_from_slice(&signature);
72
73        assert_eq!(proof.len(), constants::EXPL_LENGTH);
74        assert_eq!(
75            validate_proof(&proof, &packet_hash, &identity),
76            ProofResult::Valid
77        );
78    }
79
80    #[test]
81    fn test_explicit_proof_wrong_hash() {
82        let identity = make_test_identity();
83        let packet_hash = crate::hash::full_hash(b"test packet data");
84        let wrong_hash = crate::hash::full_hash(b"wrong data");
85
86        let signature = identity.sign(&packet_hash).unwrap();
87
88        let mut proof = Vec::new();
89        proof.extend_from_slice(&wrong_hash); // wrong hash in proof
90        proof.extend_from_slice(&signature);
91
92        assert_eq!(
93            validate_proof(&proof, &packet_hash, &identity),
94            ProofResult::InvalidHash
95        );
96    }
97
98    #[test]
99    fn test_explicit_proof_bad_signature() {
100        let identity = make_test_identity();
101        let packet_hash = crate::hash::full_hash(b"test packet data");
102
103        let mut bad_sig = [0u8; 64];
104        bad_sig[0] = 0xFF;
105
106        let mut proof = Vec::new();
107        proof.extend_from_slice(&packet_hash);
108        proof.extend_from_slice(&bad_sig);
109
110        assert_eq!(
111            validate_proof(&proof, &packet_hash, &identity),
112            ProofResult::InvalidSignature
113        );
114    }
115
116    #[test]
117    fn test_implicit_proof_valid() {
118        let identity = make_test_identity();
119        let packet_hash = crate::hash::full_hash(b"test packet data");
120
121        let signature = identity.sign(&packet_hash).unwrap();
122
123        assert_eq!(signature.len(), constants::IMPL_LENGTH);
124        assert_eq!(
125            validate_proof(&signature, &packet_hash, &identity),
126            ProofResult::Valid
127        );
128    }
129
130    #[test]
131    fn test_implicit_proof_bad_signature() {
132        let identity = make_test_identity();
133        let packet_hash = crate::hash::full_hash(b"test packet data");
134
135        let bad_sig = [0u8; 64];
136        assert_eq!(
137            validate_proof(&bad_sig, &packet_hash, &identity),
138            ProofResult::InvalidSignature
139        );
140    }
141
142    #[test]
143    fn test_wrong_length_proof() {
144        let identity = make_test_identity();
145        let packet_hash = crate::hash::full_hash(b"test packet data");
146
147        let proof = [0u8; 50]; // wrong length
148        assert_eq!(
149            validate_proof(&proof, &packet_hash, &identity),
150            ProofResult::InvalidLength
151        );
152    }
153}