evidence

package
v0.1.8 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 15, 2026 License: Apache-2.0 Imports: 8 Imported by: 0

Documentation

Overview

Package evidence models tamper-evident, hash-chained records of what an engagement produced (scans, findings, reports). Each item's Hash covers its content AND the previous item's Hash, so any later edit, insertion, or removal breaks the chain – and the report path must refuse to proceed on a mismatch . This is the domain groundwork; persistence + wiring land with the evidence vault.

Index

Constants

View Source
const (
	AttestationContextEvidence = "synapse-evidence-head:v1"
	AttestationContextAudit    = "synapse-audit-head:v1"
)

Attestation context tags provide DOMAIN SEPARATION for the signed message: one ed25519 key signs both evidence and audit chain heads, so the signed bytes are prefixed with a per-chain tag. This makes an attestation self-describing about WHICH custody chain it covers and means an evidence-head signature can never be presented as an audit-head signature (and vice versa) even though both heads are 64-char hex sha256 strings. The `:v1` suffix lets the format evolve.

Variables

View Source
var ErrBadAttestation = errors.New("evidence attestation invalid")

ErrBadAttestation is returned when a chain-head signature fails verification.

View Source
var ErrChainBroken = errors.New("evidence chain broken")

ErrChainBroken is returned when an evidence chain fails verification.

Functions

func AttestationMessage

func AttestationMessage(context, head string) []byte

AttestationMessage builds the exact bytes that are signed/verified for a chain head under a context. An empty context reproduces the legacy bare-head message so attestations minted before domain separation still verify; a non-empty context binds the signature to that chain kind. Sign and VerifyAttestation MUST agree by going through this one function.

func ComputeHash

func ComputeHash(e Evidence) string

ComputeHash returns the chain hash binding an evidence link to its predecessor. It binds not just previous_hash + content but ALSO the attribution + metadata (kind, finding_id, storage_ref, created_by, created_at) – so a rewrite of WHO produced the evidence or WHEN is detected by VerifyChain, not just a content edit. The timestamp is truncated to µs (matching Postgres timestamptz) so the hash is stable across a DB round-trip. Including previous_hash links the chain: any earlier change cascades.

func KeyFingerprint

func KeyFingerprint(pub ed25519.PublicKey) string

KeyFingerprint returns a short, stable id for an ed25519 public key (first 16 hex chars of its sha256) – used as the attestation KeyID and to pin a signer.

func VerifyAttestation

func VerifyAttestation(att Attestation) error

VerifyAttestation checks that att is a well-formed ed25519 signature over its context-tagged head by att.PublicKey, and that the embedded KeyID matches that key. It does NOT decide whether the key is trusted, nor whether the Context is the one the caller expected – those are the verifier's policy (pin a known key; assert the context for your chain). Returns ErrBadAttestation on any failure.

func VerifyChain

func VerifyChain(items []Evidence) error

VerifyChain checks that items form an unbroken hash chain in order: each item's PreviousHash equals the prior item's Hash, and each Hash recomputes from its own content + previous hash. It returns ErrChainBroken at the first break.

Types

type Attestation

type Attestation struct {
	Algorithm string `json:"algorithm"`         // "ed25519"
	KeyID     string `json:"key_id"`            // short fingerprint of the public key (sha256 prefix)
	PublicKey string `json:"public_key"`        // base64-std of the 32-byte ed25519 public key
	Context   string `json:"context,omitempty"` // domain-separation tag (e.g. AttestationContextAudit); empty = legacy bare-head
	Head      string `json:"head"`              // the chain head hash that was signed
	Signature string `json:"signature"`         // base64-std of the 64-byte signature
}

Attestation is a detached signature over a chain head: it proves WHICH key attested to that head (origin / non-repudiation) and, via Context, WHICH chain it covers, on top of the chain's integrity. ed25519 signatures are deterministic (RFC 8032), and only the (context-tagged) head is signed – so re-signing the same chain yields identical bytes, keeping the report byte-reproducible. Verification needs only the public key, so it is a pure function here; only signing needs the private key (a port).

type Evidence

type Evidence struct {
	ID           shared.ID
	EngagementID shared.ID
	FindingID    shared.ID // optional link to the finding this evidence supports
	Kind         string    // e.g. "scan", "finding", "report"
	Content      []byte    // the sealed payload (or a digest of it)
	StorageRef   string    // optional content-addressed blob key (sha256) for an out-of-line artifact; the same hash is also inside Content, so the blob is chain-protected
	Hash         string    // hex sha256 binding previous_hash + attribution + metadata + content
	PreviousHash string    // the prior item's Hash; empty for the first link
	CreatedBy    string    // human/agent id that produced this evidence (attribution)
	CreatedAt    time.Time
}

Evidence is one link in an engagement's append-only hash chain.

func (Evidence) Seal

func (e Evidence) Seal() Evidence

Seal returns a copy of e with Hash computed from its chained fields.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL