Craton Shield
vs-evidence-envelope
Standardized metadata envelope for Craton Shield compliance report payloads (IEC 62304, IEC 62443, ISO/SAE 21434, ...).
The Evidence<T> type wraps a report payload with:
- a
Standarddiscriminant (which standard the payload is evidence for), - a
SchemaVersion(semantic version of the payload schema), - a
GeneratedAtmonotonic counter (caller-supplied opaque timestamp), - a
GeneratorVersion(crate version that produced the payload).
Fields are private; consumers must use the constructor (Evidence::new
or Evidence::with_metadata) and read them back through the const-fn
accessors on Evidence<T>. This prevents accidental mutation of the
metadata and gives downstream auditors a stable contract.
#![no_std], zero-allocation, #![forbid(unsafe_code)] (stronger than
deny: no unsafe block can ever appear in this crate).
Security
This envelope provides NO cryptographic binding between the metadata
and the wrapped payload. Despite the name "evidence envelope", nothing
in this crate signs, hashes, or authenticates the payload, and
EvidenceMetadata::input_hash is a plain byte array that this crate
never validates.
If tamper-evidence is required, producers MUST sign the envelope
externally -- for example by computing a vs-crypto ECDSA signature
over a stable serialization (including a hash of the full struct) and
distributing that signature alongside the envelope. Consumers MUST
verify that external signature before trusting any field on
Evidence<T>.
Treat an unverified Evidence<T> exactly as you would treat its raw
payload: untrusted input.
EvidenceMetadata / with_metadata
For producers that prefer to assemble metadata as a single struct,
EvidenceMetadata carries the same information as the per-field
arguments of Evidence::new:
let env = Evidence::with_metadata(payload, Standard::Iso21434, metadata);
Notable details:
- The caller passes
Standardexplicitly -- it is not stored insideEvidenceMetadata. schema_version: u32is packed as(major << 16) | (minor << 8) | patch, each component limited to 8 bits.tool_version: [u8; 16]is mapped throughGeneratorVersion::from_bytes, which treats the first NUL byte as end-of-string. UseGeneratorVersion::from_bytes_with_lenif you need to preserve interior NULs.input_hash: [u8; 32]is opaque to this crate -- see Security above.
License
Apache-2.0.