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