"""Behavioral signature generator. This module implements a compact, deterministic behavioral fingerprint for a compiled genome bundle. It expects two inputs: - syscall_sequence: an iterable of syscall/call names observed or statically extracted from the artifact (e.g. ["open","read","write","socket"]). - static_imports: an iterable of import or feature strings (e.g. ["wasi::fd_read"]). The generator computes n-gram sketches over the syscall sequence and a feature-bit vector for imports, then produces a keyed HMAC-SHA256 over a canonical JSON payload. The result is a compact hex string representing the fingerprint. The implementation aims to be small, deterministic, and fast so it can be used in constrained admission controllers. """ from __future__ import annotations import hmac import hashlib import json from collections import Counter, deque from typing import Iterable, List, Tuple DEFAULT_KEY = b"GenomeLoom::BehavioralSig::v1" # stable keyed hash def _ngrams(seq: List[str], n: int) -> Iterable[Tuple[str, ...]]: if n <= 0: return [] dq = deque(maxlen=n) out = [] for item in seq: dq.append(item) if len(dq) == n: out.append(tuple(dq)) return out def generate_behavioral_signature( syscall_sequence: Iterable[str], static_imports: Iterable[str] = (), ngram_ns: Tuple[int, ...] = (1, 2, 3), top_k: int = 32, key: bytes = DEFAULT_KEY, ) -> str: """Generate a deterministic behavioral signature. Returns a hex string (64 chars) representing HMAC-SHA256 over a canonical payload. The payload contains: - top n-gram counts (sorted) - sorted list of imports Parameters: - syscall_sequence: iterable of syscall/call names - static_imports: iterable of import feature strings - ngram_ns: tuple sizes for n-grams - top_k: how many n-grams to keep - key: keyed hash secret (should be globally stable for the operator) """ seq = list(syscall_sequence) # collect n-gram counts counts = Counter() for n in ngram_ns: for ng in _ngrams(seq, n): counts["+".join(ng)] += 1 # pick top-k by count then lexicographic for determinism top = sorted(counts.items(), key=lambda kv: (-kv[1], kv[0]))[:top_k] top_list = [(k, v) for k, v in top] imports_sorted = sorted(set(static_imports)) payload = {"ngrams": top_list, "imports": imports_sorted} canon = json.dumps(payload, separators=(",", ":"), sort_keys=True) mac = hmac.new(key, canon.encode("utf-8"), hashlib.sha256).hexdigest() return mac def signature_summary(syscall_sequence: Iterable[str], static_imports: Iterable[str] = ()) -> dict: """Return a structured summary used in certificates (not the HMAC). This includes top n-grams and feature import bits. Useful for human inspection and sparse indexing. """ seq = list(syscall_sequence) counts = Counter() for n in (1, 2, 3): for ng in _ngrams(seq, n): counts["+".join(ng)] += 1 top = sorted(counts.items(), key=lambda kv: (-kv[1], kv[0]))[:32] return {"ngrams": top, "imports": sorted(set(static_imports))}