rns_core/link/
identify.rs1use alloc::vec::Vec;
2
3use rns_crypto::ed25519::Ed25519PublicKey;
4use rns_crypto::identity::Identity;
5
6use super::types::{LinkError, LinkId};
7use crate::constants::{KEYSIZE, SIGLENGTH};
8
9pub fn build_identify_data(identity: &Identity, link_id: &LinkId) -> Result<Vec<u8>, LinkError> {
13 let public_key = identity.get_public_key().ok_or(LinkError::CryptoError)?;
14
15 let mut signed_data = Vec::with_capacity(16 + 64);
16 signed_data.extend_from_slice(link_id);
17 signed_data.extend_from_slice(&public_key);
18
19 let signature = identity
20 .sign(&signed_data)
21 .map_err(|_| LinkError::CryptoError)?;
22
23 let mut data = Vec::with_capacity(128);
24 data.extend_from_slice(&public_key);
25 data.extend_from_slice(&signature);
26
27 Ok(data)
28}
29
30pub fn validate_identify_data(
34 plaintext: &[u8],
35 link_id: &LinkId,
36) -> Result<([u8; 16], [u8; 64]), LinkError> {
37 let expected_len = KEYSIZE / 8 + SIGLENGTH / 8; if plaintext.len() != expected_len {
39 return Err(LinkError::InvalidData);
40 }
41
42 let mut public_key = [0u8; 64];
43 public_key.copy_from_slice(&plaintext[..64]);
44
45 let mut signature = [0u8; 64];
46 signature.copy_from_slice(&plaintext[64..128]);
47
48 let mut signed_data = Vec::with_capacity(16 + 64);
49 signed_data.extend_from_slice(link_id);
50 signed_data.extend_from_slice(&public_key);
51
52 let sig_pub = Ed25519PublicKey::from_bytes(&{
54 let mut b = [0u8; 32];
55 b.copy_from_slice(&public_key[32..64]);
56 b
57 });
58
59 if sig_pub.verify(&signature, &signed_data) {
60 let identity = Identity::from_public_key(&public_key);
62 let identity_hash = *identity.hash();
63 Ok((identity_hash, public_key))
64 } else {
65 Err(LinkError::InvalidSignature)
66 }
67}
68
69#[cfg(test)]
70mod tests {
71 use super::*;
72 use rns_crypto::FixedRng;
73
74 #[test]
75 fn test_identify_roundtrip() {
76 let mut rng = FixedRng::new(&[0x42; 128]);
77 let identity = Identity::new(&mut rng);
78 let link_id: LinkId = [0xAA; 16];
79
80 let data = build_identify_data(&identity, &link_id).unwrap();
81 assert_eq!(data.len(), 128);
82
83 let (hash, pubkey) = validate_identify_data(&data, &link_id).unwrap();
84 assert_eq!(hash, *identity.hash());
85 assert_eq!(pubkey, identity.get_public_key().unwrap());
86 }
87
88 #[test]
89 fn test_identify_wrong_link_id() {
90 let mut rng = FixedRng::new(&[0x42; 128]);
91 let identity = Identity::new(&mut rng);
92 let link_id: LinkId = [0xAA; 16];
93 let wrong_id: LinkId = [0xBB; 16];
94
95 let data = build_identify_data(&identity, &link_id).unwrap();
96 assert_eq!(
97 validate_identify_data(&data, &wrong_id),
98 Err(LinkError::InvalidSignature)
99 );
100 }
101
102 #[test]
103 fn test_identify_tampered() {
104 let mut rng = FixedRng::new(&[0x42; 128]);
105 let identity = Identity::new(&mut rng);
106 let link_id: LinkId = [0xAA; 16];
107
108 let mut data = build_identify_data(&identity, &link_id).unwrap();
109 data[10] ^= 0xFF; assert_eq!(
111 validate_identify_data(&data, &link_id),
112 Err(LinkError::InvalidSignature)
113 );
114 }
115
116 #[test]
117 fn test_identify_invalid_length() {
118 let link_id: LinkId = [0xAA; 16];
119 assert_eq!(
120 validate_identify_data(&[0u8; 64], &link_id),
121 Err(LinkError::InvalidData)
122 );
123 }
124
125 #[test]
126 fn test_identify_public_only_fails() {
127 let mut rng = FixedRng::new(&[0x42; 128]);
128 let identity = Identity::new(&mut rng);
129 let pubkey = identity.get_public_key().unwrap();
130 let public_only = Identity::from_public_key(&pubkey);
131 let link_id: LinkId = [0xAA; 16];
132
133 assert!(build_identify_data(&public_only, &link_id).is_err());
135 }
136}