Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions lean/VerifiedGarbage/Impl/Argon2/X86_64/DependentWord.lean
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import VerifiedGarbage.Impl.Argon2.X86_64.FillKernel

/-! Read the previous cell's first word for data-dependent addressing. Only the
public loop position and matrix base determine the read address.
-/

namespace VG.Impl.Argon2.X86_64.DependentWord

open VG.X86_64
open VG.Impl.Argon2.X86_64 (at_)

def args : List Instr := [.mov .rcx (.reg .rdi), .mov .rax (.reg .rbx)]

def pointer : Prog isa := .seq (.block FillKernel.matrix)
(.seq FillColumn.code (.seq (.block args) BlockAddress.code))

def read : List Instr := [.mov .rdi (.mem (at_ .rax 0))]

def code : Prog isa := .seq pointer (.block read)

end VG.Impl.Argon2.X86_64.DependentWord
68 changes: 68 additions & 0 deletions lean/VerifiedGarbage/Proof/Argon2/X86_64/DependentWord.lean
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import VerifiedGarbage.Proof.Argon2.X86_64.DependentWordPointer
import VerifiedGarbage.Proof.Argon2.X86_64.FillKernelSpec

/-! Select the specified secret random word from the public previous-cell address. -/

namespace VG.Proof.Argon2.X86_64.DependentWord

open VG VG.X86_64 VG.Spec.Argon2 VG.Impl.Argon2.X86_64.DependentWord

theorem read_ok (s : State) (hr : InRegions (s.rd ++ s.wr) (s.gpr .rax) 8) :
WP isa (.block Impl.Argon2.X86_64.DependentWord.read) s fun t => t.gpr .rdi = s.mem.readW (s.gpr .rax) 64 ∧ Divide.Keeps [.rdi] s t := by
apply WP.of_runBlock
simp only [Impl.Argon2.X86_64.DependentWord.read, runBlock_cons, runStep_some, runBlock_nil, exec, readSrc, State.load64,
ea_at, BitVec.add_zero, hr, Option.map_some,
Option.some.injEq, exists_eq_left', RegUpd.gpr_setReg, ite_true]
refine ⟨trivial, ?_⟩
constructor
· intro r hr
simp only [List.mem_cons, List.not_mem_nil, or_false] at hr
simp only [RegUpd.gpr_setReg, hr, ite_false]
all_goals rfl

theorem code_ok (s : State) (p : Params) (pass lane slice index : Nat)
(h : FillKernel.Ready p pass lane slice index s) : WP isa code s fun t =>
t.gpr .rdi = (blockAt s.mem (FillKernel.previous s p lane slice index))[0] ∧
Divide.Keeps ReferenceMap.changed s t := by
unfold code
refine WP.seq ((pointer_ok s p pass lane slice index h).mono ?_)
rintro a ⟨pointer, keeps⟩
have bound := Proof.Argon2.previous_column_lt p h.bounds.lanesPositive h.bounds.memoryMinimum
(slice * p.segmentLen + index)
have cover := h.layout.cell_cover h.bounds.lanesPositive h.bounds.laneBound bound
have hr : InRegions (a.rd ++ a.wr) (a.gpr .rax) 8 := by
rw [keeps.rd, keeps.wr, pointer]
have contains : (⟨FillKernel.previous s p lane slice index, 1024⟩ : Region).Contains
(FillKernel.previous s p lane slice index) 8 :=
by simpa only [BitVec.add_zero] using (Offset.contains_base
(FillKernel.previous s p lane slice index) (d := 0) (n := 8) (k := 1024) (by decide) (by decide))
obtain ⟨r, hr, hc⟩ := cover _ _ ⟨⟨FillKernel.previous s p lane slice index, 1024⟩,
by simp [FillKernel.previous, FillKernel.previousColumn, FillKernel.currentColumn], contains⟩
exact ⟨r, List.mem_append_right _ hr, hc⟩
refine (read_ok a hr).mono ?_
rintro t ⟨random, tail⟩
refine ⟨?_, keeps.trans (tail.mono (by decide))⟩
rw [random, pointer, keeps.mem]
change s.mem.readW _ 64 = (blockAt _ _)[(⟨0, by decide⟩ : Fin 128)]
rw [blockAt_get]
change s.mem.readW _ 64 = s.mem.readW (_ + 0#64) 64
rw [BitVec.add_zero]

theorem code_spec_ok (s : State) (p : Params) (pass lane slice index : Nat)
(h : FillKernel.Ready p pass lane slice index s) (state : FillState)
(represented : Proof.Argon2.Represents s.mem (FillKernel.matrix s) p.blocks state.memory)
(dependent : independent p pass slice = false) : WP isa code s fun t =>
t.gpr .rdi = Proof.Argon2.FillStep.random p pass lane slice index state.memory ∧
Divide.Keeps ReferenceMap.changed s t := by
refine (code_ok s p pass lane slice index h).mono ?_
rintro t ⟨random, keeps⟩
have bound := Proof.Argon2.previous_cell_lt p h.bounds.lanesPositive h.bounds.memoryMinimum
h.bounds.laneBound (column := FillKernel.currentColumn p slice index)
have block := represented.block (FillKernel.previousIndex p lane slice index) bound
change blockAt s.mem (FillKernel.previous s p lane slice index) = _ at block
rw [block] at random
refine ⟨?_, keeps⟩
simpa only [Proof.Argon2.FillStep.random, dependent, Bool.false_eq_true, ite_false, FillKernel.previousIndex, FillKernel.previousColumn,
FillKernel.currentColumn] using random

end VG.Proof.Argon2.X86_64.DependentWord
53 changes: 53 additions & 0 deletions lean/VerifiedGarbage/Proof/Argon2/X86_64/DependentWordCT.lean
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import VerifiedGarbage.Proof.Argon2.X86_64.DependentWord
import VerifiedGarbage.Proof.Argon2.X86_64.DependentWordLit
import VerifiedGarbage.Proof.Framework.X86_64.RelCT

/-! The previous cell is read at an address determined by public parameters. -/

namespace VG.Proof.Argon2.X86_64.DependentWord

open VG VG.X86_64 VG.Spec.Argon2 VG.Impl.Argon2.X86_64.DependentWord

structure Related (p : Params) (pass lane slice index : Nat) (s t : State) : Prop where
left : FillKernel.Ready p pass lane slice index s
right : FillKernel.Ready p pass lane slice index t
bases : s.gpr .rbp = t.gpr .rbp
matrices : FillKernel.matrix s = FillKernel.matrix t

theorem pointer_rel : RelCT isa
(fun s t => ∀ r ∈ [Reg.rbp, .r12, .r13, .r14, .r15], s.gpr r = t.gpr r)
pointer (fun _ _ => True) :=
RelCT.taint (A := taint) (Taint.ofRegs [.rbp, .r12, .r13, .r14, .r15])
(fun _ _ h => Taint.agree_ofRegs h) (by taint_decide)

theorem read_rel : RelCT isa (fun s t => s.gpr .rax = t.gpr .rax) (.block Impl.Argon2.X86_64.DependentWord.read) (fun _ _ => True) :=
RelCT.taint (A := taint) (Taint.ofRegs [.rax])
(fun _ _ h => Taint.agree_ofRegs (by
intro r hr
simp only [List.mem_cons, List.not_mem_nil, or_false] at hr
subst r
exact h)) (by taint_decide)

theorem code_rel (p : Params) (pass lane slice index : Nat) :
RelCT isa (Related p pass lane slice index) code (fun _ _ => True) := by
have trace := pointer_rel.mono (P' := Related p pass lane slice index) (by
intro s t h r hr
simp only [List.mem_cons, List.not_mem_nil, or_false] at hr
rcases hr with rfl | rfl | rfl | rfl | rfl
· exact h.bases
· exact h.left.position.laneLength.trans h.right.position.laneLength.symm
· exact h.left.position.segmentLength.trans h.right.position.segmentLength.symm
· exact h.left.position.slice.trans h.right.position.slice.symm
· exact h.left.position.index.trans h.right.position.index.symm) (fun _ _ h => h)
have full := trace.wpDep (fun s t h =>
⟨pointer_ok s p pass lane slice index h.left, pointer_ok t p pass lane slice index h.right⟩)
have publicTrace : RelCT isa (Related p pass lane slice index) pointer
(fun s t => s.gpr .rax = t.gpr .rax) := full.mono (fun _ _ h => h) (by
intro a b h
obtain ⟨_, s, t, hp, ⟨pa, _⟩, ⟨pb, _⟩⟩ := h
have equal : FillKernel.previous s p lane slice index = FillKernel.previous t p lane slice index := by
unfold FillKernel.previous; rw [hp.matrices]
exact pa.trans (equal.trans pb.symm))
exact publicTrace.seq read_rel

end VG.Proof.Argon2.X86_64.DependentWord
10 changes: 10 additions & 0 deletions lean/VerifiedGarbage/Proof/Argon2/X86_64/DependentWordLit.lean
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import VerifiedGarbage.Proof.Framework.X86_64.Lit
import VerifiedGarbage.Impl.Argon2.X86_64.DependentWord

/-! Checked literal of the public predecessor-address computation. -/

namespace VG

materialize_code Impl.Argon2.X86_64.DependentWord.pointer

end VG
52 changes: 52 additions & 0 deletions lean/VerifiedGarbage/Proof/Argon2/X86_64/DependentWordPointer.lean
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import VerifiedGarbage.Impl.Argon2.X86_64.DependentWord
import VerifiedGarbage.Proof.Argon2.X86_64.FillKernelArgs
import VerifiedGarbage.Proof.Argon2.X86_64.FillKernelPrepare

/-! The data-dependent word's address is the specification's cyclic predecessor. -/

namespace VG.Proof.Argon2.X86_64.DependentWord

open VG VG.X86_64 VG.Spec.Argon2 VG.Impl.Argon2.X86_64.DependentWord

theorem args_ok (s : State) : WP isa (.block args) s fun t =>
t.gpr .rcx = s.gpr .rdi ∧ t.gpr .rax = s.gpr .rbx ∧ Divide.Keeps [.rcx, .rax] s t := by
apply WP.of_runBlock
simp only [args, runBlock_cons, runStep_some, runBlock_nil, exec, readSrc,
RegUpd.gpr_setReg, reduceCtorEq, ite_true, ite_false, Option.map_some,
Option.some.injEq, exists_eq_left']
refine ⟨trivial, trivial, ?_⟩
constructor
· intro r hr
simp only [List.mem_cons, List.not_mem_nil, or_false, not_or] at hr
simp only [RegUpd.gpr_setReg, hr.1, hr.2, ite_false]
all_goals rfl

theorem pointer_ok (s : State) (p : Params) (pass lane slice index : Nat)
(h : FillKernel.Ready p pass lane slice index s) : WP isa pointer s fun t =>
t.gpr .rax = FillKernel.previous s p lane slice index ∧ Divide.Keeps ReferenceMap.changed s t := by
unfold pointer
refine WP.seq ((FillKernel.load_ok s .r8 232 (h.layout.frameRead 232 (by simp))).mono ?_)
rintro a ⟨base, ka⟩
have k : Divide.Keeps ReferenceMap.changed s a := ka.mono (by decide)
have pos := h.position.of_keeps k
have columnBound := Proof.Argon2.column_lt p h.bounds.lanesPositive h.bounds.sliceBound h.bounds.indexBound
have segment := Proof.Argon2.segmentLen_ge_two p h.bounds.lanesPositive h.bounds.memoryMinimum
have q := Proof.Argon2.laneLen_segments p h.bounds.lanesPositive
refine WP.seq ((FillColumn.code_nat_ok a slice p.segmentLen index p.laneLen
pos.slice pos.segmentLength pos.index pos.laneLength (by omega)
(Nat.lt_trans h.bounds.laneLength_bound (by decide)) columnBound).mono ?_)
rintro b ⟨_, prev, kb⟩
refine WP.seq ((args_ok b).mono ?_)
rintro c ⟨col, laneReg, kc⟩
have col' := col.trans prev
have lane' : c.gpr .rax = BitVec.ofNat 64 lane := laneReg.trans ((kb.regs .rbx (by decide)).trans pos.current)
have length : c.gpr .r12 = BitVec.ofNat 64 p.laneLen :=
(kc.regs .r12 (by decide)).trans ((kb.regs .r12 (by decide)).trans pos.laneLength)
refine (BlockAddress.code_nat_ok c lane
((slice * p.segmentLen + index + p.laneLen - 1) % p.laneLen) p.laneLen lane' col' length).mono ?_
rintro t ⟨address, kt⟩
refine ⟨?_, ((k.trans (kb.mono (by decide))).trans (kc.mono (by decide))).trans (kt.mono (by decide))⟩
rw [address, kc.regs .r8 (by decide), kb.regs .r8 (by decide), base]
rfl

end VG.Proof.Argon2.X86_64.DependentWord
25 changes: 25 additions & 0 deletions lean/VerifiedGarbage/Proof/Argon2/X86_64/DependentWordState.lean
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import VerifiedGarbage.Proof.Argon2.X86_64.DependentWord
import VerifiedGarbage.Proof.Argon2.X86_64.FillKernelStable

/-! The dependent source hands the filling step its random word and unchanged matrix. -/

namespace VG.Proof.Argon2.X86_64.DependentWord

open VG VG.X86_64 VG.Spec.Argon2 VG.Impl.Argon2.X86_64.DependentWord

theorem state_ok (s : State) (p : Params) (pass lane slice index : Nat)
(h : FillKernel.Ready p pass lane slice index s) (state : FillState)
(represented : Proof.Argon2.Represents s.mem (FillKernel.matrix s) p.blocks state.memory)
(dependent : independent p pass slice = false) : WP isa code s fun t =>
t.gpr .rdi = Proof.Argon2.FillStep.random p pass lane slice index state.memory ∧
FillKernel.Ready p pass lane slice index t ∧
Proof.Argon2.Represents t.mem (FillKernel.matrix t) p.blocks state.memory ∧
Divide.Keeps ReferenceMap.changed s t := by
refine (code_spec_ok s p pass lane slice index h state represented dependent).mono ?_
rintro t ⟨random, keeps⟩
refine ⟨random, h.of_keeps keeps, ?_, keeps⟩
have base : FillKernel.matrix t = FillKernel.matrix s := by
unfold FillKernel.matrix; rw [keeps.mem, keeps.regs .rbp (by decide)]
rw [keeps.mem, base]; exact represented

end VG.Proof.Argon2.X86_64.DependentWord
16 changes: 16 additions & 0 deletions lean/VerifiedGarbage/Proof/Argon2/X86_64/FillKernelStable.lean
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import VerifiedGarbage.Proof.Argon2.X86_64.FillKernelArgs

/-! Register-only helpers retain the filling allocation and position invariants. -/

namespace VG.Proof.Argon2.X86_64.FillKernel

open VG VG.X86_64

theorem Ready.of_keeps {p : Spec.Argon2.Params} {pass lane slice index : Nat} {s t : State}
(h : Ready p pass lane slice index s) (k : Divide.Keeps ReferenceMap.changed s t) :
Ready p pass lane slice index t := by
refine ⟨h.layout.of_keeps k, h.bounds, h.position.of_keeps k, ?_, ?_⟩
· rw [k.mem, k.regs .rbp (by decide)]; exact h.passWord
· rw [k.mem, k.regs .rbp (by decide)]; exact h.lanesWord

end VG.Proof.Argon2.X86_64.FillKernel
Loading