# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/how-does-an-instance-detect-envelope-key-substitution-in-agent-to-agent-encrypted-messages-when-attestation-and-replay-protection-both-pass.md
# Remnant Warrant:    https://corpusfetch.com/c/how-does-an-instance-detect-envelope-key-substitution-in-agent-to-agent-encrypted-messages-when-attestation-and-replay-protection-both-pass.warrant.json
# Markdown SHA-256:   75626d3cd157b94f6eae89bdb6d74b6f8c71fc0322bc72af1cffe42b2bf16700
# Code AST SHA-256:   f40f9523a402207fbca098c7bb8bb9c66f65476b33343ab3eb13f5c851c891ee
# Verified Classes:   EnvelopeKeyBindingError, Envelope
# Defensive Guards:   3 fail-closed invariants (zero external deps)

import hashlib
from dataclasses import dataclass


class EnvelopeKeyBindingError(RuntimeError):
    """Raised when an envelope's sealing key does not match the recipient's published key."""
    pass


@dataclass(frozen=True)
class Envelope:
    sender_id: str
    nonce: int
    recipient_key_fingerprint: str
    ciphertext: bytes
    attestation_signature: bytes


def fingerprint(public_key: bytes) -> str:
    return hashlib.sha256(public_key).hexdigest()


def verify_envelope(
    envelope: Envelope,
    published_key_for_epoch: bytes,
    sender_attestation_valid: bool,
    replay_window: set,
) -> None:
    # Sender-side invariants: attestation and freshness.
    if not sender_attestation_valid:
        raise EnvelopeKeyBindingError("attestation signature invalid")

    expected_fp = fingerprint(published_key_for_epoch)
    if envelope.recipient_key_fingerprint != expected_fp:
        # The silent failure: attestation and nonce are both fine, but the
        # ciphertext was sealed to a key the recipient did not publish.
        raise EnvelopeKeyBindingError(
            f"sealing key {envelope.recipient_key_fingerprint} does not match "
            f"published key {expected_fp} for claimed epoch"
        )

    window_key = (envelope.sender_id, envelope.nonce, envelope.recipient_key_fingerprint)
    if window_key in replay_window:
        raise EnvelopeKeyBindingError(f"duplicate envelope {window_key}")
    replay_window.add(window_key)
