import ApcOptimizer.Spec set_option autoImplicit false /-! Helper functions to encode the semantics of memory buses, to be used to implement `BusSemantics::admissible`. Memory buses are stateful buses that follow the pattern that bus interactions come in pairs like: `send(memBusId, (
, , ))` `receive(memoryBusId, (
, , ))` such that if `
=
`: - ` = ` - ` = ` Using `admissibleMemoryBus` just *asserts* that this discipline is followed. In practice, it could be enforced (e.g. by an argument like [1]), or it could be not enforced, but guaranteed that the prover *can* satisfy the property (without sacrificing completeness). Note that this assumes that *bus interactions are ordered by time*! [1] https://link.springer.com/article/10.1007/BF01185212 -/ variable {p : ℕ} /-- A description of a memory bus interaction. -/ structure MemoryBusShape where /-- Payload positions forming the access key (e.g. OpenVM's two-limb address). Can be empty for a single global cell. -/ addressFields : List Nat /-- The address projection of an evaluated message, per a memory-bus shape. -/ def MemoryBusShape.address (shape : MemoryBusShape) (m : BusInteraction (ZMod p)) : List (Option (ZMod p)) := shape.addressFields.map (fun (slot : Nat) => m.payload[slot]?) /-- Given an ordered list of memory bus interaction messages *on the same bus*, decide whether it follows the memory bus discipline: After a *send* to a given address, the next *receive* from the same address observes the same payload, with no intervening active messages to the same address. -/ def admissibleMemoryBus (shape : MemoryBusShape) (L : List (BusInteraction (ZMod p))) : Prop := ∀ (pre mid post : List (BusInteraction (ZMod p))) (S R : BusInteraction (ZMod p)), L = pre ++ S :: mid ++ R :: post → S.multiplicity = 1 → R.multiplicity = -1 → shape.address S = shape.address R → (∀ m ∈ mid, m.multiplicity ≠ 0 → shape.address m = shape.address S → False) → S.payload = R.payload -- TODO: Move this out of the auditing surface /-- The consumption form the passes use. Given `admissibleMemoryBus` over the **active** sublist of a raw (all-multiplicity) message list `Lraw`, a send `S` followed by a receive `R` to the same address in `Lraw`, with no active same-address message between them, have equal payloads. The passes exhibit the split of `Lraw` (the raw per-bus interaction list) directly; this lemma filters it to the active sublist that `admissibleMemoryBus` ranges over (`S`, `R` survive as they are active, given `1 ≠ 0`). -/ theorem admissibleMemoryBus.consecutive (shape : MemoryBusShape) (Lraw : List (BusInteraction (ZMod p))) (hp1 : (1 : ZMod p) ≠ 0) (h : admissibleMemoryBus shape (Lraw.filter (fun m => decide (m.multiplicity ≠ 0)))) (pre mid post : List (BusInteraction (ZMod p))) (S R : BusInteraction (ZMod p)) (hsplit : Lraw = pre ++ S :: mid ++ R :: post) (hS : S.multiplicity = 1) (hR : R.multiplicity = -1) (haddr : shape.address S = shape.address R) (hmid : ∀ m ∈ mid, m.multiplicity ≠ 0 → shape.address m = shape.address S → False) : S.payload = R.payload := by have hPS : decide (S.multiplicity ≠ 0) = true := by simp only [hS, decide_eq_true_eq]; exact hp1 have hPR : decide (R.multiplicity ≠ 0) = true := by simp only [hR, decide_eq_true_eq]; exact fun hh => hp1 (neg_eq_zero.mp hh) refine h (pre.filter (fun m => decide (m.multiplicity ≠ 0))) (mid.filter (fun m => decide (m.multiplicity ≠ 0))) (post.filter (fun m => decide (m.multiplicity ≠ 0))) S R ?_ hS hR haddr ?_ · subst hsplit simp only [List.filter_append, List.filter_cons, hPS, hPR, if_true] · intro m hm hmne hmaddr exact hmid m (List.mem_of_mem_filter hm) hmne hmaddr