mkit_git_bridge/verify.rs
1//! Shallow signature verification (SPEC-GIT-BRIDGE §10).
2//!
3//! Shallow mode rebuilds the mkit object from a single bridge-emitted
4//! git commit/tag (self-contained: the carried headers include the
5//! mkit tree/parent/target hashes) and checks its Ed25519 signature
6//! under the proper domain via mkit-core's strict verifier. It proves
7//! the carried fields are exactly what the original signer signed; it
8//! does NOT prove the surrounding git graph corresponds to those
9//! BLAKE3 hashes — that is deep verification (full [`crate::reconstruct`]
10//! over the closure, driven by the caller).
11
12use crate::error::BridgeError;
13use crate::gitobj::{GitObject, GitType};
14use crate::reconstruct;
15use mkit_core::object::Object;
16
17/// Outcome of a shallow check.
18#[derive(Debug, Clone, Copy, PartialEq, Eq)]
19pub enum ShallowVerdict {
20 /// Signature verifies under the object's signing domain.
21 Verified,
22 /// All-zero signature: the unsigned convention (SPEC-SIGNING §4a).
23 /// Report as "unsigned", never as tampered.
24 Unsigned,
25 /// A non-zero signature that does not verify.
26 Failed,
27}
28
29/// Shallow-verify a bridge-emitted git commit or tag.
30pub fn shallow_verify(obj: &GitObject) -> Result<ShallowVerdict, BridgeError> {
31 let rec = match obj.gtype {
32 GitType::Commit => reconstruct::reconstruct_commit(&obj.body)?,
33 GitType::Tag => reconstruct::reconstruct_tag(&obj.body)?,
34 GitType::Blob | GitType::Tree => {
35 return Err(BridgeError::NotBridgeObject(
36 "shallow verification applies to commits and tags only".into(),
37 ));
38 }
39 };
40 Ok(match rec.object {
41 Object::Commit(ref c) => {
42 if c.signature == [0u8; 64] {
43 ShallowVerdict::Unsigned
44 } else if mkit_core::sign::verify_commit(c).is_ok() {
45 ShallowVerdict::Verified
46 } else {
47 ShallowVerdict::Failed
48 }
49 }
50 Object::Tag(ref t) => {
51 if t.signature == [0u8; 64] {
52 ShallowVerdict::Unsigned
53 } else if mkit_core::sign::verify_tag(t).is_ok() {
54 ShallowVerdict::Verified
55 } else {
56 ShallowVerdict::Failed
57 }
58 }
59 _ => unreachable!("reconstruct_commit/tag return Commit/Tag"),
60 })
61}