qhermes-kernel 26.0.0

QHermes 26 — post-quantum delegation chain primitives (ML-DSA-65, HKDF-SHA3-512)
Documentation
qhermes-kernel-26.0.0 has been yanked.

qhermes-kernel

Part of QHermes 26 by Copertino.

Thank you for choosing QHermes 26.

ML-DSA-65 key derivation, credential issuance, permission encoding, caveat evaluation, and wire serialization. No allocator dependency. No unsafe code. All operations over caller-supplied byte slices.

Signatures: ML-DSA-65 (FIPS 204). Key derivation: HKDF-SHA3-512.

Design

The signing key is a trait, not a type. IdentitySigner defines the signing interface. IdentityIsland is one implementation — deterministic derivation from a master seed. The trait may be implemented directly for HSM, TPM, enclave, or any hardware-backed key store. The kernel has no dependency on where the key material resides.

Derived identities are one-way. IdentityIsland::derive accepts a master seed, a deployment string, and a context string. The HKDF info parameter is deployment:context. Two islands derived from the same master under different parameters have no mathematical relationship. The master and all sibling islands remain unrecoverable from a compromised island.

All buffers are caller-owned. Every function writes into slices or fixed-size arrays supplied by the caller. No allocations are performed internally. Maximum output buffer sizes are exported as constants to permit static allocation at all call sites.

Scope subset enforcement is exact. Resource and verb fields are opaque byte strings compared for equality. The only wildcard is b"*", which matches any single field. A resource string such as b"src/**" is treated as a fixed identifier, not a glob pattern. Pattern interpretation is the responsibility of the application layer. The kernel enforces containment mechanically on the bytes supplied.

Timestamps are seconds, not milliseconds. Every Timestamp value is seconds since the Unix epoch. Supplying milliseconds produces incorrect caveat evaluation without error — the caveat will appear to expire far in the future. The kernel has no access to a system clock and performs no validation of timestamp units.

Wire format is anti-malleable. Trailing bytes following expected fields in any payload return WireInvalid. A credential count of zero is rejected. The first byte of every chain is a version tag. These properties make it structurally difficult to construct inputs that parse as valid but carry unintended semantics.

Errors are #[non_exhaustive]. New variants may be added in minor releases. Match arms must include a wildcard.

Architecture

Four layers, each calling only downward.

Crypto — key derivation from a master seed and ML-DSA-65 sign/verify.

Policy — permission TLV encoding, scope subset enforcement, caveat evaluation.

Delegation — credential issuance and chain verification against a trust anchor.

Wire — credential chain serialization and deserialization.

Usage

use qhermes_kernel::{
    IdentityIsland, IdentitySigner as _,
    DelegationManifest, Role, Depth,
    BoundedScope, BoundedCaveats,
    issue_credential, verify_delegation,
    write_credential_chain, read_credential_chain,
    perm_tlv, not_after, Timestamp,
};

// Derive an identity from a master seed.
let identity = IdentityIsland::derive(&master_seed, b"prod", b"agent-0")?;

// Build a scope.
let mut scope_buf = [0u8; PERM_TLV_MAX];
let scope_len = perm_tlv(b"/tasks", b"write", &mut scope_buf)?;

let expiry_bytes = not_after(Timestamp(unix_expiry));

// Issue a credential to a child public key.
let manifest = DelegationManifest {
    child_pk: child_pk,
    role:     Role::Leaf,
    depth:    Depth(1),
    scope:    BoundedScope::try_new(&scope_buf[..scope_len])?,
    caveats:  BoundedCaveats::try_new(&expiry_bytes)?,
};

let mut payload_buf = [0u8; MAX_PAYLOAD_SIZE];
let mut sig_buf     = [0u8; SIG_SIZE];
let n = issue_credential(&identity, &manifest, &mut payload_buf, &mut sig_buf)?;

// Verify a delegation chain.
verify_delegation(root_pk, &chain, Timestamp(now))?;

Wire format

A credential chain begins with a version byte (0x01) and a 4-byte little-endian credential count, followed by the credential records.

Each record: issuer public key (PK_SIZE bytes), ML-DSA-65 signature (SIG_SIZE bytes), payload length (4 bytes, little-endian), payload bytes.

Each payload: child public key (PK_SIZE bytes), role byte (0x00 for Leaf, 0x01 for Node), depth (4 bytes, little-endian), scope length (4 bytes), scope bytes, caveat length (4 bytes), caveat bytes.

Permission encoding

Each permission: 1-byte resource length, resource bytes, 1-byte verb length, verb bytes. b"*" in either field matches any value during scope subset checks. All other values are compared for exact byte equality.

Caveat encoding

Each caveat: 1-byte tag, 8-byte little-endian Unix timestamp in seconds.

Tag 0x01 (not_before) — invalid if now < ts. Tag 0x02 (not_after) — invalid if now > ts.

Constants

Name Value Description
PK_SIZE 1952 ML-DSA-65 public key, bytes
SIG_SIZE 3309 ML-DSA-65 signature, bytes
SEED_SIZE 32 Master seed, bytes
MAX_DEPTH 16 Maximum delegation chain depth
MAX_SCOPE_PERMS 64 Maximum permissions per credential
MAX_CAVEATS 64 Maximum caveats per credential
PERM_TLV_MAX 512 Maximum encoded scope bytes
CAVEAT_SIZE 9 Fixed caveat record size, bytes

License

Copertino Source License 1.0. Change Date: 2036-01-01. Change License: Apache-2.0. See LICENSE.

Copyright © 2026 Copertino. All rights reserved.