aeat.core.hashing module

Canonical SHA-256 utilities for bytes, files, and JSON content ids.

Provides sha256_hex(), sha256_file(), hash_file(), canonical_json_bytes(), and content_hash_hex() as the single authoritative SHA-256 implementations. Byte callers hash in memory; file callers pass a Path and share the chunked-read loop. All adapters, application services, and domain modules import from here rather than inlining hashlib.sha256(data).hexdigest() or re-deriving the canonical-JSON content-hash serialisation.

This module owns digest mechanics only. Domain identities such as profile snapshots, calculation revisions, evidence bundles, and filing records own the payload schema, value normalisation, contract-change policy, and pinned digest tests that make a digest semantically stable.

sha256_hex(data)[source]

Return the lowercase hex SHA-256 digest of data.

Use this for in-memory payloads once the caller has already chosen the byte representation (serialised JSON, string keys, ciphertext, etc.). It does not normalise text or domain values. For file-path inputs use sha256_file() or hash_file().

Return type:

str

Parameters:

data (bytes)

canonical_json_bytes(payload)[source]

Return deterministic canonical-JSON bytes for content hashing.

Sorted keys, compact separators, UTF-8 — the single serialisation the content-hash helpers feed into SHA-256 so two semantically equal payloads produce the same bytes (and therefore the same content hash / id).

The payload must already be JSON-compatible. Callers normalise Decimal, Path, datetimes, enums, and domain objects into stable strings or dictionaries before entering this helper; any change to that projection is a caller-owned identity change.

Return type:

bytes

Parameters:

payload (object)

content_hash_hex(payload)[source]

Return the SHA-256 hex digest of the canonical-JSON form of payload.

The canonical content-addressing primitive: equivalent to sha256_hex(canonical_json_bytes(payload)). Callers that need a truncated id slice the returned digest (content_hash_hex(payload)[:16]).

Use this only after the caller’s payload shape is part of that domain’s identity contract. Changing keys, value normalisation, or included fields changes the digest and should be handled as an explicit identity contract change backed by pinned fixtures.

Return type:

str

Parameters:

payload (object)

hash_file(path)[source]

Return (sha256_hex, byte_count) for the file at path.

Reads in 64 KiB chunks so large files (PDFs, export artefacts) hash cleanly without loading the entire file into memory. Hashes file contents exactly; path metadata, permissions, archive member names, and manifest normalisation stay outside this helper. Use this variant when the caller needs both the digest and the content length.

Return type:

tuple[str, int]

Parameters:

path (Path)

sha256_file(path)[source]

Return the lowercase hex SHA-256 of the bytes at path.

Reads in 64 KiB chunks so large files (PDFs, export artefacts) hash cleanly without loading the entire file into memory. Hashes file contents exactly, not the file’s path or metadata. Use hash_file() when the byte count is also needed.

Return type:

str

Parameters:

path (Path)