osyra_ome.verify.claim_fields
Private pre-release / network boundary: The currently usable customer surface is offline verification of an existing signed artifact against an out-of-band trust anchor. Memory/network RPC APIs and host snippets on this page describe protocol and interface shape; the public Edge bridge, package publication, and release acceptance remain pending. Do not treat
api.osyra.ai:443examples as a released customer route.
Extract the SIGNATURE-ATTESTED hash fields from a Claim signing preimage.
**This is the AP00013 mirror of the AP00014 TypeScript ``claim-fields.ts`` (ENG-2413 verify-on-read body-binding fix).**
Why this exists (the forgeable verify-on-read gap)
``verify_receipt(encoded_cbor, sig, trusted_pub_key)`` Ed25519-verifies ONLY ``encoded_cbor`` — the Form-B claim PREIMAGE bytes. The kernel decodes that preimage solely to confirm the dsTag and then DISCARDS the claim map. A :class:`~osyra_ome.types.SignedClaim`'s ``claim`` field is a DECODED VIEW that is **NOT** covered by the signature, and the ``content_hash`` field on a ``GetClaimBody`` response is an UNSIGNED, server-provided value. An attacker relaying claims over the (untrusted) transport that verify-on-read defends against can rewrite ``signed.claim.content_hash`` / the response ``content_hash`` freely. A binding check that compares a recomputed body hash to either of those attacker-controllable values is therefore bypassable.
This helper re-derives the AUTHENTIC ``ch`` (content hash) and ``eh`` (embedding hash) directly from the SIGNED preimage bytes (the exact bytes the Ed25519 signature attests), so the caller can bind the returned body to the SIGNATURE rather than to an untrusted decoded view or response field.
Wire shape
Per ``receipt.py`` / ADR-157 / the claim-preimage KAT (``ome-proto/go/testdata/claim-preimage-kat-v1.json``): the preimage is the Form-B 2-tuple ``[tstr("osyra-ome-claim-v1"), claimMap]``, where ``claimMap`` is a canonical (RFC 8949 §4.2) text-keyed map with the 9 short keys ``ws, id, sub, par, iss, ch, eh, kn, ts`` (see the Go reference ``claimPreimageMap`` struct in ``ome-proto/go/claim.go``). ``ch`` and ``eh`` are 32-byte SHA-256 byte strings (``eh`` is the all-zero digest when the claim carries no embedding).
Decoding goes through the strict canonical-CBOR decoder (1 MiB cap, depth cap, duplicate-key + indefinite-length rejection) — so a malformed or non-canonical preimage RAISES rather than yielding garbage. The dsTag is asserted to be the claim tag (cross-protocol-confusion guard: a Witness/Bundle preimage must never be mined for "claim" hashes here).
Imports ONLY from ``osyra_ome.verify._kernel`` + ``osyra_ome.errors`` (the BC-13 isolation boundary — the Apache-2.0 verify surface).
Functions
extract_attested_claim_fields
def extract_attested_claim_fields(encoded_cbor: bytes) -> AttestedClaimFieldsExtract the attested ``content_hash`` (+ ``embedding_hash``) from a preimage.
Strict-canonical-decodes the Form-B claim signing-preimage bytes (the bytes the Ed25519 signature attests), asserts the claim dsTag, and reads the short-key ``ch`` / ``eh`` byte-string fields from the claim map.
Args:
encoded_cbor: The claim signing-preimage bytes
(SignedClaim.encoded_cbor; the bytes verify_receipt covers).
Returns:
An :class:AttestedClaimFields carrying the authentic 32-byte
content_hash and, when present (non-zero), the authentic 32-byte
embedding_hash.
Raises:
OmeWireFormatError: the bytes are not strict-canonical CBOR, are not a
2-tuple, carry the wrong dsTag (cross-protocol confusion), the
payload is not a CBOR map, or ch is absent / not a 32-byte
byte string. Fail-CLOSED: there is no path that returns a partial
or default result.
Classes
class AttestedClaimFields
Bases: NamedTuple
The signature-attested hash fields decoded from a claim preimage.
Attributes:
content_hash: The signature-attested content hash (SHA-256; 32 bytes).
Always present (a claim preimage MUST carry ch).
embedding_hash: The signature-attested embedding hash (SHA-256;
32 bytes), present ONLY when the claim carries a NON-ZERO embedding
digest. The proto always encodes an eh field; a 32-byte zero
digest means "no embedding" and is reported as None here (a
chat-message claim has no embedding). Mirrors the TS
AttestedClaimFields.embeddingHash? optionality.
Attributes
| Name | Type | Default |
| --- | --- | --- |
| content_hash | bytes | |
| embedding_hash | bytes | None | |