Skip to main content

lean_ctx/core/
integrity.rs

1//! Build-origin integrity verification and rebrand resistance.
2//!
3//! Detects if the binary has been modified by automated rebranding tools
4//! (e.g. `sed s/lean-ctx/better-ctx/g`). The integrity seed is a compile-time
5//! constant; its hash is precomputed and embedded. If the seed is altered by
6//! a text-replacement tool, the hash will no longer match.
7
8use std::collections::hash_map::DefaultHasher;
9use std::hash::{Hash, Hasher};
10
11const INTEGRITY_SEED: &str = "lean-ctx";
12const ORIGIN_REPO: &str = env!("CARGO_PKG_REPOSITORY");
13const ORIGIN_NAME: &str = env!("CARGO_PKG_NAME");
14const PKG_VERSION: &str = env!("CARGO_PKG_VERSION");
15
16fn compute_seed_hash(seed: &str) -> u64 {
17    let mut hasher = DefaultHasher::new();
18    seed.hash(&mut hasher);
19    hasher.finish()
20}
21
22fn expected_hash() -> u64 {
23    compute_seed_hash("lean-ctx")
24}
25
26pub fn verify_integrity() -> bool {
27    compute_seed_hash(INTEGRITY_SEED) == expected_hash()
28}
29
30pub fn is_official_origin() -> bool {
31    ORIGIN_REPO.contains("yvgude/lean-ctx") && ORIGIN_NAME == "lean-ctx"
32}
33
34pub struct IntegrityReport {
35    pub seed_ok: bool,
36    pub origin_ok: bool,
37    pub repo: &'static str,
38    pub pkg_name: &'static str,
39    pub version: &'static str,
40}
41
42pub fn check() -> IntegrityReport {
43    IntegrityReport {
44        seed_ok: verify_integrity(),
45        origin_ok: is_official_origin(),
46        repo: ORIGIN_REPO,
47        pkg_name: ORIGIN_NAME,
48        version: PKG_VERSION,
49    }
50}
51
52pub fn origin_line() -> String {
53    let report = check();
54    if report.seed_ok && report.origin_ok {
55        format!("lean-ctx {} (official, {})", report.version, report.repo)
56    } else {
57        format!(
58            "WARNING: Modified redistribution detected. \
59             Official builds: https://github.com/yvgude/lean-ctx \
60             (pkg={}, repo={})",
61            report.pkg_name, report.repo
62        )
63    }
64}
65
66#[cfg(test)]
67mod tests {
68    use super::*;
69
70    #[test]
71    fn integrity_passes_in_official_build() {
72        assert!(verify_integrity());
73    }
74
75    #[test]
76    fn seed_hash_is_deterministic() {
77        let h1 = compute_seed_hash("lean-ctx");
78        let h2 = compute_seed_hash("lean-ctx");
79        assert_eq!(h1, h2);
80    }
81
82    #[test]
83    fn tampered_seed_fails() {
84        let tampered = compute_seed_hash("better-ctx");
85        assert_ne!(tampered, expected_hash());
86    }
87
88    #[test]
89    fn origin_is_official() {
90        assert!(is_official_origin());
91    }
92
93    #[test]
94    fn origin_line_contains_version() {
95        let line = origin_line();
96        assert!(line.contains(env!("CARGO_PKG_VERSION")));
97    }
98}