///|
pub(all) struct VerifyResult {
package_name : String
is_valid : Bool
signature_ok : Bool
trust_status : String
errors : Array[String]
warnings : Array[String]
}
///|
/// Default `is_valid` threshold: signature must verify, all file hashes
/// must match the manifest, and the signer must be trusted.
pub fn verify_package(
package_name : String,
signature_hex : String,
public_key_hex : String,
content : String,
) -> VerifyResult {
let errors : Array[String] = []
let warnings : Array[String] = []
if signature_hex.length() != 128 {
errors.push("invalid signature length")
return VerifyResult::{
package_name,
is_valid: false,
signature_ok: false,
trust_status: "unknown",
errors,
warnings,
}
}
if public_key_hex.length() != 64 {
errors.push("invalid public key length")
return VerifyResult::{
package_name,
is_valid: false,
signature_ok: false,
trust_status: "unknown",
errors,
warnings,
}
}
let sig_r = @manifest.take_chars_(signature_hex, 64)
let sig_s = @manifest.slice_chars_(signature_hex, 64, 128)
let sig = @crypto.Signature::{ r: sig_r, s: sig_s }
let valid = @crypto.verify(content, sig, public_key_hex)
if !valid {
errors.push("signature verification failed")
}
VerifyResult::{
package_name,
is_valid: valid,
signature_ok: valid,
trust_status: if valid {
"verified"
} else {
"failed"
},
errors,
warnings,
}
}
///|
/// Full verification pipeline that ties together manifest integrity,
/// signature verification, and trust-store lookup into one call. Used
/// by the `moon_guard audit` CLI subcommand.
pub fn audit_package(
package_name : String,
_package_version : String,
manifest : @manifest.Manifest,
entries : Array[@manifest.FileEntry],
signature_hex : String,
signer_key_id : String,
trust_store : @trust.TrustStore,
) -> VerifyResult {
let errors : Array[String] = []
let warnings : Array[String] = []
// 1. File integrity — every entry must match the recorded hash.
let mismatches = @manifest.verify_manifest(manifest, entries)
for i = 0; i < mismatches.length(); i = i + 1 {
errors.push("hash mismatch: " + mismatches[i])
}
// 2. Signature — verify against the canonical manifest JSON.
let manifest_json = @manifest.manifest_to_json(manifest)
let sig_result = verify_package(
package_name,
signature_hex,
lookup_public_key(trust_store, signer_key_id),
manifest_json,
)
if !sig_result.signature_ok {
for i = 0; i < sig_result.errors.length(); i = i + 1 {
errors.push(sig_result.errors[i])
}
}
// 3. Trust — the signer must be in the store at Full or Partial level.
let trust_status = if trust_store.is_trusted(signer_key_id) {
"trusted"
} else if trust_store.get_key(signer_key_id) is Some(_) {
"untrusted"
} else {
"unknown"
}
if trust_status == "untrusted" {
errors.push("signer " + signer_key_id + " is in store with Untrusted level")
} else if trust_status == "unknown" {
warnings.push("signer " + signer_key_id + " is not in trust store")
}
let is_valid = sig_result.signature_ok &&
mismatches.length() == 0 &&
trust_status == "trusted"
VerifyResult::{
package_name,
is_valid,
signature_ok: sig_result.signature_ok,
trust_status,
errors,
warnings,
}
}
///|
fn lookup_public_key(store : @trust.TrustStore, key_id : String) -> String {
match store.get_key(key_id) {
Some(k) => k.public_key
None => ""
}
}
///|
/// Convenience helper for the CLI: hex-encode a `(Signature r, s)` pair
/// without forcing callers to know the inner layout.
pub fn signature_to_hex(sig : @crypto.Signature) -> String {
@crypto.signature_to_hex(sig)
}
///|
/// Generate a fresh keypair from a 32-byte seed (64 hex chars) and emit
/// both the public and secret halves in hex. Used by `moon_guard keygen`.
pub fn generate_demo_keypair(
seed : String,
) -> (@crypto.KeyPair, @crypto.KeyPair) {
let kp = @crypto.generate_keypair(seed)
(kp, kp)
}