1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
use serde::{Deserialize, Serialize};
/// Represents cryptographic proof provided by a verifier attempting to rejoin the federation after downtime.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct RejoinProof {
/// The identity of the verifier attempting to rejoin.
pub verifier_id: String,
/// The last governance epoch this verifier was synchronized with.
pub last_known_epoch: u64,
/// The minimum required retained checkpoint root proving historical continuity depth.
pub retained_checkpoint_root: [u8; 32],
/// The root of the verifier's local timeline.
pub timeline_root: [u8; 32],
/// The root of the verifier's local governance state.
pub governance_root: [u8; 32],
/// Proof of the verifier's recovery lineage ancestry.
pub lineage_proof_root: [u8; 32],
}
impl RejoinProof {
/// Validates a rejoin attempt against the federation's current consensus state.
///
/// # Arguments
/// * `current_epoch` - The active governance epoch.
/// * `is_revoked` - Whether this verifier identity has been revoked.
/// * `expected_lineage` - The required recovery lineage for the given `last_known_epoch`.
/// * `is_hlc_synchronized` - Whether the verifier has successfully synchronized its Hybrid Logical Clock.
#[must_use]
pub fn is_valid_rejoin(
&self,
current_epoch: u64,
is_revoked: bool,
expected_lineage: &[u8; 32],
is_hlc_synchronized: bool,
) -> bool {
// A revoked verifier can NEVER rejoin.
if is_revoked {
return false;
}
// Verifier must not be claiming a future epoch.
if self.last_known_epoch > current_epoch {
return false;
}
// Must prove recovery lineage.
if self.lineage_proof_root != *expected_lineage {
return false;
}
// Time semantics must be synchronized before joining consensus.
if !is_hlc_synchronized {
return false;
}
true
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn valid_rejoin_proof() {
let proof = RejoinProof {
verifier_id: "ver-01".into(),
last_known_epoch: 10,
retained_checkpoint_root: [1; 32],
timeline_root: [2; 32],
governance_root: [3; 32],
lineage_proof_root: [4; 32],
};
assert!(proof.is_valid_rejoin(12, false, &[4; 32], true));
}
#[test]
fn revoked_verifier_rejected() {
let proof = RejoinProof {
verifier_id: "ver-01".into(),
last_known_epoch: 10,
retained_checkpoint_root: [1; 32],
timeline_root: [2; 32],
governance_root: [3; 32],
lineage_proof_root: [4; 32],
};
// is_revoked = true
assert!(!proof.is_valid_rejoin(12, true, &[4; 32], true));
}
#[test]
fn unsynchronized_hlc_rejected() {
let proof = RejoinProof {
verifier_id: "ver-01".into(),
last_known_epoch: 10,
retained_checkpoint_root: [1; 32],
timeline_root: [2; 32],
governance_root: [3; 32],
lineage_proof_root: [4; 32],
};
// is_hlc_synchronized = false
assert!(!proof.is_valid_rejoin(12, false, &[4; 32], false));
}
#[test]
fn invalid_lineage_rejected() {
let proof = RejoinProof {
verifier_id: "ver-01".into(),
last_known_epoch: 10,
retained_checkpoint_root: [1; 32],
timeline_root: [2; 32],
governance_root: [3; 32],
lineage_proof_root: [5; 32], // Doesn't match expected [4; 32]
};
assert!(!proof.is_valid_rejoin(12, false, &[4; 32], true));
}
}