API Reference
Rust
qhermes-kernel = "26.0.0"
qhermes-channels = "26.0.0"
qhermes-a2a = "26.0.0" All three crates are #![no_std] and #![forbid(unsafe_code)]. qhermes-a2a depends on qhermes-kernel and qhermes-channels. All operations use caller-supplied byte slices and fixed-size stack arrays. No heap allocations.
qhermes-kernel
IdentityIsland::derive(master, deployment, context)
Derives an ML-DSA-65 keypair from a 32-byte master seed via HKDF-SHA3-512. Different deployment or context values yield independent key material. Returns Result<IdentityIsland, KernelError>.
let identity = IdentityIsland::derive(
&master_seed,
b"prod",
b"orchestrator",
)?; IdentitySigner trait
Implemented by IdentityIsland. Implement this trait to use HSM, TPM, enclave, or any hardware-backed key store.
fn public_key(&self) -> PublicKey<'_>;
fn sign_into(&self, payload: &[u8], out: &mut [u8; SIG_SIZE]) -> Result<(), KernelError>; perm_tlv(resource, verb, out)
Encodes a (resource, verb) permission into a caller-supplied buffer. Returns bytes written. Resource and verb are opaque byte strings, max 255 bytes each.
not_before(t) / not_after(t)
Construct a 9-byte caveat record from a Timestamp. Concatenate records into a caveats buffer. Timestamps are Unix epoch seconds.
BoundedScope::try_new(raw)
Validates a TLV permission buffer. Returns ScopeEmpty, WireInvalid, or ScopeTooLarge on failure. Maximum 64 permissions.
BoundedCaveats::try_new(raw)
Validates a caveat buffer. Must be a multiple of 9 bytes. Maximum 64 caveats.
issue_credential(issuer, manifest, payload_out, sig_out)
Serializes a DelegationManifest and signs it with the issuer's key. Writes into caller-supplied fixed-size buffers. Returns bytes written to payload_out.
let mut payload = [0u8; MAX_PAYLOAD_SIZE];
let mut sig = [0u8; SIG_SIZE];
let n = issue_credential(&identity, &manifest, &mut payload, &mut sig)?; verify_delegation(root_pk, chain, timestamp)
Verifies a slice of Credential records: signatures, depth sequence, scope subset enforcement, caveat validity, and leaf role compliance. Returns credential count on success.
enforce_scope_subset(child, parent)
Checks that every permission in child is covered by parent. A parent permission covers a child when resource and verb match exactly, or when the parent field is b"*". Returns ScopeEscalation on failure.
evaluate_caveats(caveats, now)
Evaluates all time caveats against now. Returns NotBeforeViolation or NotAfterViolation as appropriate.
write_credential_chain(out, chain) / read_credential_chain(wire, chain)
Serialize and deserialize a credential chain. All slices in the deserialized chain point into wire, zero copy.
qhermes-a2a
seal_auth(chain, out)
Serializes a credential chain into a caller-supplied buffer. Returns bytes written. out must be at least AUTH_BLOB_MAX bytes.
let mut buf = [0u8; AUTH_BLOB_MAX];
let n = seal_auth(&chain, &mut buf)?; verify_auth(root_pk, wire, now, chain_buf)
Deserializes and fully verifies a wire blob. chain_buf is a caller-supplied scratch buffer with at least MAX_DEPTH slots. Returns credential count on success.
sign_agent_card(signer, card_bytes, sig_out)
Signs a canonicalized card payload (JCS/RFC 8785) with ML-DSA-65. The signature field must be absent from card_bytes during signing.
verify_agent_card(root_pk, card_bytes, sig)
Verifies a card signature against root_pk.
kem_offer(peer_ek, context, rng, out)
Initiator side of the ML-KEM-768 handshake. Writes a KEM_OFFER_SIZE-byte ciphertext into out. Returns the SessionKey. context is forwarded to HKDF as domain separation material.
kem_accept(dk, offer, context)
Responder side. Decapsulates the shared secret. Returns the equivalent SessionKey. context must match the initiator's value.
qhermes-channels
derive_kem_keypair(dsa_seed)
Derives an ML-KEM-768 keypair from a 32-byte seed. Passing the same seed used in IdentityIsland::derive binds both identities under the same root secret, with domain separation via b"QHermes-KEM-768-v1".
encapsulate(ek, context, rng)
Encapsulates a fresh shared secret for ek. Returns the ciphertext to send to the receiver and a SessionKey derived via HKDF-SHA3-512.
decapsulate(dk, ct, context)
Decapsulates the shared secret from ct. Returns a SessionKey equivalent to the one returned by encapsulate. context must be identical to the value passed to encapsulate.
SessionKey::seal / SessionKey::open
ChaCha20-Poly1305 encrypt and decrypt over caller-supplied slices. The nonce must not be reused under the same key. SessionKey is zeroed on drop.
Error types
KernelError, A2AError, and ChannelError are all #[non_exhaustive]. Match arms must include a wildcard. Notable variants:
ScopeEscalation: child claims a permission absent from the parent scopeLeafCannotDelegate: a leaf credential attempted to issue a further delegationParentKeyMismatch: chain is broken; an issuer key does not match the previous child keyNotBeforeViolation/NotAfterViolation: credential evaluated outside its validity windowWireVersionMismatch: wire format version not recognizedAuthenticationFailed: AEAD tag verification failed
Constants
PK_SIZE = 1952: ML-DSA-65 public key, bytesSIG_SIZE = 3309: ML-DSA-65 signature, bytesSEED_SIZE = 32: master seed, bytesMAX_DEPTH = 16: maximum delegation chain depthMAX_SCOPE_PERMS = 64: maximum permissions per credentialEK_SIZE = 1184: ML-KEM-768 encapsulation key, bytesCT_SIZE = 1088: ML-KEM-768 ciphertext, bytesKEM_OFFER_SIZE = 1088: KEM offer blob, bytes
Next: Examples