hypercall_blocks/
authority.rs1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
9pub struct SigningAuthority {
10 pub delegator: [u8; 20],
11 pub delegate: [u8; 20],
12 pub valid_from: u64,
13 pub valid_until: u64,
14 pub signature: Vec<u8>,
15}
16
17impl SigningAuthority {
18 pub fn delegation_hash(&self) -> [u8; 32] {
20 use sha3::{Digest, Keccak256};
21
22 let mut h = Keccak256::new();
23 h.update(self.delegator);
24 h.update(self.delegate);
25 h.update(self.valid_from.to_be_bytes());
26 h.update(self.valid_until.to_be_bytes());
27 h.finalize().into()
28 }
29
30 pub fn is_valid_at(&self, timestamp_ms: u64) -> bool {
32 timestamp_ms >= self.valid_from && timestamp_ms < self.valid_until
33 }
34}
35
36#[cfg(test)]
37mod tests {
38 use super::*;
39
40 fn authority() -> SigningAuthority {
41 SigningAuthority {
42 delegator: [1; 20],
43 delegate: [2; 20],
44 valid_from: 1000,
45 valid_until: 2000,
46 signature: vec![3; 65],
47 }
48 }
49
50 #[test]
51 fn validity_window_is_inclusive_start_exclusive_end() {
52 let auth = authority();
53
54 assert!(!auth.is_valid_at(999));
55 assert!(auth.is_valid_at(1000));
56 assert!(auth.is_valid_at(1500));
57 assert!(!auth.is_valid_at(2000));
58 }
59
60 #[test]
61 fn delegation_hash_is_deterministic() {
62 let auth = authority();
63
64 assert_eq!(auth.delegation_hash(), auth.delegation_hash());
65 }
66
67 #[test]
68 fn delegation_hash_excludes_signature() {
69 let mut auth = authority();
70 let hash = auth.delegation_hash();
71
72 auth.signature = vec![0xff; 65];
73
74 assert_eq!(hash, auth.delegation_hash());
75 }
76
77 #[test]
78 fn delegation_hash_changes_when_signed_field_changes() {
79 let baseline = authority();
80 let baseline_hash = baseline.delegation_hash();
81
82 let mut changed = baseline.clone();
83 changed.delegator = [0x10; 20];
84 assert_ne!(baseline_hash, changed.delegation_hash());
85
86 let mut changed = baseline.clone();
87 changed.delegate = [0x20; 20];
88 assert_ne!(baseline_hash, changed.delegation_hash());
89
90 let mut changed = baseline.clone();
91 changed.valid_from += 1;
92 assert_ne!(baseline_hash, changed.delegation_hash());
93
94 let mut changed = baseline;
95 changed.valid_until += 1;
96 assert_ne!(baseline_hash, changed.delegation_hash());
97 }
98
99 #[test]
100 fn authority_roundtrips_through_msgpack() {
101 let auth = authority();
102
103 assert_eq!(msgpack_roundtrip(&auth), auth);
104 }
105
106 fn msgpack_roundtrip<T>(value: &T) -> T
107 where
108 T: Clone + PartialEq + std::fmt::Debug + Serialize + for<'de> Deserialize<'de>,
109 {
110 let bytes = rmp_serde::to_vec_named(value).expect("serialize signing authority");
111 rmp_serde::from_slice(&bytes).expect("deserialize signing authority")
112 }
113}