diff --git a/lean/VerifiedGarbage/Impl/Md5/X86/Stream.lean b/lean/VerifiedGarbage/Impl/Md5/X86/Stream.lean index 1b0c67fbf..73028b153 100644 --- a/lean/VerifiedGarbage/Impl/Md5/X86/Stream.lean +++ b/lean/VerifiedGarbage/Impl/Md5/X86/Stream.lean @@ -32,6 +32,8 @@ def init : Prog isa := /-- The sizes, the length field and the digest. -/ def params : Params where N := 16 + B := 64 + L := 8 so := 64 len := len64 64 72 false out := out32 4 false diff --git a/lean/VerifiedGarbage/Impl/MdStream/X86.lean b/lean/VerifiedGarbage/Impl/MdStream/X86.lean index 3cb301102..92f1560f7 100644 --- a/lean/VerifiedGarbage/Impl/MdStream/X86.lean +++ b/lean/VerifiedGarbage/Impl/MdStream/X86.lean @@ -3,15 +3,14 @@ import VerifiedGarbage.TCB.X86.Isa /-! # Streaming Merkle–Damgård hash functions: x86 (32-bit) implementation -The streaming `update` and `finalize` of the hash functions whose blocks are -64 bytes and whose length fields are 8 bytes, which differ only in the size -of their hash values, in how they store the message length and output the -digest, and in the compression function they call (`Params`). Each hash -function's `Impl//X86/Stream.lean` instantiates them. The same -algorithm as on x86-64 (`VG.Impl.MdStream.X86_64`). +The streaming `update` and `finalize` of MD5, SHA-1, SHA-256 and the SHA-512 +family, which differ only in their sizes, in how they store the message +length and output the digest, and in the compression function they call +(`Params`). Each hash function's `Impl//X86/Stream.lean` instantiates +them. The same algorithm as on x86-64 (`VG.Impl.MdStream.X86_64`). -The streaming state (`N + 64` bytes at `state`) is the hash value (`N` -bytes) followed by a 64-byte buffer. Every argument is on the stack (cdecl). +The streaming state (`N + B` bytes at `state`) is the hash value (`N` bytes) +followed by a `B`-byte buffer. Every argument is on the stack (cdecl). * `update(state, count, data, len, scratch)` compresses, in each iteration, every whole block left in `data` with one call if the buffer is empty (so @@ -41,12 +40,16 @@ def at_ (b : Reg) (d : Nat) : MemOp := { base := b, disp := d } structure Params where /-- The size of the hash value, where the buffer starts. -/ N : Nat + /-- The block size. -/ + B : Nat + /-- The size of the length field at the end of the last block. -/ + L : Nat /-- Where our caller's registers are saved in the scratch space, after the compression function's own; `finalize` keeps `count` and `out` after them, in `scratch[so+16..so+28)`. -/ so : Nat /-- Stores the length field, from `count` in `[ebp + so + 16]` (low word) - and `[ebp + so + 20]` (high word), at `ebx + N + 56`; writes only `eax`, + and `[ebp + so + 20]` (high word), at `ebx + N + B - L`; writes only `eax`, `ecx` and `edx` (and the flags). -/ len : List Instr /-- Writes the digest, from the hash value at `ebx`, to `eax`; writes only @@ -83,29 +86,30 @@ Registers: `ebx` = `state`, `ebp` = `data`, `esi` = bytes of `data` left, compress and `ecx` = the number of blocks to compress there. `scratch` is read from its argument slot (`[esp + 24]`) when needed. -/ -/-- Every whole block left, straight from `data`: `esi - (esi & 63)` bytes, -`(esi - (esi & 63)) >> 6` blocks. -/ +/-- Every whole block left, straight from `data`: `esi - esi mod B` bytes, +`(esi - esi mod B) >> log₂ B` blocks. -/ def direct : List Instr := - [.mov .eax (.reg .ebp), .mov .ecx (.reg .esi), .alu .and .ecx (.imm 63), .mov .edx (.reg .esi), - .alu .sub .edx (.reg .ecx), .alu .add .ebp (.reg .edx), .mov .esi (.reg .ecx), .mov .ecx (.reg .edx), - .shift .shr .ecx 6] + [.mov .eax (.reg .ebp), .mov .ecx (.reg .esi), .alu .and .ecx (.imm (BitVec.ofNat 32 (P.B - 1))), + .mov .edx (.reg .esi), .alu .sub .edx (.reg .ecx), .alu .add .ebp (.reg .edx), .mov .esi (.reg .ecx), + .mov .ecx (.reg .edx), .shift .shr .ecx (Nat.log2 P.B)] -/-- Copy `min(64 - edi, esi)` bytes of `data` into the buffer; if that fills it, +/-- Copy `min(B - edi, esi)` bytes of `data` into the buffer; if that fills it, compress it. -/ def fill : Prog isa := - .seq (.block [.mov .eax (.imm 64), .alu .sub .eax (.reg .edi), .alu .cmp .esi (.reg .eax)]) + .seq (.block [.mov .eax (.imm (BitVec.ofNat 32 P.B)), .alu .sub .eax (.reg .edi), .alu .cmp .esi (.reg .eax)]) (.seq (.ite .b (.block [.mov .eax (.reg .esi)]) (.block [])) (.seq (.block [.alu .sub .esi (.reg .eax), .alu .add .edi (.reg .ebx), .alu .test .eax (.reg .eax)]) (.seq (.ite .e (.block []) (.loop (.block [.movzx8 .ecx (at_ .ebp 0), .store8 (at_ .edi P.N) .cl, .alu .add .ebp (.imm 1), .alu .add .edi (.imm 1), .alu .sub .eax (.imm 1)]) .ne)) - (.seq (.block [.alu .sub .edi (.reg .ebx), .mov .ecx (.imm 0), .alu .cmp .edi (.imm 64)]) + (.seq (.block [.alu .sub .edi (.reg .ebx), .mov .ecx (.imm 0), .alu .cmp .edi (.imm (BitVec.ofNat 32 P.B))]) (.ite .e (.block [.mov .eax (.reg .ebx), .alu .add .eax (.imm (BitVec.ofNat 32 P.N)), .mov .edi (.imm 0), .mov .ecx (.imm 1)]) (.block [])))))) def updateBody (name : String) (code : Prog isa) : Prog isa := .seq (.block [.alu .test .edi (.reg .edi)]) - (.seq (.ite .e (.seq (.block [.alu .cmp .esi (.imm 64)]) (.ite .ae (.block direct) (fill P))) (fill P)) + (.seq (.ite .e (.seq (.block [.alu .cmp .esi (.imm (BitVec.ofNat 32 P.B))]) (.ite .ae (.block (direct P)) (fill P))) + (fill P)) (.seq (.block [.alu .test .ecx (.reg .ecx)]) (.ite .ne (.seq (.block [.mov .edx (.mem (at_ .esp 24))]) (.seq (compressN name code .ebx .edx) (.block [.mov .ecx (.imm 1), .alu .test .ecx (.reg .ecx)]))) @@ -114,7 +118,7 @@ def updateBody (name : String) (code : Prog isa) : Prog isa := def update (name : String) (code : Prog isa) : Prog isa := .seq (.block ([.mov .eax (.mem (at_ .esp 24))] ++ save P .eax ++ [.mov .ebx (.mem (at_ .esp 4)), .mov .ebp (.mem (at_ .esp 16)), .mov .esi (.mem (at_ .esp 20)), - .mov .edi (.mem (at_ .esp 8)), .alu .and .edi (.imm 63)])) + .mov .edi (.mem (at_ .esp 8)), .alu .and .edi (.imm (BitVec.ofNat 32 (P.B - 1)))])) (.seq (.loop (updateBody P name code) .ne) (.block (.mov .eax (.mem (at_ .esp 24)) :: restore P .eax))) /-! ## `finalize` @@ -124,9 +128,9 @@ Registers: `ebx` = `state`, `ebp` = `scratch`, `edi` = bytes in the buffer, `out` are kept in `scratch[so+16..so+28)`. -/ def finalizeBody (name : String) (code : Prog isa) : Prog isa := - -- Zero the buffer from `edi` to 64, or to 56 in the last block. - .seq (.block [.mov .eax (.imm 64), .alu .test .esi (.reg .esi)]) - (.seq (.ite .e (.block [.mov .eax (.imm 56)]) (.block [])) + -- Zero the buffer from `edi` to `B`, or to `B - L` in the last block. + .seq (.block [.mov .eax (.imm (BitVec.ofNat 32 P.B)), .alu .test .esi (.reg .esi)]) + (.seq (.ite .e (.block [.mov .eax (.imm (BitVec.ofNat 32 (P.B - P.L)))]) (.block [])) (.seq (.block [.mov .ecx (.imm 0), .alu .sub .eax (.reg .edi)]) (.seq (.ite .e (.block []) (.loop (.block [.mov .edx (.reg .ebx), .alu .add .edx (.reg .edi), .store8 (at_ .edx P.N) .cl, @@ -144,12 +148,12 @@ def finalize (name : String) (code : Prog isa) : Prog isa := .mov .ecx (.mem (at_ .esp 8)), .store (at_ .ebp (P.so + 16)) .ecx, .mov .ecx (.mem (at_ .esp 12)), .store (at_ .ebp (P.so + 20)) .ecx, .mov .ecx (.mem (at_ .esp 16)), .store (at_ .ebp (P.so + 24)) .ecx, - .mov .edi (.mem (at_ .esp 8)), .alu .and .edi (.imm 63), + .mov .edi (.mem (at_ .esp 8)), .alu .and .edi (.imm (BitVec.ofNat 32 (P.B - 1))), -- The `0x80` byte. .mov .edx (.reg .ebx), .alu .add .edx (.reg .edi), .mov .ecx (.imm 0x80), .store8 (at_ .edx P.N) .cl, .alu .add .edi (.imm 1), - -- Two blocks if it leaves fewer than 8 bytes for the length. - .mov .esi (.imm 0), .alu .cmp .edi (.imm 57)])) + -- Two blocks if it leaves fewer than `L` bytes for the length. + .mov .esi (.imm 0), .alu .cmp .edi (.imm (BitVec.ofNat 32 (P.B - P.L + 1)))])) (.seq (.ite .ae (.block [.mov .esi (.imm 1)]) (.block [])) (.seq (.loop (finalizeBody P name code) .e) (.block (.mov .eax (.mem (at_ .ebp (P.so + 24))) :: (P.out ++ restore P .ebp))))) @@ -158,21 +162,35 @@ def finalize (name : String) (code : Prog isa) : Prog isa := The `len` and `out` of the hash functions here. -/ -/-- The length in bits, `8 · count` (modulo 2⁶⁴, from `count` in `[ebp + so + -16]` and `[ebp + so + 20]`), as 8 bytes at `ebx + d`, big-endian if `be` and +/-- The length in bits, `8 · count` (modulo 2⁶⁴, from `count` in `eax` (low +word) and `ecx` (high word)), as 8 bytes at `ebx + d`, big-endian if `be` and little-endian otherwise. -/ -def len64 (so d : Nat) (be : Bool) : List Instr := - [.mov .eax (.mem (at_ .ebp (so + 16))), .mov .ecx (.mem (at_ .ebp (so + 20))), - .alu .add .ecx (.reg .ecx), .alu .add .ecx (.reg .ecx), .alu .add .ecx (.reg .ecx), +def len64Of (d : Nat) (be : Bool) : List Instr := + [.alu .add .ecx (.reg .ecx), .alu .add .ecx (.reg .ecx), .alu .add .ecx (.reg .ecx), .mov .edx (.reg .eax), .shift .shr .edx 29, .alu .or .ecx (.reg .edx), .alu .add .eax (.reg .eax), .alu .add .eax (.reg .eax), .alu .add .eax (.reg .eax)] ++ if be then [.bswap .ecx, .store (at_ .ebx d) .ecx, .bswap .eax, .store (at_ .ebx (d + 4)) .eax] else [.store (at_ .ebx d) .eax, .store (at_ .ebx (d + 4)) .ecx] +/-- Load `count`, from `[ebp + so + 16]` (low word) and `[ebp + so + 20]` +(high word), into `eax` and `ecx`. -/ +def loadCount (so : Nat) : List Instr := + [.mov .eax (.mem (at_ .ebp (so + 16))), .mov .ecx (.mem (at_ .ebp (so + 20)))] + +/-- `len64Of` from `count` in scratch. -/ +def len64 (so d : Nat) (be : Bool) : List Instr := loadCount so ++ len64Of d be + /-- The `n` 32-bit words at `ebx`, written to `eax`, big-endian if `be` and little-endian otherwise. -/ def out32 (n : Nat) (be : Bool) : List Instr := (List.range n).flatMap fun k => [.mov .ecx (.mem (at_ .ebx (4 * k)))] ++ (if be then [.bswap .ecx] else []) ++ [.store (at_ .eax (4 * k)) .ecx] +/-- The `n` 64-bit words at `ebx` (each little-endian: its low half first), +written to `eax` big-endian. -/ +def out64 (n : Nat) : List Instr := + (List.range n).flatMap fun k => + [.mov .ecx (.mem (at_ .ebx (8 * k + 4))), .bswap .ecx, .store (at_ .eax (8 * k)) .ecx, + .mov .ecx (.mem (at_ .ebx (8 * k))), .bswap .ecx, .store (at_ .eax (8 * k + 4)) .ecx] + end VG.Impl.MdStream.X86 diff --git a/lean/VerifiedGarbage/Impl/Sha1/X86/Stream.lean b/lean/VerifiedGarbage/Impl/Sha1/X86/Stream.lean index 8d893cc4b..d00f7ba74 100644 --- a/lean/VerifiedGarbage/Impl/Sha1/X86/Stream.lean +++ b/lean/VerifiedGarbage/Impl/Sha1/X86/Stream.lean @@ -32,6 +32,8 @@ def init : Prog isa := /-- The sizes, the length field and the digest. -/ def params : Params where N := 20 + B := 64 + L := 8 so := 112 len := len64 112 76 true out := out32 5 true diff --git a/lean/VerifiedGarbage/Impl/Sha256/X86/Stream.lean b/lean/VerifiedGarbage/Impl/Sha256/X86/Stream.lean index e4f755809..cc738443c 100644 --- a/lean/VerifiedGarbage/Impl/Sha256/X86/Stream.lean +++ b/lean/VerifiedGarbage/Impl/Sha256/X86/Stream.lean @@ -68,6 +68,8 @@ The generic streaming code (`Impl/MdStream/X86.lean`). -/ /-- SHA-256's sizes, length field and digest in the generic streaming code. -/ def params : MdStream.X86.Params where N := 32 + B := 64 + L := 8 so := 112 len := MdStream.X86.len64 112 88 true out := MdStream.X86.out32 8 true diff --git a/lean/VerifiedGarbage/Impl/Sha512/X86/Stream.lean b/lean/VerifiedGarbage/Impl/Sha512/X86/Stream.lean index d623219fc..095fbd08d 100644 --- a/lean/VerifiedGarbage/Impl/Sha512/X86/Stream.lean +++ b/lean/VerifiedGarbage/Impl/Sha512/X86/Stream.lean @@ -1,4 +1,5 @@ import VerifiedGarbage.Impl.Sha512.X86 +import VerifiedGarbage.Impl.MdStream.X86 /-! # Streaming SHA-512: x86 (32-bit) implementation @@ -9,29 +10,22 @@ value is stored little-endian, so as its low half followed by its high half. Every argument is on the stack (cdecl). * `init iv (state)` stores the initial hash value `iv`. -* `update(state, count, data, len, scratch)` processes the data in pieces: - each iteration copies as many bytes as fit into the buffer, and compresses - the buffer once it is full. -* `finalize(state, count, out, scratch)` pads the buffered bytes (one or two - blocks), compresses them and writes the final hash value. - -The buffer is compressed by calling `vg_sha512_compress`, with -`scratch[0..224)` as its scratch space. Each call pushes the four arguments -(`scratch`, `1`, the buffer and `state`) in a frame of its own, popped (into -`eax`) when it returns: with the return address the call stores, it uses the -20 bytes below `esp`. The compression function preserves `ebx`, `esi`, -`edi` and `ebp`, so our variables live there across it, and our caller's -values of those registers are saved in `scratch[224..240)`; `scratch` and -`count` are read from their argument slots when needed. Byte `r` of the -buffer is addressed as `[eax + 64]` with `eax = state + r` computed just -before the access. Every address and branch depends only on `esp`, the -pointers, `count` and `len`. +* `update(state, count, data, len, scratch)` and + `finalize(state, count, out, scratch)` are the generic streaming code of + `Impl/MdStream/X86.lean`, calling `vg_sha512_compress` + (`Impl.Sha512.X86.compress`) with `scratch[0..224)` as its scratch space; + our caller's callee-saved registers are saved in `scratch[224..240)`, and + `finalize` keeps `count` and `out` in `scratch[240..252)`. The length + field is the length in bits as a 128-bit big-endian integer: `count >> 61`, + then `count << 3` (modulo 2⁶⁴); the words of the final hash value are + big-endian. -/ namespace VG.Impl.Sha512.X86.Stream open VG.X86 open VG.Impl.Sha512.X86 (at_ compress lo hi) +open VG.Impl.MdStream.X86 (Params loadCount len64Of out64) /-- Store word `k` of `iv`, at `eax`. -/ def initW (iv : Spec.Sha512.HashValue) (k : Nat) : List Instr := @@ -41,103 +35,18 @@ def initW (iv : Spec.Sha512.HashValue) (k : Nat) : List Instr := def init (iv : Spec.Sha512.HashValue) : Prog isa := .block (.mov .eax (.mem (at_ .esp 4)) :: (List.range 8).flatMap (initW iv)) -/-- The callee-saved registers, and where they are saved in `scratch`. -/ -def saved : List (Reg × Nat) := [(.ebx, 224), (.esi, 228), (.edi, 232), (.ebp, 236)] - -/-- Save them, with `scratch` in `eax`. -/ -def save : List Instr := saved.map fun (r, d) => .store (at_ .eax d) r - -/-- Restore them, with `scratch` in `eax`. -/ -def restore : List Instr := saved.map fun (r, d) => .mov r (.mem (at_ .eax d)) - -/-- A call of `vg_sha512_compress(ebx, eax, ecx, edx)`: its arguments pushed -last to first. -/ -def compressCall : Prog isa := - .frame (.push [.edx, .ecx, .eax, .ebx]) (.call "vg_sha512_compress" compress) (.pop .eax 4) - -/-- Compress the buffer of the state at `ebx` into its hash value, with the -scratch space whose address is at `[esp + d]`. -/ -def compressAt (d : Nat) : Prog isa := - .seq (.block [.mov .eax (.reg .ebx), .alu .add .eax (.imm 64), .mov .ecx (.imm 1), - .mov .edx (.mem (at_ .esp d))]) compressCall - -/-! ## `update` - -Registers: `ebx` = `state`, `esi` = `data`, `ebp` = bytes of `data` left, -`edi` = bytes in the buffer (`r`); `scratch` is at `[esp + 24]`. The loop -runs while `ebp ≠ 0`, so each iteration starts with `ebp ≥ 1` and `edi < -128`. -/ - -/-- Copy `ecx = min(128 - r, len) ≥ 1` bytes of `data` into the buffer; if -that fills it, compress it. -/ -def fill : Prog isa := - .seq (.block [.mov .ecx (.imm 128), .alu .sub .ecx (.reg .edi), .alu .cmp .ebp (.reg .ecx)]) - (.seq (.ite .b (.block [.mov .ecx (.reg .ebp)]) (.block [])) - (.seq (.block [.alu .sub .ebp (.reg .ecx)]) - (.seq (.loop (.block [.movzx8 .edx (at_ .esi 0), .mov .eax (.reg .ebx), .alu .add .eax (.reg .edi), - .store8 (at_ .eax 64) .dl, .alu .add .esi (.imm 1), .alu .add .edi (.imm 1), - .alu .sub .ecx (.imm 1)]) .ne) - -- Full: compress the buffer. - (.seq (.block [.alu .cmp .edi (.imm 128)]) - (.ite .e (.seq (compressAt 24) (.block [.mov .edi (.imm 0)])) (.block [])))))) - -def updateBody : Prog isa := .seq fill (.block [.alu .test .ebp (.reg .ebp)]) - -def update : Prog isa := - .seq (.block ([.mov .eax (.mem (at_ .esp 24))] ++ save ++ - [.mov .ebx (.mem (at_ .esp 4)), .mov .edi (.mem (at_ .esp 8)), .alu .and .edi (.imm 127), - .mov .esi (.mem (at_ .esp 16)), .mov .ebp (.mem (at_ .esp 20)), .alu .test .ebp (.reg .ebp)])) - (.seq (.ite .e (.block []) (.loop updateBody .ne)) - (.block (.mov .eax (.mem (at_ .esp 24)) :: restore))) - -/-! ## `finalize` - -Registers: `ebx` = `state`, `edi` = bytes in the buffer (`r`), `esi` = 1 -while the block being padded is not the last one (then 0); `count` is at -`[esp + 8]`, `out` at `[esp + 16]` and `scratch` at `[esp + 20]`. -/ - -/-- The message length in bits as a 128-bit big-endian integer, at the end of -the buffer: `count >> 61`, then `count << 3` (modulo 2⁶⁴). -/ -def lenW : List Instr := - [.mov .eax (.mem (at_ .esp 8)), .mov .ecx (.mem (at_ .esp 12)), - .mov .edx (.imm 0), .store (at_ .ebx 176) .edx, - .mov .edx (.reg .ecx), .shift .shr .edx 29, .bswap .edx, .store (at_ .ebx 180) .edx, - .alu .add .ecx (.reg .ecx), .alu .add .ecx (.reg .ecx), .alu .add .ecx (.reg .ecx), - .mov .edx (.reg .eax), .shift .shr .edx 29, .alu .or .ecx (.reg .edx), .bswap .ecx, - .store (at_ .ebx 184) .ecx, - .alu .add .eax (.reg .eax), .alu .add .eax (.reg .eax), .alu .add .eax (.reg .eax), .bswap .eax, - .store (at_ .ebx 188) .eax] - -def finalizeBody : Prog isa := - -- Zero the buffer from `r` to 128, or to 112 in the last block. - .seq (.block [.mov .eax (.imm 128), .alu .test .esi (.reg .esi)]) - (.seq (.ite .e (.block [.mov .eax (.imm 112)]) (.block [])) - (.seq (.block [.mov .ecx (.imm 0), .alu .sub .eax (.reg .edi)]) - (.seq (.ite .e (.block []) - (.loop (.block [.mov .edx (.reg .ebx), .alu .add .edx (.reg .edi), .store8 (at_ .edx 64) .cl, - .alu .add .edi (.imm 1), .alu .sub .eax (.imm 1)]) .ne)) - -- In the last block, the message length. - (.seq (.block [.alu .test .esi (.reg .esi)]) - (.seq (.ite .e (.block lenW) (.block [])) - (.seq (compressAt 20) - (.block [.mov .edi (.imm 0), .alu .sub .esi (.imm 1)]))))))) +/-- The sizes, the length field and the digest. -/ +def params : Params where + N := 64 + B := 128 + L := 16 + so := 224 + len := loadCount 224 ++ [.mov .edx (.imm 0), .store (at_ .ebx 176) .edx, + .mov .edx (.reg .ecx), .shift .shr .edx 29, .bswap .edx, .store (at_ .ebx 180) .edx] ++ len64Of 184 true + out := out64 8 -/-- Word `k` of the final hash value, big-endian, to `out` at `eax`. -/ -def outW (k : Nat) : List Instr := - [.mov .ecx (.mem (at_ .ebx (8 * k))), .mov .edx (.mem (at_ .ebx (8 * k + 4))), .bswap .edx, - .bswap .ecx, .store (at_ .eax (8 * k)) .edx, .store (at_ .eax (8 * k + 4)) .ecx] +def update : Prog isa := MdStream.X86.update params "vg_sha512_compress" compress -def finalize : Prog isa := - .seq (.block ([.mov .eax (.mem (at_ .esp 20))] ++ save ++ - [.mov .ebx (.mem (at_ .esp 4)), .mov .edi (.mem (at_ .esp 8)), .alu .and .edi (.imm 127), - -- The `0x80` byte. - .mov .eax (.reg .ebx), .alu .add .eax (.reg .edi), .mov .ecx (.imm 0x80), - .store8 (at_ .eax 64) .cl, .alu .add .edi (.imm 1), - -- Two blocks if that leaves fewer than 16 bytes for the length (r ≥ 113). - .mov .esi (.imm 0), .alu .cmp .edi (.imm 113)])) - (.seq (.ite .ae (.block [.mov .esi (.imm 1)]) (.block [])) - (.seq (.loop finalizeBody .e) - (.block (.mov .eax (.mem (at_ .esp 16)) :: (List.range 8).flatMap outW ++ - .mov .eax (.mem (at_ .esp 20)) :: restore)))) +def finalize : Prog isa := MdStream.X86.finalize params "vg_sha512_compress" compress end VG.Impl.Sha512.X86.Stream diff --git a/lean/VerifiedGarbage/Proof/Md5/X86/Stream/Md.lean b/lean/VerifiedGarbage/Proof/Md5/X86/Stream/Md.lean index 2db13b563..3058275ce 100644 --- a/lean/VerifiedGarbage/Proof/Md5/X86/Stream/Md.lean +++ b/lean/VerifiedGarbage/Proof/Md5/X86/Stream/Md.lean @@ -25,11 +25,12 @@ open VG VG.X86 VG.Proof.MdStream VG.Proof.MdStream.X86 abbrev params := Impl.Md5.X86.Stream.params -theorem dims : Dims params 112 := ⟨by decide, by decide, by decide⟩ +theorem dims : Dims params 112 := ⟨.inl rfl, by decide, by decide, by decide, by decide⟩ theorem shape : Shape (P := params) md where - len _ hfit hlo hhi ho₁ ho₂ := len64_ok (so := params.so) (d := params.N + 56) (be := false) (by omega) - hlo hhi ho₁ ho₂ + len _ hfit hlo hhi ho := len64_ok (so := params.so) (d := params.N + params.B - params.L) (be := false) + (by have : params.N + params.B - params.L + 8 = params.N + params.B := rfl; omega) hlo hhi + (ho _ (Nat.le_refl _) (by decide)) (ho _ (by decide) (by decide)) out _ hbx hax hin hout hd := by refine (out32_ok (n := 4) false (by decide) hbx hax hin hout hd).mono fun s' ⟨g, rd, wr, m⟩ => ⟨g, rd, wr, ?_⟩ diff --git a/lean/VerifiedGarbage/Proof/MdStream/X86/Common.lean b/lean/VerifiedGarbage/Proof/MdStream/X86/Common.lean index 7fbc39a70..7a6ea2084 100644 --- a/lean/VerifiedGarbage/Proof/MdStream/X86/Common.lean +++ b/lean/VerifiedGarbage/Proof/MdStream/X86/Common.lean @@ -140,12 +140,6 @@ theorem ofNat_add_add (x : BitVec 32) (a b : Nat) : theorem lit32 (n : Nat) : (OfNat.ofNat n : BitVec 32) = BitVec.ofNat 32 n := rfl -theorem and63 (x : BitVec 32) : x &&& 63 = BitVec.ofNat 32 (x.toNat % 64) := by - apply BitVec.eq_of_toNat_eq - simp only [BitVec.toNat_and, BitVec.toNat_ofNat] - rw [show (63 : BitVec 32).toNat = 2 ^ 6 - 1 from rfl, Nat.and_two_pow_sub_one_eq_mod] - omega - theorem toNat_ofNat_lt {k : Nat} (h : k < 2 ^ 32) : (BitVec.ofNat 32 k).toNat = k := by rw [BitVec.toNat_ofNat, Nat.mod_eq_of_lt h] @@ -297,14 +291,62 @@ theorem seq_assoc {M : ISA} {a b c : Prog M} {s : M.State} {Q : M.State → Prop /-! ## Sizes -/ -/-- The sizes the generic proofs support, for a hash value of `N` bytes, a -compression function using `so` bytes of scratch space, and `S` bytes of -scratch space in all: checked for each hash function by `decide`. -/ +/-- The sizes the generic proofs support, for blocks of `B` bytes, a hash +value of `N` bytes, a length field of `L` bytes, a compression function using +`so` bytes of scratch space, and `S` bytes of scratch space in all: checked for +each hash function by `decide`. -/ structure Dims (P : Params) (S : Nat) : Prop where + B : P.B = 64 ∨ P.B = 128 N : 0 < P.N ∧ P.N ≤ 64 + L : 0 < P.L ∧ P.L ≤ 16 so : P.so + 28 ≤ S S : S ≤ 4096 +section +variable {P : Params} {S : Nat} (hd : Dims P S) +include hd + +theorem Dims.pos : 0 < P.B := by rcases hd.B with h | h <;> omega + +theorem Dims.le : P.B ≤ 128 := by rcases hd.B with h | h <;> omega + +theorem Dims.ge : 64 ≤ P.B := by rcases hd.B with h | h <;> omega + +theorem Dims.mod (n : Nat) : n % 2 ^ 64 % P.B = n % P.B := by + rcases hd.B with h | h <;> rw [h] <;> omega + +/-- A byte count modulo `B`, from its low word. -/ +theorem Dims.mod_append (hi lo : BitVec 32) : (hi ++ lo).toNat % P.B = lo.toNat % P.B := by + rw [BitVec.toNat_append, ← Nat.shiftLeft_add_eq_or_of_lt lo.isLt, Nat.shiftLeft_eq] + rcases hd.B with h | h <;> rw [h] <;> omega + +/-- `x mod B`, as `direct`, `update` and `finalize` compute it. -/ +theorem Dims.and (x : BitVec 32) : x &&& BitVec.ofNat 32 (P.B - 1) = BitVec.ofNat 32 (x.toNat % P.B) := by + apply BitVec.eq_of_toNat_eq + simp only [BitVec.toNat_and, BitVec.toNat_ofNat] + rcases hd.B with h | h <;> rw [h] + · rw [show (64 - 1) % 2 ^ 32 = 2 ^ 6 - 1 from rfl, Nat.and_two_pow_sub_one_eq_mod]; omega + · rw [show (128 - 1) % 2 ^ 32 = 2 ^ 7 - 1 from rfl, Nat.and_two_pow_sub_one_eq_mod]; omega + +/-- The shift count of `direct`. -/ +theorem Dims.lg : 1 ≤ Nat.log2 P.B ∧ Nat.log2 P.B ≤ 31 := by + rcases hd.B with h | h <;> rw [h] + · rw [show (64 : Nat) = 2 ^ 6 from rfl, Nat.log2_two_pow]; decide + · rw [show (128 : Nat) = 2 ^ 7 from rfl, Nat.log2_two_pow]; decide + +/-- `a / B`, as `direct` computes it. -/ +theorem Dims.shr {a : Nat} (ha : a < 2 ^ 32) : + BitVec.ofNat 32 a >>> Nat.log2 P.B = BitVec.ofNat 32 (a / P.B) := by + have e : 2 ^ Nat.log2 P.B = P.B := by + rcases hd.B with h | h <;> rw [h] + · rw [show (64 : Nat) = 2 ^ 6 from rfl, Nat.log2_two_pow] + · rw [show (128 : Nat) = 2 ^ 7 from rfl, Nat.log2_two_pow] + apply BitVec.eq_of_toNat_eq + rw [BitVec.toNat_ushiftRight, BitVec.toNat_ofNat, BitVec.toNat_ofNat, Nat.mod_eq_of_lt ha, + Nat.shiftRight_eq_div_pow, e, Nat.mod_eq_of_lt (Nat.lt_of_le_of_lt (Nat.div_le_self _ _) ha)] + +end + theorem restore_eq (P : Params) (b : Reg) : restore P b = [ .mov .ebx (.mem (at_ b P.so)), .mov .esi (.mem (at_ b (P.so + 4))), .mov .edi (.mem (at_ b (P.so + 8))), .mov .ebp (.mem (at_ b (P.so + 12)))] := @@ -331,7 +373,7 @@ and 2 (cdecl: the low word first). -/ def count (s : State) : BitVec 64 := arg s 2 ++ arg s 1 section -variable {P : Params} (H : Md 64 P.N 8) +variable {P : Params} (H : Md P.B P.N P.L) /-- The contract of the compression function `compress(state, blocks, n, scratch)`: updates the hash value at `state` @@ -339,14 +381,14 @@ with the `n` blocks at `blocks`, with `so` bytes of scratch space. -/ def compressK : Contract isa where pre s := let state : Region := ⟨(arg s 0).setWidth 64, P.N⟩ - let blocks : Region := ⟨(arg s 1).setWidth 64, 64 * (arg s 2).toNat⟩ + let blocks : Region := ⟨(arg s 1).setWidth 64, P.B * (arg s 2).toNat⟩ let scratch : Region := ⟨(arg s 3).setWidth 64, P.so⟩ let args : Region := ⟨argAddr s 0, 16⟩ let ret : Region := ⟨(s.gpr .esp).setWidth 64, 4⟩ s.rd = [blocks, args] ∧ s.wr = [state, scratch] ∧ state.Disjoint scratch ∧ blocks.Disjoint state ∧ blocks.Disjoint scratch ∧ args.Disjoint state ∧ args.Disjoint scratch ∧ ret.Disjoint state ∧ ret.Disjoint scratch ∧ - (arg s 0).toNat + P.N ≤ 2 ^ 32 ∧ (arg s 1).toNat + 64 * (arg s 2).toNat ≤ 2 ^ 32 ∧ + (arg s 0).toNat + P.N ≤ 2 ^ 32 ∧ (arg s 1).toNat + P.B * (arg s 2).toNat ≤ 2 ^ 32 ∧ (arg s 3).toNat + P.so ≤ 2 ^ 32 ∧ (s.gpr .esp).toNat + 20 ≤ 2 ^ 32 post s s' := H.stateAt s'.mem ((arg s 0).setWidth 64) = @@ -364,7 +406,7 @@ value, it then represents that message followed by the `len` bytes at memory only while nothing that may alias them is written). -/ def updK : Contract isa where pre s := - let state : Region := ⟨(arg s 0).setWidth 64, P.N + 64⟩ + let state : Region := ⟨(arg s 0).setWidth 64, P.N + P.B⟩ let data : Region := ⟨(arg s 3).setWidth 64, (arg s 4).toNat⟩ let scratch : Region := ⟨(arg s 5).setWidth 64, S⟩ let args : Region := ⟨argAddr s 0, 24⟩ @@ -375,7 +417,7 @@ def updK : Contract isa where args.Disjoint state ∧ args.Disjoint scratch ∧ ret.Disjoint state ∧ ret.Disjoint scratch ∧ stack.Disjoint state ∧ stack.Disjoint scratch ∧ stack.Disjoint data ∧ - (arg s 0).toNat + (P.N + 64) ≤ 2 ^ 32 ∧ (arg s 3).toNat + (arg s 4).toNat ≤ 2 ^ 32 ∧ + (arg s 0).toNat + (P.N + P.B) ≤ 2 ^ 32 ∧ (arg s 3).toNat + (arg s 4).toNat ≤ 2 ^ 32 ∧ (arg s 5).toNat + S ≤ 2 ^ 32 ∧ 20 ≤ (s.gpr .esp).toNat ∧ (s.gpr .esp).toNat + 28 ≤ 2 ^ 32 post s s' := ∀ iv m, H.Repr iv s.mem ((arg s 0).setWidth 64) m → count s = BitVec.ofNat 64 m.length → H.Repr iv s'.mem ((arg s 0).setWidth 64) (m ++ bytesAt s.mem ((arg s 3).setWidth 64) (arg s 4).toNat) @@ -384,43 +426,62 @@ def updK : Contract isa where /-- The contract of `finalize(state, count, out, scratch)`: if the state represents a message of `count` bytes, writes its final hash value to `out` -(`N` bytes). -/ +(`N` bytes). The arguments are only read. -/ def finK : Contract isa where pre s := - let state : Region := ⟨(arg s 0).setWidth 64, P.N + 64⟩ + let state : Region := ⟨(arg s 0).setWidth 64, P.N + P.B⟩ let out : Region := ⟨(arg s 3).setWidth 64, P.N⟩ let scratch : Region := ⟨(arg s 4).setWidth 64, S⟩ let args : Region := ⟨argAddr s 0, 20⟩ let ret : Region := ⟨(s.gpr .esp).setWidth 64, 4⟩ let stack : Region := ⟨(s.gpr .esp).setWidth 64 - 20, 20⟩ - s.rd = [] ∧ s.wr = [state, out, scratch, args] ∧ + s.rd = [args] ∧ s.wr = [state, out, scratch] ∧ state.Disjoint out ∧ state.Disjoint scratch ∧ out.Disjoint scratch ∧ args.Disjoint state ∧ args.Disjoint out ∧ args.Disjoint scratch ∧ ret.Disjoint state ∧ ret.Disjoint out ∧ ret.Disjoint scratch ∧ stack.Disjoint state ∧ stack.Disjoint out ∧ stack.Disjoint scratch ∧ - (arg s 0).toNat + (P.N + 64) ≤ 2 ^ 32 ∧ (arg s 3).toNat + P.N ≤ 2 ^ 32 ∧ + (arg s 0).toNat + (P.N + P.B) ≤ 2 ^ 32 ∧ (arg s 3).toNat + P.N ≤ 2 ^ 32 ∧ (arg s 4).toNat + S ≤ 2 ^ 32 ∧ 20 ≤ (s.gpr .esp).toNat ∧ (s.gpr .esp).toNat + 24 ≤ 2 ^ 32 post s s' := ∀ iv m, H.Repr iv s.mem ((arg s 0).setWidth 64) m → H.lenOk m.length → count s = BitVec.ofNat 64 m.length → bytesAt s'.mem ((arg s 3).setWidth 64) P.N = H.hash iv m pub s₁ s₂ := s₁.gpr .esp = s₂.gpr .esp ∧ ∀ i < 5, arg s₁ i = arg s₂ i +/-- `finK`, but letting `finalize` write its arguments (as the contracts of the +hash functions whose `finalize` is only verified against this say). -/ +def finKw : Contract isa := + { finK H S with + pre := fun s => + let state : Region := ⟨(arg s 0).setWidth 64, P.N + P.B⟩ + let out : Region := ⟨(arg s 3).setWidth 64, P.N⟩ + let scratch : Region := ⟨(arg s 4).setWidth 64, S⟩ + let args : Region := ⟨argAddr s 0, 20⟩ + let ret : Region := ⟨(s.gpr .esp).setWidth 64, 4⟩ + let stack : Region := ⟨(s.gpr .esp).setWidth 64 - 20, 20⟩ + s.rd = [] ∧ s.wr = [state, out, scratch, args] ∧ + state.Disjoint out ∧ state.Disjoint scratch ∧ out.Disjoint scratch ∧ + args.Disjoint state ∧ args.Disjoint out ∧ args.Disjoint scratch ∧ + ret.Disjoint state ∧ ret.Disjoint out ∧ ret.Disjoint scratch ∧ + stack.Disjoint state ∧ stack.Disjoint out ∧ stack.Disjoint scratch ∧ + (arg s 0).toNat + (P.N + P.B) ≤ 2 ^ 32 ∧ (arg s 3).toNat + P.N ≤ 2 ^ 32 ∧ + (arg s 4).toNat + S ≤ 2 ^ 32 ∧ 20 ≤ (s.gpr .esp).toNat ∧ (s.gpr .esp).toNat + 24 ≤ 2 ^ 32 } + end /-! ## What each hash function's own code must do -/ /-- The length field and the digest: `P.len` stores the length field for the byte count in `[ebp + so + 16]` (low word) and `[ebp + so + 20]` (high word) -at `ebx + N + 56`, writing only `eax`, `ecx` and `edx`, and `P.out` writes +at `ebx + N + B - L`, writing only `eax`, `ecx` and `edx`, and `P.out` writes the digest of the hash value at `ebx` to `eax`, writing only `ecx`. -/ -structure Shape {P : Params} (H : Md 64 P.N 8) : Prop where - len : ∀ s : State, (s.gpr .ebx).toNat + (P.N + 64) ≤ 2 ^ 32 → +structure Shape {P : Params} (H : Md P.B P.N P.L) : Prop where + len : ∀ s : State, (s.gpr .ebx).toNat + (P.N + P.B) ≤ 2 ^ 32 → InRegions (s.rd ++ s.wr) (addr (s.gpr .ebp) (P.so + 16)) 4 → InRegions (s.rd ++ s.wr) (addr (s.gpr .ebp) (P.so + 20)) 4 → - InRegions s.wr (addr (s.gpr .ebx) (P.N + 56)) 4 → InRegions s.wr (addr (s.gpr .ebx) (P.N + 60)) 4 → + (∀ d, P.N + P.B - P.L ≤ d → d + 4 ≤ P.N + P.B → InRegions s.wr (addr (s.gpr .ebx) d) 4) → WP isa (.block P.len) s fun s' => (∀ r, r ≠ .eax → r ≠ .ecx → r ≠ .edx → s'.gpr r = s.gpr r) ∧ s'.rd = s.rd ∧ s'.wr = s.wr ∧ - s'.mem = writeBytes s.mem ((s.gpr .ebx).setWidth 64 + BitVec.ofNat 64 (P.N + 56)) + s'.mem = writeBytes s.mem ((s.gpr .ebx).setWidth 64 + BitVec.ofNat 64 (P.N + P.B - P.L)) (H.lenOf (s.mem.readW (addr (s.gpr .ebp) (P.so + 20)) 32 ++ s.mem.readW (addr (s.gpr .ebp) (P.so + 16)) 32)) out : ∀ s : State, (s.gpr .ebx).toNat + P.N ≤ 2 ^ 32 → (s.gpr .eax).toNat + P.N ≤ 2 ^ 32 → @@ -435,7 +496,7 @@ structure Shape {P : Params} (H : Md 64 P.N 8) : Prop where /-- What `compressAt` needs of the compression function it calls: that it is correct, does not touch `esp` but to call, and calls nothing that uses the stack. -/ -structure CalleeOk {P : Params} (H : Md 64 P.N 8) (code : Prog isa) : Prop where +structure CalleeOk {P : Params} (H : Md P.B P.N P.L) (code : Prog isa) : Prop where verified : ∀ s, (compressK H).pre s → ∃ t s', Exec isa code s t s' ∧ abiPreserved s s' ∧ (compressK H).post s s' nosp : NoSp code @@ -448,7 +509,7 @@ theorem stk_eq {E : BitVec 32} (h : 20 ≤ E.toNat) : below E 20 = ⟨E.setWidth theorem arg_eq (s : State) (i : Nat) : arg s i = s.mem.readW (addr (s.gpr .esp) (4 + 4 * i)) 32 := rfl section -variable {P : Params} {H : Md 64 P.N 8} +variable {P : Params} {H : Md P.B P.N P.L} /-- Compressing the `k` blocks at `eax` (`blk`, their number in `ecx`) into the hash value at `st` (in register `sr`), with the scratch space at `scr` @@ -459,15 +520,15 @@ theorem compressFrame_ok {name : String} {code : Prog isa} (hf : CalleeOk H code (hsr : sr ≠ .esp) (hcr : cr ≠ .esp) {s : State} {st scr blk E : BitVec 32} {k : Nat} (hesp : s.gpr .esp = E) (hS : s.gpr sr = st) (hC : s.gpr cr = scr) (heax : s.gpr .eax = blk) (hk : (s.gpr .ecx).toNat = k) - (hE : 20 ≤ E.toNat) (f₀ : st.toNat + P.N ≤ 2 ^ 32) (f₁ : blk.toNat + 64 * k ≤ 2 ^ 32) + (hE : 20 ≤ E.toNat) (f₀ : st.toNat + P.N ≤ 2 ^ 32) (f₁ : blk.toNat + P.B * k ≤ 2 ^ 32) (f₃ : scr.toNat + P.so ≤ 2 ^ 32) (d₁ : Region.Disjoint ⟨st.setWidth 64, P.N⟩ ⟨scr.setWidth 64, P.so⟩) - (d₂ : Region.Disjoint ⟨blk.setWidth 64, 64 * k⟩ ⟨st.setWidth 64, P.N⟩) - (d₃ : Region.Disjoint ⟨blk.setWidth 64, 64 * k⟩ ⟨scr.setWidth 64, P.so⟩) + (d₂ : Region.Disjoint ⟨blk.setWidth 64, P.B * k⟩ ⟨st.setWidth 64, P.N⟩) + (d₃ : Region.Disjoint ⟨blk.setWidth 64, P.B * k⟩ ⟨scr.setWidth 64, P.so⟩) (dS : Region.Disjoint (below E 20) ⟨st.setWidth 64, P.N⟩) (dC : Region.Disjoint (below E 20) ⟨scr.setWidth 64, P.so⟩) - (dB : Region.Disjoint (below E 20) ⟨blk.setWidth 64, 64 * k⟩) - (hc : Covers [⟨blk.setWidth 64, 64 * k⟩] (s.rd ++ s.wr)) + (dB : Region.Disjoint (below E 20) ⟨blk.setWidth 64, P.B * k⟩) + (hc : Covers [⟨blk.setWidth 64, P.B * k⟩] (s.rd ++ s.wr)) (hw : Covers [⟨st.setWidth 64, P.N⟩, ⟨scr.setWidth 64, P.so⟩] s.wr) {Q : State → Prop} (hQ : ∀ s', s'.rd = s.rd → s'.wr = s.wr → (∀ r ∈ calleeSaved, s'.gpr r = s.gpr r) → @@ -495,7 +556,7 @@ theorem compressFrame_ok {name : String} {code : Prog isa} (hf : CalleeOk H code exact this refine WP.callWith (k := compressK H) hf.verified hf.nosp (by simp) hrs (by rw [hf.stack, hesp]; simp only [List.length_cons, List.length_nil]; omega) - (rd := [⟨blk.setWidth 64, 64 * k⟩, ⟨argAddr sE 0, 16⟩]) + (rd := [⟨blk.setWidth 64, P.B * k⟩, ⟨argAddr sE 0, 16⟩]) (wr := [⟨st.setWidth 64, P.N⟩, ⟨scr.setWidth 64, P.so⟩]) ⟨?_, ?_, ?_⟩ fun s' rd' wr' cs' f' ⟨s₂, m₂, post⟩ => ?_ · rw [← hsE] @@ -535,7 +596,7 @@ theorem compressFrame_ok {name : String} {code : Prog isa} (hf : CalleeOk H code have e₂ : H.compressBlocks (H.stateAt s.mem (st.setWidth 64)) sE.mem (blk.setWidth 64) k = H.compressBlocks (H.stateAt s.mem (st.setWidth 64)) s.mem (blk.setWidth 64) k := H.compressBlocks_congr fun j hj => - hsE'.bytes (R := ⟨blk.setWidth 64, 64 * k⟩) (by simpa using dB.symm) (by simp; omega) hj + hsE'.bytes (R := ⟨blk.setWidth 64, P.B * k⟩) (by simpa using dB.symm) (by simp; omega) hj rw [post, e₁, e₂] /-- Compressing the block at `eax` (`blk`) into the hash value at `st` (in @@ -547,15 +608,15 @@ theorem compressAt_ok {name : String} {code : Prog isa} (hf : CalleeOk H code) { (hsr : sr ≠ .esp) (hcr : cr ≠ .esp) (hsr' : sr ≠ .ecx) (hcr' : cr ≠ .ecx) {s : State} {st scr blk E : BitVec 32} (hesp : s.gpr .esp = E) (hS : s.gpr sr = st) (hC : s.gpr cr = scr) (heax : s.gpr .eax = blk) - (hE : 20 ≤ E.toNat) (f₀ : st.toNat + P.N ≤ 2 ^ 32) (f₁ : blk.toNat + 64 ≤ 2 ^ 32) + (hE : 20 ≤ E.toNat) (f₀ : st.toNat + P.N ≤ 2 ^ 32) (f₁ : blk.toNat + P.B ≤ 2 ^ 32) (f₃ : scr.toNat + P.so ≤ 2 ^ 32) (d₁ : Region.Disjoint ⟨st.setWidth 64, P.N⟩ ⟨scr.setWidth 64, P.so⟩) - (d₂ : Region.Disjoint ⟨blk.setWidth 64, 64⟩ ⟨st.setWidth 64, P.N⟩) - (d₃ : Region.Disjoint ⟨blk.setWidth 64, 64⟩ ⟨scr.setWidth 64, P.so⟩) + (d₂ : Region.Disjoint ⟨blk.setWidth 64, P.B⟩ ⟨st.setWidth 64, P.N⟩) + (d₃ : Region.Disjoint ⟨blk.setWidth 64, P.B⟩ ⟨scr.setWidth 64, P.so⟩) (dS : Region.Disjoint (below E 20) ⟨st.setWidth 64, P.N⟩) (dC : Region.Disjoint (below E 20) ⟨scr.setWidth 64, P.so⟩) - (dB : Region.Disjoint (below E 20) ⟨blk.setWidth 64, 64⟩) - (hc : Covers [⟨blk.setWidth 64, 64⟩] (s.rd ++ s.wr)) + (dB : Region.Disjoint (below E 20) ⟨blk.setWidth 64, P.B⟩) + (hc : Covers [⟨blk.setWidth 64, P.B⟩] (s.rd ++ s.wr)) (hw : Covers [⟨st.setWidth 64, P.N⟩, ⟨scr.setWidth 64, P.so⟩] s.wr) {Q : State → Prop} (hQ : ∀ s', s'.rd = s.rd → s'.wr = s.wr → (∀ r ∈ calleeSaved, s'.gpr r = s.gpr r) → @@ -563,6 +624,7 @@ theorem compressAt_ok {name : String} {code : Prog isa} (hf : CalleeOk H code) { H.stateAt s'.mem (st.setWidth 64) = H.compress (H.stateAt s.mem (st.setWidth 64)) (H.blockAt s.mem (blk.setWidth 64)) → Q s') : WP isa (compressAt name code sr cr) s Q := by + rw [← Nat.mul_one P.B] at f₁ d₂ d₃ dB hc unfold compressAt compressWith refine WP.seq (WP.cons (s' := s.setReg .ecx 1) rfl (WP.block_nil ?_)) set s₁ := s.setReg .ecx 1 with hs₁ diff --git a/lean/VerifiedGarbage/Proof/MdStream/X86/Finalize.lean b/lean/VerifiedGarbage/Proof/MdStream/X86/Finalize.lean index c3fedf66b..981bcaec9 100644 --- a/lean/VerifiedGarbage/Proof/MdStream/X86/Finalize.lean +++ b/lean/VerifiedGarbage/Proof/MdStream/X86/Finalize.lean @@ -2,6 +2,7 @@ import VerifiedGarbage.Proof.MdStream.X86.Common import Mathlib.Tactic.Tauto import VerifiedGarbage.Proof.Framework.Offset import VerifiedGarbage.Proof.Framework.Omega +import VerifiedGarbage.Proof.Framework.X86.Inline /-! # Streaming Merkle–Damgård hash functions on x86 (32-bit): `update` @@ -36,7 +37,7 @@ abbrev scr : BitVec 32 := arg s₀ 5 abbrev stA : Addr := (st s₀).setWidth 64 abbrev dA : Addr := (dp s₀).setWidth 64 abbrev scA : Addr := (scr s₀).setWidth 64 -abbrev stR : Region := ⟨stA s₀, P.N + 64⟩ +abbrev stR : Region := ⟨stA s₀, P.N + P.B⟩ abbrev dR : Region := ⟨dA s₀, len s₀⟩ abbrev scR : Region := ⟨scA s₀, S⟩ abbrev argR : Region := ⟨argAddr s₀ 0, 24⟩ @@ -53,7 +54,7 @@ def Saved (m : Mem) : Prop := ∀ p ∈ saved P, m.readW (addr (scr s₀) p.2) 3 end /-- The messages the initial state represents, from `iv`. -/ -def R₀ {P : Params} (H : Md 64 P.N 8) (s₀ : State) (iv : H.HV) (m : List Byte) : Prop := +def R₀ {P : Params} (H : Md P.B P.N P.L) (s₀ : State) (iv : H.HV) (m : List Byte) : Prop := H.Repr iv s₀.mem (stA s₀) m ∧ count s₀ = BitVec.ofNat 64 m.length structure Pre (P : Params) (S : Nat) (s₀ : State) : Prop where @@ -69,14 +70,14 @@ structure Pre (P : Params) (S : Nat) (s₀ : State) : Prop where stk_st : (stkR s₀).Disjoint (stR P s₀) stk_scr : (stkR s₀).Disjoint (scR S s₀) stk_d : (stkR s₀).Disjoint (dR s₀) - st_fit : (st s₀).toNat + (P.N + 64) ≤ 2 ^ 32 + st_fit : (st s₀).toNat + (P.N + P.B) ≤ 2 ^ 32 d_fit : (dp s₀).toNat + len s₀ ≤ 2 ^ 32 scr_fit : (scr s₀).toNat + S ≤ 2 ^ 32 sp_lo : 20 ≤ (esp₀ s₀).toNat sp_fit : (esp₀ s₀).toNat + 28 ≤ 2 ^ 32 section -variable {P : Params} {S : Nat} {H : Md 64 P.N 8} +variable {P : Params} {S : Nat} {H : Md P.B P.N P.L} theorem pre_of {s₀ : State} (h : (updK H S).pre s₀) : Pre P S s₀ := by obtain ⟨h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11, h12, h13, h14, h15, h16, h17⟩ := h @@ -85,14 +86,12 @@ theorem pre_of {s₀ : State} (h : (updK H S).pre s₀) : Pre P S s₀ := by by show (below _ _).Disjoint _; rw [e]; exact h11, by show (below _ _).Disjoint _; rw [e]; exact h12, h13, h14, h15, h16, h17⟩ -theorem cnt_mod (s₀ : State) : cnt s₀ % 64 = (arg s₀ 1).toNat % 64 := by - simp only [cnt, count] - rw [BitVec.toNat_append, ← Nat.shiftLeft_add_eq_or_of_lt (arg s₀ 1).isLt, Nat.shiftLeft_eq] - omega +theorem cnt_mod (hd : Dims P S) (s₀ : State) : cnt s₀ % P.B = (arg s₀ 1).toNat % P.B := + hd.mod_append _ _ -theorem R₀.length {s₀ : State} {iv : H.HV} {m : List Byte} (h : R₀ H s₀ iv m) : cnt s₀ % 64 = m.length % 64 := by - rw [cnt, h.2, BitVec.toNat_ofNat] - omega +theorem R₀.length {s₀ : State} {iv : H.HV} {m : List Byte} (h : R₀ H s₀ iv m) (hd : Dims P S) : + cnt s₀ % P.B = m.length % P.B := by + rw [cnt, h.2, BitVec.toNat_ofNat, hd.mod] theorem len_lt (s₀ : State) : len s₀ < 2 ^ 32 := (arg s₀ 4).isLt @@ -155,31 +154,31 @@ structure Common (P : Params) (S : Nat) (s₀ : State) (c : Nat) (s : State) : P /-- The loop invariant: the state represents the message followed by the first `c` bytes of data. -/ -structure Inv {P : Params} (S : Nat) (H : Md 64 P.N 8) (s₀ : State) (c : Nat) (s : State) : Prop +structure Inv {P : Params} (S : Nat) (H : Md P.B P.N P.L) (s₀ : State) (c : Nat) (s : State) : Prop extends Common P S s₀ c s where - edi : s.gpr .edi = BitVec.ofNat 32 ((cnt s₀ + c) % 64) + edi : s.gpr .edi = BitVec.ofNat 32 ((cnt s₀ + c) % P.B) repr : ∀ iv m, R₀ H s₀ iv m → H.Repr iv s.mem (stA s₀) (m ++ (D s₀).take c) /-- `k ≥ 1` whole blocks are ready at `eax` (the buffer, or the data), and compressing them absorbs the first `c` bytes of data. -/ -structure Pending {P : Params} (S : Nat) (H : Md 64 P.N 8) (s₀ : State) (c k : Nat) (s : State) : Prop +structure Pending {P : Params} (S : Nat) (H : Md P.B P.N P.L) (s₀ : State) (c k : Nat) (s : State) : Prop extends Common P S s₀ c s where edi : s.gpr .edi = 0 ecx : s.gpr .ecx = BitVec.ofNat 32 k k_pos : 0 < k - mod : (cnt s₀ + c) % 64 = 0 + mod : (cnt s₀ + c) % P.B = 0 src : (s.gpr .eax = st s₀ + BitVec.ofNat 32 P.N ∧ k = 1) ∨ - ∃ c₀, s.gpr .eax = dp s₀ + BitVec.ofNat 32 c₀ ∧ c₀ + 64 * k ≤ len s₀ + ∃ c₀, s.gpr .eax = dp s₀ + BitVec.ofNat 32 c₀ ∧ c₀ + P.B * k ≤ len s₀ repr : ∀ iv m, R₀ H s₀ iv m → ∀ mem', H.stateAt mem' (stA s₀) = H.compressBlocks (H.stateAt s.mem (stA s₀)) s.mem ((s.gpr .eax).setWidth 64) k → H.Repr iv mem' (stA s₀) (m ++ (D s₀).take c) /-- All the data is absorbed, and nothing is pending. -/ -def Done {P : Params} (S : Nat) (H : Md 64 P.N 8) (s₀ : State) (s : State) : Prop := +def Done {P : Params} (S : Nat) (H : Md P.B P.N P.L) (s₀ : State) (s : State) : Prop := Inv S H s₀ (len s₀) s ∧ s.gpr .ecx = 0 section -variable {P : Params} {S : Nat} {H : Md 64 P.N 8} +variable {P : Params} {S : Nat} {H : Md P.B P.N P.L} theorem Common.of_gpr {s₀ : State} {c : Nat} {s s' : State} (h : Common P S s₀ c s) (hg : ∀ r ∈ [Reg.ebx, .esp, .ebp, .esi], s'.gpr r = s.gpr r) @@ -247,8 +246,8 @@ theorem saveMem_saved (hd : Dims P S) {s₀ : State} (hp : Pre P S s₀) : Saved theorem prologue_ok (hd : Dims P S) {s₀ : State} (hp : Pre P S s₀) : WP isa (.block (([.mov .eax (.mem (at_ .esp 24))] : List Instr) ++ save P .eax ++ ([.mov .ebx (.mem (at_ .esp 4)), .mov .ebp (.mem (at_ .esp 16)), .mov .esi (.mem (at_ .esp 20)), - .mov .edi (.mem (at_ .esp 8)), .alu .and .edi (.imm 63)] : List Instr))) s₀ (Inv S H s₀ 0) := by - have := hd.so; have := hd.N + .mov .edi (.mem (at_ .esp 8)), .alu .and .edi (.imm (BitVec.ofNat 32 (P.B - 1)))] : List Instr))) s₀ (Inv S H s₀ 0) := by + have := hd.so; have := hd.N; have := hd.le have rin : ∀ d, 4 ≤ d → d + 4 ≤ 28 → InRegions (s₀.rd ++ s₀.wr) (addr (esp₀ s₀) d) 4 := fun d h₁ h₂ => ⟨argR s₀, by simp [hp.rd], hp.arg_in h₁ h₂⟩ have sin : ∀ d, d + 4 ≤ S → InRegions s₀.wr (addr (scr s₀) d) 4 := @@ -311,8 +310,8 @@ theorem prologue_ok (hd : Dims P S) {s₀ : State} (hp : Pre P S s₀) : ld 16 (by omega) (by omega)]; rfl have esi₁₀ : s₁₀.gpr .esi = arg s₀ 4 := by rw [u₁₀.other _ (by decide), u₉.other _ (by decide), u₈.gpr, u₇.mem, u₆.mem, ld 20 (by omega) (by omega)]; rfl - have edi₁₀ : s₁₀.gpr .edi = BitVec.ofNat 32 (cnt s₀ % 64) := by - rw [u₁₀.gpr, u₉.gpr, u₈.mem, u₇.mem, u₆.mem, ld 8 (by omega) (by omega), and63, cnt_mod]; rfl + have edi₁₀ : s₁₀.gpr .edi = BitVec.ofNat 32 (cnt s₀ % P.B) := by + rw [u₁₀.gpr, u₉.gpr, u₈.mem, u₇.mem, u₆.mem, ld 8 (by omega) (by omega), hd.and, cnt_mod hd]; rfl have rd₁₀ : s₁₀.rd = s₀.rd := by rw [u₁₀.rd, u₉.rd, u₈.rd, u₇.rd, u₆.rd, rd₅] have wr₁₀ : s₁₀.wr = s₀.wr := by rw [u₁₀.wr, u₉.wr, u₈.wr, u₇.wr, u₆.wr, wr₅] refine ⟨⟨Nat.zero_le _, rd₁₀, wr₁₀, ebx₁₀, sp₁₀, by rw [ebp₁₀]; simp, ?_, @@ -320,7 +319,7 @@ theorem prologue_ok (hd : Dims P S) {s₀ : State} (hp : Pre P S s₀) : by rw [edi₁₀, Nat.add_zero], fun iv m hm => ?_⟩ · rw [esi₁₀, Nat.sub_zero, len, BitVec.ofNat_toNat, BitVec.setWidth_eq] · rw [List.take_zero, List.append_nil, m₁₀] - exact H.repr_congr (by omega) (fun i hi => frame_bytes (saveMem_frame hd hp) (R := stR P s₀) + exact H.repr_congr hd.pos (fun i hi => frame_bytes (saveMem_frame hd hp) (R := stR P s₀) (by simpa using hp.st_scr) (by simp; omega) hi) hm.1 theorem epilogue_ok (hd : Dims P S) {s₀ : State} (hp : Pre P S s₀) {s : State} (hI : Inv S H s₀ (len s₀) s) : @@ -382,33 +381,29 @@ theorem Common.data {s₀ : State} (hp : Pre P S s₀) {c : Nat} {s : State} (h exact frame_bytes h.frame (R := dR s₀) (by simpa using ⟨hp.d_st, hp.d_scr, hp.stk_d.symm⟩) (by simp only; have := len_lt s₀; omega) hi -theorem length_mid (s₀ : State) {iv : H.HV} {m : List Byte} (hm : R₀ H s₀ iv m) {c : Nat} (hc : c ≤ len s₀) : - (m ++ (D s₀).take c).length % 64 = (cnt s₀ + c) % 64 := by - have := hm.length +theorem length_mid (hd : Dims P S) (s₀ : State) {iv : H.HV} {m : List Byte} (hm : R₀ H s₀ iv m) {c : Nat} + (hc : c ≤ len s₀) : (m ++ (D s₀).take c).length % P.B = (cnt s₀ + c) % P.B := by simp only [List.length_append, List.length_take, D_length, Nat.min_eq_left hc] - omega + rw [Nat.add_mod, ← hm.length hd, ← Nat.add_mod] theorem take_add_data (s₀ : State) (c t : Nat) (m : List Byte) : m ++ (D s₀).take c ++ ((D s₀).drop c).take t = m ++ (D s₀).take (c + t) := by rw [List.take_add, List.append_assoc] -theorem ofNat_shr6 {a : Nat} (h : a < 2 ^ 32) : BitVec.ofNat 32 a >>> 6 = BitVec.ofNat 32 (a / 64) := by - apply BitVec.eq_of_toNat_eq - rw [BitVec.toNat_ushiftRight, BitVec.toNat_ofNat, BitVec.toNat_ofNat, Nat.mod_eq_of_lt h, - Nat.shiftRight_eq_div_pow, Nat.mod_eq_of_lt (by omega)] - /-- Every whole block left, straight from the data. -/ -theorem direct_ok {s₀ : State} (hp : Pre P S s₀) {c : Nat} {s : State} (hI : Inv S H s₀ c s) - (hr : (cnt s₀ + c) % 64 = 0) (hl : 64 ≤ len s₀ - c) : - WP isa (.block direct) s (Pending S H s₀ (c + 64 * ((len s₀ - c) / 64)) ((len s₀ - c) / 64)) := by - have hd := hp.d_fit; have hc := hI.c_le; have hlen := len_lt s₀ - generalize hq : (len s₀ - c) / 64 = q - have hq1 : 1 ≤ q := by omega - have hq2 : (len s₀ - c) - (len s₀ - c) % 64 = 64 * q := by omega +theorem direct_ok (hd : Dims P S) {s₀ : State} (hp : Pre P S s₀) {c : Nat} {s : State} (hI : Inv S H s₀ c s) + (hr : (cnt s₀ + c) % P.B = 0) (hl : P.B ≤ len s₀ - c) : + WP isa (.block (direct P)) s (Pending S H s₀ (c + P.B * ((len s₀ - c) / P.B)) ((len s₀ - c) / P.B)) := by + have hdf := hp.d_fit; have hc := hI.c_le; have hlen := len_lt s₀; have hB := hd.pos + have hq1 : 1 ≤ (len s₀ - c) / P.B := (Nat.le_div_iff_mul_le hB).mpr (by omega) + have hdm := Nat.div_add_mod (len s₀ - c) P.B + have hml := Nat.mod_lt (len s₀ - c) hB + generalize hq : (len s₀ - c) / P.B = q at hq1 hdm + have hq2 : (len s₀ - c) - (len s₀ - c) % P.B = P.B * q := by omega unfold direct refine wp_mov fun s₁ u₁ => wp_mov fun s₂ u₂ => wp_andi fun s₃ u₃ => wp_mov fun s₄ u₄ => wp_sub fun s₅ u₅ _ => wp_add fun s₆ u₆ => wp_mov fun s₇ u₇ => wp_mov fun s₈ u₈ => - wp_shr (by decide) fun s₉ u₉ => WP.block_nil ?_ + wp_shr hd.lg fun s₉ u₉ => WP.block_nil ?_ have g : ∀ r, r ≠ .eax → r ≠ .ecx → r ≠ .edx → r ≠ .ebp → r ≠ .esi → s₉.gpr r = s.gpr r := fun r h1 h2 h3 h4 h5 => by rw [u₉.other r h2, u₈.other r h2, u₇.other r h5, u₆.other r h4, u₅.other r h3, u₄.other r h3, @@ -419,18 +414,19 @@ theorem direct_ok {s₀ : State} (hp : Pre P S s₀) {c : Nat} {s : State} (hI : rw [u₉.other _ (by decide), u₈.other _ (by decide), u₇.other _ (by decide), u₆.other _ (by decide), u₅.other _ (by decide), u₄.other _ (by decide), u₃.other _ (by decide), u₂.other _ (by decide), u₁.gpr, hI.ebp] - have h3 : s₃.gpr .ecx = BitVec.ofNat 32 ((len s₀ - c) % 64) := by - rw [u₃.gpr, u₂.gpr, u₁.other _ (by decide), hI.esi, and63, toNat_ofNat_lt (by omega)] - have h5 : s₅.gpr .edx = BitVec.ofNat 32 (64 * q) := by + have h3 : s₃.gpr .ecx = BitVec.ofNat 32 ((len s₀ - c) % P.B) := by + rw [u₃.gpr, u₂.gpr, u₁.other _ (by decide), hI.esi, hd.and, toNat_ofNat_lt (by omega)] + have h5 : s₅.gpr .edx = BitVec.ofNat 32 (P.B * q) := by rw [u₅.gpr, u₄.gpr, u₄.other _ (by decide), h3, u₃.other _ (by decide), u₂.other _ (by decide), u₁.other _ (by decide), hI.esi, sub_ofNat (by omega), hq2] - have h6 : s₆.gpr .edx = BitVec.ofNat 32 (64 * q) := by rw [u₆.other _ (by decide), h5] + have h6 : s₆.gpr .edx = BitVec.ofNat 32 (P.B * q) := by rw [u₆.other _ (by decide), h5] refine ⟨⟨by omega, ?_, ?_, by rw [g _ (by decide) (by decide) (by decide) (by decide) (by decide), hI.ebx], by rw [g _ (by decide) (by decide) (by decide) (by decide) (by decide), hI.esp], ?_, ?_, by rw [hm]; exact hI.frame, by rw [hm]; exact hI.saved⟩, by rw [g _ (by decide) (by decide) (by decide) (by decide) (by decide), hI.edi, hr]; rfl, - ?_, hq1, by omega, .inr ⟨c, heax, by omega⟩, fun iv m hm₀ mem' hs => ?_⟩ + ?_, hq1, by rw [← Nat.add_assoc, Nat.add_mul_mod_self_left]; exact hr, .inr ⟨c, heax, by omega⟩, + fun iv m hm₀ mem' hs => ?_⟩ · rw [u₉.rd, u₈.rd, u₇.rd, u₆.rd, u₅.rd, u₄.rd, u₃.rd, u₂.rd, u₁.rd, hI.rd] · rw [u₉.wr, u₈.wr, u₇.wr, u₆.wr, u₅.wr, u₄.wr, u₃.wr, u₂.wr, u₁.wr, hI.wr] · rw [u₉.other _ (by decide), u₈.other _ (by decide), u₇.other _ (by decide), u₆.gpr, h5, @@ -439,11 +435,10 @@ theorem direct_ok {s₀ : State} (hp : Pre P S s₀) {c : Nat} {s : State} (hI : · rw [u₉.other _ (by decide), u₈.other _ (by decide), u₇.gpr, u₆.other _ (by decide), u₅.other _ (by decide), u₄.other _ (by decide), h3] congr 1; omega - · rw [u₉.gpr, u₈.gpr, u₇.other _ (by decide), h6, ofNat_shr6 (by omega)] - congr 1; omega - · have hmod := length_mid s₀ hm₀ (c := c) (by omega) + · rw [u₉.gpr, u₈.gpr, u₇.other _ (by decide), h6, hd.shr (by omega), Nat.mul_div_cancel_left q hB] + · have hmod := length_mid hd s₀ hm₀ (c := c) (by omega) rw [← take_add_data] - refine H.repr_append_blocks (n := q) (by omega) (hI.repr iv m hm₀) (by rw [hmod, hr]) + refine H.repr_append_blocks (n := q) hB (hI.repr iv m hm₀) (by rw [hmod, hr]) (by rw [List.length_take, List.length_drop, D_length]; omega) ?_ rw [hs, hm, heax, show (dp s₀ + BitVec.ofNat 32 c).setWidth 64 = addr (dp s₀) c from rfl, addr_eq (by omega)] @@ -455,16 +450,18 @@ theorem direct_ok {s₀ : State} (hp : Pre P S s₀) {c : Nat} {s : State} (hI : /-! ## Compressing -/ -theorem Pending.k_lt {s₀ : State} {c k : Nat} {s : State} (h : Pending S H s₀ c k s) : k < 2 ^ 32 := by - have := len_lt s₀ +theorem Pending.k_lt (hd : Dims P S) {s₀ : State} {c k : Nat} {s : State} (h : Pending S H s₀ c k s) : + k < 2 ^ 32 := by + have := len_lt s₀; have := Nat.le_mul_of_pos_left k hd.pos rcases h.src with ⟨_, rfl⟩ | ⟨c₀, _, hc₀⟩ <;> omega /-- The blocks to compress. -/ -theorem Pending.blk {s₀ : State} (hp : Pre P S s₀) {c k : Nat} {s : State} (h : Pending S H s₀ c k s) : - (s.gpr .eax).toNat + 64 * k ≤ 2 ^ 32 ∧ +theorem Pending.blk (hd : Dims P S) {s₀ : State} (hp : Pre P S s₀) {c k : Nat} {s : State} (h : Pending S H s₀ c k s) : + (s.gpr .eax).toNat + P.B * k ≤ 2 ^ 32 ∧ (((s.gpr .eax).setWidth 64 = stA s₀ + BitVec.ofNat 64 P.N ∧ k = 1) ∨ - ∃ c₀, (s.gpr .eax).setWidth 64 = dA s₀ + BitVec.ofNat 64 c₀ ∧ c₀ + 64 * k ≤ len s₀) := by - have hst := hp.st_fit; have hd := hp.d_fit; have := h.k_pos + ∃ c₀, (s.gpr .eax).setWidth 64 = dA s₀ + BitVec.ofNat 64 c₀ ∧ c₀ + P.B * k ≤ len s₀) := by + have hst := hp.st_fit; have hdf := hp.d_fit; have := h.k_pos; have := hd.pos + have := Nat.le_mul_of_pos_left k hd.pos rcases h.src with ⟨h', rfl⟩ | ⟨c₀, h', hc₀⟩ · refine ⟨by rw [h', BitVec.toNat_add, toNat_ofNat_lt (by omega), Nat.mod_eq_of_lt (by omega)]; omega, .inl ⟨?_, rfl⟩⟩ @@ -474,10 +471,10 @@ theorem Pending.blk {s₀ : State} (hp : Pre P S s₀) {c k : Nat} {s : State} ( rw [h']; exact addr_eq (by omega) /-- The blocks lie in the state or in the data. -/ -theorem Pending.blk_sub {s₀ : State} (hp : Pre P S s₀) {c k : Nat} {s : State} (h : Pending S H s₀ c k s) : - Region.Sub ⟨(s.gpr .eax).setWidth 64, 64 * k⟩ (stR P s₀) ∨ - Region.Sub ⟨(s.gpr .eax).setWidth 64, 64 * k⟩ (dR s₀) := by - rcases (h.blk hp).2 with ⟨he, rfl⟩ | ⟨c₀, he, hc₀⟩ +theorem Pending.blk_sub (hd : Dims P S) {s₀ : State} (hp : Pre P S s₀) {c k : Nat} {s : State} (h : Pending S H s₀ c k s) : + Region.Sub ⟨(s.gpr .eax).setWidth 64, P.B * k⟩ (stR P s₀) ∨ + Region.Sub ⟨(s.gpr .eax).setWidth 64, P.B * k⟩ (dR s₀) := by + rcases (h.blk hd hp).2 with ⟨he, rfl⟩ | ⟨c₀, he, hc₀⟩ · exact .inl (by rw [he]; exact sub_offset (by omega) (by have := hp.st_fit; omega)) · exact .inr (by rw [he]; exact sub_offset hc₀ (by have := len_lt s₀; omega)) @@ -486,11 +483,11 @@ theorem Pending.compress_ok (hd : Dims P S) {name : String} {code : Prog isa} (h {s₀ : State} (hp : Pre P S s₀) {c k : Nat} {s s₁ : State} (h : Pending S H s₀ c k s) (u : Upd s s₁ .edx (scr s₀)) : WP isa (compressN name code .ebx .edx) s₁ (Inv S H s₀ c) := by have hst := hp.st_fit; have hsc := hp.scr_fit; have := hd.so; have := hd.N - obtain ⟨hbf, hb⟩ := h.blk hp - have hbs := h.blk_sub hp + obtain ⟨hbf, hb⟩ := h.blk hd hp + have hbs := h.blk_sub hd hp have eN : Region.Sub ⟨stA s₀, P.N⟩ (stR P s₀) := Region.sub_prefix (by omega) have eso : Region.Sub ⟨scA s₀, P.so⟩ (scR S s₀) := Region.sub_prefix (by omega) - have hk : (s₁.gpr .ecx).toNat = k := by rw [u.other _ (by decide), h.ecx, toNat_ofNat_lt h.k_lt] + have hk : (s₁.gpr .ecx).toNat = k := by rw [u.other _ (by decide), h.ecx, toNat_ofNat_lt (h.k_lt hd)] unfold compressN compressWith refine WP.seq (WP.block_nil ?_) refine compressFrame_ok hf (st := st s₀) (scr := scr s₀) (blk := s.gpr .eax) (E := esp₀ s₀) @@ -559,11 +556,11 @@ theorem Pending.congr {s₀ : State} {c k : Nat} {s s' : State} (h : Pending S H end /-- The loop's postcondition for one iteration from `c` bytes. -/ -def Step {P : Params} (S : Nat) (H : Md 64 P.N 8) (s₀ : State) (c : Nat) (s : State) : Prop := +def Step {P : Params} (S : Nat) (H : Md P.B P.N P.L) (s₀ : State) (c : Nat) (s : State) : Prop := (eval .ne s = some false ∧ Inv S H s₀ (len s₀) s) ∨ (eval .ne s = some true ∧ ∃ c', c < c' ∧ Inv S H s₀ c' s) section -variable {P : Params} {S : Nat} {H : Md 64 P.N 8} +variable {P : Params} {S : Nat} {H : Md P.B P.N P.L} /-- The second half of the loop body: compress if a block is ready, and loop back if so. -/ @@ -578,7 +575,7 @@ theorem tail_ok (hd : Dims P S) {name : String} {code : Prog isa} (hf : CalleeOk · refine WP.seq (wp_test fun s₂ f₂ z₂ => WP.block_nil ?_) have hP₂ : Pending S H s₀ c' k s₂ := hP.congr f₂.gpr f₂.mem f₂.rd f₂.wr have hz : s₂.zf = some false := by - rw [z₂, hP.ecx, BitVec.and_self, ofNat_beq_zero hP.k_lt, decide_eq_false (Nat.pos_iff_ne_zero.mp hP.k_pos)] + rw [z₂, hP.ecx, BitVec.and_self, ofNat_beq_zero (hP.k_lt hd), decide_eq_false (Nat.pos_iff_ne_zero.mp hP.k_pos)] refine WP.ite true (by show s₂.zf.map (!·) = _; rw [hz]; rfl) (fun _ => ?_) (fun h => by cases h) refine WP.seq (wp_movm (a := addr (esp₀ s₀) 24) (by rw [ea_at, hP₂.esp]) ⟨argR s₀, by simp [hP₂.rd, hp.rd], hp.arg_in (by omega) (by omega)⟩ fun s₃ u₃ => WP.block_nil ?_) @@ -602,57 +599,58 @@ end section variable (P : Params) (s₀ : State) (c : Nat) /-- Bytes in the buffer before this iteration. -/ -abbrev rr : Nat := (cnt s₀ + c) % 64 +abbrev rr : Nat := (cnt s₀ + c) % P.B /-- Bytes copied into the buffer in this iteration. -/ -abbrev tt : Nat := min (64 - rr s₀ c) (len s₀ - c) +abbrev tt : Nat := min (P.B - rr P s₀ c) (len s₀ - c) /-- Where they go. -/ -abbrev q : Addr := stA s₀ + BitVec.ofNat 64 (P.N + rr s₀ c) +abbrev q : Addr := stA s₀ + BitVec.ofNat 64 (P.N + rr P s₀ c) /-- The data copied. -/ -abbrev xs : List Byte := ((D s₀).drop c).take (tt s₀ c) +abbrev xs : List Byte := ((D s₀).drop c).take (tt P s₀ c) end -theorem rr_lt (s₀ : State) (c : Nat) : rr s₀ c < 64 := Nat.mod_lt _ (by omega) -theorem rr_eq (s₀ : State) (c : Nat) : rr s₀ c = (cnt s₀ + c) % 64 := rfl -theorem tt_eq (s₀ : State) (c : Nat) : tt s₀ c = min (64 - rr s₀ c) (len s₀ - c) := rfl -theorem tt_le (s₀ : State) (c : Nat) : tt s₀ c ≤ len s₀ - c := Nat.min_le_right _ _ -theorem tt_le' (s₀ : State) (c : Nat) : tt s₀ c ≤ 64 - rr s₀ c := Nat.min_le_left _ _ +theorem rr_lt {P : Params} {S : Nat} (hd : Dims P S) (s₀ : State) (c : Nat) : rr P s₀ c < P.B := + Nat.mod_lt _ hd.pos +theorem rr_eq (P : Params) (s₀ : State) (c : Nat) : rr P s₀ c = (cnt s₀ + c) % P.B := rfl +theorem tt_eq (P : Params) (s₀ : State) (c : Nat) : tt P s₀ c = min (P.B - rr P s₀ c) (len s₀ - c) := rfl +theorem tt_le (P : Params) (s₀ : State) (c : Nat) : tt P s₀ c ≤ len s₀ - c := Nat.min_le_right _ _ +theorem tt_le' (P : Params) (s₀ : State) (c : Nat) : tt P s₀ c ≤ P.B - rr P s₀ c := Nat.min_le_left _ _ -theorem xs_length (s₀ : State) (c : Nat) : (xs s₀ c).length = tt s₀ c := by - have := tt_le s₀ c +theorem xs_length (P : Params) (s₀ : State) (c : Nat) : (xs P s₀ c).length = tt P s₀ c := by + have := tt_le P s₀ c simp only [xs, List.length_take, List.length_drop, D_length]; omega /-- The state while copying: `j` bytes copied, into memory `mI` otherwise unchanged. -/ structure Copy (P : Params) (s₀ : State) (c : Nat) (mI : Mem) (j : Nat) (s : State) : Prop where - j_le : j ≤ tt s₀ c + j_le : j ≤ tt P s₀ c rd : s.rd = s₀.rd wr : s.wr = s₀.wr ebx : s.gpr .ebx = st s₀ esp : s.gpr .esp = esp₀ s₀ ebp : s.gpr .ebp = dp s₀ + BitVec.ofNat 32 (c + j) - esi : s.gpr .esi = BitVec.ofNat 32 (len s₀ - c - tt s₀ c) - edi : s.gpr .edi = st s₀ + BitVec.ofNat 32 (rr s₀ c + j) - eax : s.gpr .eax = BitVec.ofNat 32 (tt s₀ c - j) - mem : s.mem = writeBytes mI (q P s₀ c) ((xs s₀ c).take j) + esi : s.gpr .esi = BitVec.ofNat 32 (len s₀ - c - tt P s₀ c) + edi : s.gpr .edi = st s₀ + BitVec.ofNat 32 (rr P s₀ c + j) + eax : s.gpr .eax = BitVec.ofNat 32 (tt P s₀ c - j) + mem : s.mem = writeBytes mI (q P s₀ c) ((xs P s₀ c).take j) section -variable {P : Params} {S : Nat} {H : Md 64 P.N 8} +variable {P : Params} {S : Nat} {H : Md P.B P.N P.L} theorem write_frame (hd : Dims P S) {s₀ : State} (hp : Pre P S s₀) (c : Nat) (mI : Mem) (j : Nat) - (hj : j ≤ tt s₀ c) : Frame [stR P s₀] mI (writeBytes mI (q P s₀ c) ((xs s₀ c).take j)) := by - have := tt_le' s₀ c; have := rr_lt s₀ c; have := hp.st_fit; have := hd.N + (hj : j ≤ tt P s₀ c) : Frame [stR P s₀] mI (writeBytes mI (q P s₀ c) ((xs P s₀ c).take j)) := by + have := tt_le' P s₀ c; have := rr_lt hd s₀ c; have := hp.st_fit; have := hd.N refine writeBytes_frame _ _ _ ?_ simp only [q] exact contains_offset (by simp only [List.length_take]; omega) (by omega) theorem copy_step (hd : Dims P S) {s₀ : State} (hp : Pre P S s₀) {c : Nat} {sI : State} (hI : Inv S H s₀ c sI) - {j : Nat} (hj : j < tt s₀ c) {s : State} (h : Copy P s₀ c sI.mem j s) : + {j : Nat} (hj : j < tt P s₀ c) {s : State} (h : Copy P s₀ c sI.mem j s) : WP isa (.block [.movzx8 .ecx (at_ .ebp 0), .store8 (at_ .edi P.N) .cl, .alu .add .ebp (.imm 1), .alu .add .edi (.imm 1), .alu .sub .eax (.imm 1)]) s fun s' => - Copy P s₀ c sI.mem (j + 1) s' ∧ s'.zf = some (decide (tt s₀ c - (j + 1) = 0)) := by + Copy P s₀ c sI.mem (j + 1) s' ∧ s'.zf = some (decide (tt P s₀ c - (j + 1) = 0)) := by have hdf := hp.d_fit; have hst := hp.st_fit; have := hd.N have hc := hI.c_le - have hr := rr_lt s₀ c - have ht := tt_le s₀ c; have ht' := tt_le' s₀ c + have hr := rr_lt hd s₀ c + have ht := tt_le P s₀ c; have ht' := tt_le' P s₀ c -- The byte read. have ea₁ : s.ea (at_ .ebp 0) = dA s₀ + BitVec.ofNat 64 (c + j) := by rw [ea_at, h.ebp, addr_add_ofNat (by omega), Nat.add_zero] @@ -663,7 +661,7 @@ theorem copy_step (hd : Dims P S) {s₀ : State} (hp : Pre P S s₀) {c : Nat} { exact frame_bytes (write_frame hd hp c sI.mem j h.j_le) (R := dR s₀) (by simpa using hp.d_st) (by show len s₀ ≤ 2 ^ 64; omega) (by show c + j < len s₀; omega) -- The byte written. - have ea₂ : ∀ t : State, t.gpr .edi = st s₀ + BitVec.ofNat 32 (rr s₀ c + j) → + have ea₂ : ∀ t : State, t.gpr .edi = st s₀ + BitVec.ofNat 32 (rr P s₀ c + j) → t.ea (at_ .edi P.N) = q P s₀ c + BitVec.ofNat 64 j := by intro t ht rw [ea_at, ht, addr_add_ofNat (by omega), q, BitVec.add_assoc, ← BitVec.ofNat_add] @@ -671,14 +669,14 @@ theorem copy_step (hd : Dims P S) {s₀ : State} (hp : Pre P S s₀) {c : Nat} { have hout : InRegions s.wr (q P s₀ c + BitVec.ofNat 64 j) 1 := ⟨stR P s₀, by simp [h.wr, hp.wr], by simp only [q]; rw [BitVec.add_assoc, ← BitVec.ofNat_add]; exact contains_offset (by omega) (by omega)⟩ - have hxs := xs_length s₀ c + have hxs := xs_length P s₀ c refine wp_movzx8 (d := .ecx) ea₁ hin fun s₁ u₁ => ?_ refine wp_store8 (r := .cl) (a := q P s₀ c + BitVec.ofNat 64 j) (ea₂ s₁ (by rw [u₁.other _ (by decide), h.edi])) (by rw [u₁.wr]; exact hout) fun s₂ u₂ => ?_ refine wp_addi fun s₃ u₃ => wp_addi fun s₄ u₄ => wp_subi fun s₅ u₅ hz₅ => WP.block_nil ?_ have g : ∀ r, r ≠ .eax → r ≠ .edi → r ≠ .ebp → r ≠ .ecx → s₅.gpr r = s.gpr r := fun r h1 h2 h3 h4 => by rw [u₅.other r h1, u₄.other r h2, u₃.other r h3, u₂.gpr, u₁.other r h4] - have hrax : s₅.gpr .eax = BitVec.ofNat 32 (tt s₀ c - (j + 1)) := by + have hrax : s₅.gpr .eax = BitVec.ofNat 32 (tt P s₀ c - (j + 1)) := by rw [u₅.gpr, u₄.other .eax (by decide), u₃.other .eax (by decide), u₂.gpr, u₁.other .eax (by decide), h.eax, ofNat_pred (by omega), Nat.sub_sub] refine ⟨⟨by omega, ?_, ?_, ?_, ?_, ?_, ?_, ?_, hrax, ?_⟩, ?_⟩ @@ -691,46 +689,47 @@ theorem copy_step (hd : Dims P S) {s₀ : State} (hp : Pre P S s₀) {c : Nat} { · rw [g .esi (by decide) (by decide) (by decide) (by decide), h.esi] · rw [u₅.other .edi (by decide), u₄.gpr, u₃.other .edi (by decide), u₂.gpr, u₁.other .edi (by decide), h.edi, lit32, ofNat_add_add, Nat.add_assoc] - · have hj' : j < (xs s₀ c).length := by omega + · have hj' : j < (xs P s₀ c).length := by omega have hv : BitVec.setWidth 8 (s₁.gpr Reg8.cl.reg) = (D s₀).getD (c + j) 0 := by rw [show Reg8.cl.reg = Reg.ecx from rfl, u₁.gpr, BitVec.setWidth_setWidth_of_le _ (by omega), BitVec.setWidth_eq, hbyte] rw [u₅.mem, u₄.mem, u₃.mem, u₂.mem, u₁.mem, hv, h.mem, List.take_add_one, List.getElem?_eq_getElem hj', Option.toList_some, writeBytes_snoc _ _ _ _ (by simp only [List.length_take]; omega)] - have hl : (List.take j (xs s₀ c)).length = j := by rw [List.length_take, Nat.min_eq_left (Nat.le_of_lt hj')] + have hl : (List.take j (xs P s₀ c)).length = j := by rw [List.length_take, Nat.min_eq_left (Nat.le_of_lt hj')] rw [hl] congr 1 simp only [xs, List.getElem_take, List.getElem_drop, List.getD_eq_getElem?_getD, List.getElem?_eq_getElem (show c + j < (D s₀).length by rw [D_length]; omega), Option.getD_some] · rw [hz₅, u₄.other .eax (by decide), u₃.other .eax (by decide), u₂.gpr, u₁.other .eax (by decide), h.eax, - ofNat_pred (by omega), ofNat_beq_zero (by omega), show tt s₀ c - j - 1 = tt s₀ c - (j + 1) by omega] + ofNat_pred (by omega), ofNat_beq_zero (by omega), show tt P s₀ c - j - 1 = tt P s₀ c - (j + 1) by omega] theorem copy_loop_ok (hd : Dims P S) {s₀ : State} (hp : Pre P S s₀) {c : Nat} {sI : State} (hI : Inv S H s₀ c sI) - {s : State} (h : Copy P s₀ c sI.mem 0 s) (ht : 0 < tt s₀ c) : + {s : State} (h : Copy P s₀ c sI.mem 0 s) (ht : 0 < tt P s₀ c) : WP isa (.loop (.block [.movzx8 .ecx (at_ .ebp 0), .store8 (at_ .edi P.N) .cl, .alu .add .ebp (.imm 1), .alu .add .edi (.imm 1), .alu .sub .eax (.imm 1)]) .ne) s - (Copy P s₀ c sI.mem (tt s₀ c)) := by - refine WP.loop (M := isa) (fun n s => ∃ j, n = tt s₀ c - j ∧ j < tt s₀ c ∧ Copy P s₀ c sI.mem j s) - ?_ (tt s₀ c) s ⟨0, rfl, ht, h⟩ + (Copy P s₀ c sI.mem (tt P s₀ c)) := by + refine WP.loop (M := isa) (fun n s => ∃ j, n = tt P s₀ c - j ∧ j < tt P s₀ c ∧ Copy P s₀ c sI.mem j s) + ?_ (tt P s₀ c) s ⟨0, rfl, ht, h⟩ rintro n s ⟨j, rfl, hj, hc⟩ refine WP.mono (copy_step hd hp hI hj hc) fun s' ⟨hc', hz⟩ => ?_ - by_cases hl : tt s₀ c - (j + 1) = 0 + by_cases hl : tt P s₀ c - (j + 1) = 0 · refine .inl ⟨by show s'.zf.map (!·) = _; rw [hz]; simp [hl], ?_⟩ - rwa [show j + 1 = tt s₀ c by omega] at hc' + rwa [show j + 1 = tt P s₀ c by omega] at hc' · exact .inr ⟨by show s'.zf.map (!·) = _; rw [hz]; simp [hl], _, by omega, j + 1, rfl, by omega, hc'⟩ /-- The memory after copying `tt` bytes. -/ theorem copied_facts (hd : Dims P S) {s₀ : State} (hp : Pre P S s₀) {c : Nat} {sI : State} (hI : Inv S H s₀ c sI) : - let mem := writeBytes sI.mem (q P s₀ c) (xs s₀ c) + let mem := writeBytes sI.mem (q P s₀ c) (xs P s₀ c) Frame [stR P s₀, scR S s₀, stkR s₀] s₀.mem mem ∧ Saved P s₀ mem ∧ H.stateAt mem (stA s₀) = H.stateAt sI.mem (stA s₀) ∧ - bytesAt mem (buf P s₀) (rr s₀ c + tt s₀ c) = bytesAt sI.mem (buf P s₀) (rr s₀ c) ++ xs s₀ c := by + bytesAt mem (buf P s₀) (rr P s₀ c + tt P s₀ c) = bytesAt sI.mem (buf P s₀) (rr P s₀ c) ++ xs P s₀ c := by intro mem - have hr := rr_lt s₀ c; have ht' := tt_le' s₀ c; have := hd.N; have := hd.so; have := hd.S - have hxs := xs_length s₀ c + have hr := rr_lt hd s₀ c; have ht' := tt_le' P s₀ c; have := hd.N; have := hd.so; have := hd.S + have := hd.le + have hxs := xs_length P s₀ c have hf : Frame [stR P s₀] sI.mem mem := by - have := write_frame hd hp c sI.mem (tt s₀ c) (Nat.le_refl _) + have := write_frame hd hp c sI.mem (tt P s₀ c) (Nat.le_refl _) rwa [List.take_of_length_le (by omega)] at this have word : ∀ (R : Region), R.Disjoint (stR P s₀) → R.Contains R.base 4 → mem.readW R.base 32 = sI.mem.readW R.base 32 := fun R hR hc => @@ -742,8 +741,8 @@ theorem copied_facts (hd : Dims P S) {s₀ : State} (hp : Pre P S s₀) {c : Nat · apply H.stateAt_congr intro i hi exact writeBytes_before _ _ _ (by omega) (by omega) - · show bytesAt (writeBytes sI.mem (q P s₀ c) (xs s₀ c)) (buf P s₀) (rr s₀ c + tt s₀ c) = _ - rw [← hxs, show q P s₀ c = buf P s₀ + BitVec.ofNat 64 (rr s₀ c) by + · show bytesAt (writeBytes sI.mem (q P s₀ c) (xs P s₀ c)) (buf P s₀) (rr P s₀ c + tt P s₀ c) = _ + rw [← hxs, show q P s₀ c = buf P s₀ + BitVec.ofNat 64 (rr P s₀ c) by simp only [q, buf]; rw [add_ofNat]] exact bytesAt_writeBytes _ _ _ _ (by omega) @@ -753,11 +752,11 @@ structure Copied (P : Params) (s₀ : State) (c : Nat) (mI : Mem) (s : State) : wr : s.wr = s₀.wr ebx : s.gpr .ebx = st s₀ esp : s.gpr .esp = esp₀ s₀ - ebp : s.gpr .ebp = dp s₀ + BitVec.ofNat 32 (c + tt s₀ c) - esi : s.gpr .esi = BitVec.ofNat 32 (len s₀ - c - tt s₀ c) - mem : s.mem = writeBytes mI (q P s₀ c) (xs s₀ c) + ebp : s.gpr .ebp = dp s₀ + BitVec.ofNat 32 (c + tt P s₀ c) + esi : s.gpr .esi = BitVec.ofNat 32 (len s₀ - c - tt P s₀ c) + mem : s.mem = writeBytes mI (q P s₀ c) (xs P s₀ c) -theorem Copy.copied {s₀ : State} {c : Nat} {mI : Mem} {s : State} (h : Copy P s₀ c mI (tt s₀ c) s) : +theorem Copy.copied {s₀ : State} {c : Nat} {mI : Mem} {s : State} (h : Copy P s₀ c mI (tt P s₀ c) s) : Copied P s₀ c mI s := ⟨h.rd, h.wr, h.ebx, h.esp, h.ebp, h.esi, by rw [h.mem, List.take_of_length_le (by rw [xs_length])]⟩ @@ -771,11 +770,11 @@ theorem Copied.of_gpr {s₀ : State} {c : Nat} {mI : Mem} {s s' : State} (h : Co /-- A full buffer: compress it. -/ theorem fill_pending (hd : Dims P S) {s₀ : State} (hp : Pre P S s₀) {c : Nat} {sI : State} (hI : Inv S H s₀ c sI) - {s : State} (h : Copied P s₀ c sI.mem s) (hfull : rr s₀ c + tt s₀ c = 64) : + {s : State} (h : Copied P s₀ c sI.mem s) (hfull : rr P s₀ c + tt P s₀ c = P.B) : WP isa (.block [.mov .eax (.reg .ebx), .alu .add .eax (.imm (BitVec.ofNat 32 P.N)), .mov .edi (.imm 0), - .mov .ecx (.imm 1)]) s (Pending S H s₀ (c + tt s₀ c) 1) := by - have ht := tt_le s₀ c; have hrr := rr_eq s₀ c - have hxs := xs_length s₀ c + .mov .ecx (.imm 1)]) s (Pending S H s₀ (c + tt P s₀ c) 1) := by + have ht := tt_le P s₀ c; have hrr := rr_eq P s₀ c + have hxs := xs_length P s₀ c have hc := hI.c_le; have := hd.N obtain ⟨hfr, hsv, hst, hby⟩ := copied_facts hd hp hI refine wp_mov fun s₁ u₁ => wp_addi fun s₂ u₂ => wp_movi fun s₃ u₃ => wp_movi fun s₄ u₄ => WP.block_nil ?_ @@ -785,7 +784,8 @@ theorem fill_pending (hd : Dims P S) {s₀ : State} (hp : Pre P S s₀) {c : Nat have heax : s₄.gpr .eax = st s₀ + BitVec.ofNat 32 P.N := by rw [u₄.other _ (by decide), u₃.other _ (by decide), u₂.gpr, u₁.gpr, h.ebx] refine ⟨⟨by omega, ?_, ?_, ?_, ?_, ?_, ?_, by rw [m₄, h.mem]; exact hfr, by rw [m₄, h.mem]; exact hsv⟩, - by rw [u₄.other _ (by decide), u₃.gpr], by rw [u₄.gpr]; rfl, Nat.one_pos, by omega, .inl ⟨heax, rfl⟩, ?_⟩ + by rw [u₄.other _ (by decide), u₃.gpr], by rw [u₄.gpr]; rfl, Nat.one_pos, + by rw [← Nat.add_assoc]; exact Md.add_mod_of_eq hfull, .inl ⟨heax, rfl⟩, ?_⟩ · rw [u₄.rd, u₃.rd, u₂.rd, u₁.rd, h.rd] · rw [u₄.wr, u₃.wr, u₂.wr, u₁.wr, h.wr] · rw [g .ebx (by decide) (by decide) (by decide), h.ebx] @@ -795,35 +795,37 @@ theorem fill_pending (hd : Dims P S) {s₀ : State} (hp : Pre P S s₀) {c : Nat · intro iv m hm mem' hs rw [Md.compressBlocks_one] at hs rw [← take_add_data] - have hmod := length_mid s₀ hm hc - refine H.repr_append_block (by omega) (hI.repr iv m hm) (by rw [hmod, hxs]; exact hfull) ?_ + have hmod := length_mid hd s₀ hm hc + refine H.repr_append_block hd.pos (hI.repr iv m hm) (by rw [hmod, hxs]; exact hfull) ?_ rw [hs, m₄, h.mem, hst, heax, show (st s₀ + BitVec.ofNat 32 P.N).setWidth 64 = addr (st s₀) P.N from rfl, - addr_eq (by have := hp.st_fit; omega)] + addr_eq (by have := hp.st_fit; have := hd.pos; omega)] refine congrArg (H.compress _) ?_ apply H.parse_congr intro k hk have hb := (hI.repr iv m hm).2 rw [hmod] at hb - rw [hb, show rr s₀ c + tt s₀ c = 64 from hfull] at hby + rw [hb, show rr P s₀ c + tt P s₀ c = P.B from hfull] at hby exact bytesAt_getD hby hk /-- All the data fits in the buffer. -/ theorem fill_done (hd : Dims P S) {s₀ : State} (hp : Pre P S s₀) {c : Nat} {sI : State} (hI : Inv S H s₀ c sI) - {s : State} (h : Copied P s₀ c sI.mem s) (hedi : s.gpr .edi = BitVec.ofNat 32 (rr s₀ c + tt s₀ c)) - (hecx : s.gpr .ecx = 0) (hnf : rr s₀ c + tt s₀ c ≠ 64) : Done S H s₀ s := by - have hr := rr_lt s₀ c; have ht' := tt_le' s₀ c - have hrr := rr_eq s₀ c; have htt := tt_eq s₀ c - have hxs := xs_length s₀ c + {s : State} (h : Copied P s₀ c sI.mem s) (hedi : s.gpr .edi = BitVec.ofNat 32 (rr P s₀ c + tt P s₀ c)) + (hecx : s.gpr .ecx = 0) (hnf : rr P s₀ c + tt P s₀ c ≠ P.B) : Done S H s₀ s := by + have hr := rr_lt hd s₀ c; have ht' := tt_le' P s₀ c + have hrr := rr_eq P s₀ c; have htt := tt_eq P s₀ c + have hxs := xs_length P s₀ c have hc := hI.c_le - have htl : tt s₀ c = len s₀ - c := by omega + have htl : tt P s₀ c = len s₀ - c := by omega obtain ⟨hfr, hsv, hst, hby⟩ := copied_facts hd hp hI refine ⟨⟨⟨(Nat.le_refl _), h.rd, h.wr, h.ebx, h.esp, ?_, ?_, by rw [h.mem]; exact hfr, by rw [h.mem]; exact hsv⟩, ?_, fun iv m hm => ?_⟩, hecx⟩ · rw [h.ebp]; congr 2; omega_using [htl, hc] · rw [h.esi]; congr 1; omega_using [htl] - · rw [hedi]; congr 1; omega_using [htl, hc, hrr, hr, ht', hnf] - · have hmod := length_mid s₀ hm hc - rw [show len s₀ = c + tt s₀ c by omega_using [htl, hc], ← take_add_data] + · rw [hedi]; congr 1 + rw [show cnt s₀ + len s₀ = cnt s₀ + c + tt P s₀ c by omega_using [htl, hc], + Md.add_mod_of_lt (by omega_using [hrr, hr, ht', hnf])] + · have hmod := length_mid hd s₀ hm hc + rw [show len s₀ = c + tt P s₀ c by omega_using [htl, hc], ← take_add_data] refine H.repr_append_buf (hI.repr iv m hm) (by rw [hmod, hxs]; omega) (by rw [h.mem, hst]) ?_ rw [hmod, hxs, h.mem, hby] have hb := (hI.repr iv m hm).2 @@ -832,28 +834,28 @@ theorem fill_done (hd : Dims P S) {s₀ : State} (hp : Pre P S s₀) {c : Nat} { theorem fill_ok (hd : Dims P S) {s₀ : State} (hp : Pre P S s₀) {c : Nat} {s : State} (hI : Inv S H s₀ c s) : WP isa (fill P) s fun s' => (∃ c' k, c < c' ∧ Pending S H s₀ c' k s') ∨ Done S H s₀ s' := by - have hr := rr_lt s₀ c; have ht' := tt_le' s₀ c - have htt := tt_eq s₀ c - have hlen := len_lt s₀ + have hr := rr_lt hd s₀ c; have ht' := tt_le' P s₀ c + have htt := tt_eq P s₀ c + have hlen := len_lt s₀; have := hd.le unfold fill - -- `eax := 64 - edi; cmp esi, eax` + -- `eax := B - edi; cmp esi, eax` refine WP.seq (wp_movi fun s₂ u₂ => wp_sub fun s₃ u₃ _ => wp_cmp fun s₄ f₄ cf₄ _ => WP.block_nil ?_) have e₄ : ∀ r, r ≠ .eax → s₄.gpr r = s.gpr r := fun r h => by rw [f₄.gpr, u₃.other r h, u₂.other r h] have hm₄ : s₄.mem = s.mem := by rw [f₄.mem, u₃.mem, u₂.mem] have hrd₄ : s₄.rd = s.rd := by rw [f₄.rd, u₃.rd, u₂.rd] have hwr₄ : s₄.wr = s.wr := by rw [f₄.wr, u₃.wr, u₂.wr] - have heax₃ : s₃.gpr .eax = BitVec.ofNat 32 (64 - rr s₀ c) := by - rw [u₃.gpr, u₂.gpr, u₂.other _ (by decide), hI.edi, ← rr_eq, lit32, - sub_ofNat (a := 64) (b := rr s₀ c) (by omega)] - have hcf : s₄.cf = some (decide (len s₀ - c < 64 - rr s₀ c)) := by + have heax₃ : s₃.gpr .eax = BitVec.ofNat 32 (P.B - rr P s₀ c) := by + rw [u₃.gpr, u₂.gpr, u₂.other _ (by decide), hI.edi, ← rr_eq, + sub_ofNat (a := P.B) (b := rr P s₀ c) (by omega)] + have hcf : s₄.cf = some (decide (len s₀ - c < P.B - rr P s₀ c)) := by rw [cf₄, heax₃, u₃.other _ (by decide), u₂.other _ (by decide), hI.esi, toNat_ofNat_lt (by omega), toNat_ofNat_lt (by omega)] -- `eax := min(eax, esi)` - refine WP.seq (WP.mono (Q := fun (s₅ : State) => s₅.gpr .eax = BitVec.ofNat 32 (tt s₀ c) ∧ + refine WP.seq (WP.mono (Q := fun (s₅ : State) => s₅.gpr .eax = BitVec.ofNat 32 (tt P s₀ c) ∧ (∀ r, r ≠ .eax → s₅.gpr r = s₄.gpr r) ∧ s₅.mem = s₄.mem ∧ s₅.rd = s₄.rd ∧ s₅.wr = s₄.wr) ?_ fun s₅ ⟨heax₅, g₅, m₅, rd₅, wr₅⟩ => ?_) - · refine WP.ite (decide (len s₀ - c < 64 - rr s₀ c)) (by show s₄.cf = _; rw [hcf]) (fun hb => ?_) (fun hb => ?_) + · refine WP.ite (decide (len s₀ - c < P.B - rr P s₀ c)) (by show s₄.cf = _; rw [hcf]) (fun hb => ?_) (fun hb => ?_) · refine wp_mov fun s₅ u₅ => WP.block_nil ⟨?_, u₅.other, u₅.mem, u₅.rd, u₅.wr⟩ rw [u₅.gpr, e₄ _ (by decide), hI.esi]; congr 1; simp at hb; omega · refine WP.block_nil ⟨?_, fun _ _ => rfl, rfl, rfl, rfl⟩ @@ -875,11 +877,11 @@ theorem fill_ok (hd : Dims P S) {s₀ : State} (hp : Pre P S s₀) {c : Nat} {s u₆.other _ (by decide), g₅ _ (by decide), e₄ _ (by decide), hI.ebx, BitVec.add_comm, ← rr_eq, Nat.add_zero] · rw [f₈.gpr, u₇.other _ (by decide), u₆.other _ (by decide), heax₅, Nat.sub_zero] - have hz₈ : s₈.zf = some (decide (tt s₀ c = 0)) := by + have hz₈ : s₈.zf = some (decide (tt P s₀ c = 0)) := by rw [z₈, u₇.other _ (by decide), u₆.other _ (by decide), heax₅, BitVec.and_self, ofNat_beq_zero (by omega)] -- Copy the bytes. - refine WP.seq (WP.mono (Q := Copy P s₀ c s.mem (tt s₀ c)) ?_ fun s₉ hC => ?_) - · refine WP.ite (decide (tt s₀ c = 0)) (by show s₈.zf = _; rw [hz₈]) (fun hb => ?_) (fun hb => ?_) + refine WP.seq (WP.mono (Q := Copy P s₀ c s.mem (tt P s₀ c)) ?_ fun s₉ hC => ?_) + · refine WP.ite (decide (tt P s₀ c = 0)) (by show s₈.zf = _; rw [hz₈]) (fun hb => ?_) (fun hb => ?_) · simp only [decide_eq_true_eq] at hb exact WP.block_nil (hb ▸ hC₀) · simp only [decide_eq_false_iff_not] at hb @@ -891,38 +893,39 @@ theorem fill_ok (hd : Dims P S) {s₀ : State} (hp : Pre P S s₀) {c : Nat} {s rw [f₁₂.gpr, u₁₁.other r (by simp at hr; rcases hr with rfl | rfl | rfl | rfl <;> decide), u₁₀.other r (by simp at hr; rcases hr with rfl | rfl | rfl | rfl <;> decide)]) (by rw [f₁₂.mem, u₁₁.mem, u₁₀.mem]) (by rw [f₁₂.rd, u₁₁.rd, u₁₀.rd]) (by rw [f₁₂.wr, u₁₁.wr, u₁₀.wr]) - have hedi₁₂ : s₁₂.gpr .edi = BitVec.ofNat 32 (rr s₀ c + tt s₀ c) := by + have hedi₁₂ : s₁₂.gpr .edi = BitVec.ofNat 32 (rr P s₀ c + tt P s₀ c) := by rw [f₁₂.gpr, u₁₁.other _ (by decide), u₁₀.gpr, hC.edi, hC.ebx, BitVec.add_comm, BitVec.add_sub_cancel] - have hz₁₂ : s₁₂.zf = some (decide (rr s₀ c + tt s₀ c = 64)) := by - rw [z₁₂, ← f₁₂.gpr, hedi₁₂, lit32, sub_beq (a := rr s₀ c + tt s₀ c) (b := 64) (by omega) (by omega)] + have hz₁₂ : s₁₂.zf = some (decide (rr P s₀ c + tt P s₀ c = P.B)) := by + rw [z₁₂, ← f₁₂.gpr, hedi₁₂, sub_beq (a := rr P s₀ c + tt P s₀ c) (b := P.B) (by omega) (by omega)] have hecx : s₁₂.gpr .ecx = 0 := by rw [f₁₂.gpr, u₁₁.gpr] - refine WP.ite (decide (rr s₀ c + tt s₀ c = 64)) (by show s₁₂.zf = _; rw [hz₁₂]) (fun hb => ?_) (fun hb => ?_) + refine WP.ite (decide (rr P s₀ c + tt P s₀ c = P.B)) (by show s₁₂.zf = _; rw [hz₁₂]) (fun hb => ?_) (fun hb => ?_) · simp only [decide_eq_true_eq] at hb - exact WP.mono (fill_pending hd hp hI hC₁₂ hb) fun s' h => .inl ⟨c + tt s₀ c, 1, by omega, h⟩ + exact WP.mono (fill_pending hd hp hI hC₁₂ hb) fun s' h => .inl ⟨c + tt P s₀ c, 1, by omega, h⟩ · simp only [decide_eq_false_iff_not] at hb exact WP.block_nil (.inr (fill_done hd hp hI hC₁₂ hedi₁₂ hecx hb)) theorem body_ok (hd : Dims P S) {name : String} {code : Prog isa} (hf : CalleeOk H code) {s₀ : State} (hp : Pre P S s₀) {c : Nat} {s : State} (hI : Inv S H s₀ c s) : WP isa (updateBody P name code) s (Step S H s₀ c) := by - have hlen := len_lt s₀; have hr := rr_lt s₀ c + have hlen := len_lt s₀; have hr : (cnt s₀ + c) % P.B < P.B := rr_lt hd s₀ c; have := hd.le unfold updateBody refine WP.seq (wp_test fun s₁ f₁ z₁ => WP.block_nil ?_) have hI₁ := hI.of_gpr (fun r _ => by rw [f₁.gpr]) f₁.mem f₁.rd f₁.wr refine WP.seq (WP.mono (Q := fun s' => (∃ c' k, c < c' ∧ Pending S H s₀ c' k s') ∨ Done S H s₀ s') ?_ fun s' h => tail_ok hd hf hp h) - refine WP.ite (decide (rr s₀ c = 0)) + refine WP.ite (decide (rr P s₀ c = 0)) (by show s₁.zf = _; rw [z₁, hI.edi, BitVec.and_self, ofNat_beq_zero (by omega)]) (fun hb => ?_) (fun _ => fill_ok hd hp hI₁) simp only [decide_eq_true_eq] at hb refine WP.seq (wp_cmpi fun s₂ f₂ cf₂ _ => WP.block_nil ?_) have hI₂ := hI₁.of_gpr (fun r _ => by rw [f₂.gpr]) f₂.mem f₂.rd f₂.wr - have hcf : s₂.cf = some (decide (len s₀ - c < 64)) := by - rw [cf₂, hI₁.esi, toNat_ofNat_lt (by omega)]; rfl - refine WP.ite (!decide (len s₀ - c < 64)) (by show s₂.cf.map (!·) = _; rw [hcf]; rfl) + have hcf : s₂.cf = some (decide (len s₀ - c < P.B)) := by + rw [cf₂, hI₁.esi, toNat_ofNat_lt (k := len s₀ - c) (by omega), toNat_ofNat_lt (k := P.B) (by omega)] + refine WP.ite (!decide (len s₀ - c < P.B)) (by show s₂.cf.map (!·) = _; rw [hcf]; rfl) (fun hb' => ?_) (fun _ => fill_ok hd hp hI₂) simp only [Bool.not_eq_true', decide_eq_false_iff_not, Nat.not_lt] at hb' - exact WP.mono (direct_ok hp hI₂ hb hb') fun s' h => .inl ⟨_, _, by omega, h⟩ + have := Nat.mul_pos hd.pos (Nat.div_pos hb' hd.pos) + exact WP.mono (direct_ok hd hp hI₂ hb hb') fun s' h => .inl ⟨_, _, by omega, h⟩ theorem correct (hd : Dims P S) {name : String} {code : Prog isa} (hf : CalleeOk H code) {s₀ : State} (hp : Pre P S s₀) : @@ -953,11 +956,11 @@ theorem argWord_eq {s : State} {n : Nat} (hsp : (s.gpr .esp).toNat + 4 + n ≤ 2 `state` and `scratch` are the base addresses of the writable regions, and the 20 bytes below `esp` are outside them. -/ def τ₀ (P : Params) (S : Nat) : VG.X86.Taint.T := - { regs := .ofList [.esp], flags := false, lens := [P.N + 64, S], argLen := 28, + { regs := .ofList [.esp], flags := false, lens := [P.N + P.B, S], argLen := 28, argBases := [(4, 0), (24, 1)], room := 20 } section -variable {P : Params} {S : Nat} {H : Md 64 P.N 8} +variable {P : Params} {S : Nat} {H : Md P.B P.N P.L} theorem wf₀ (hd : Dims P S) {s : State} (h : (updK H S).pre s) : VG.X86.Taint.Wf (τ₀ P S) s := by have hp := pre_of h @@ -1023,13 +1026,13 @@ def sat₀ : State where /-- A state satisfying the precondition (with no data). -/ def sat (P : Params) (S : Nat) : State := - { sat₀ with rd := [⟨0x2000, 0⟩, ⟨0x5004, 24⟩], wr := [⟨0x1000, P.N + 64⟩, ⟨0x3000, S⟩] } + { sat₀ with rd := [⟨0x2000, 0⟩, ⟨0x5004, 24⟩], wr := [⟨0x1000, P.N + P.B⟩, ⟨0x3000, S⟩] } section -variable {P : Params} {S : Nat} {H : Md 64 P.N 8} +variable {P : Params} {S : Nat} {H : Md P.B P.N P.L} theorem sat_pre (hd : Dims P S) : (updK H S).pre (sat P S) := by - have := hd.N; have := hd.S + have := hd.N; have := hd.S; have := hd.le have a0 : arg (sat P S) 0 = 0x1000 := show arg sat₀ 0 = _ by decide have a3 : arg (sat P S) 3 = 0x2000 := show arg sat₀ 3 = _ by decide have a4 : arg (sat P S) 4 = 0 := show arg sat₀ 4 = _ by decide @@ -1094,7 +1097,7 @@ abbrev scr : BitVec 32 := arg s₀ 4 abbrev stA : Addr := (st s₀).setWidth 64 abbrev outA : Addr := (out s₀).setWidth 64 abbrev scA : Addr := (scr s₀).setWidth 64 -abbrev stR : Region := ⟨stA s₀, P.N + 64⟩ +abbrev stR : Region := ⟨stA s₀, P.N + P.B⟩ abbrev outR : Region := ⟨outA s₀, P.N⟩ abbrev scR : Region := ⟨scA s₀, S⟩ abbrev argR : Region := ⟨addr (esp₀ s₀) 4, 20⟩ @@ -1109,7 +1112,7 @@ def Saved (m : Mem) : Prop := ∀ p ∈ saved P, m.readW (addr (scr s₀) p.2) 3 end section -variable {P : Params} (H : Md 64 P.N 8) (s₀ : State) +variable {P : Params} (H : Md P.B P.N P.L) (s₀ : State) /-- The messages the initial state represents, from `iv`. -/ def R₀ (iv : H.HV) (m : List Byte) : Prop := @@ -1118,20 +1121,20 @@ def R₀ (iv : H.HV) (m : List Byte) : Prop := /-- The final hash value, if `n` bytes are buffered in a block that is not the last. -/ def Fin1 (mem : Mem) (n : Nat) (m : List Byte) : H.HV := H.compress (H.compress (H.stateAt mem (stA s₀)) - (H.parse fun t => (bytesAt mem (buf P s₀) n ++ List.replicate (64 - n) 0).getD t 0)) - (H.parse fun t => (List.replicate (64 - 8) 0 ++ H.lenBytes m.length).getD t 0) + (H.parse fun t => (bytesAt mem (buf P s₀) n ++ List.replicate (P.B - n) 0).getD t 0)) + (H.parse fun t => (List.replicate (P.B - P.L) 0 ++ H.lenBytes m.length).getD t 0) /-- The final hash value, if `n` bytes are buffered in the last block. -/ def Fin0 (mem : Mem) (n : Nat) (m : List Byte) : H.HV := H.compress (H.stateAt mem (stA s₀)) - (H.parse fun t => (bytesAt mem (buf P s₀) n ++ List.replicate (64 - 8 - n) 0 ++ + (H.parse fun t => (bytesAt mem (buf P s₀) n ++ List.replicate (P.B - P.L - n) 0 ++ H.lenBytes m.length).getD t 0) end structure Pre (P : Params) (S : Nat) (s₀ : State) : Prop where - rd : s₀.rd = [] - wr : s₀.wr = [stR P s₀, outR P s₀, scR S s₀, argR s₀] + rd : s₀.rd = [argR s₀] + wr : s₀.wr = [stR P s₀, outR P s₀, scR S s₀] st_out : (stR P s₀).Disjoint (outR P s₀) st_scr : (stR P s₀).Disjoint (scR S s₀) out_scr : (outR P s₀).Disjoint (scR S s₀) @@ -1144,14 +1147,14 @@ structure Pre (P : Params) (S : Nat) (s₀ : State) : Prop where stk_st : (stkR s₀).Disjoint (stR P s₀) stk_out : (stkR s₀).Disjoint (outR P s₀) stk_scr : (stkR s₀).Disjoint (scR S s₀) - st_fit : (st s₀).toNat + (P.N + 64) ≤ 2 ^ 32 + st_fit : (st s₀).toNat + (P.N + P.B) ≤ 2 ^ 32 out_fit : (out s₀).toNat + P.N ≤ 2 ^ 32 scr_fit : (scr s₀).toNat + S ≤ 2 ^ 32 sp_lo : 20 ≤ (esp₀ s₀).toNat sp_fit : (esp₀ s₀).toNat + 24 ≤ 2 ^ 32 section -variable {P : Params} {S : Nat} {H : Md 64 P.N 8} +variable {P : Params} {S : Nat} {H : Md P.B P.N P.L} theorem pre_of {s₀ : State} (h : (finK H S).pre s₀) : Pre P S s₀ := by obtain ⟨h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11, h12, h13, h14, h15, h16, h17, h18, h19⟩ := h @@ -1160,14 +1163,12 @@ theorem pre_of {s₀ : State} (h : (finK H S).pre s₀) : Pre P S s₀ := by by show (below _ _).Disjoint _; rw [e]; exact h13, by show (below _ _).Disjoint _; rw [e]; exact h14, h15, h16, h17, h18, h19⟩ -theorem cnt_mod (s₀ : State) : cnt s₀ % 64 = (arg s₀ 1).toNat % 64 := by - simp only [cnt, count] - rw [BitVec.toNat_append, ← Nat.shiftLeft_add_eq_or_of_lt (arg s₀ 1).isLt, Nat.shiftLeft_eq] - omega +theorem cnt_mod (hd : Dims P S) (s₀ : State) : cnt s₀ % P.B = (arg s₀ 1).toNat % P.B := + hd.mod_append _ _ -theorem R₀.length {s₀ : State} {iv : H.HV} {m : List Byte} (h : R₀ H s₀ iv m) : cnt s₀ % 64 = m.length % 64 := by - rw [cnt, h.2, BitVec.toNat_ofNat] - omega +theorem R₀.length {s₀ : State} {iv : H.HV} {m : List Byte} (h : R₀ H s₀ iv m) (hd : Dims P S) : + cnt s₀ % P.B = m.length % P.B := by + rw [cnt, h.2, BitVec.toNat_ofNat, hd.mod] namespace Pre variable {s₀ : State} (hp : Pre P S s₀) @@ -1211,6 +1212,15 @@ end /-! ## Invariants -/ +/-- Where the zeros end in the block being padded: at the length field in the +last block (`k = 0`), at its end in the one before (`k = 1`). -/ +def lim (P : Params) (k : Nat) : Nat := if k = 0 then P.B - P.L else P.B + +theorem lim_zero (P : Params) : lim P 0 = P.B - P.L := rfl +theorem lim_one (P : Params) : lim P 1 = P.B := rfl +theorem lim_le (P : Params) (k : Nat) : lim P k ≤ P.B := by unfold lim; split <;> omega +theorem lim_ge (P : Params) (k : Nat) : P.B - P.L ≤ lim P k := by unfold lim; split <;> omega + structure Common (P : Params) (S : Nat) (s₀ : State) (s : State) : Prop where rd : s.rd = s₀.rd wr : s.wr = s₀.wr @@ -1225,21 +1235,21 @@ structure Common (P : Params) (S : Nat) (s₀ : State) (s : State) : Prop where /-- The loop invariant: `k = 1` while the block being padded is not the last one, with `n` bytes of it buffered. -/ -structure LInv {P : Params} (S : Nat) (H : Md 64 P.N 8) (s₀ : State) (k n : Nat) (s : State) : Prop +structure LInv {P : Params} (S : Nat) (H : Md P.B P.N P.L) (s₀ : State) (k n : Nat) (s : State) : Prop extends Common P S s₀ s where k_le : k ≤ 1 - n_le : n ≤ 56 + 8 * k + n_le : n ≤ lim P k edi : s.gpr .edi = BitVec.ofNat 32 n esi : s.gpr .esi = BitVec.ofNat 32 k hash : ∀ iv m, R₀ H s₀ iv m → H.lenOk m.length → H.hash iv m = H.digest (if k = 1 then Fin1 H s₀ s.mem n m else Fin0 H s₀ s.mem n m) /-- All blocks are compressed. -/ -def Done {P : Params} (S : Nat) (H : Md 64 P.N 8) (s₀ : State) (s : State) : Prop := +def Done {P : Params} (S : Nat) (H : Md P.B P.N P.L) (s₀ : State) (s : State) : Prop := Common P S s₀ s ∧ ∀ iv m, R₀ H s₀ iv m → H.lenOk m.length → H.hash iv m = H.digest (H.stateAt s.mem (stA s₀)) section -variable {P : Params} {S : Nat} {H : Md 64 P.N 8} +variable {P : Params} {S : Nat} {H : Md P.B P.N P.L} theorem Common.of_gpr {s₀ : State} {s s' : State} (h : Common P S s₀ s) (hg : ∀ r ∈ [Reg.ebx, .ebp, .esp], s'.gpr r = s.gpr r) @@ -1280,9 +1290,9 @@ theorem buf_add (s₀ : State) (n : Nat) : buf P s₀ + BitVec.ofNat 64 n = stA add_ofNat _ _ _ /-- Writing buffer bytes `[n, n + |xs|)`. -/ -theorem buf_frame (hd : Dims P S) {s₀ : State} (m : Mem) {n : Nat} {xs : List Byte} (hn : n + xs.length ≤ 64) : +theorem buf_frame (hd : Dims P S) {s₀ : State} (m : Mem) {n : Nat} {xs : List Byte} (hn : n + xs.length ≤ P.B) : Frame [stR P s₀] m (writeBytes m (buf P s₀ + BitVec.ofNat 64 n) xs) := by - have := hd.N + have := hd.N; have := hd.le refine writeBytes_frame _ _ _ ?_ rw [buf_add] exact contains_offset (by omega) (by omega) @@ -1300,7 +1310,7 @@ structure Zero (P : Params) (s₀ : State) (sI : State) (n lim j : Nat) (s : Sta mem : s.mem = writeBytes sI.mem (buf P s₀ + BitVec.ofNat 64 n) (List.replicate j 0) theorem zero_step (hd : Dims P S) {s₀ : State} (hp : Pre P S s₀) {sI : State} (hC : Common P S s₀ sI) - (hecx : sI.gpr .ecx = 0) {n lim j : Nat} (hlim : lim ≤ 64) (hj : j < lim - n) {s : State} + (hecx : sI.gpr .ecx = 0) {n lim j : Nat} (hlim : lim ≤ P.B) (hj : j < lim - n) {s : State} (h : Zero P s₀ sI n lim j s) : WP isa (.block [.mov .edx (.reg .ebx), .alu .add .edx (.reg .edi), .store8 (at_ .edx P.N) .cl, .alu .add .edi (.imm 1), .alu .sub .eax (.imm 1)]) s fun s' => @@ -1337,7 +1347,7 @@ theorem zero_step (hd : Dims P S) {s₀ : State} (hp : Pre P S s₀) {sI : State ofNat_pred (by omega), ofNat_beq_zero (by omega), Nat.sub_sub, Nat.sub_sub] theorem zero_ok (hd : Dims P S) {s₀ : State} (hp : Pre P S s₀) {sI : State} (hC : Common P S s₀ sI) - (hecx : sI.gpr .ecx = 0) {n lim : Nat} (hlim : lim ≤ 64) (hn : n ≤ lim) {s : State} + (hecx : sI.gpr .ecx = 0) {n lim : Nat} (hlim : lim ≤ P.B) (hn : n ≤ lim) {s : State} (h : Zero P s₀ sI n lim 0 s) (hz : s.zf = some (decide (lim - n = 0))) : WP isa (.ite .e (.block []) (.loop (.block [.mov .edx (.reg .ebx), .alu .add .edx (.reg .edi), .store8 (at_ .edx P.N) .cl, .alu .add .edi (.imm 1), .alu .sub .eax (.imm 1)]) .ne)) s @@ -1364,11 +1374,11 @@ theorem compress_buf (hd : Dims P S) {name : String} {code : Prog isa} (hf : Cal (hQ : ∀ s', Common P S s₀ s' → (∀ r ∈ calleeSaved, s'.gpr r = s.gpr r) → H.stateAt s'.mem (stA s₀) = H.compress (H.stateAt s.mem (stA s₀)) (H.blockAt s.mem (buf P s₀)) → Q s') : WP isa (compressAt name code .ebx .ebp) s Q := by - have hst := hp.st_fit; have hsc := hp.scr_fit; have := hd.N; have := hd.so + have hst := hp.st_fit; have hsc := hp.scr_fit; have := hd.N; have := hd.so; have := hd.pos; have := hd.le have eN : Region.Sub ⟨stA s₀, P.N⟩ (stR P s₀) := Region.sub_prefix (by omega) have eso : Region.Sub ⟨scA s₀, P.so⟩ (scR S s₀) := Region.sub_prefix (by omega) have hb : (st s₀ + BitVec.ofNat 32 P.N).setWidth 64 = stA s₀ + BitVec.ofNat 64 P.N := addr_eq (by omega) - have eb : Region.Sub ⟨(st s₀ + BitVec.ofNat 32 P.N).setWidth 64, 64⟩ (stR P s₀) := by + have eb : Region.Sub ⟨(st s₀ + BitVec.ofNat 32 P.N).setWidth 64, P.B⟩ (stR P s₀) := by rw [hb]; exact sub_offset (by omega) (by omega) refine compressAt_ok hf (st := st s₀) (scr := scr s₀) (blk := st s₀ + BitVec.ofNat 32 P.N) (E := esp₀ s₀) (by decide) (by decide) (by decide) (by decide) hC.esp hC.ebx hC.ebp heax hp.sp_lo (by omega) @@ -1430,7 +1440,7 @@ theorem args_ok {s₀ : State} {s : State} (hC : Common P S s₀ s) : end /-- The loop's postcondition for one iteration. -/ -def Step {P : Params} (S : Nat) (H : Md 64 P.N 8) (s₀ : State) (k : Nat) (s : State) : Prop := +def Step {P : Params} (S : Nat) (H : Md P.B P.N P.L) (s₀ : State) (k : Nat) (s : State) : Prop := (eval .e s = some false ∧ Done S H s₀ s) ∨ (eval .e s = some true ∧ k = 1 ∧ LInv S H s₀ 0 0 s) theorem regs3 {r : Reg} (hr : r ∈ [Reg.ebx, .ebp, .esp]) : r ≠ .eax ∧ r ≠ .ecx ∧ r ≠ .edx ∧ r ≠ .edi ∧ r ≠ .esi := by @@ -1438,19 +1448,20 @@ theorem regs3 {r : Reg} (hr : r ∈ [Reg.ebx, .ebp, .esp]) : r ≠ .eax ∧ r rcases hr with rfl | rfl | rfl <;> decide section -variable {P : Params} {S : Nat} {H : Md 64 P.N 8} +variable {P : Params} {S : Nat} {H : Md P.B P.N P.L} theorem body_ok (hd : Dims P S) (hs : Shape H) {name : String} {code : Prog isa} (hf : CalleeOk H code) {s₀ : State} (hp : Pre P S s₀) {k n : Nat} {s : State} (h : LInv S H s₀ k n s) : WP isa (finalizeBody P name code) s (Step S H s₀ k) := by have hk := h.k_le; have hn := h.n_le; have hst := hp.st_fit; have := hd.N; have := hd.so; have := hd.S + have := hd.ge; have := hd.le; have := hd.L; have := lim_le P k; have := lim_ge P k have hC := h.toCommon unfold finalizeBody - -- `eax := 64` or `56`: the end of the zeros. + -- `eax := B` or `B - L`: the end of the zeros. refine WP.seq (wp_movi fun s₁ u₁ => wp_test fun s₂ f₂ z₂ => WP.block_nil ?_) have hz₂ : s₂.zf = some (decide (k = 0)) := by rw [z₂, u₁.other _ (by decide), h.esi, BitVec.and_self, ofNat_beq_zero (by omega)] - refine WP.seq (WP.mono (Q := fun (s₃ : State) => s₃.gpr .eax = BitVec.ofNat 32 (56 + 8 * k) ∧ + refine WP.seq (WP.mono (Q := fun (s₃ : State) => s₃.gpr .eax = BitVec.ofNat 32 (lim P k) ∧ (∀ r, r ≠ .eax → s₃.gpr r = s.gpr r) ∧ s₃.mem = s.mem ∧ s₃.rd = s.rd ∧ s₃.wr = s.wr) ?_ fun s₃ ⟨heax₃, g₃, m₃, rd₃, wr₃⟩ => ?_) · refine WP.ite (decide (k = 0)) (by show s₂.zf = _; rw [hz₂]) (fun hb => ?_) (fun hb => ?_) @@ -1472,15 +1483,15 @@ theorem body_ok (hd : Dims P S) (hs : Shape H) {name : String} {code : Prog isa} have hC₄ : Common P S s₀ s₄ := hC₃.of_gpr (fun r hr => u₄.other r (regs3 hr).2.1) u₄.mem u₄.rd u₄.wr have hecx₄ : s₄.gpr .ecx = 0 := u₄.gpr have hedi₄ : s₄.gpr .edi = BitVec.ofNat 32 n := by rw [u₄.other _ (by decide), g₃ _ (by decide), h.edi] - have heax₅ : s₅.gpr .eax = BitVec.ofNat 32 (56 + 8 * k - n) := by - rw [u₅.gpr, u₄.other _ (by decide), heax₃, hedi₄, sub_ofNat (a := 56 + 8 * k) (b := n) (by omega)] - have hZ : Zero P s₀ s₄ n (56 + 8 * k) 0 s₅ := by + have heax₅ : s₅.gpr .eax = BitVec.ofNat 32 (lim P k - n) := by + rw [u₅.gpr, u₄.other _ (by decide), heax₃, hedi₄, sub_ofNat (a := lim P k) (b := n) (by omega)] + have hZ : Zero P s₀ s₄ n (lim P k) 0 s₅ := by refine ⟨Nat.zero_le _, fun r hr => u₅.other r ?_, u₅.rd, u₅.wr, by rw [u₅.other _ (by decide), hedi₄, Nat.add_zero], by rw [heax₅, Nat.sub_zero], by rw [u₅.mem, List.replicate_zero, writeBytes_nil]⟩ simp only [List.mem_cons, List.not_mem_nil, or_false] at hr rcases hr with rfl | rfl | rfl | rfl | rfl <;> decide - have hz₅ : s₅.zf = some (decide (56 + 8 * k - n = 0)) := by + have hz₅ : s₅.zf = some (decide (lim P k - n = 0)) := by rw [z₅, ← u₅.gpr, heax₅, ofNat_beq_zero (by omega)] refine WP.seq (WP.mono (zero_ok hd hp hC₄ hecx₄ (by omega) hn hZ hz₅) fun s₆ hZ₆ => ?_) have hm₄ : s₄.mem = s.mem := by rw [u₄.mem, m₃] @@ -1495,8 +1506,8 @@ theorem body_ok (hd : Dims P S) (hs : Shape H) {name : String} {code : Prog isa} intro i hi rw [buf_add] exact writeBytes_before _ _ _ (by omega) (by simp only [List.length_replicate]; omega) - have hby₆ : bytesAt s₆.mem (buf P s₀) (56 + 8 * k) = - bytesAt s.mem (buf P s₀) n ++ List.replicate (56 + 8 * k - n) 0 := by + have hby₆ : bytesAt s₆.mem (buf P s₀) (lim P k) = + bytesAt s.mem (buf P s₀) n ++ List.replicate (lim P k - n) 0 := by rw [hZ₆.mem, hm₄, ← bytesAt_writeBytes _ _ _ _ (by simp only [List.length_replicate]; omega)] congr 1; simp only [List.length_replicate]; omega have hesi₆ : s₆.gpr .esi = BitVec.ofNat 32 k := by @@ -1509,18 +1520,19 @@ theorem body_ok (hd : Dims P S) (hs : Shape H) {name : String} {code : Prog isa} have hesi₇ : s₇.gpr .esi = BitVec.ofNat 32 k := by rw [f₇.gpr, hesi₆] refine WP.seq (WP.mono (Q := fun (s₈ : State) => Common P S s₀ s₈ ∧ s₈.gpr .esi = BitVec.ofNat 32 k ∧ H.stateAt s₈.mem (stA s₀) = H.stateAt s.mem (stA s₀) ∧ - ∀ iv m, R₀ H s₀ iv m → H.lenOk m.length → bytesAt s₈.mem (buf P s₀) 64 = bytesAt s.mem (buf P s₀) n ++ - (if k = 1 then List.replicate (64 - n) 0 else List.replicate (56 - n) 0 ++ H.lenBytes m.length)) ?_ + ∀ iv m, R₀ H s₀ iv m → H.lenOk m.length → bytesAt s₈.mem (buf P s₀) P.B = bytesAt s.mem (buf P s₀) n ++ + (if k = 1 then List.replicate (P.B - n) 0 else List.replicate (P.B - P.L - n) 0 ++ H.lenBytes m.length)) ?_ fun s₈ ⟨hC₈, hesi₈, hst₈, hby₈⟩ => ?_) · refine WP.ite (decide (k = 0)) (by show s₇.zf = _; rw [hz₇]) (fun hb => ?_) (fun hb => ?_) · simp only [decide_eq_true_eq] at hb; subst hb + rw [lim_zero] at hby₆ have hsc₇ : ∀ d, d + 4 ≤ S → InRegions (s₇.rd ++ s₇.wr) (addr (s₇.gpr .ebp) d) 4 := fun d hd => ⟨scR S s₀, by simp [hC₇.rd, hC₇.wr, hp.wr], by rw [hC₇.ebp]; exact hp.scr_in hd⟩ - have hso₇ : ∀ d, d + 4 ≤ P.N + 64 → InRegions s₇.wr (addr (s₇.gpr .ebx) d) 4 := + have hso₇ : ∀ d, d + 4 ≤ P.N + P.B → InRegions s₇.wr (addr (s₇.gpr .ebx) d) 4 := fun d hd => ⟨stR P s₀, by simp [hC₇.wr, hp.wr], by rw [hC₇.ebx]; exact contains_addr hd (by omega) hst⟩ refine WP.mono (hs.len s₇ (by rw [hC₇.ebx]; exact hst) (hsc₇ _ (by omega)) (hsc₇ _ (by omega)) - (hso₇ _ (by omega)) (hso₇ _ (by omega))) fun s₈ ⟨g₈, rd₈, wr₈, m₈⟩ => ?_ - rw [hC₇.ebx, hC₇.ebp, hC₇.lo, hC₇.hi, show P.N + 56 = P.N + (64 - 8) by omega, ← buf_add] at m₈ + fun d _ h₂ => hso₇ d h₂) fun s₈ ⟨g₈, rd₈, wr₈, m₈⟩ => ?_ + rw [hC₇.ebx, hC₇.ebp, hC₇.lo, hC₇.hi, show P.N + P.B - P.L = P.N + (P.B - P.L) by omega, ← buf_add] at m₈ have hlen := H.lenOf_length (arg s₀ 2 ++ arg s₀ 1) have hfL : Frame [stR P s₀] s₇.mem s₈.mem := by rw [m₈]; exact buf_frame hd _ (by omega) @@ -1536,14 +1548,15 @@ theorem body_ok (hd : Dims P S) (hs : Shape H) {name : String} {code : Prog isa} exact writeBytes_before _ _ _ (by omega) (by omega) · simp only [show ¬ ((0 : Nat) = 1) by decide, ite_false] rw [show arg s₀ 2 ++ arg s₀ 1 = count s₀ from rfl, hm.2, H.lenOf_eq _ hok] at m₈ - have e := bytesAt_writeBytes s₇.mem (buf P s₀) (64 - 8) (H.lenBytes m.length) + have e := bytesAt_writeBytes s₇.mem (buf P s₀) (P.B - P.L) (H.lenBytes m.length) (by rw [H.lenBytes_length]; omega) - rw [H.lenBytes_length] at e + rw [H.lenBytes_length, show P.B - P.L + P.L = P.B by omega] at e rw [m₈, e, f₇.mem, hby₆, List.append_assoc] · simp only [decide_eq_false_iff_not] at hb have hk1 : k = 1 := by omega subst hk1 refine WP.block_nil ⟨hC₇, hesi₇, by rw [f₇.mem, hst₆], fun iv m _ _ => ?_⟩ + rw [lim_one] at hby₆ rw [f₇.mem, hby₆]; simp -- Compress the block. refine WP.seq (WP.mono (args_ok hC₈) fun s₉ ⟨hC₉, g₉, heax₉, hm₉⟩ => ?_) @@ -1552,7 +1565,7 @@ theorem body_ok (hd : Dims P S) (hs : Shape H) {name : String} {code : Prog isa} rw [cs₁₀ _ (by decide), g₉ _ (by decide), hesi₈] have hblk : ∀ iv m, R₀ H s₀ iv m → H.lenOk m.length → H.blockAt s₉.mem (buf P s₀) = H.parse fun t => (bytesAt s.mem (buf P s₀) n ++ - (if k = 1 then List.replicate (64 - n) 0 else List.replicate (56 - n) 0 ++ H.lenBytes m.length)).getD t 0 := by + (if k = 1 then List.replicate (P.B - n) 0 else List.replicate (P.B - P.L - n) 0 ++ H.lenBytes m.length)).getD t 0 := by intro iv m hm hok apply H.parse_congr intro t ht @@ -1568,7 +1581,7 @@ theorem body_ok (hd : Dims P S) (hs : Shape H) {name : String} {code : Prog isa} have hst : ∀ iv m, R₀ H s₀ iv m → H.lenOk m.length → H.stateAt s₁₂.mem (stA s₀) = H.compress (H.stateAt s.mem (stA s₀)) (H.parse fun t => (bytesAt s.mem (buf P s₀) n ++ - (if k = 1 then List.replicate (64 - n) 0 else List.replicate (56 - n) 0 ++ H.lenBytes m.length)).getD t 0) := by + (if k = 1 then List.replicate (P.B - n) 0 else List.replicate (P.B - P.L - n) 0 ++ H.lenBytes m.length)).getD t 0) := by intro iv m hm hok rw [u₁₂.mem, u₁₁.mem, hst₁₀, hm₉, hst₈, ← hblk iv m hm hok, hm₉] by_cases hk1 : k = 1 @@ -1642,17 +1655,17 @@ theorem prologue_ok (hd : Dims P S) {s₀ : State} (hp : Pre P S s₀) : .mov .ecx (.mem (at_ .esp 8)), .store (at_ .ebp (P.so + 16)) .ecx, .mov .ecx (.mem (at_ .esp 12)), .store (at_ .ebp (P.so + 20)) .ecx, .mov .ecx (.mem (at_ .esp 16)), .store (at_ .ebp (P.so + 24)) .ecx, - .mov .edi (.mem (at_ .esp 8)), .alu .and .edi (.imm 63), + .mov .edi (.mem (at_ .esp 8)), .alu .and .edi (.imm (BitVec.ofNat 32 (P.B - 1))), .mov .edx (.reg .ebx), .alu .add .edx (.reg .edi), .mov .ecx (.imm 0x80), .store8 (at_ .edx P.N) .cl, .alu .add .edi (.imm 1), - .mov .esi (.imm 0), .alu .cmp .edi (.imm 57)] : List Instr))) + .mov .esi (.imm 0), .alu .cmp .edi (.imm (BitVec.ofNat 32 (P.B - P.L + 1)))] : List Instr))) (.ite .ae (.block [.mov .esi (.imm 1)]) (.block []))) s₀ - fun s => ∃ k, LInv S H s₀ k (cnt s₀ % 64 + 1) s := by - have hst := hp.st_fit; have := hd.so; have := hd.N - have hr : cnt s₀ % 64 < 64 := Nat.mod_lt _ (by omega) + fun s => ∃ k, LInv S H s₀ k (cnt s₀ % P.B + 1) s := by + have hst := hp.st_fit; have := hd.so; have := hd.N; have := hd.ge; have := hd.le; have := hd.L + have hr : cnt s₀ % P.B < P.B := Nat.mod_lt _ hd.pos have ain : ∀ e, 4 ≤ e → e + 4 ≤ 24 → ∀ t : State, t.rd = s₀.rd → t.wr = s₀.wr → InRegions (t.rd ++ t.wr) (addr (esp₀ s₀) e) 4 := - fun e h₁ h₂ t hrd hwr => ⟨argR s₀, by simp [hrd, hwr, hp.wr], hp.arg_in h₁ h₂⟩ + fun e h₁ h₂ t hrd hwr => ⟨argR s₀, by simp [hrd, hwr, hp.rd], hp.arg_in h₁ h₂⟩ have sout : ∀ d, d + 4 ≤ S → ∀ t : State, t.wr = s₀.wr → InRegions t.wr (addr (scr s₀) d) 4 := fun d hd t hwr => ⟨scR S s₀, by simp [hwr, hp.wr], hp.scr_in hd⟩ have fw : ∀ {m : Mem}, Frame [scR S s₀] s₀.mem m → ∀ d, d + 4 ≤ S → ∀ v : BitVec 32, @@ -1721,21 +1734,21 @@ theorem prologue_ok (hd : Dims P S) {s₀ : State} (hp : Pre P S s₀) : -- The `0x80` byte. refine wp_movm (a := addr (esp₀ s₀) 8) (by rw [ea_at, g₁₃ _ (by decide), sp₇]) (ain 8 (by omega) (by omega) _ rd₁₃ wr₁₃) fun s₁₄ u₁₄ => wp_andi fun s₁₅ u₁₅ => ?_ - have edi₁₅ : s₁₅.gpr .edi = BitVec.ofNat 32 (cnt s₀ % 64) := by - rw [u₁₅.gpr, u₁₄.gpr, m₁₃, arg_read hp (proMem_frame hd hp) (by omega) (by omega), and63, cnt_mod] + have edi₁₅ : s₁₅.gpr .edi = BitVec.ofNat 32 (cnt s₀ % P.B) := by + rw [u₁₅.gpr, u₁₄.gpr, m₁₃, arg_read hp (proMem_frame hd hp) (by omega) (by omega), hd.and, cnt_mod hd] rfl refine wp_mov fun s₁₆ u₁₆ => wp_add fun s₁₇ u₁₇ => wp_movi fun s₁₈ u₁₈ => ?_ - have edx₁₈ : s₁₈.gpr .edx = st s₀ + BitVec.ofNat 32 (cnt s₀ % 64) := by + have edx₁₈ : s₁₈.gpr .edx = st s₀ + BitVec.ofNat 32 (cnt s₀ % P.B) := by rw [u₁₈.other _ (by decide), u₁₇.gpr, u₁₆.gpr, u₁₆.other _ (by decide), edi₁₅, u₁₅.other _ (by decide), u₁₄.other _ (by decide), g₁₃ _ (by decide), ebx₇] - have hq : addr (s₁₈.gpr .edx) P.N = buf P s₀ + BitVec.ofNat 64 (cnt s₀ % 64) := by + have hq : addr (s₁₈.gpr .edx) P.N = buf P s₀ + BitVec.ofNat 64 (cnt s₀ % P.B) := by rw [edx₁₈, addr_add_ofNat (by omega), buf_add, Nat.add_comm] - have hout : InRegions s₁₈.wr (buf P s₀ + BitVec.ofNat 64 (cnt s₀ % 64)) 1 := + have hout : InRegions s₁₈.wr (buf P s₀ + BitVec.ofNat 64 (cnt s₀ % P.B)) 1 := ⟨stR P s₀, by simp [u₁₈.wr, u₁₇.wr, u₁₆.wr, u₁₅.wr, u₁₄.wr, wr₁₃, hp.wr], by rw [buf_add]; exact contains_offset (by omega) (by omega)⟩ - refine wp_store8 (r := .cl) (a := buf P s₀ + BitVec.ofNat 64 (cnt s₀ % 64)) (by rw [ea_at, hq]) hout + refine wp_store8 (r := .cl) (a := buf P s₀ + BitVec.ofNat 64 (cnt s₀ % P.B)) (by rw [ea_at, hq]) hout fun s₁₉ u₁₉ => wp_addi fun s₂₀ u₂₀ => wp_movi fun s₂₁ u₂₁ => wp_cmpi fun s₂₂ f₂₂ cf₂₂ _ => WP.block_nil ?_ - have hm₁₉ : s₁₉.mem = writeBytes (proMem P s₀) (buf P s₀ + BitVec.ofNat 64 (cnt s₀ % 64)) [0x80] := by + have hm₁₉ : s₁₉.mem = writeBytes (proMem P s₀) (buf P s₀ + BitVec.ofNat 64 (cnt s₀ % P.B)) [0x80] := by rw [u₁₉.mem, show Reg8.cl.reg = Reg.ecx from rfl, u₁₈.gpr, u₁₈.mem, u₁₇.mem, u₁₆.mem, u₁₅.mem, u₁₄.mem, m₁₃, ← List.nil_append [(0x80 : Byte)], writeBytes_snoc _ _ _ _ (by simp), writeBytes_nil] simp @@ -1762,46 +1775,47 @@ theorem prologue_ok (hd : Dims P S) {s₀ : State} (hp : Pre P S s₀) : rw [word _ (by omega)]; exact hsv p hp', by rw [word _ (by omega)]; exact hlo, by rw [word _ (by omega)]; exact hhi, by rw [word _ (by omega)]; exact hou⟩ - have edi₂₂ : s₂₂.gpr .edi = BitVec.ofNat 32 (cnt s₀ % 64 + 1) := by + have edi₂₂ : s₂₂.gpr .edi = BitVec.ofNat 32 (cnt s₀ % P.B + 1) := by rw [f₂₂.gpr, u₂₁.other _ (by decide), u₂₀.gpr, u₁₉.gpr, u₁₈.other _ (by decide), u₁₇.other _ (by decide), u₁₆.other _ (by decide), edi₁₅, ofNat_succ] - have hcf : s₂₂.cf = some (decide (cnt s₀ % 64 + 1 < 57)) := by - rw [cf₂₂, ← f₂₂.gpr, edi₂₂, toNat_ofNat_lt (by omega)]; rfl + have hcf : s₂₂.cf = some (decide (cnt s₀ % P.B + 1 < P.B - P.L + 1)) := by + rw [cf₂₂, ← f₂₂.gpr, edi₂₂, toNat_ofNat_lt (k := cnt s₀ % P.B + 1) (by omega), + toNat_ofNat_lt (k := P.B - P.L + 1) (by omega)] -- The facts about the buffer. have hst' : H.stateAt s₂₂.mem (stA s₀) = H.stateAt s₀.mem (stA s₀) := by apply H.stateAt_congr intro i hi rw [hm₂₂, hm₁₉, buf_add, writeBytes_before _ _ _ (by omega) (by simp; omega)] exact frame_bytes (proMem_frame hd hp) (R := stR P s₀) (by simpa using hp.st_scr) (by simp; omega) - (by show i < P.N + 64; omega) + (by show i < P.N + P.B; omega) have hbytes : ∀ iv m, R₀ H s₀ iv m → - bytesAt s₂₂.mem (buf P s₀) (cnt s₀ % 64 + 1) = MdStream.Md.rest 64 m ++ [0x80] := by + bytesAt s₂₂.mem (buf P s₀) (cnt s₀ % P.B + 1) = MdStream.Md.rest P.B m ++ [0x80] := by intro iv m hm - have e := bytesAt_writeBytes (proMem P s₀) (buf P s₀) (cnt s₀ % 64) [0x80] (by simp; omega) + have e := bytesAt_writeBytes (proMem P s₀) (buf P s₀) (cnt s₀ % P.B) [0x80] (by simp; omega) simp only [List.length_singleton] at e rw [hm₂₂, hm₁₉, e] refine congrArg (· ++ [0x80]) ?_ - rw [hm.length] + rw [hm.length hd] refine (bytesAt_congr ?_).trans hm.1.2 intro i hi rw [buf_add] exact frame_bytes (proMem_frame hd hp) (R := stR P s₀) (by simpa using hp.st_scr) (by simp; omega) - (by show P.N + i < P.N + 64; have := hm.length; omega) + (by show P.N + i < P.N + P.B; have := hm.length hd; omega) have hesi : s₂₂.gpr .esi = 0 := by rw [f₂₂.gpr, u₂₁.gpr] - refine WP.ite (!decide (cnt s₀ % 64 + 1 < 57)) (by show s₂₂.cf.map (!·) = _; rw [hcf]; rfl) + refine WP.ite (!decide (cnt s₀ % P.B + 1 < P.B - P.L + 1)) (by show s₂₂.cf.map (!·) = _; rw [hcf]; rfl) (fun hb => ?_) (fun hb => ?_) · simp only [Bool.not_eq_true', decide_eq_false_iff_not, Nat.not_lt] at hb refine wp_movi fun s₂₃ u₂₃ => WP.block_nil ⟨1, hC.of_gpr (fun r hr => u₂₃.other r (regs3 hr).2.2.2.2) - u₂₃.mem u₂₃.rd u₂₃.wr, (Nat.le_refl _), by omega, by rw [u₂₃.other _ (by decide), edi₂₂], by rw [u₂₃.gpr]; rfl, + u₂₃.mem u₂₃.rd u₂₃.wr, (Nat.le_refl _), by rw [lim_one]; omega, by rw [u₂₃.other _ (by decide), edi₂₂], by rw [u₂₃.gpr]; rfl, fun iv m hm _ => ?_⟩ simp only [↓reduceIte] - rw [H.hash_two (by omega) (by omega) (by rw [← hm.length]; omega), Fin1, u₂₃.mem, hbytes iv m hm, hst', - hm.1.1, ← hm.length, show 64 - (cnt s₀ % 64 + 1) = 64 - 1 - cnt s₀ % 64 by omega] + rw [H.hash_two hd.pos (by omega) (by rw [← hm.length hd]; omega), Fin1, u₂₃.mem, hbytes iv m hm, hst', + hm.1.1, ← (hm.length hd), show P.B - (cnt s₀ % P.B + 1) = P.B - 1 - cnt s₀ % P.B by omega] · simp only [Bool.not_eq_false', decide_eq_true_eq] at hb - refine WP.block_nil ⟨0, hC, by omega, by omega, edi₂₂, by rw [hesi]; rfl, fun iv m hm _ => ?_⟩ + refine WP.block_nil ⟨0, hC, Nat.zero_le _, by rw [lim_zero]; omega, edi₂₂, by rw [hesi]; rfl, fun iv m hm _ => ?_⟩ simp only [show ((0 : Nat) = 1) = False by decide, ite_false] - rw [H.hash_one (by omega) (by rw [← hm.length]; omega), Fin0, hbytes iv m hm, hst', hm.1.1, - ← hm.length, show 64 - 8 - (cnt s₀ % 64 + 1) = 64 - 8 - 1 - cnt s₀ % 64 by omega] + rw [H.hash_one hd.pos (by rw [← hm.length hd]; omega), Fin0, hbytes iv m hm, hst', hm.1.1, + ← (hm.length hd), show P.B - P.L - (cnt s₀ % P.B + 1) = P.B - P.L - 1 - cnt s₀ % P.B by omega] /-! ## Output and epilogue -/ @@ -1811,10 +1825,10 @@ theorem finalize_eq {name : String} {code : Prog isa} : finalize P name code = .mov .ecx (.mem (at_ .esp 8)), .store (at_ .ebp (P.so + 16)) .ecx, .mov .ecx (.mem (at_ .esp 12)), .store (at_ .ebp (P.so + 20)) .ecx, .mov .ecx (.mem (at_ .esp 16)), .store (at_ .ebp (P.so + 24)) .ecx, - .mov .edi (.mem (at_ .esp 8)), .alu .and .edi (.imm 63), + .mov .edi (.mem (at_ .esp 8)), .alu .and .edi (.imm (BitVec.ofNat 32 (P.B - 1))), .mov .edx (.reg .ebx), .alu .add .edx (.reg .edi), .mov .ecx (.imm 0x80), .store8 (at_ .edx P.N) .cl, .alu .add .edi (.imm 1), - .mov .esi (.imm 0), .alu .cmp .edi (.imm 57)] : List Instr))) + .mov .esi (.imm 0), .alu .cmp .edi (.imm (BitVec.ofNat 32 (P.B - P.L + 1)))] : List Instr))) (.seq (.ite .ae (.block [.mov .esi (.imm 1)]) (.block [])) (.seq (.loop (finalizeBody P name code) .e) (.block (.mov .eax (.mem (at_ .ebp (P.so + 24))) :: (P.out ++ restore P .ebp))))) := rfl @@ -1897,7 +1911,7 @@ theorem correct (hd : Dims P S) (hs : Shape H) {name : String} {code : Prog isa} epilogue_ok hd hp hD (by rw [rd, u₁.rd, hC.rd]) (by rw [wr, u₁.wr, hC.wr]) (fun r hr => by rw [g r (regs3 hr).2.1, u₁.other r (regs3 hr).1]) (by rw [m, heax, hebx, u₁.mem]) · refine ⟨stR P s₀, by simp [u₁.rd, u₁.wr, hC.rd, hC.wr, hp.wr, hp.rd], ?_⟩ - rw [hebx]; simpa using contains_offset (base := stA s₀) (off := 0) (n := P.N) (len := P.N + 64) + rw [hebx]; simpa using contains_offset (base := stA s₀) (off := 0) (n := P.N) (len := P.N + P.B) (by omega) (by omega) · refine ⟨outR P s₀, by simp [u₁.wr, hC.wr, hp.wr], ?_⟩ rw [heax]; simpa using contains_offset (base := outA s₀) (off := 0) (n := P.N) (len := P.N) @@ -1909,86 +1923,58 @@ end /-! ## Constant time -/ -/-- The initial taint: `esp + 4` is the base of the (public) arguments, whose -words at offsets 0, 12 and 16 are the base addresses of `state`, `out` and -`scratch`, and the 20 bytes below `esp` are outside the writable regions. -/ +/-- The initial taint: the stack arguments are public, the words holding +`state`, `out` and `scratch` are the base addresses of the writable regions, +and the 20 bytes below `esp` are outside them. -/ def τ₀ (P : Params) (S : Nat) : VG.X86.Taint.T := - { regs := .ofList [.esp], flags := false, lens := [P.N + 64, P.N, S, 20], bases := [(.esp, 3, 4)], - slots := [(3, 0, 20)], wbases := [(3, 0, 0), (3, 12, 1), (3, 16, 2)], room := 20 } + { regs := .ofList [.esp], flags := false, lens := [P.N + P.B, P.N, S], argLen := 24, + argBases := [(4, 0), (16, 1), (20, 2)], room := 20 } section -variable {P : Params} {S : Nat} {H : Md 64 P.N 8} +variable {P : Params} {S : Nat} {H : Md P.B P.N P.L} theorem wf₀ (hd : Dims P S) {s : State} (h : (finK H S).pre s) : VG.X86.Taint.Wf (τ₀ P S) s := by have hp := pre_of h have hst := hp.st_fit; have ho := hp.out_fit; have hsc := hp.scr_fit; have hs := hp.sp_fit have hlo := hp.sp_lo; have := hd.N obtain ⟨-, -, -, -, -, -, -, -, -, -, -, k1, k2, k3, -⟩ := h - refine VG.X86.Taint.Wf.entryRoom rfl ⟨fun _ => ⟨by simp [hp.wr, τ₀], ?_, ?_⟩, ?_, ?_, - fun h => absurd h (Nat.lt_irrefl 0), fun _ h => (List.not_mem_nil h).elim⟩ fun _ => ⟨hlo, ?_⟩ + refine VG.X86.Taint.Wf.entryRoom rfl ⟨fun _ => ⟨by simp [hp.wr, τ₀], ?_, ?_⟩, + fun _ h => (List.not_mem_nil h).elim, fun _ h => (List.not_mem_nil h).elim, + fun _ => ⟨hs, ?_⟩, ?_⟩ fun _ => ⟨hlo, ?_⟩ · simp only [hp.wr, List.pairwise_cons, List.mem_cons, List.not_mem_nil, or_false, forall_eq_or_imp, forall_eq, List.Pairwise.nil, and_true] - exact ⟨⟨hp.st_out, hp.st_scr, hp.a_st.symm⟩, ⟨hp.out_scr, hp.a_out.symm⟩, hp.a_scr.symm, fun _ h => h.elim⟩ + exact ⟨⟨hp.st_out, hp.st_scr⟩, hp.out_scr, fun _ h => h.elim⟩ · simp only [hp.wr, List.mem_cons, List.not_mem_nil, or_false] - rintro r (rfl | rfl | rfl | rfl) - · simp only [addr_toNat]; omega - · simp only [addr_toNat]; omega - · simp only [addr_toNat]; omega - · simp only; rw [addr_eq (by omega), BitVec.toNat_add, addr_toNat, BitVec.toNat_ofNat]; omega - · intro p hp' - simp only [τ₀, List.mem_singleton] at hp' - subst hp' - simp [VG.X86.Taint.region, hp.wr] + rintro r (rfl | rfl | rfl) <;> simp only [BitVec.toNat_setWidth] <;> omega + · simp only [hp.wr, List.mem_cons, List.not_mem_nil, or_false] + rintro r (rfl | rfl | rfl) + · exact VG.X86.Taint.frame_disjoint (n := 20) (by omega) hp.ret_st hp.a_st + · exact VG.X86.Taint.frame_disjoint (n := 20) (by omega) hp.ret_out hp.a_out + · exact VG.X86.Taint.frame_disjoint (n := 20) (by omega) hp.ret_scr hp.a_scr · intro p hp' simp only [τ₀, List.mem_cons, List.not_mem_nil, or_false] at hp' - rcases hp' with rfl | rfl | rfl - · refine ⟨by simp [τ₀], ?_⟩ - simp only [VG.X86.Taint.byteAddr, VG.X86.Taint.region, hp.wr] - show addr (s.mem.readW (addr (esp₀ s) 4 + BitVec.ofNat 64 0) 32) 0 = stA s - simp [addr, st, arg, argAddr] - · refine ⟨by simp [τ₀], ?_⟩ - simp only [VG.X86.Taint.byteAddr, VG.X86.Taint.region, hp.wr] - show addr (s.mem.readW (addr (esp₀ s) 4 + BitVec.ofNat 64 12) 32) 0 = outA s - rw [argWord_eq (n := 20) (by omega) (k := 12) (by omega)] - simp [addr, out, arg] - · refine ⟨by simp [τ₀], ?_⟩ - simp only [VG.X86.Taint.byteAddr, VG.X86.Taint.region, hp.wr] - show addr (s.mem.readW (addr (esp₀ s) 4 + BitVec.ofNat 64 16) 32) 0 = scA s - rw [argWord_eq (n := 20) (by omega) (k := 16) (by omega)] - simp [addr, scr, arg] + rcases hp' with rfl | rfl | rfl <;> refine ⟨by simp [τ₀], ?_⟩ <;> + simp [VG.X86.Taint.region, hp.wr, addr, arg, argAddr] · simp only [hp.wr, List.mem_cons, List.not_mem_nil, or_false] - rintro r (rfl | rfl | rfl | rfl) - · exact k1 - · exact k2 - · exact k3 - · intro a h₁ h₂ - simp only [Region.Contains, τ₀] at h₁ h₂ - rw [addr_eq (by omega)] at h₂ - have hE : ((esp₀ s).setWidth 64).toNat = (esp₀ s).toNat := addr_toNat _ - generalize (esp₀ s).setWidth 64 = b at * - bv_omega + rintro r (rfl | rfl | rfl) + exacts [k1, k2, k3] theorem agree₀ (hd : Dims P S) {s₁ s₂ : State} (h₁ : (finK H S).pre s₁) (h₂ : (finK H S).pre s₂) (hpub : (finK H S).pub s₁ s₂) : VG.X86.Taint.Agree (τ₀ P S) s₁ s₂ := by obtain ⟨hesp, ha⟩ := hpub have hp₁ := pre_of h₁; have hp₂ := pre_of h₂ - refine ⟨⟨fun r hr => ?_, fun h => nomatch h⟩, fun _ => ?_, wf₀ hd h₁, wf₀ hd h₂, ?_, ?_, - fun h => absurd h (Nat.lt_irrefl 0), fun _ _ h => absurd h (Nat.not_lt_zero _)⟩ + refine ⟨⟨fun r hr => ?_, fun h => nomatch h⟩, fun _ => ?_, wf₀ hd h₁, wf₀ hd h₂, + fun _ h => (List.not_mem_nil h).elim, fun _ h => (List.not_mem_nil h).elim, fun _ => hesp, + fun k h4 hk => ?_⟩ · simp only [τ₀, RegSet.mem_ofList, List.mem_singleton] at hr subst hr; exact hesp · rw [hp₁.wr, hp₂.wr] - simp only [stR, outR, scR, argR, stA, outA, scA, st, out, scr, esp₀, ha 0 (by omega), ha 3 (by omega), - ha 4 (by omega), hesp] - · intro sl hsl - simp only [τ₀, List.mem_singleton] at hsl - subst hsl; simp [τ₀] - · intro sl hsl k _ hk - simp only [τ₀, List.mem_singleton] at hsl - subst hsl - simp only [Nat.zero_add] at hk - simp only [VG.X86.Taint.byteAddr, VG.X86.Taint.region, hp₁.wr, hp₂.wr] - show s₁.mem (addr (esp₀ s₁) 4 + BitVec.ofNat 64 k) = s₂.mem (addr (esp₀ s₂) 4 + BitVec.ofNat 64 k) - rw [argWord_eq (n := 20) (by have := hp₁.sp_fit; omega) hk, argWord_eq (n := 20) (by have := hp₂.sp_fit; omega) hk, + simp only [stR, outR, scR, stA, outA, scA, st, out, scr, ha 0 (by omega), ha 3 (by omega), ha 4 (by omega)] + · simp only [τ₀] at hk + rw [show VG.X86.Taint.depth (τ₀ P S).stk = 0 from rfl, Nat.zero_add] + have f₁ : (s₁.gpr .esp).toNat + 24 ≤ 2 ^ 32 := hp₁.sp_fit + have f₂ : (s₂.gpr .esp).toNat + 24 ≤ 2 ^ 32 := hp₂.sp_fit + rw [VG.X86.Taint.argByte_eq f₁ h4 hk, VG.X86.Taint.argByte_eq f₂ h4 hk, Mem.readW_byte s₁.mem _ (Nat.mod_lt _ (by omega)), Mem.readW_byte s₂.mem _ (Nat.mod_lt _ (by omega))] exact congrArg _ (ha _ (by omega)) @@ -1998,7 +1984,7 @@ end def satMem : Mem := fun a => if a = 0x5005 then 0x10 else if a = 0x5011 then 0x20 else if a = 0x5015 then 0x30 else 0 -/-- The registers and memory of a state satisfying the precondition. -/ +/-- The registers and memory of a state satisfying the preconditions. -/ def sat₀ : State where gpr r := match r with | .esp => 0x5000 | _ => 0 @@ -2010,20 +1996,24 @@ def sat₀ : State where rd := [] wr := [] -/-- A state satisfying the precondition. -/ +/-- A state satisfying `finK`'s precondition. -/ +def satR (P : Params) (S : Nat) : State := + { sat₀ with rd := [⟨0x5004, 20⟩], wr := [⟨0x1000, P.N + P.B⟩, ⟨0x2000, P.N⟩, ⟨0x3000, S⟩] } + +/-- A state satisfying `finKw`'s precondition. -/ def sat (P : Params) (S : Nat) : State := - { sat₀ with wr := [⟨0x1000, P.N + 64⟩, ⟨0x2000, P.N⟩, ⟨0x3000, S⟩, ⟨0x5004, 20⟩] } + { sat₀ with wr := [⟨0x1000, P.N + P.B⟩, ⟨0x2000, P.N⟩, ⟨0x3000, S⟩, ⟨0x5004, 20⟩] } section -variable {P : Params} {S : Nat} {H : Md 64 P.N 8} - -theorem sat_pre (hd : Dims P S) : (finK H S).pre (sat P S) := by - have := hd.N; have := hd.S - have a0 : arg (sat P S) 0 = 0x1000 := show arg sat₀ 0 = _ by decide - have a3 : arg (sat P S) 3 = 0x2000 := show arg sat₀ 3 = _ by decide - have a4 : arg (sat P S) 4 = 0x3000 := show arg sat₀ 4 = _ by decide - have e : argAddr (sat P S) 0 = 0x5004 := show argAddr sat₀ 0 = _ by decide - have hsp : (sat P S).gpr .esp = 0x5000 := rfl +variable {P : Params} {S : Nat} {H : Md P.B P.N P.L} + +theorem satR_pre (hd : Dims P S) : (finK H S).pre (satR P S) := by + have := hd.N; have := hd.S; have := hd.le + have a0 : arg (satR P S) 0 = 0x1000 := show arg sat₀ 0 = _ by decide + have a3 : arg (satR P S) 3 = 0x2000 := show arg sat₀ 3 = _ by decide + have a4 : arg (satR P S) 4 = 0x3000 := show arg sat₀ 4 = _ by decide + have e : argAddr (satR P S) 0 = 0x5004 := show argAddr sat₀ 0 = _ by decide + have hsp : (satR P S).gpr .esp = 0x5000 := rfl simp only [finK, a0, a3, a4, e, hsp] have hs : ((0x5000 : BitVec 32).setWidth 64 - 20 : Addr) = 0x4FEC := by decide simp only [hs] @@ -2035,15 +2025,57 @@ theorem sat_pre (hd : Dims P S) : (finK H S).pre (sat P S) := by | exact (Offset.disjoint_of_le (by simp only [BitVec.toNat_setWidth, BitVec.reduceToNat]; omega) (by simp only [BitVec.toNat_setWidth, BitVec.reduceToNat]; omega)).symm +theorem sat_pre (hd : Dims P S) : (finKw H S).pre (sat P S) := by + have ⟨_, _, h⟩ := satR_pre (H := H) hd + have a0 : arg (sat P S) 0 = 0x1000 := show arg sat₀ 0 = _ by decide + have a3 : arg (sat P S) 3 = 0x2000 := show arg sat₀ 3 = _ by decide + have a4 : arg (sat P S) 4 = 0x3000 := show arg sat₀ 4 = _ by decide + have e : argAddr (sat P S) 0 = 0x5004 := show argAddr sat₀ 0 = _ by decide + refine ⟨rfl, ?_, h⟩ + simp only [a0, a3, a4, e]; rfl + /-- `finalize` is verified, given that it is constant time (by the taint analysis of each hash function's code, from `τ₀` and `agree₀`). -/ -theorem verified (hd : Dims P S) (hs : Shape H) {name : String} {code : Prog isa} (hf : CalleeOk H code) +theorem verified_ro (hd : Dims P S) (hs : Shape H) {name : String} {code : Prog isa} (hf : CalleeOk H code) (hct : ConstantTime isa (finK H S).pre (finK H S).pub (finalize P name code)) : Verified X86.target (finalize P name code) (finK H S) := by - refine ⟨fun s hs' => ?_, hct, ⟨sat P S, sat_pre hd⟩⟩ + refine ⟨fun s hs' => ?_, hct, ⟨satR P S, satR_pre hd⟩⟩ obtain ⟨t, s', he, h⟩ := correct hd hs hf (pre_of hs') exact ⟨t, s', he, h⟩ +/-- `finalize` is also verified against `finKw`, which lets it write its arguments. -/ +theorem verified (hd : Dims P S) (hs : Shape H) {name : String} {code : Prog isa} (hf : CalleeOk H code) + (hct : ConstantTime isa (finK H S).pre (finK H S).pub (finalize P name code)) : + Verified X86.target (finalize P name code) (finKw H S) := by + have pre : ∀ s, (finKw H S).pre s → (finK H S).pre (s.withRegions + [⟨argAddr s 0, 20⟩] [⟨(arg s 0).setWidth 64, P.N + P.B⟩, ⟨(arg s 3).setWidth 64, P.N⟩, + ⟨(arg s 4).setWidth 64, S⟩]) := by + intro s h + obtain ⟨_, _, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11, h12, h13, h14, h15, h16, h17, h18⟩ := h + simp only [finK, arg_withRegions, argAddr_withRegions, State.withRegions_gpr, State.withRegions_rd, + State.withRegions_wr] + exact ⟨trivial, trivial, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11, h12, h13, h14, h15, h16, h17, h18⟩ + refine Verified.narrowTo (verified_ro hd hs hf hct) _ _ pre (fun s h => ?_) (fun s h => ?_) + (fun _ _ _ h => h) (fun _ _ _ _ h => h) ⟨sat P S, sat_pre hd⟩ + · obtain ⟨h1, h2, _⟩ := h + rw [h1, h2] + refine Covers.of_sub fun r hr => ?_ + simp only [List.cons_append, List.nil_append, List.mem_cons, List.not_mem_nil, or_false] at hr + rcases hr with rfl | rfl | rfl | rfl + · exact ⟨_, List.mem_cons_of_mem _ (List.mem_cons_of_mem _ (List.mem_cons_of_mem _ List.mem_cons_self)), 0, + by simp, by simp⟩ + · exact ⟨_, List.mem_cons_self, 0, by simp, by simp⟩ + · exact ⟨_, List.mem_cons_of_mem _ List.mem_cons_self, 0, by simp, by simp⟩ + · exact ⟨_, List.mem_cons_of_mem _ (List.mem_cons_of_mem _ List.mem_cons_self), 0, by simp, by simp⟩ + · obtain ⟨_, h2, _⟩ := h + rw [h2] + refine Covers.of_sub fun r hr => ?_ + simp only [List.mem_cons, List.not_mem_nil, or_false] at hr + rcases hr with rfl | rfl | rfl + · exact ⟨_, List.mem_cons_self, 0, by simp, by simp⟩ + · exact ⟨_, List.mem_cons_of_mem _ List.mem_cons_self, 0, by simp, by simp⟩ + · exact ⟨_, List.mem_cons_of_mem _ (List.mem_cons_of_mem _ List.mem_cons_self), 0, by simp, by simp⟩ + end end VG.Proof.MdStream.X86.Finalize diff --git a/lean/VerifiedGarbage/Proof/MdStream/X86/Words.lean b/lean/VerifiedGarbage/Proof/MdStream/X86/Words.lean index ae10ed5d9..64953641c 100644 --- a/lean/VerifiedGarbage/Proof/MdStream/X86/Words.lean +++ b/lean/VerifiedGarbage/Proof/MdStream/X86/Words.lean @@ -56,40 +56,31 @@ theorem bitCount (hi lo : BitVec 32) : (hi <<< 3 ||| lo >>> 29) ++ lo <<< 3 = BitVec.ofNat 64 (8 * (hi ++ lo).toNat) := by rw [shl3, bits8] -/-- `len64 so d be` stores `8 · count`, from `count` in `[ebp + so + 16]` (low -word) and `[ebp + so + 20]` (high word), at `ebx + d`. -/ -theorem len64_ok {so d : Nat} {be : Bool} {s : State} (hfit : (s.gpr .ebx).toNat + d + 8 ≤ 2 ^ 32) - (hlo : InRegions (s.rd ++ s.wr) (addr (s.gpr .ebp) (so + 16)) 4) - (hhi : InRegions (s.rd ++ s.wr) (addr (s.gpr .ebp) (so + 20)) 4) +/-- `len64Of d be` stores `8 · count`, from `count` in `eax` (low word) and `ecx` (high word), at +`ebx + d`. -/ +theorem len64Of_ok {d : Nat} {be : Bool} {s : State} {hi lo : BitVec 32} + (hfit : (s.gpr .ebx).toNat + d + 8 ≤ 2 ^ 32) (hax : s.gpr .eax = lo) (hcx : s.gpr .ecx = hi) (ho₁ : InRegions s.wr (addr (s.gpr .ebx) d) 4) (ho₂ : InRegions s.wr (addr (s.gpr .ebx) (d + 4)) 4) : - WP isa (.block (len64 so d be)) s fun s' => + WP isa (.block (len64Of d be)) s fun s' => (∀ r, r ≠ .eax → r ≠ .ecx → r ≠ .edx → s'.gpr r = s.gpr r) ∧ s'.rd = s.rd ∧ s'.wr = s.wr ∧ s'.mem = writeBytes s.mem ((s.gpr .ebx).setWidth 64 + BitVec.ofNat 64 d) - (bytes64 be (BitVec.ofNat 64 (8 * (s.mem.readW (addr (s.gpr .ebp) (so + 20)) 32 ++ - s.mem.readW (addr (s.gpr .ebp) (so + 16)) 32).toNat))) := by - set lo := s.mem.readW (addr (s.gpr .ebp) (so + 16)) 32 with hlo' - set hi := s.mem.readW (addr (s.gpr .ebp) (so + 20)) 32 with hhi' - unfold len64 - refine wp_movm (a := addr (s.gpr .ebp) (so + 16)) (ea_at _ _ _) hlo fun s₁ u₁ => ?_ - refine wp_movm (a := addr (s.gpr .ebp) (so + 20)) (by rw [ea_at, u₁.other _ (by decide)]) - (by rw [u₁.rd, u₁.wr]; exact hhi) fun s₂ u₂ => ?_ + (bytes64 be (BitVec.ofNat 64 (8 * (hi ++ lo).toNat))) := by + unfold len64Of refine wp_add fun s₃ u₃ => wp_add fun s₄ u₄ => wp_add fun s₅ u₅ => wp_mov fun s₆ u₆ => wp_shr (by decide) fun s₇ u₇ => wp_or fun s₈ u₈ => wp_add fun s₉ u₉ => wp_add fun s₁₀ u₁₀ => wp_add fun s₁₁ u₁₁ => ?_ have g : ∀ r, r ≠ .eax → r ≠ .ecx → r ≠ .edx → s₁₁.gpr r = s.gpr r := fun r h1 h2 h3 => by rw [u₁₁.other r h1, u₁₀.other r h1, u₉.other r h1, u₈.other r h2, u₇.other r h3, - u₆.other r h3, u₅.other r h2, u₄.other r h2, u₃.other r h2, u₂.other r h2, u₁.other r h1] + u₆.other r h3, u₅.other r h2, u₄.other r h2, u₃.other r h2] have m₁₁ : s₁₁.mem = s.mem := by - rw [u₁₁.mem, u₁₀.mem, u₉.mem, u₈.mem, u₇.mem, u₆.mem, u₅.mem, u₄.mem, u₃.mem, u₂.mem, u₁.mem] + rw [u₁₁.mem, u₁₀.mem, u₉.mem, u₈.mem, u₇.mem, u₆.mem, u₅.mem, u₄.mem, u₃.mem] have rd₁₁ : s₁₁.rd = s.rd := by - rw [u₁₁.rd, u₁₀.rd, u₉.rd, u₈.rd, u₇.rd, u₆.rd, u₅.rd, u₄.rd, u₃.rd, u₂.rd, u₁.rd] + rw [u₁₁.rd, u₁₀.rd, u₉.rd, u₈.rd, u₇.rd, u₆.rd, u₅.rd, u₄.rd, u₃.rd] have wr₁₁ : s₁₁.wr = s.wr := by - rw [u₁₁.wr, u₁₀.wr, u₉.wr, u₈.wr, u₇.wr, u₆.wr, u₅.wr, u₄.wr, u₃.wr, u₂.wr, u₁.wr] - have c2 : s₂.gpr .ecx = hi := by rw [u₂.gpr, u₁.mem] - have a2 : s₂.gpr .eax = lo := by rw [u₂.other _ (by decide), u₁.gpr] - have c5 : s₅.gpr .ecx = hi <<< 3 := by rw [u₅.gpr, u₄.gpr, u₃.gpr, c2, times8] + rw [u₁₁.wr, u₁₀.wr, u₉.wr, u₈.wr, u₇.wr, u₆.wr, u₅.wr, u₄.wr, u₃.wr] + have c5 : s₅.gpr .ecx = hi <<< 3 := by rw [u₅.gpr, u₄.gpr, u₃.gpr, hcx, times8] have a5 : s₅.gpr .eax = lo := by - rw [u₅.other _ (by decide), u₄.other _ (by decide), u₃.other _ (by decide), a2] + rw [u₅.other _ (by decide), u₄.other _ (by decide), u₃.other _ (by decide), hax] have d7 : s₇.gpr .edx = lo >>> 29 := by rw [u₇.gpr, u₆.gpr, a5] have c8 : s₈.gpr .ecx = (hi <<< 3) ||| (lo >>> 29) := by rw [u₈.gpr, u₇.other _ (by decide), u₆.other _ (by decide), c5, d7] @@ -100,9 +91,6 @@ theorem len64_ok {so d : Nat} {be : Bool} {s : State} (hfit : (s.gpr .ebx).toNat rw [u₁₁.other _ (by decide), u₁₀.other _ (by decide), u₉.other _ (by decide), c8] have ebx₁₁ : s₁₁.gpr .ebx = s.gpr .ebx := g _ (by decide) (by decide) (by decide) have e₁ : addr (s.gpr .ebx) d = (s.gpr .ebx).setWidth 64 + BitVec.ofNat 64 d := addr_eq (by omega) - have e₂ : addr (s.gpr .ebx) (d + 4) = (s.gpr .ebx).setWidth 64 + BitVec.ofNat 64 d + - BitVec.ofNat 64 (bytes32 true (lo <<< 3)).length := by - rw [addr_eq (by omega), add_ofNat]; rfl have hx := bitCount hi lo cases be · simp only [Bool.false_eq_true, ite_false] @@ -139,62 +127,108 @@ theorem len64_ok {so d : Nat} {be : Bool} {s : State} (hfit : (s.gpr .ebx).toNat rw [addr_eq (by omega), add_ofNat]; rfl, writeBytes_append _ _ _ _ (by simp [bytes32])] +/-- `loadCount so` loads `count` into `eax` (low word) and `ecx` (high word). -/ +theorem loadCount_ok {so : Nat} {s : State} {rest : List Instr} {Q : State → Prop} + (hlo : InRegions (s.rd ++ s.wr) (addr (s.gpr .ebp) (so + 16)) 4) + (hhi : InRegions (s.rd ++ s.wr) (addr (s.gpr .ebp) (so + 20)) 4) + (k : ∀ s', (∀ r, r ≠ .eax → r ≠ .ecx → s'.gpr r = s.gpr r) → s'.mem = s.mem → s'.rd = s.rd → + s'.wr = s.wr → s'.gpr .eax = s.mem.readW (addr (s.gpr .ebp) (so + 16)) 32 → + s'.gpr .ecx = s.mem.readW (addr (s.gpr .ebp) (so + 20)) 32 → WP isa (.block rest) s' Q) : + WP isa (.block (loadCount so ++ rest)) s Q := by + refine wp_movm (a := addr (s.gpr .ebp) (so + 16)) (ea_at _ _ _) hlo fun s₁ u₁ => ?_ + refine wp_movm (a := addr (s.gpr .ebp) (so + 20)) (by rw [ea_at, u₁.other _ (by decide)]) + (by rw [u₁.rd, u₁.wr]; exact hhi) fun s₂ u₂ => k s₂ (fun r h1 h2 => by rw [u₂.other r h2, u₁.other r h1]) + (by rw [u₂.mem, u₁.mem]) (by rw [u₂.rd, u₁.rd]) (by rw [u₂.wr, u₁.wr]) + (by rw [u₂.other _ (by decide), u₁.gpr]) (by rw [u₂.gpr, u₁.mem]) + +/-- `len64 so d be` stores `8 · count`, from `count` in `[ebp + so + 16]` (low +word) and `[ebp + so + 20]` (high word), at `ebx + d`. -/ +theorem len64_ok {so d : Nat} {be : Bool} {s : State} (hfit : (s.gpr .ebx).toNat + d + 8 ≤ 2 ^ 32) + (hlo : InRegions (s.rd ++ s.wr) (addr (s.gpr .ebp) (so + 16)) 4) + (hhi : InRegions (s.rd ++ s.wr) (addr (s.gpr .ebp) (so + 20)) 4) + (ho₁ : InRegions s.wr (addr (s.gpr .ebx) d) 4) (ho₂ : InRegions s.wr (addr (s.gpr .ebx) (d + 4)) 4) : + WP isa (.block (len64 so d be)) s fun s' => + (∀ r, r ≠ .eax → r ≠ .ecx → r ≠ .edx → s'.gpr r = s.gpr r) ∧ s'.rd = s.rd ∧ s'.wr = s.wr ∧ + s'.mem = writeBytes s.mem ((s.gpr .ebx).setWidth 64 + BitVec.ofNat 64 d) + (bytes64 be (BitVec.ofNat 64 (8 * (s.mem.readW (addr (s.gpr .ebp) (so + 20)) 32 ++ + s.mem.readW (addr (s.gpr .ebp) (so + 16)) 32).toNat))) := + loadCount_ok hlo hhi fun s' g m rd wr ha hc => by + have hb : s'.gpr .ebx = s.gpr .ebx := g _ (by decide) (by decide) + refine (len64Of_ok (by rw [hb]; exact hfit) ha hc (by rw [wr, hb]; exact ho₁) (by rw [wr, hb]; exact ho₂)).mono + fun s'' ⟨g', rd', wr', m'⟩ => ⟨fun r h1 h2 h3 => by rw [g' r h1 h2 h3, g r h1 h2], rd'.trans rd, + wr'.trans wr, by rw [m', m, hb]⟩ + /-! ## The digest -/ -/-- Words `[k, n)` of the hash value at `ebx` are written as `f` says, the +/-- The `w`-byte words `[k, n)` of the hash value at `ebx` are written to `eax` as `g` says, the first `k` already written. -/ -theorem out_words (n : Nat) (hn : 4 * n ≤ 64) (f : BitVec 32 → List Byte) - (hf : ∀ x, (f x).length = 4) (ins : Nat → List Instr) {s₀ : State} +theorem out_words (n w : Nat) (hwn : w * n ≤ 64) (g : Nat → List Byte) (hg : ∀ k, (g k).length = w) + (ins : Nat → List Instr) {s₀ : State} (hstep : ∀ k < n, ∀ (s : State) (rest : List Instr) (Q : State → Prop), s.gpr .ebx = s₀.gpr .ebx → s.gpr .eax = s₀.gpr .eax → s.rd = s₀.rd → s.wr = s₀.wr → + Frame [⟨(s₀.gpr .eax).setWidth 64, w * n⟩] s₀.mem s.mem → (∀ s', (∀ r, r ≠ .ecx → s'.gpr r = s.gpr r) → s'.rd = s.rd → s'.wr = s.wr → - s'.mem = writeBytes s.mem ((s₀.gpr .eax).setWidth 64 + BitVec.ofNat 64 (4 * k)) - (f (s.mem.readW ((s₀.gpr .ebx).setWidth 64 + BitVec.ofNat 64 (4 * k)) 32)) → WP isa (.block rest) s' Q) → - WP isa (.block (ins k ++ rest)) s Q) - (hd : Region.Disjoint ⟨(s₀.gpr .ebx).setWidth 64, 4 * n⟩ ⟨(s₀.gpr .eax).setWidth 64, 4 * n⟩) : + s'.mem = writeBytes s.mem ((s₀.gpr .eax).setWidth 64 + BitVec.ofNat 64 (w * k)) (g k) → + WP isa (.block rest) s' Q) → + WP isa (.block (ins k ++ rest)) s Q) : ∀ j ≤ n, ∀ s, (∀ r, r ≠ .ecx → s.gpr r = s₀.gpr r) → s.rd = s₀.rd → s.wr = s₀.wr → - s.mem = writeBytes s₀.mem ((s₀.gpr .eax).setWidth 64) - ((List.range (n - j)).flatMap fun k => f (s₀.mem.readW ((s₀.gpr .ebx).setWidth 64 + BitVec.ofNat 64 (4 * k)) 32)) → + s.mem = writeBytes s₀.mem ((s₀.gpr .eax).setWidth 64) ((List.range (n - j)).flatMap g) → WP isa (.block (((List.range n).drop (n - j)).flatMap ins)) s fun s' => (∀ r, r ≠ .ecx → s'.gpr r = s₀.gpr r) ∧ s'.rd = s₀.rd ∧ s'.wr = s₀.wr ∧ - s'.mem = writeBytes s₀.mem ((s₀.gpr .eax).setWidth 64) - ((List.range n).flatMap fun k => f (s₀.mem.readW ((s₀.gpr .ebx).setWidth 64 + BitVec.ofNat 64 (4 * k)) 32)) := by - have hflat : ∀ k, ((List.range k).flatMap fun k => f (s₀.mem.readW ((s₀.gpr .ebx).setWidth 64 + - BitVec.ofNat 64 (4 * k)) 32)).length = 4 * k := by + s'.mem = writeBytes s₀.mem ((s₀.gpr .eax).setWidth 64) ((List.range n).flatMap g) := by + have hflat : ∀ k, ((List.range k).flatMap g).length = w * k := by intro k - rw [List.length_flatMap, List.map_congr_left (fun x _ => hf _), List.map_const', List.sum_replicate_nat, + rw [List.length_flatMap, List.map_congr_left (fun x _ => hg _), List.map_const', List.sum_replicate_nat, List.length_range, Nat.mul_comm] intro j induction j with | zero => - intro _ s g rd wr m + intro _ s hg' rd wr m rw [Nat.sub_zero, List.drop_of_length_le (by simp), List.flatMap_nil] - exact WP.block_nil ⟨g, rd, wr, m⟩ + exact WP.block_nil ⟨hg', rd, wr, m⟩ | succ j ih => - intro hj s g rd wr m + intro hj s hg' rd wr m have hk : n - (j + 1) < n := by omega + have hle : w * (n - (j + 1)) + w ≤ w * n := by + rw [← Nat.mul_succ]; exact Nat.mul_le_mul_left w (by omega) rw [List.drop_eq_getElem_cons (by simp; omega), List.flatMap_cons, List.getElem_range] - refine hstep _ hk s _ _ (by rw [g _ (by decide)]) (by rw [g _ (by decide)]) rd wr - fun s' g' rd' wr' m' => ?_ - rw [show n - (j + 1) + 1 = n - j by omega] - refine ih (by omega) s' (fun r h => by rw [g' r h, g r h]) (rd'.trans rd) (wr'.trans wr) ?_ - -- The word read is not yet overwritten. - have h1 : 4 * (n - (j + 1)) + 4 ≤ 4 * n := by omega - have hread : s.mem.readW ((s₀.gpr .ebx).setWidth 64 + BitVec.ofNat 64 (4 * (n - (j + 1)))) 32 = - s₀.mem.readW ((s₀.gpr .ebx).setWidth 64 + BitVec.ofNat 64 (4 * (n - (j + 1)))) 32 := by + have hf : Frame [⟨(s₀.gpr .eax).setWidth 64, w * n⟩] s₀.mem s.mem := by rw [m] - refine (writeBytes_frame _ _ _ (R := ⟨(s₀.gpr .eax).setWidth 64, 4 * n⟩) ?_).readW - (r := ⟨(s₀.gpr .ebx).setWidth 64 + BitVec.ofNat 64 (4 * (n - (j + 1))), 4⟩) - (Region.contains_self _ _) ?_ (by decide) - · rw [hflat] - simp only [Region.Contains, BitVec.sub_self, BitVec.toNat_zero, Nat.zero_add] - omega - · intro r' hr' - simp only [List.mem_cons, List.not_mem_nil, or_false] at hr' - subst hr' - exact hd.sub_left (sub_offset h1 (by omega)) - rw [m', hread, m, show n - j = n - (j + 1) + 1 by omega, List.range_succ, List.flatMap_append, - List.flatMap_singleton, ← writeBytes_append _ _ _ _ (by rw [hflat, hf]; omega), hflat] + refine writeBytes_frame _ _ _ ?_ + rw [hflat] + simp only [Region.Contains, BitVec.sub_self, BitVec.toNat_zero, Nat.zero_add] + omega + refine hstep _ hk s _ _ (by rw [hg' _ (by decide)]) (by rw [hg' _ (by decide)]) rd wr hf + fun s' hg'' rd' wr' m' => ?_ + rw [show n - (j + 1) + 1 = n - j by omega] + refine ih (by omega) s' (fun r h => by rw [hg'' r h, hg' r h]) (rd'.trans rd) (wr'.trans wr) ?_ + rw [m', m, show n - j = n - (j + 1) + 1 by omega, List.range_succ, List.flatMap_append, + List.flatMap_singleton, ← writeBytes_append _ _ _ _ (by rw [hflat, hg]; omega), hflat] + +/-- A word of the hash value at `ebx`, while only the digest at `eax` is written. -/ +theorem out_read {s₀ : State} {m : Mem} {n o : Nat} + (hf : Frame [⟨(s₀.gpr .eax).setWidth 64, n⟩] s₀.mem m) + (hd : Region.Disjoint ⟨(s₀.gpr .ebx).setWidth 64, n⟩ ⟨(s₀.gpr .eax).setWidth 64, n⟩) + (h : o + 4 ≤ n) (hn : n ≤ 64) : + m.readW ((s₀.gpr .ebx).setWidth 64 + BitVec.ofNat 64 o) 32 = + s₀.mem.readW ((s₀.gpr .ebx).setWidth 64 + BitVec.ofNat 64 o) 32 := + hf.readW (r := ⟨_, 4⟩) (Region.contains_self _ _) (fun r' hr' => by + simp only [List.mem_cons, List.not_mem_nil, or_false] at hr' + subst hr' + exact hd.sub_left (sub_offset h (by omega))) (by decide) + +/-- `[x + o, x + o + 4)` lies in a region of `n` bytes at `x`. -/ +theorem out_in {rs : List Region} {a : Addr} {n o : Nat} (h : InRegions rs a n) (ho : o + 4 ≤ n) (hn : n ≤ 64) : + InRegions rs (a + BitVec.ofNat 64 o) 4 := by + obtain ⟨R, hR, hc⟩ := h + refine ⟨R, hR, ?_⟩ + simp only [Region.Contains] at * + have : (a + BitVec.ofNat 64 o - R.base).toNat ≤ (a - R.base).toNat + o := by + rw [show a + BitVec.ofNat 64 o - R.base = (a - R.base) + BitVec.ofNat 64 o by + rw [VG.Offset.add_sub_comm], + BitVec.toNat_add, BitVec.toNat_ofNat, Nat.mod_eq_of_lt (a := o) (by omega)] + exact Nat.mod_le _ _ + omega /-- `out32 n be` writes the `n` 32-bit words at `ebx` to `eax`. -/ theorem out32_ok {n : Nat} (be : Bool) (hn : 4 * n ≤ 64) {s₀ : State} @@ -207,41 +241,86 @@ theorem out32_ok {n : Nat} (be : Bool) (hn : 4 * n ≤ 64) {s₀ : State} s'.mem = writeBytes s₀.mem ((s₀.gpr .eax).setWidth 64) ((List.range n).flatMap fun k => bytes32 be (s₀.mem.readW ((s₀.gpr .ebx).setWidth 64 + BitVec.ofNat 64 (4 * k)) 32)) := by - have h := out_words n hn (bytes32 be) (bytes32_length be) + have h := out_words n 4 hn (fun k => bytes32 be (s₀.mem.readW ((s₀.gpr .ebx).setWidth 64 + + BitVec.ofNat 64 (4 * k)) 32)) (fun _ => bytes32_length be _) (fun k => [.mov .ecx (.mem (at_ .ebx (4 * k)))] ++ (if be then [.bswap .ecx] else []) ++ - [.store (at_ .eax (4 * k)) .ecx]) (s₀ := s₀) ?_ hd n (Nat.le_refl _) s₀ (fun _ _ => rfl) rfl rfl + [.store (at_ .eax (4 * k)) .ecx]) (s₀ := s₀) ?_ n (Nat.le_refl _) s₀ (fun _ _ => rfl) rfl rfl (by rw [Nat.sub_self, List.range_zero, List.flatMap_nil, writeBytes_nil]) · rw [Nat.sub_self, List.drop_zero] at h exact h - intro k hk s rest Q hbx' hax' hrd hwr kk + intro k hk s rest Q hbx' hax' hrd hwr hf kk have hoff : 4 * k + 4 ≤ 4 * n := by omega - have inr : ∀ {rs : List Region} {a : Addr}, InRegions rs a (4 * n) → - InRegions rs (a + BitVec.ofNat 64 (4 * k)) 4 := by - intro rs a ⟨R, hR, hc⟩ - refine ⟨R, hR, ?_⟩ - simp only [Region.Contains] at * - have : (a + BitVec.ofNat 64 (4 * k) - R.base).toNat ≤ (a - R.base).toNat + 4 * k := by - rw [show a + BitVec.ofNat 64 (4 * k) - R.base = (a - R.base) + BitVec.ofNat 64 (4 * k) by - rw [VG.Offset.add_sub_comm], - BitVec.toNat_add, BitVec.toNat_ofNat, Nat.mod_eq_of_lt (a := 4 * k) (by omega)] - exact Nat.mod_le _ _ - omega + have hread := out_read hf hd hoff hn refine wp_movm (a := (s₀.gpr .ebx).setWidth 64 + BitVec.ofNat 64 (4 * k)) (by rw [ea_at, hbx', addr_eq (by omega)]) - (by rw [hrd, hwr]; exact inr hin) fun s₁ u₁ => ?_ + (by rw [hrd, hwr]; exact out_in hin hoff hn) fun s₁ u₁ => ?_ have ea₁ : ∀ t : State, t.gpr .eax = s₀.gpr .eax → t.ea (at_ .eax (4 * k)) = (s₀.gpr .eax).setWidth 64 + BitVec.ofNat 64 (4 * k) := fun t ht => by rw [ea_at, ht, addr_eq (by omega)] cases be · refine wp_store (ea₁ s₁ (by rw [u₁.other _ (by decide), hax'])) - (by rw [u₁.wr, hwr]; exact inr hout) fun s₂ u₂ => ?_ + (by rw [u₁.wr, hwr]; exact out_in hout hoff hn) fun s₂ u₂ => ?_ refine kk s₂ (fun r h => by rw [u₂.gpr, u₁.other r h]) (by rw [u₂.rd, u₁.rd]) (by rw [u₂.wr, u₁.wr]) ?_ - rw [u₂.mem, u₁.mem, u₁.gpr, ← writeW32 _ _ false]; rfl + rw [u₂.mem, u₁.mem, u₁.gpr, hread, ← writeW32 _ _ false]; rfl · refine wp_bswap fun s₂ u₂ => wp_store (ea₁ s₂ (by rw [u₂.other _ (by decide), - u₁.other _ (by decide), hax'])) (by rw [u₂.wr, u₁.wr, hwr]; exact inr hout) + u₁.other _ (by decide), hax'])) (by rw [u₂.wr, u₁.wr, hwr]; exact out_in hout hoff hn) fun s₃ u₃ => ?_ refine kk s₃ (fun r h => by rw [u₃.gpr, u₂.other r h, u₁.other r h]) (by rw [u₃.rd, u₂.rd, u₁.rd]) (by rw [u₃.wr, u₂.wr, u₁.wr]) ?_ - rw [u₃.mem, u₂.mem, u₁.mem, u₂.gpr, u₁.gpr, ← writeW32 _ _ true]; rfl + rw [u₃.mem, u₂.mem, u₁.mem, u₂.gpr, u₁.gpr, hread, ← writeW32 _ _ true]; rfl + +/-- `out64 n` writes the `n` 64-bit words at `ebx`, each stored little-endian (its low half +first), to `eax` big-endian: the high half, then the low half. -/ +theorem out64_ok {n : Nat} (hn : 8 * n ≤ 64) {s₀ : State} + (hbx : (s₀.gpr .ebx).toNat + 8 * n ≤ 2 ^ 32) (hax : (s₀.gpr .eax).toNat + 8 * n ≤ 2 ^ 32) + (hin : InRegions (s₀.rd ++ s₀.wr) ((s₀.gpr .ebx).setWidth 64) (8 * n)) + (hout : InRegions s₀.wr ((s₀.gpr .eax).setWidth 64) (8 * n)) + (hd : Region.Disjoint ⟨(s₀.gpr .ebx).setWidth 64, 8 * n⟩ ⟨(s₀.gpr .eax).setWidth 64, 8 * n⟩) : + WP isa (.block (out64 n)) s₀ fun s' => + (∀ r, r ≠ .ecx → s'.gpr r = s₀.gpr r) ∧ s'.rd = s₀.rd ∧ s'.wr = s₀.wr ∧ + s'.mem = writeBytes s₀.mem ((s₀.gpr .eax).setWidth 64) + ((List.range n).flatMap fun k => + bytes32 true (s₀.mem.readW ((s₀.gpr .ebx).setWidth 64 + BitVec.ofNat 64 (8 * k + 4)) 32) ++ + bytes32 true (s₀.mem.readW ((s₀.gpr .ebx).setWidth 64 + BitVec.ofNat 64 (8 * k)) 32)) := by + have h := out_words n 8 hn (fun k => + bytes32 true (s₀.mem.readW ((s₀.gpr .ebx).setWidth 64 + BitVec.ofNat 64 (8 * k + 4)) 32) ++ + bytes32 true (s₀.mem.readW ((s₀.gpr .ebx).setWidth 64 + BitVec.ofNat 64 (8 * k)) 32)) + (fun _ => by simp [bytes32_length]) + (fun k => [.mov .ecx (.mem (at_ .ebx (8 * k + 4))), .bswap .ecx, .store (at_ .eax (8 * k)) .ecx, + .mov .ecx (.mem (at_ .ebx (8 * k))), .bswap .ecx, .store (at_ .eax (8 * k + 4)) .ecx]) + (s₀ := s₀) ?_ n (Nat.le_refl _) s₀ (fun _ _ => rfl) rfl rfl + (by rw [Nat.sub_self, List.range_zero, List.flatMap_nil, writeBytes_nil]) + · rw [Nat.sub_self, List.drop_zero] at h + exact h + intro k hk s rest Q hbx' hax' hrd hwr hf kk + have h₀ : 8 * k + 4 ≤ 8 * n := by omega + have h₄ : 8 * k + 4 + 4 ≤ 8 * n := by omega + have ea : ∀ (t : State) (r : Reg) (o : Nat), t.gpr r = s₀.gpr r → (s₀.gpr r).toNat + o < 2 ^ 32 → + t.ea (at_ r o) = (s₀.gpr r).setWidth 64 + BitVec.ofNat 64 o := fun t r o ht ho => by + rw [ea_at, ht, addr_eq ho] + simp only [List.cons_append, List.nil_append] + refine wp_movm (ea s .ebx _ hbx' (by omega)) (by rw [hrd, hwr]; exact out_in hin h₄ hn) fun s₁ u₁ => + wp_bswap fun s₂ u₂ => ?_ + refine wp_store (ea s₂ .eax _ (by rw [u₂.other _ (by decide), u₁.other _ (by decide), hax']) (by omega)) + (by rw [u₂.wr, u₁.wr, hwr]; exact out_in hout h₀ hn) fun s₃ u₃ => ?_ + have hf₃ : Frame [⟨(s₀.gpr .eax).setWidth 64, 8 * n⟩] s₀.mem s₃.mem := by + rw [u₃.mem, u₂.mem, u₁.mem] + exact hf.writeW (List.mem_singleton_self _) _ (contains_offset h₀ (by omega)) + refine wp_movm (ea s₃ .ebx _ (by rw [u₃.gpr, u₂.other _ (by decide), u₁.other _ (by decide), hbx']) + (by omega)) (by rw [u₃.rd, u₃.wr, u₂.rd, u₂.wr, u₁.rd, u₁.wr, hrd, hwr]; exact out_in hin h₀ hn) + fun s₄ u₄ => wp_bswap fun s₅ u₅ => ?_ + refine wp_store (ea s₅ .eax _ (by rw [u₅.other _ (by decide), u₄.other _ (by decide), u₃.gpr, + u₂.other _ (by decide), u₁.other _ (by decide), hax']) (by omega)) + (by rw [u₅.wr, u₄.wr, u₃.wr, u₂.wr, u₁.wr, hwr]; exact out_in hout h₄ hn) fun s₆ u₆ => ?_ + refine kk s₆ (fun r h => by rw [u₆.gpr, u₅.other r h, u₄.other r h, u₃.gpr, u₂.other r h, u₁.other r h]) + (by rw [u₆.rd, u₅.rd, u₄.rd, u₃.rd, u₂.rd, u₁.rd]) (by rw [u₆.wr, u₅.wr, u₄.wr, u₃.wr, u₂.wr, u₁.wr]) ?_ + have v₂ : s₂.gpr .ecx = bswap (s₀.mem.readW ((s₀.gpr .ebx).setWidth 64 + BitVec.ofNat 64 (8 * k + 4)) 32) := by + rw [u₂.gpr, u₁.gpr, out_read hf hd h₄ hn] + have v₅ : s₅.gpr .ecx = bswap (s₀.mem.readW ((s₀.gpr .ebx).setWidth 64 + BitVec.ofNat 64 (8 * k)) 32) := by + rw [u₅.gpr, u₄.gpr, out_read hf₃ hd (by omega) hn] + have w := fun (m : Mem) (a : Addr) (x : BitVec 32) => writeW32 m a true x + simp only [ite_true] at w + rw [u₆.mem, u₅.mem, u₄.mem, v₅, u₃.mem, v₂, u₂.mem, u₁.mem, w, w, + ← writeBytes_append _ _ _ _ (by simp [bytes32_length]), bytes32_length, add_ofNat] end VG.Proof.MdStream.X86 diff --git a/lean/VerifiedGarbage/Proof/Pbkdf2/Md/X86/Hashes.lean b/lean/VerifiedGarbage/Proof/Pbkdf2/Md/X86/Hashes.lean index 6f7fb6baa..1e03db575 100644 --- a/lean/VerifiedGarbage/Proof/Pbkdf2/Md/X86/Hashes.lean +++ b/lean/VerifiedGarbage/Proof/Pbkdf2/Md/X86/Hashes.lean @@ -9,11 +9,11 @@ import VerifiedGarbage.Proof.Sha512.X86.Stream.Finalize MD5, SHA-1 and the SHA-512 family as `Hash`es of `Impl/Pbkdf2/Md/X86.lean`: their streaming functions (`Proof/Pbkdf2/Stream/X86/Hashes.lean`), their compression functions and the code writing their digests -(`Impl.MdStream.X86.out32` for MD5 and SHA-1, SHA-512's `outW`), and what the -proofs know of them (`MdOk`), from their own proofs: the `Md` of the generic -streaming proofs (`Proof/Md5/Md.lean` and the others), the digests their code -writes (`out512_ok` for the SHA-512 family), and their compression functions' -contracts, which are `cmpK`. SHA-256, whose compression function has a +(the `out` of their `Impl.MdStream.X86` parameters), and what the proofs know +of them (`MdOk`), from their own proofs: the `Md` of the generic streaming +proofs (`Proof/Md5/Md.lean` and the others), the digests their code writes +(from their `Shape`s), and their compression functions' contracts, which are +`cmpK`. SHA-256, whose compression function has a variant for each backend on x86, is in `Sha256.lean`. -/ @@ -40,140 +40,18 @@ value `iv`: a 64-byte hash value, a big-endian 16-byte length field, and the digest of the whole hash value (`D` bytes of which are output). -/ def sha512M (D : Nat) (initN : String) (iv : Spec.Sha512.HashValue) : Hash := ⟨sha512H D initN iv, 64, 16, true, 224, "vg_sha512_compress", Impl.Sha512.X86.compress, - (List.range 8).flatMap Impl.Sha512.X86.Stream.outW⟩ + Impl.Sha512.X86.Stream.params.out⟩ def sha384M : Hash := sha512M 48 "vg_sha384_init" Spec.Sha512.H0_384 def sha512M' : Hash := sha512M 64 "vg_sha512_init" Spec.Sha512.H0_512 def sha512_224M : Hash := sha512M 28 "vg_sha512_224_init" Spec.Sha512.H0_512_224 def sha512_256M : Hash := sha512M 32 "vg_sha512_256_init" Spec.Sha512.H0_512_256 -/-! ## The digest of a SHA-512 hash value -/ - -section -open VG.Impl.Sha512.X86.Stream (outW) -open VG.Proof.Sha256.X86.Stream (Upd Mupd wp_movm wp_store wp_bswap contains_addr sub_offset) -open VG.Proof.Sha512.X86.Stream (ea_at) -open VG.Proof.Sha512.X86.Stream.Finalize (writeW_bswap flat_length) -open VG.Proof.Sha512.Word64 (lo hi wordBytes_split) -open VG.Proof.Sha512.X86 (lo_rd64 hi_rd64) -open VG.Proof.Sha512.X86 (stateAt_get) -open Spec.Sha512 (stateAt wordBytes) - -/-- What `outW` has written after `k` words of the hash value at `x` (in -`ebx`) to `y` (in `eax`), from the memory `m₀`. -/ -structure Out512 (s₀ : State) (k : Nat) (s : State) : Prop where - gpr : ∀ r, r ≠ .ecx → r ≠ .edx → s.gpr r = s₀.gpr r - rd : s.rd = s₀.rd - wr : s.wr = s₀.wr - mem : s.mem = writeBytes s₀.mem ((s₀.gpr .eax).setWidth 64) - (((stateAt s₀.mem ((s₀.gpr .ebx).setWidth 64)).toList.take k).flatMap wordBytes) - -theorem out512_step {s₀ : State} (hbx : (s₀.gpr .ebx).toNat + 64 ≤ 2 ^ 32) - (hax : (s₀.gpr .eax).toNat + 64 ≤ 2 ^ 32) - (hin : InRegions (s₀.rd ++ s₀.wr) ((s₀.gpr .ebx).setWidth 64) 64) - (hout : InRegions s₀.wr ((s₀.gpr .eax).setWidth 64) 64) - (hd : Region.Disjoint ⟨(s₀.gpr .ebx).setWidth 64, 64⟩ ⟨(s₀.gpr .eax).setWidth 64, 64⟩) - {k : Nat} (hk : k < 8) {s : State} (h : Out512 s₀ k s) {rest : List Instr} {Q : State → Prop} - (hnext : ∀ s', Out512 s₀ (k + 1) s' → WP isa (.block rest) s' Q) : - WP isa (.block (outW k ++ rest)) s Q := by - set x := s₀.gpr .ebx - set y := s₀.gpr .eax - have hebx : s.gpr .ebx = x := h.gpr _ (by decide) (by decide) - have heax : s.gpr .eax = y := h.gpr _ (by decide) (by decide) - have hP := flat_length (stateAt s₀.mem (x.setWidth 64)) k (Nat.le_of_lt hk) - have sub : ∀ {rs : List Region} {b : BitVec 32}, b.toNat + 64 ≤ 2 ^ 32 → InRegions rs (b.setWidth 64) 64 → - ∀ o, o + 4 ≤ 8 → InRegions rs (addr b (8 * k + o)) 4 := by - intro rs b hb ⟨R, hR, hc⟩ o ho - refine ⟨R, hR, ?_⟩ - rw [addr_eq (by omega)] - have := Offset.contains_base (b.setWidth 64) (d := 8 * k + o) (n := 4) (k := 64) (by omega) (by omega) - simp only [Region.Contains] at hc this ⊢ - have e : (b.setWidth 64 + BitVec.ofNat 64 (8 * k + o) - R.base).toNat ≤ (b.setWidth 64 - R.base).toNat + (8 * k + o) := by - rw [show b.setWidth 64 + BitVec.ofNat 64 (8 * k + o) - R.base = (b.setWidth 64 - R.base) + BitVec.ofNat 64 (8 * k + o) by - rw [VG.Offset.add_sub_comm], BitVec.toNat_add, BitVec.toNat_ofNat, Nat.mod_eq_of_lt (a := 8 * k + o) (by omega)] - exact Nat.mod_le _ _ - omega - -- The word's halves, unchanged since the start. - have hread : ∀ o, o + 4 ≤ 8 → s.mem.readW (addr x (8 * k + o)) 32 = s₀.mem.readW (addr x (8 * k + o)) 32 := by - intro o ho' - rw [h.mem] - have hc : (⟨y.setWidth 64, 64⟩ : Region).Contains (y.setWidth 64) - (((stateAt s₀.mem (x.setWidth 64)).toList.take k).flatMap wordBytes).length := by - have := Offset.contains_base (y.setWidth 64) (d := 0) (n := 8 * k) (k := 64) (by omega) (by omega) - rw [hP]; rwa [show y.setWidth 64 + BitVec.ofNat 64 0 = y.setWidth 64 from BitVec.add_zero _] at this - refine (writeBytes_frame _ _ _ hc).readW - (r := ⟨addr x (8 * k + o), 4⟩) (Region.contains_self _ _) ?_ (by decide) - intro r' hr' - simp only [List.mem_cons, List.not_mem_nil, or_false] at hr' - subst hr' - rw [addr_eq (by omega)] - exact hd.sub_left (Offset.sub_base _ (by omega)) - have hw := stateAt_get (st := x) hbx s₀.mem hk - have wlo : s₀.mem.readW (addr x (8 * k + 0)) 32 = lo (stateAt s₀.mem (x.setWidth 64))[k] := by - rw [hw, lo_rd64, Nat.add_zero] - have whi : s₀.mem.readW (addr x (8 * k + 4)) 32 = hi (stateAt s₀.mem (x.setWidth 64))[k] := by - rw [hw, hi_rd64] - simp only [outW, List.cons_append, List.nil_append] - refine wp_movm (a := addr x (8 * k + 0)) (by rw [ea_at, hebx, Nat.add_zero]) - (by rw [h.rd, h.wr]; exact sub hbx hin 0 (by omega)) fun s₁ u₁ => ?_ - refine wp_movm (a := addr x (8 * k + 4)) (by rw [ea_at, u₁.other _ (by decide), hebx]) - (by rw [u₁.rd, u₁.wr, h.rd, h.wr]; exact sub hbx hin 4 (by omega)) fun s₂ u₂ => - wp_bswap fun s₃ u₃ => wp_bswap fun s₄ u₄ => ?_ - have heax₄ : s₄.gpr .eax = y := by - rw [u₄.other _ (by decide), u₃.other _ (by decide), u₂.other _ (by decide), u₁.other _ (by decide), heax] - refine wp_store (a := addr y (8 * k + 0)) (by rw [ea_at, heax₄, Nat.add_zero]) - (by rw [u₄.wr, u₃.wr, u₂.wr, u₁.wr, h.wr]; exact sub hax hout 0 (by omega)) fun s₅ u₅ => ?_ - refine wp_store (a := addr y (8 * k + 4)) (by rw [ea_at, u₅.gpr, heax₄]) - (by rw [u₅.wr, u₄.wr, u₃.wr, u₂.wr, u₁.wr, h.wr]; exact sub hax hout 4 (by omega)) fun s₆ u₆ => - hnext s₆ ⟨fun r h1 h2 => ?_, by rw [u₆.rd, u₅.rd, u₄.rd, u₃.rd, u₂.rd, u₁.rd, h.rd], - by rw [u₆.wr, u₅.wr, u₄.wr, u₃.wr, u₂.wr, u₁.wr, h.wr], ?_⟩ - · rw [u₆.gpr, u₅.gpr, u₄.other r h1, u₃.other r h2, u₂.other r h2, u₁.other r h1, h.gpr r h1 h2] - · have v2 : s₄.gpr .edx = bswap (hi (stateAt s₀.mem (x.setWidth 64))[k]) := by - rw [u₄.other _ (by decide), u₃.gpr, u₂.gpr, u₁.mem, hread 4 (by omega), whi] - have v1 : s₅.gpr .ecx = bswap (lo (stateAt s₀.mem (x.setWidth 64))[k]) := by - rw [u₅.gpr, u₄.gpr, u₃.other _ (by decide), u₂.other _ (by decide), u₁.gpr, hread 0 (by omega), wlo] - have a0 : addr y (8 * k + 0) = y.setWidth 64 + - BitVec.ofNat 64 (((stateAt s₀.mem (x.setWidth 64)).toList.take k).flatMap wordBytes).length := by - rw [hP, addr_eq (by omega), Nat.add_zero] - have a4 : addr y (8 * k + 4) = y.setWidth 64 + - BitVec.ofNat 64 (((stateAt s₀.mem (x.setWidth 64)).toList.take k).flatMap wordBytes).length + - BitVec.ofNat 64 (Spec.Sha256.wordBytes (hi (stateAt s₀.mem (x.setWidth 64))[k])).length := by - rw [hP, addr_eq (by omega), BitVec.add_assoc, ← BitVec.ofNat_add]; rfl - rw [u₆.mem, v1, u₅.mem, v2, u₄.mem, u₃.mem, u₂.mem, u₁.mem, writeW_bswap, writeW_bswap, a0, a4, - writeBytes_append _ _ _ _ (by simp [Spec.Sha256.wordBytes]), ← wordBytes_split, h.mem, - writeBytes_append _ _ _ _ (by rw [hP]; simp [wordBytes]; omega), List.take_add_one, - List.getElem?_eq_getElem (by simp; omega), Option.toList_some, List.flatMap_append, - List.flatMap_singleton, Vector.getElem_toList] - -theorem out512_ok : OutOk Proof.Sha512.md ((List.range 8).flatMap outW) := by - intro s₀ hbx hax hin hout hd - have all : ∀ j ≤ 8, ∀ s, Out512 s₀ (8 - j) s → WP isa (.block (((List.range 8).drop (8 - j)).flatMap outW)) s - fun s' => Out512 s₀ 8 s' := by - intro j - induction j with - | zero => - intro _ s h - rw [show (List.range 8).drop (8 - 0) = [] from rfl, List.flatMap_nil] - exact WP.block_nil h - | succ j ih => - intro hj s h - rw [List.drop_eq_getElem_cons (by simp; omega), List.flatMap_cons, List.getElem_range] - refine out512_step hbx hax hin hout hd (by omega) h fun s' h' => ?_ - rw [show 8 - (j + 1) + 1 = 8 - j by omega] at h' ⊢ - exact ih (by omega) s' h' - have := all 8 (Nat.le_refl _) s₀ ⟨fun _ _ _ => rfl, rfl, rfl, by simp [writeBytes_nil]⟩ - rw [show 8 - 8 = 0 from rfl, List.drop_zero] at this - refine WP.mono this fun s' h => ⟨h.gpr, h.rd, h.wr, ?_⟩ - rw [h.mem, List.take_of_length_le (by simp)] - rfl - -end - /-! ## What the proofs know of them -/ /-- The weaker register guarantee `OutOk` asks of `Impl.MdStream.X86`'s `out`, from its `Shape`. -/ -theorem outOk_of_shape {P : Impl.MdStream.X86.Params} {H : Md 64 P.N 8} (hs : Proof.MdStream.X86.Shape H) : +theorem outOk_of_shape {P : Impl.MdStream.X86.Params} {H : Md P.B P.N P.L} (hs : Proof.MdStream.X86.Shape H) : OutOk H P.out := fun s hbx hax hin hout hd => WP.mono (hs.out s hbx hax hin hout hd) fun _ ⟨g, rd, wr, m⟩ => ⟨fun r h _ => g r h, rd, wr, m⟩ @@ -234,9 +112,9 @@ def sha512Ok {D : Nat} {initN : String} {iv : Spec.Sha512.HashValue} simp only [Proof.Sha512.md, Spec.Sha512.stateAt, Vector.getElem_ofFn] exact Hmac.Generic.Common.readW_reloc (n := 64) h (by omega) tail := tail - out := out512_ok - comp := ⟨Proof.Sha512.X86.Compress.compress_verified, Proof.Sha512.X86.Stream.compress_nosp, - Proof.Sha512.X86.Stream.compress_stackUse⟩ + out := outOk_of_shape Proof.Sha512.X86.Stream.shape + comp := ⟨Proof.Sha512.X86.Compress.compress_verified, Proof.Sha512.X86.Stream.callee.nosp, + Proof.Sha512.X86.Stream.callee.stack⟩ sizes := sizes def sha384Ok : MdOk sha384M := sha512Ok sha384OK rfl (fun _ => rfl) rfl rfl rfl (by decide) (by decide) ⟨by decide, by decide, by decide, by decide, rfl, by decide, by decide, by decide⟩ diff --git a/lean/VerifiedGarbage/Proof/Sha1/X86/Stream/Md.lean b/lean/VerifiedGarbage/Proof/Sha1/X86/Stream/Md.lean index 8e6abdc0b..b96048322 100644 --- a/lean/VerifiedGarbage/Proof/Sha1/X86/Stream/Md.lean +++ b/lean/VerifiedGarbage/Proof/Sha1/X86/Stream/Md.lean @@ -25,11 +25,12 @@ open VG VG.X86 VG.Proof.MdStream VG.Proof.MdStream.X86 abbrev params := Impl.Sha1.X86.Stream.params -theorem dims : Dims params 160 := ⟨by decide, by decide, by decide⟩ +theorem dims : Dims params 160 := ⟨.inl rfl, by decide, by decide, by decide, by decide⟩ theorem shape : Shape (P := params) md where - len _ hfit hlo hhi ho₁ ho₂ := len64_ok (so := params.so) (d := params.N + 56) (be := true) (by omega) - hlo hhi ho₁ ho₂ + len _ hfit hlo hhi ho := len64_ok (so := params.so) (d := params.N + params.B - params.L) (be := true) + (by have : params.N + params.B - params.L + 8 = params.N + params.B := rfl; omega) hlo hhi + (ho _ (Nat.le_refl _) (by decide)) (ho _ (by decide) (by decide)) out _ hbx hax hin hout hd := by refine (out32_ok (n := 5) true (by decide) hbx hax hin hout hd).mono fun s' ⟨g, rd, wr, m⟩ => ⟨g, rd, wr, ?_⟩ diff --git a/lean/VerifiedGarbage/Proof/Sha256/X86/Shared.lean b/lean/VerifiedGarbage/Proof/Sha256/X86/Shared.lean index 841a43029..9907ac99e 100644 --- a/lean/VerifiedGarbage/Proof/Sha256/X86/Shared.lean +++ b/lean/VerifiedGarbage/Proof/Sha256/X86/Shared.lean @@ -182,6 +182,8 @@ open VG.Impl.MdStream.X86 (Params len64 out32) /-- SHA-256's sizes, length field and digest in the generic streaming code. -/ def params : Params where N := 32 + B := 64 + L := 8 so := 112 len := len64 112 88 true out := out32 8 true @@ -195,11 +197,12 @@ theorem finalize_eq : Impl.MdStream.X86.finalize params "vg_sha256_compress" Impl.Sha256.X86.compress := rfl -theorem dims : Dims params 160 := ⟨by decide, by decide, by decide⟩ +theorem dims : Dims params 160 := ⟨.inl rfl, by decide, by decide, by decide, by decide⟩ theorem shape : Shape (P := params) md where - len _ hfit hlo hhi ho₁ ho₂ := len64_ok (so := params.so) (d := params.N + 56) (be := true) (by omega) - hlo hhi ho₁ ho₂ + len _ hfit hlo hhi ho := len64_ok (so := params.so) (d := params.N + params.B - params.L) (be := true) + (by have : params.N + params.B - params.L + 8 = params.N + params.B := rfl; omega) hlo hhi + (ho _ (Nat.le_refl _) (by decide)) (ho _ (by decide) (by decide)) out _ hbx hax hin hout hd := by refine (out32_ok (n := 8) true (by decide) hbx hax hin hout hd).mono fun s' ⟨g, rd, wr, m⟩ => ⟨g, rd, wr, ?_⟩ diff --git a/lean/VerifiedGarbage/Proof/Sha512/X86/Shared.lean b/lean/VerifiedGarbage/Proof/Sha512/X86/Shared.lean index b86672f76..ada1abf42 100644 --- a/lean/VerifiedGarbage/Proof/Sha512/X86/Shared.lean +++ b/lean/VerifiedGarbage/Proof/Sha512/X86/Shared.lean @@ -174,8 +174,8 @@ theorem init (iv : Spec.Sha512.HashValue) : theorem updateWide_implies : updateWide.Implies (Spec.Sha512.updateContract X86.abi 20) := by sig_implies [Spec.Sha512.updateContract, Spec.Sha512.updateSig, updateWide, Proof.Sha512.updateX86, Proof.Sha512.countX86, X86.abi, X86.argSlots, X86.argVal, X86.argBytes] - [updateSat, Proof.Sha512.X86.Stream.Update.sat, Proof.Sha512.X86.Stream.Update.satMem, X86.arg, - X86.argAddr, Mem.readW, Mem.read] using updateSat + [updateSat, Proof.Sha512.X86.Stream.Update.sat, MdStream.X86.Update.sat, MdStream.X86.Update.sat₀, + MdStream.X86.Update.satMem, X86.arg, X86.argAddr, Mem.readW, Mem.read] using updateSat theorem update : Verified X86.target Impl.Sha512.X86.Stream.update (Spec.Sha512.updateContract X86.abi 20) := @@ -184,8 +184,8 @@ theorem update : theorem finalizeWide_implies : finalizeWide.Implies (Spec.Sha512.finalizeContract X86.abi 20) := by contract_implies [Spec.Sha512.finalizeContract, Spec.Sha512.finalizeSig, finalizeWide, Proof.Sha512.finalizeX86, Proof.Sha512.countX86, X86.abi, X86.argSlots, X86.argVal, X86.argBytes] - [finalizeSat, Proof.Sha512.X86.Stream.Finalize.sat, Proof.Sha512.X86.Stream.Finalize.satMem, - X86.arg, X86.argAddr, Mem.readW, Mem.read] using finalizeSat + [finalizeSat, Proof.Sha512.X86.Stream.Finalize.sat, MdStream.X86.Finalize.satR, MdStream.X86.Finalize.sat₀, + MdStream.X86.Finalize.satMem, X86.arg, X86.argAddr, Mem.readW, Mem.read] using finalizeSat theorem finalize : Verified X86.target Impl.Sha512.X86.Stream.finalize (Spec.Sha512.finalizeContract X86.abi 20) := diff --git a/lean/VerifiedGarbage/Proof/Sha512/X86/Stream/Common.lean b/lean/VerifiedGarbage/Proof/Sha512/X86/Stream/Common.lean deleted file mode 100644 index 84637eacd..000000000 --- a/lean/VerifiedGarbage/Proof/Sha512/X86/Stream/Common.lean +++ /dev/null @@ -1,324 +0,0 @@ -import VerifiedGarbage.Proof.Framework.X86.RelCT -import VerifiedGarbage.Proof.Sha512.X86.Compress -import VerifiedGarbage.Proof.Sha512.Stream -import VerifiedGarbage.Impl.Sha512.X86.Stream -import VerifiedGarbage.Proof.Sha512.X86.Lit -import VerifiedGarbage.Proof.Framework.Omega - -/-! -# Streaming SHA-512 on x86 (32-bit): common lemmas - -The call of the compression function in the terms of the streaming proofs: its -frame of arguments (`WP.frame`) and the call (`WP.call`), whose effect the -compression function's own `Verified` proof gives. --/ - -namespace VG.Proof.Sha512.X86.Stream - -open VG VG.X86 VG.Impl.Sha512.X86.Stream -open VG.Impl.Sha512.X86 (at_) -open VG.Proof.Sha256.X86.Stream (contains_addr Upd Mupd wp_mov wp_addi wp_movi wp_movm) -open VG.Proof.Sha512.X86.Compress (compress_verified) -open VG.Spec.Sha512 (HashValue stateAt blockAt compress compressBlocks parseBlock) - -theorem ea_at (s : State) (b : Reg) (d : Nat) : s.ea (at_ b d) = addr (s.gpr b) d := rfl - -/-! ## The call of the compression function -/ - -theorem compressBlocks_one (H : HashValue) (m : Mem) (p : Addr) : - compressBlocks H m p 1 = compress H (blockAt m p) := by - simp [compressBlocks] - -theorem compress_nosp : NoSp Impl.Sha512.X86.compress := NoSp.of_all (by lit_decide) - -theorem compress_stackUse : stackUse Impl.Sha512.X86.compress = 0 := by lit_decide - -/-- The frame's argument registers, pushed last to first. -/ -abbrev args : List Reg := [.edx, .ecx, .eax, .ebx] - -theorem popped_esp (r : Reg) (k : Nat) (s : State) : - (popped r k s).gpr .esp = s.gpr .esp + BitVec.ofNat 32 (4 * k) := (popReg_eq s r k).2.2.1 - -theorem popped_gpr (r : Reg) (k : Nat) (s : State) {q : Reg} (h₁ : q ≠ .esp) (h₂ : q ≠ r) : - (popped r k s).gpr q = s.gpr q := (popReg_eq s r k).2.2.2 q h₁ h₂ - -theorem popped_rd (r : Reg) (k : Nat) (s : State) : (popped r k s).rd = s.rd := (popReg_eq s r k).1 - -theorem popped_wr (r : Reg) (k : Nat) (s : State) : (popped r k s).wr = s.wr.tail := rfl - -theorem popped_mem (r : Reg) (k : Nat) (s : State) : (popped r k s).mem = s.mem := - (popReg_rest s r k).1 - -/-- The address of byte `k` of the region at `x`, in 64 bits. -/ -theorem setWidth_add {x : BitVec 32} {k : Nat} (h : x.toNat + k < 2 ^ 32) : - (x + BitVec.ofNat 32 k).setWidth 64 = x.setWidth 64 + BitVec.ofNat 64 k := by - have := addr_eq (x := x) (k := k) h - simpa only [addr] using this - -/-- The regions the compression function is given to read (the block in the -buffer and its frame of arguments) and to write (the hash value and the -scratch space it uses). -/ -def rdC (st E : BitVec 32) : List Region := - [⟨(st + 64).setWidth 64, 128 * 1⟩, ⟨(E - BitVec.ofNat 32 16).setWidth 64, 16⟩] -def wrC (st scr : BitVec 32) : List Region := [⟨st.setWidth 64, 64⟩, ⟨scr.setWidth 64, 224⟩] - -section -variable {s : State} {st scr E : BitVec 32} - (hesp : s.gpr .esp = E) (hebx : s.gpr .ebx = st) (heax : s.gpr .eax = st + 64) - (hecx : s.gpr .ecx = 1) (hedx : s.gpr .edx = scr) - (f₀ : st.toNat + 192 ≤ 2 ^ 32) (f₃ : scr.toNat + 272 ≤ 2 ^ 32) (hE : 20 ≤ E.toNat) - (d : Region.Disjoint ⟨st.setWidth 64, 192⟩ ⟨scr.setWidth 64, 272⟩) - (dS : Region.Disjoint (below E 20) ⟨st.setWidth 64, 192⟩) - (dV : Region.Disjoint (below E 20) ⟨scr.setWidth 64, 272⟩) - (hS : ⟨st.setWidth 64, 192⟩ ∈ s.wr) (hV : ⟨scr.setWidth 64, 272⟩ ∈ s.wr) -include hesp hE - -/-- The arguments, as the callee sees them. -/ -theorem compressCall_arg : ∀ j, j < 4 → arg (pushed args s).callEntry j = s.gpr (args[3 - j]!) := by - intro j hj - rw [callEntry_arg (by rw [hesp]; simp only [args]; simp; omega_arith) (by decide) (by simp [args]; omega_arith)] - simp only [args, List.length_cons, List.length_nil] - rcases (by omega_arith : j = 0 ∨ j = 1 ∨ j = 2 ∨ j = 3) with rfl | rfl | rfl | rfl <;> rfl - -include hebx heax hecx hedx f₀ f₃ d dS dV hS hV in -/-- `vg_sha512_compress(ebx, eax, ecx, edx)`, with `eax = ebx + 64` (the buffer -of the streaming state at `st`), `ecx = 1` and `edx` the scratch space `scr`, -may be called with its arguments pushed: its precondition holds, narrowed to -`rdC` and `wrC`. -/ -theorem compressCall_pre : CallPre Proof.Sha512.compressX86 args (rdC st E) (wrC st scr) s := by - set sE := (pushed args s).callEntry with hsE - have ha := compressCall_arg hesp hE - have e0 : arg sE 0 = st := by rw [ha 0 (by omega_arith)]; exact hebx - have e1 : arg sE 1 = st + 64 := by rw [ha 1 (by omega_arith)]; exact heax - have e2 : arg sE 2 = 1 := by rw [ha 2 (by omega_arith)]; exact hecx - have e3 : arg sE 3 = scr := by rw [ha 3 (by omega_arith)]; exact hedx - have hbase : (st + 64).setWidth 64 = st.setWidth 64 + BitVec.ofNat 64 64 := - setWidth_add (k := 64) (by omega_arith) - have hbt : (st + 64).toNat = st.toNat + 64 := by - rw [BitVec.toNat_add, show (64 : BitVec 32).toNat = 64 from rfl, Nat.mod_eq_of_lt (by omega_arith)] - have hE16 : ((pushed args s).gpr .esp) = E - BitVec.ofNat 32 16 := by rw [pushed_esp, hesp]; rfl - have espE : (sE.gpr .esp) = E - BitVec.ofNat 32 20 := by - rw [hsE, State.callEntry_esp, hE16, BitVec.sub_sub]; exact congrArg (E - ·) (by decide) - have argA : argAddr sE 0 = (E - BitVec.ofNat 32 16).setWidth 64 := by - rw [hsE, argAddr_callEntry, hE16]; simp - -- The stack below `esp`. - have below16 : Region.Sub (below E 16) (below E 20) := below_sub (by omega_arith) hE - have ret_sub : Region.Sub ⟨(sE.gpr .esp).setWidth 64, 4⟩ (below E 20) := by - have := below_inner (sp := E) (a := 4) (b := 20) (k := 16) (by omega_arith) hE - rw [espE, show E - BitVec.ofNat 32 20 = E - BitVec.ofNat 32 16 - BitVec.ofNat 32 4 by - rw [BitVec.sub_sub]; exact congrArg (E - ·) (by decide)] - exact this - have sS : Region.Sub ⟨st.setWidth 64, 64⟩ ⟨st.setWidth 64, 192⟩ := Region.sub_prefix (by omega_arith) - have sB : Region.Sub ⟨(st + 64).setWidth 64, 128 * 1⟩ ⟨st.setWidth 64, 192⟩ := by - rw [hbase]; exact Proof.Sha256.X86.Stream.sub_offset (by decide) (by decide) - have sV : Region.Sub ⟨scr.setWidth 64, 224⟩ ⟨scr.setWidth 64, 272⟩ := Region.sub_prefix (by omega_arith) - have dBS : Region.Disjoint ⟨(st + 64).setWidth 64, 128 * 1⟩ ⟨st.setWidth 64, 64⟩ := by - rw [hbase]; exact Offset.disjoint_base _ (by omega) (by omega) - have hA16 : Region.Sub ⟨(E - BitVec.ofNat 32 16).setWidth 64, 16⟩ (below E 20) := by - rw [← argA, argA]; exact fun a h => below16 a h - refine ⟨?_, ?_, ?_⟩ - · -- The callee's precondition. - have wA : ∀ j, arg (sE.withRegions (rdC st E) (wrC st scr)) j = arg sE j := fun _ => rfl - have wAA : argAddr (sE.withRegions (rdC st E) (wrC st scr)) 0 = argAddr sE 0 := rfl - have wG : (sE.withRegions (rdC st E) (wrC st scr)).gpr = sE.gpr := rfl - rw [← hsE] - simp only [Proof.Sha512.compressX86, wA, wAA, wG, State.withRegions_rd, State.withRegions_wr] - rw [e0, e1, e2, e3, argA] - refine ⟨rfl, rfl, (d.sub_left sS).sub_right sV, dBS, (d.sub_left sB).sub_right sV, - (dS.symm.sub_right hA16).sub_left sS |>.symm, (dV.symm.sub_right hA16).sub_left sV |>.symm, - ((dS.symm.sub_right ret_sub).sub_left sS).symm, ((dV.symm.sub_right ret_sub).sub_left sV).symm, - by omega_arith, by rw [hbt]; simp only [show (1 : BitVec 32).toNat = 1 from rfl]; omega_arith, by omega_arith, ?_⟩ - show (sE.gpr .esp).toNat + 20 ≤ 2 ^ 32 - rw [espE, sub_toNat hE]; have := E.isLt; omega_arith - · apply Covers.of_sub - intro r hr - simp only [rdC, wrC, List.mem_cons, List.not_mem_nil, or_false, List.cons_append, List.nil_append] at hr - rcases hr with rfl | rfl | rfl | rfl - · exact ⟨_, List.mem_append_right _ (List.mem_cons_of_mem _ hS), 64, hbase, by simp⟩ - · refine ⟨below (s.gpr .esp) (4 * args.length), List.mem_append_right _ (List.mem_cons_self ..), 0, ?_, - by simp [args]⟩ - rw [← argA, argA, hesp]; simp [args] - · exact ⟨_, List.mem_append_right _ (List.mem_cons_of_mem _ hS), 0, by simp, by simp⟩ - · exact ⟨_, List.mem_append_right _ (List.mem_cons_of_mem _ hV), 0, by simp, by simp⟩ - · apply Covers.of_sub - intro r hr - simp only [wrC, List.mem_cons, List.not_mem_nil, or_false] at hr - rcases hr with rfl | rfl - · exact ⟨_, List.mem_cons_of_mem _ hS, 0, by simp, by simp⟩ - · exact ⟨_, List.mem_cons_of_mem _ hV, 0, by simp, by simp⟩ - -include hebx heax hecx hedx f₀ f₃ d dS dV hS hV in -/-- Calling `vg_sha512_compress(ebx, eax, ecx, edx)` with `eax = ebx + 64` -(the buffer of the streaming state at `st`), `ecx = 1` and `edx` the scratch -space `scr`: it compresses the buffer into the hash value, and writes only -the hash value, the first 224 bytes of the scratch space and the 20 bytes -below `esp`. -/ -theorem compressCall_ok {Q : State → Prop} - (hQ : ∀ s', s'.rd = s.rd → s'.wr = s.wr → - (∀ r ∈ [Reg.ebx, .esi, .edi, .ebp, .esp], s'.gpr r = s.gpr r) → - Frame [⟨st.setWidth 64, 64⟩, ⟨scr.setWidth 64, 224⟩, below E 20] s.mem s'.mem → - stateAt s'.mem (st.setWidth 64) = - compress (stateAt s.mem (st.setWidth 64)) (blockAt s.mem (st.setWidth 64 + 64)) → Q s') : - WP isa compressCall s Q := by - have hk := compressCall_pre hesp hebx heax hecx hedx f₀ f₃ hE d dS dV hS hV - have hd : 4 * args.length + stackUse Impl.Sha512.X86.compress + 4 ≤ (s.gpr .esp).toNat := by - rw [compress_stackUse, hesp]; simp only [args]; simp; omega_arith - set sE := (pushed args s).callEntry with hsE - have ha := compressCall_arg hesp hE - have e0 : arg sE 0 = st := by rw [ha 0 (by omega_arith)]; exact hebx - have e1 : arg sE 1 = st + 64 := by rw [ha 1 (by omega_arith)]; exact heax - have e2 : arg sE 2 = 1 := by rw [ha 2 (by omega_arith)]; exact hecx - have hbase : (st + 64).setWidth 64 = st.setWidth 64 + BitVec.ofNat 64 64 := - setWidth_add (k := 64) (by omega_arith) - refine WP.callWith compress_verified.1 compress_nosp (by simp [args]) (by decide) hd hk - fun s' hrd hwr hcs hF ⟨s₂, hm₂, hpost⟩ => ?_ - -- The callee's memory on entry is ours outside the stack. - have hFe : Frame [below E 20] s.mem sE.mem := by - have := callEntry_frame (rs := args) (s := s) (by rw [hesp]; simp only [args]; simp; omega_arith) (by decide) - rw [hesp] at this - exact this - have hst : stateAt sE.mem (st.setWidth 64) = stateAt s.mem (st.setWidth 64) := - Proof.Sha512.Stream.stateAt_congr fun i hi => - hFe.bytes (R := ⟨st.setWidth 64, 192⟩) (by simpa using dS.symm) (by simp) (show _ < 192 by omega_arith) - have hblk : blockAt sE.mem (st.setWidth 64 + 64) = blockAt s.mem (st.setWidth 64 + 64) := by - simp only [blockAt] - refine Proof.Sha512.Stream.parseBlock_congr fun k hk => ?_ - rw [show st.setWidth 64 + 64 + BitVec.ofNat 64 k = st.setWidth 64 + BitVec.ofNat 64 (64 + k) by - rw [BitVec.add_assoc, BitVec.ofNat_add]; rfl] - exact hFe.bytes (R := ⟨st.setWidth 64, 192⟩) (by simpa using dS.symm) (by simp) (show _ < 192 by omega_arith) - have hpost' : stateAt s'.mem (st.setWidth 64) = - compress (stateAt s.mem (st.setWidth 64)) (blockAt s.mem (st.setWidth 64 + 64)) := by - have := (show stateAt s₂.mem ((arg (sE.withRegions (rdC st E) (wrC st scr)) 0).setWidth 64) = - compressBlocks (stateAt (sE.withRegions (rdC st E) (wrC st scr)).mem - ((arg (sE.withRegions (rdC st E) (wrC st scr)) 0).setWidth 64)) - (sE.withRegions (rdC st E) (wrC st scr)).mem ((arg (sE.withRegions (rdC st E) (wrC st scr)) 1).setWidth 64) - (arg (sE.withRegions (rdC st E) (wrC st scr)) 2).toNat from hpost) - rw [show arg (sE.withRegions (rdC st E) (wrC st scr)) = arg sE from rfl, e0, e1, e2, hm₂, - State.withRegions_mem, show (1 : BitVec 32).toNat = 1 from rfl, compressBlocks_one, hbase, hst] at this - rw [this, ← hblk]; rfl - refine hQ _ hrd hwr (fun r hr => hcs r (by simpa [calleeSaved] using hr)) ?_ hpost' - rw [compress_stackUse, hesp] at hF - exact hF - -end - -/-- The arguments of `compressAt d`'s call. -/ -def argsAt (d : Nat) : List Instr := - [.mov .eax (.reg .ebx), .alu .add .eax (.imm 64), .mov .ecx (.imm 1), .mov .edx (.mem (at_ .esp d))] - -theorem compressAt_eq (d : Nat) : compressAt d = .seq (.block (argsAt d)) compressCall := rfl - -/-- What `compressAt d` needs of the state it starts from: the state at `st` -in `ebx`, the scratch space `scr` at `[E + d]`. -/ -structure AtPre (st scr E : BitVec 32) (d : Nat) (s : State) : Prop where - esp : s.gpr .esp = E - ebx : s.gpr .ebx = st - arg : InRegions (s.rd ++ s.wr) (addr E d) 4 - scrW : s.mem.readW (addr E d) 32 = scr - hS : ⟨st.setWidth 64, 192⟩ ∈ s.wr - hV : ⟨scr.setWidth 64, 272⟩ ∈ s.wr - -/-- The registers `compressCall` is made with. -/ -structure CallRegs (st scr E : BitVec 32) (s : State) : Prop where - esp : s.gpr .esp = E - ebx : s.gpr .ebx = st - eax : s.gpr .eax = st + 64 - ecx : s.gpr .ecx = 1 - edx : s.gpr .edx = scr - hS : ⟨st.setWidth 64, 192⟩ ∈ s.wr - hV : ⟨scr.setWidth 64, 272⟩ ∈ s.wr - -theorem argsAt_ok {s : State} {st scr E : BitVec 32} {d : Nat} (h : AtPre st scr E d s) : - WP isa (.block (argsAt d)) s fun s' => CallRegs st scr E s' ∧ s'.rd = s.rd ∧ s'.wr = s.wr ∧ - s'.mem = s.mem ∧ ∀ r, r ≠ .eax → r ≠ .ecx → r ≠ .edx → s'.gpr r = s.gpr r := by - refine wp_mov fun s₁ u₁ => wp_addi fun s₂ u₂ => wp_movi fun s₃ u₃ => - wp_movm (a := addr E d) (by rw [ea_of (by rw [u₃.other _ (by decide), u₂.other _ (by decide), - u₁.other _ (by decide), h.esp])]) (by rw [u₃.rd, u₃.wr, u₂.rd, u₂.wr, u₁.rd, u₁.wr]; exact h.arg) - fun s₄ u₄ => WP.block_nil ?_ - have g : ∀ r, r ≠ .eax → r ≠ .ecx → r ≠ .edx → s₄.gpr r = s.gpr r := fun r h1 h2 h3 => by - rw [u₄.other r h3, u₃.other r h2, u₂.other r h1, u₁.other r h1] - have wr₄ : s₄.wr = s.wr := by rw [u₄.wr, u₃.wr, u₂.wr, u₁.wr] - exact ⟨⟨by rw [g _ (by decide) (by decide) (by decide), h.esp], by rw [g _ (by decide) (by decide) (by decide), h.ebx], - by rw [u₄.other _ (by decide), u₃.other _ (by decide), u₂.gpr, u₁.gpr, h.ebx], - by rw [u₄.other _ (by decide), u₃.gpr], by rw [u₄.gpr, u₃.mem, u₂.mem, u₁.mem, h.scrW], - by rw [wr₄]; exact h.hS, by rw [wr₄]; exact h.hV⟩, - by rw [u₄.rd, u₃.rd, u₂.rd, u₁.rd], wr₄, by rw [u₄.mem, u₃.mem, u₂.mem, u₁.mem], g⟩ - -section -variable {st scr E : BitVec 32} (f₀ : st.toNat + 192 ≤ 2 ^ 32) (f₃ : scr.toNat + 272 ≤ 2 ^ 32) - (hE : 20 ≤ E.toNat) (dd : Region.Disjoint ⟨st.setWidth 64, 192⟩ ⟨scr.setWidth 64, 272⟩) - (dS : Region.Disjoint (below E 20) ⟨st.setWidth 64, 192⟩) - (dV : Region.Disjoint (below E 20) ⟨scr.setWidth 64, 272⟩) -include f₀ f₃ hE dd dS dV - -/-- `compressAt d`: the call of the compression function on the buffer of the -state at `ebx`, with the scratch space whose address is at `[esp + d]`. -/ -theorem compressAt_ok {d : Nat} {s : State} (h : AtPre st scr E d s) {Q : State → Prop} - (hQ : ∀ s', s'.rd = s.rd → s'.wr = s.wr → - (∀ r ∈ [Reg.ebx, .esi, .edi, .ebp, .esp], s'.gpr r = s.gpr r) → - Frame [⟨st.setWidth 64, 64⟩, ⟨scr.setWidth 64, 224⟩, below E 20] s.mem s'.mem → - stateAt s'.mem (st.setWidth 64) = - compress (stateAt s.mem (st.setWidth 64)) (blockAt s.mem (st.setWidth 64 + 64)) → Q s') : - WP isa (compressAt d) s Q := by - refine WP.seq (WP.mono (argsAt_ok h) fun s₄ ⟨c, rd₄, wr₄, m₄, g⟩ => ?_) - refine compressCall_ok c.esp c.ebx c.eax c.ecx c.edx f₀ f₃ hE dd dS dV c.hS c.hV - fun s' hrd hwr hg hf hst => ?_ - rw [m₄] at hf hst - refine hQ s' (hrd.trans rd₄) (hwr.trans wr₄) (fun r hr => ?_) hf hst - rw [hg r hr] - refine g r ?_ ?_ ?_ <;> - · simp only [List.mem_cons, List.not_mem_nil, or_false] at hr - rcases hr with rfl | rfl | rfl | rfl | rfl <;> decide - -/-- Two runs of `compressAt d` from states that agree on `st`, `scr` and -`E` leak the same trace: the arguments by the taint analysis (`ht`, checked -for each `d`), the call by the compression function's contract. -/ -theorem compressAt_rel {d : Nat} - (ht : ∃ hc, (VG.Taint.check taint (τr [.esp]) (.block (argsAt d)) hc).isSome = true) : - RelCT isa (fun s₁ s₂ => AtPre st scr E d s₁ ∧ AtPre st scr E d s₂) (compressAt d) fun _ _ => True := by - obtain ⟨_, ht⟩ := ht - rw [compressAt_eq] - refine RelCT.seq (R := fun s₁ s₂ => CallRegs st scr E s₁ ∧ CallRegs st scr E s₂) ?_ ?_ - · refine ((RelCT.taint (A := taint) (τr [.esp]) (fun _ _ h => agree_regs fun r hr => ?_) ht).wp - (F₁ := CallRegs st scr E) (F₂ := CallRegs st scr E) fun _ _ h => - ⟨WP.mono (argsAt_ok h.1) fun _ h => h.1, WP.mono (argsAt_ok h.2) fun _ h => h.1⟩).mono - (fun _ _ h => h) fun _ _ h => h.2 - simp only [List.mem_singleton] at hr - subst hr - rw [h.1.esp, h.2.esp] - · refine RelCT.callWith compress_verified.1 compress_verified.2.1 (rdC st E) (wrC st scr) - fun s₁ s₂ ⟨c₁, c₂⟩ => ⟨compressCall_pre c₁.esp c₁.ebx c₁.eax c₁.ecx c₁.edx f₀ f₃ hE dd dS dV c₁.hS c₁.hV, - compressCall_pre c₂.esp c₂.ebx c₂.eax c₂.ecx c₂.edx f₀ f₃ hE dd dS dV c₂.hS c₂.hV, - c₁.esp.trans c₂.esp.symm, ?_⟩ - have hfit : 4 * args.length + 4 ≤ (s₁.gpr .esp).toNat := by rw [c₁.esp]; simp only [args]; simp; omega_arith - have hsp : s₁.gpr .esp = s₂.gpr .esp := c₁.esp.trans c₂.esp.symm - have hr : ∀ r ∈ args, s₁.gpr r = s₂.gpr r := by - intro r hr - simp only [args, List.mem_cons, List.not_mem_nil, or_false] at hr - rcases hr with rfl | rfl | rfl | rfl - · rw [c₁.edx, c₂.edx] - · rw [c₁.ecx, c₂.ecx] - · rw [c₁.eax, c₂.eax] - · rw [c₁.ebx, c₂.ebx] - have ea : ∀ i, i < 4 → arg (pushed args s₁).callEntry i = arg (pushed args s₂).callEntry i := - fun i hi => callEntry_arg_eq (by decide) hfit hsp hr (by simp only [args]; simp; omega_arith) - have hesp : (pushed args s₁).callEntry.gpr .esp = (pushed args s₂).callEntry.gpr .esp := by - rw [callEntry_esp', callEntry_esp', hsp] - exact ⟨hesp, ea 0 (by decide), ea 1 (by decide), ea 2 (by decide), ea 3 (by decide)⟩ - -end - -/-! ## Lemmas shared by `update` and `finalize` -/ - -/-- The contract's stack region. -/ -theorem stk_eq {E : BitVec 32} (h : 20 ≤ E.toNat) : below E 20 = ⟨E.setWidth 64 - 20, 20⟩ := by - simp only [below]; rw [Taint.sub_setWidth h]; rfl - -/-- The count of bytes buffered, from the low word of the count. -/ -theorem and127 (x : BitVec 32) : x &&& 127 = BitVec.ofNat 32 (x.toNat % 128) := by - apply BitVec.eq_of_toNat_eq - simp only [BitVec.toNat_and, BitVec.toNat_ofNat] - rw [show (127 : BitVec 32).toNat = 2 ^ 7 - 1 from rfl, Nat.and_two_pow_sub_one_eq_mod] - omega - -end VG.Proof.Sha512.X86.Stream diff --git a/lean/VerifiedGarbage/Proof/Sha512/X86/Stream/Finalize.lean b/lean/VerifiedGarbage/Proof/Sha512/X86/Stream/Finalize.lean index f90a9e525..166cf2389 100644 --- a/lean/VerifiedGarbage/Proof/Sha512/X86/Stream/Finalize.lean +++ b/lean/VerifiedGarbage/Proof/Sha512/X86/Stream/Finalize.lean @@ -1,1152 +1,130 @@ -import VerifiedGarbage.Proof.Sha512.X86.Stream.Common -import VerifiedGarbage.Proof.Sha256.X86.Stream.Finalize -import VerifiedGarbage.Proof.Framework.Contract -import VerifiedGarbage.Proof.Framework.RelCTAssoc -import VerifiedGarbage.Proof.Framework.X86.ArgTaint +import VerifiedGarbage.Proof.Sha512.X86.Stream.Update +import VerifiedGarbage.Proof.MdStream.X86.Words +import VerifiedGarbage.Proof.Sha512.Word64 /-! # Streaming SHA-512 on x86 (32-bit): `finalize` -The structure of the SHA-256 proof (`VG.Proof.Sha256.X86.Stream.Finalize`), -with `state` in `ebx`, the buffered bytes in `edi` and whether the block being -padded is not the last in `esi`; `count`, `out` and `scratch` stay in their -argument words, and the compression function is called (`compressAt_ok`), with -the 20 bytes below `esp` for its frame. +The generic `finalize` (`Proof/MdStream/X86/`) for the SHA-512 family, given +what its length field and digest do (`shape`): the length in bits as a 128-bit +big-endian integer, `count >> 61` then `count << 3`, and the words of the hash +value big-endian, each the big-endian bytes of its high half, then of its low +half. -/ -namespace VG.Proof.Sha512.X86.Stream.Finalize +namespace VG.Proof.Sha512.X86.Stream -open VG VG.X86 VG.Impl.Sha512.X86.Stream +open VG VG.X86 VG.Proof.MdStream VG.Proof.MdStream.X86 +open VG.Impl.MdStream.X86 (len64Of out64) open VG.Impl.Sha512.X86 (at_) -open VG.Proof.Sha256.X86 (contains_offset) -open VG.Proof.Sha256.X86.Stream (Upd Mupd Fupd wp_mov wp_movi wp_movm wp_store wp_store8 wp_add wp_addi - wp_sub wp_subi wp_andi wp_or wp_cmpi wp_test wp_shr wp_bswap contains_addr sub_offset frame_bytes - addr_add_ofNat readW_writeW_addr ofNat_beq_zero sub_ofNat sub_beq ofNat_succ ofNat_pred toNat_ofNat_lt - bytesAt_getD addr_toNat) -open VG.Proof.Sha256.X86.Stream.Finalize (times8) -open VG.Proof.Sha512.Word64 (lo hi wordBytes_split lo_shr61 hi_shr61 lo_shl3 hi_shl3) -open VG.Proof.Sha512.Stream -open VG.Spec.Sha512 (HashValue stateAt blockAt compress parseBlock bytesAt wordBytes) -open VG.Proof.Sha512 (countX86) - -/-! ## The precondition -/ - -section -variable (s₀ : State) - -abbrev esp₀ : BitVec 32 := s₀.gpr .esp -abbrev st : BitVec 32 := arg s₀ 0 -abbrev cnt : Nat := (countX86 s₀).toNat -abbrev out : BitVec 32 := arg s₀ 3 -abbrev scr : BitVec 32 := arg s₀ 4 -abbrev stA : Addr := (st s₀).setWidth 64 -abbrev outA : Addr := (out s₀).setWidth 64 -abbrev scA : Addr := (scr s₀).setWidth 64 -abbrev stR : Region := ⟨stA s₀, 192⟩ -abbrev outR : Region := ⟨outA s₀, 64⟩ -abbrev scR : Region := ⟨scA s₀, 272⟩ -abbrev argR : Region := ⟨argAddr s₀ 0, 20⟩ -abbrev retR : Region := ⟨(esp₀ s₀).setWidth 64, 4⟩ -abbrev stkR : Region := below (esp₀ s₀) 20 - -/-- The messages the initial state represents, from the initial hash value -`iv`, of fewer than 2⁶⁴ bytes. -/ -def R₀ (iv : HashValue) (m : List Byte) : Prop := - Spec.Sha512.Repr iv s₀.mem (stA s₀) m ∧ m.length < 2 ^ 64 ∧ countX86 s₀ = BitVec.ofNat 64 m.length - -/-- Our caller's registers are saved in the scratch space. -/ -def Saved (m : Mem) : Prop := ∀ p ∈ saved, m.readW (addr (scr s₀) p.2) 32 = s₀.gpr p.1 - -/-- The digest, if `n` bytes are buffered in a block that is not the last. -/ -def Fin1 (mem : Mem) (n : Nat) (m : List Byte) : HashValue := - compress (compress (stateAt mem (stA s₀)) - (parseBlock fun t => (bytesAt mem (stA s₀ + 64) n ++ List.replicate (128 - n) 0).getD t 0)) - (parseBlock fun t => (List.replicate 112 0 ++ lenBytes m).getD t 0) - -/-- The digest, if `n` bytes are buffered in the last block. -/ -def Fin0 (mem : Mem) (n : Nat) (m : List Byte) : HashValue := - compress (stateAt mem (stA s₀)) - (parseBlock fun t => (bytesAt mem (stA s₀ + 64) n ++ List.replicate (112 - n) 0 ++ lenBytes m).getD t 0) - -end - -structure Pre (s₀ : State) : Prop where - rd : s₀.rd = [argR s₀] - wr : s₀.wr = [stR s₀, outR s₀, scR s₀] - st_out : (stR s₀).Disjoint (outR s₀) - st_scr : (stR s₀).Disjoint (scR s₀) - out_scr : (outR s₀).Disjoint (scR s₀) - a_st : (argR s₀).Disjoint (stR s₀) - a_out : (argR s₀).Disjoint (outR s₀) - a_scr : (argR s₀).Disjoint (scR s₀) - ret_st : (retR s₀).Disjoint (stR s₀) - ret_out : (retR s₀).Disjoint (outR s₀) - ret_scr : (retR s₀).Disjoint (scR s₀) - stk_st : (stkR s₀).Disjoint (stR s₀) - stk_out : (stkR s₀).Disjoint (outR s₀) - stk_scr : (stkR s₀).Disjoint (scR s₀) - st_fit : (st s₀).toNat + 192 ≤ 2 ^ 32 - out_fit : (out s₀).toNat + 64 ≤ 2 ^ 32 - scr_fit : (scr s₀).toNat + 272 ≤ 2 ^ 32 - sp_lo : 20 ≤ (esp₀ s₀).toNat - sp_fit : (esp₀ s₀).toNat + 24 ≤ 2 ^ 32 - -theorem pre_of {s₀ : State} (h : Proof.Sha512.finalizeX86.pre s₀) : Pre s₀ := by - obtain ⟨h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11, h12, h13, h14, h15, h16, h17, h18, h19⟩ := h - have e := stk_eq h18 - exact ⟨h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11, by show (below _ _).Disjoint _; rw [e]; exact h12, - by show (below _ _).Disjoint _; rw [e]; exact h13, by show (below _ _).Disjoint _; rw [e]; exact h14, - h15, h16, h17, h18, h19⟩ - -theorem cnt_mod (s₀ : State) : cnt s₀ % 128 = (arg s₀ 1).toNat % 128 := by - simp only [cnt, countX86] - rw [BitVec.toNat_append, ← Nat.shiftLeft_add_eq_or_of_lt (arg s₀ 1).isLt, Nat.shiftLeft_eq] +open VG.Proof.Sha256.Stream (writeBytes writeBytes_append) + +/-- `count >> 61`, from the halves of `count`. -/ +theorem shr61 (hi lo : BitVec 32) : (hi ++ lo) >>> 61 = (0 : BitVec 32) ++ hi >>> 29 := by + apply BitVec.eq_of_toNat_eq + simp only [BitVec.toNat_ushiftRight, BitVec.toNat_append] + rw [show (0 : BitVec 32).toNat = 0 from rfl, Nat.zero_shiftLeft, Nat.zero_or, + ← Nat.shiftLeft_add_eq_or_of_lt lo.isLt, Nat.shiftLeft_eq, Nat.shiftRight_eq_div_pow, + Nat.shiftRight_eq_div_pow] + have := lo.isLt omega -theorem R₀.length {s₀ : State} {iv : HashValue} {m : List Byte} (h : R₀ s₀ iv m) : - cnt s₀ % 128 = m.length % 128 := by - rw [cnt, h.2.2, BitVec.toNat_ofNat] - omega - -theorem st_add (s₀ : State) (n : Nat) : - stA s₀ + 64 + BitVec.ofNat 64 n = stA s₀ + BitVec.ofNat 64 (64 + n) := by - simp only [BitVec.ofNat_add]; rw [BitVec.add_assoc]; rfl - -theorem arg_eq (s : State) (i : Nat) : arg s i = s.mem.readW (addr (s.gpr .esp) (4 + 4 * i)) 32 := rfl - -namespace Pre -variable {s₀ : State} (hp : Pre s₀) -include hp - -theorem scr_in {d : Nat} (hd : d + 4 ≤ 272) : (scR s₀).Contains (addr (scr s₀) d) 4 := - contains_addr hd (by omega) hp.scr_fit - -theorem scr_sub {d : Nat} (hd : d + 4 ≤ 272) : Region.Sub ⟨addr (scr s₀) d, 4⟩ (scR s₀) := by - rw [addr_eq (by have := hp.scr_fit; omega)] - exact sub_offset hd (by omega) - -theorem arg_sub {d : Nat} (hd₁ : 4 ≤ d) (hd : d + 4 ≤ 24) : Region.Sub ⟨addr (esp₀ s₀) d, 4⟩ (argR s₀) := by - have := hp.sp_fit - show Region.Sub _ ⟨addr (esp₀ s₀) 4, 20⟩ - rw [addr_eq (by omega), addr_eq (by omega)] - exact Offset.sub _ hd₁ (by omega) - -theorem arg_in {d : Nat} (hd₁ : 4 ≤ d) (hd : d + 4 ≤ 24) : (argR s₀).Contains (addr (esp₀ s₀) d) 4 := by - have := hp.sp_fit - show (⟨addr (esp₀ s₀) 4, 20⟩ : Region).Contains _ _ - rw [addr_eq (by omega), addr_eq (by omega)] - exact Offset.contains _ hd₁ (by omega) (by omega) - -/-- The arguments are above the stack region. -/ -theorem a_stk : (argR s₀).Disjoint (stkR s₀) := by - have := hp.sp_fit; have := hp.sp_lo - show Region.Disjoint ⟨addr (esp₀ s₀) 4, 20⟩ (below (esp₀ s₀) 20) - rw [stk_eq hp.sp_lo, addr_eq (by omega)] - exact (Offset.disjoint_below_above (m := 20) (a := 4) _ (by omega)).symm - -theorem ret_stk : (retR s₀).Disjoint (stkR s₀) := by - have := hp.sp_fit; have := hp.sp_lo - show Region.Disjoint ⟨(esp₀ s₀).setWidth 64, 4⟩ (below (esp₀ s₀) 20) - rw [stk_eq hp.sp_lo] - have h := Offset.disjoint_below_above ((esp₀ s₀).setWidth 64) (m := 20) (a := 0) (l := 4) (by omega) - rw [show (esp₀ s₀).setWidth 64 + BitVec.ofNat 64 0 = (esp₀ s₀).setWidth 64 from BitVec.add_zero _] at h - exact h.symm - -/-- The words of the scratch space from 224 on (the saved registers) are -outside the regions the compression function writes. -/ -theorem saved_sep {d : Nat} (hd₁ : 224 ≤ d) (hd : d + 4 ≤ 272) : - ∀ r ∈ [(⟨stA s₀, 64⟩ : Region), ⟨scA s₀, 224⟩, stkR s₀], Region.Disjoint ⟨addr (scr s₀) d, 4⟩ r := by - have := hp.scr_fit - intro r hr - simp only [List.mem_cons, List.not_mem_nil, or_false] at hr - rcases hr with rfl | rfl | rfl - · exact (hp.st_scr.symm.sub_left (hp.scr_sub hd)).sub_right (Region.sub_prefix (by omega)) - · rw [addr_eq (by omega)] - exact Offset.disjoint_base _ hd₁ (by omega) - · exact (hp.stk_scr.symm.sub_left (hp.scr_sub hd)) - -end Pre - -/-! ## Invariants -/ - -structure Common (s₀ : State) (s : State) : Prop where - rd : s.rd = s₀.rd - wr : s.wr = s₀.wr - ebx : s.gpr .ebx = st s₀ - esp : s.gpr .esp = esp₀ s₀ - frame : Frame [stR s₀, scR s₀, stkR s₀] s₀.mem s.mem - saved : Saved s₀ s.mem - -/-- The loop invariant: `k = 1` while the block being padded is not the last -one, with `n` bytes of it buffered. -/ -structure LInv (s₀ : State) (k n : Nat) (s : State) : Prop extends Common s₀ s where - k_le : k ≤ 1 - n_le : n ≤ 112 + 16 * k - edi : s.gpr .edi = BitVec.ofNat 32 n - esi : s.gpr .esi = BitVec.ofNat 32 k - hash : ∀ iv m, R₀ s₀ iv m → Spec.Sha512.finalHash iv m = - (if k = 1 then Fin1 s₀ s.mem n m else Fin0 s₀ s.mem n m).toList.flatMap wordBytes - -/-- All blocks are compressed. -/ -def Done (s₀ : State) (s : State) : Prop := - Common s₀ s ∧ ∀ iv m, R₀ s₀ iv m → Spec.Sha512.finalHash iv m = (stateAt s.mem (stA s₀)).toList.flatMap wordBytes - -theorem Common.of_gpr {s₀ : State} {s s' : State} (h : Common s₀ s) - (hg : ∀ r ∈ [Reg.ebx, .esp], s'.gpr r = s.gpr r) - (hm : s'.mem = s.mem) (hrd : s'.rd = s.rd) (hwr : s'.wr = s.wr) : Common s₀ s' where - rd := hrd.trans h.rd - wr := hwr.trans h.wr - ebx := by rw [hg _ (by simp)]; exact h.ebx - esp := by rw [hg _ (by simp)]; exact h.esp - frame := by rw [hm]; exact h.frame - saved := by rw [hm]; exact h.saved - -/-- The argument words are never written. -/ -theorem Common.arg {s₀ : State} (hp : Pre s₀) {s : State} (h : Common s₀ s) {d : Nat} (h₁ : 4 ≤ d) - (h₂ : d + 4 ≤ 24) : s.mem.readW (addr (esp₀ s₀) d) 32 = s₀.mem.readW (addr (esp₀ s₀) d) 32 := by - refine h.frame.readW (r := ⟨addr (esp₀ s₀) d, 4⟩) (Region.contains_self _ _) ?_ (by decide) - intro r hr - simp only [List.mem_cons, List.not_mem_nil, or_false] at hr - rcases hr with rfl | rfl | rfl - · exact hp.a_st.sub_left (hp.arg_sub h₁ h₂) - · exact hp.a_scr.sub_left (hp.arg_sub h₁ h₂) - · exact hp.a_stk.sub_left (hp.arg_sub h₁ h₂) - -/-- The argument words, read with `esp`. -/ -theorem Common.argIn {s₀ : State} (hp : Pre s₀) {s : State} (h : Common s₀ s) {d : Nat} (h₁ : 4 ≤ d) - (h₂ : d + 4 ≤ 24) : InRegions (s.rd ++ s.wr) (addr (esp₀ s₀) d) 4 := - ⟨argR s₀, by simp [h.rd, hp.rd], hp.arg_in h₁ h₂⟩ - -/-- A write within the state keeps what `Common` says about memory. -/ -theorem Common.writeSt {s₀ : State} (hp : Pre s₀) {s : State} (h : Common s₀ s) {m : Mem} - (hf : Frame [stR s₀] s.mem m) : Frame [stR s₀, scR s₀, stkR s₀] s₀.mem m ∧ Saved s₀ m := by - refine ⟨h.frame.trans (hf.mono (by simp)), fun p hp' => ?_⟩ - have hd : 224 ≤ p.2 ∧ p.2 + 4 ≤ 240 := by - simp only [VG.Impl.Sha512.X86.Stream.saved, List.mem_cons, List.not_mem_nil, or_false] at hp' - rcases hp' with rfl | rfl | rfl | rfl <;> simp - rw [← h.saved p hp'] - refine hf.readW (r := ⟨addr (scr s₀) p.2, 4⟩) (Region.contains_self _ _) ?_ (by decide) - intro r hr - simp only [List.mem_singleton] at hr - subst hr - exact hp.st_scr.symm.sub_left (hp.scr_sub (by omega)) - -/-- Writing buffer bytes `[n, n + |xs|)`. -/ -theorem buf_frame {s₀ : State} (m : Mem) {n : Nat} {xs : List Byte} (hn : n + xs.length ≤ 128) : - Frame [stR s₀] m (writeBytes m (stA s₀ + 64 + BitVec.ofNat 64 n) xs) := by - refine writeBytes_frame _ _ _ ?_ - rw [st_add] - exact contains_offset (by omega) (by omega) - -/-! ## Zeroing the buffer -/ - -/-- Zeroing buffer bytes `[n, lim)` from state `sI`: `j` of them done. -/ -structure Zero (s₀ : State) (sI : State) (n lim j : Nat) (s : State) : Prop where - j_le : j ≤ lim - n - keep : ∀ r ∈ [Reg.ebx, .esp, .esi, .ecx], s.gpr r = sI.gpr r - rd : s.rd = sI.rd - wr : s.wr = sI.wr - edi : s.gpr .edi = BitVec.ofNat 32 (n + j) - eax : s.gpr .eax = BitVec.ofNat 32 (lim - n - j) - mem : s.mem = writeBytes sI.mem (stA s₀ + 64 + BitVec.ofNat 64 n) (List.replicate j 0) - -theorem zero_step {s₀ : State} (hp : Pre s₀) {sI : State} (hC : Common s₀ sI) (hecx : sI.gpr .ecx = 0) - {n lim j : Nat} (hlim : lim ≤ 128) (hj : j < lim - n) {s : State} (h : Zero s₀ sI n lim j s) : - WP isa (.block [.mov .edx (.reg .ebx), .alu .add .edx (.reg .edi), .store8 (at_ .edx 64) .cl, - .alu .add .edi (.imm 1), .alu .sub .eax (.imm 1)]) s fun s' => - Zero s₀ sI n lim (j + 1) s' ∧ s'.zf = some (decide (lim - n - (j + 1) = 0)) := by - have hst := hp.st_fit - have hebx : s.gpr .ebx = st s₀ := by rw [h.keep _ (by simp), hC.ebx] - have ha : stA s₀ + 64 + BitVec.ofNat 64 n + BitVec.ofNat 64 j = stA s₀ + BitVec.ofNat 64 (64 + n + j) := by - simp only [BitVec.ofNat_add]; ac_rfl - have hout : InRegions s.wr (stA s₀ + 64 + BitVec.ofNat 64 n + BitVec.ofNat 64 j) 1 := by - refine ⟨stR s₀, by simp [h.wr, hC.wr, hp.wr], ?_⟩ - rw [ha] - exact contains_offset (by omega) (by omega) - refine wp_mov fun s₁ u₁ => wp_add fun s₂ u₂ => ?_ - refine wp_store8 (r := .cl) (a := stA s₀ + 64 + BitVec.ofNat 64 n + BitVec.ofNat 64 j) ?_ - (by rw [u₂.wr, u₁.wr]; exact hout) fun s₃ u₃ => ?_ - · rw [ea_at, u₂.gpr, u₁.gpr, u₁.other _ (by decide), hebx, h.edi, ha, addr_add_ofNat (by omega)] - congr 2; omega - refine wp_addi fun s₄ u₄ => wp_subi fun s₅ u₅ hz₅ => WP.block_nil ⟨⟨by omega, fun r hr => ?_, - by rw [u₅.rd, u₄.rd, u₃.rd, u₂.rd, u₁.rd, h.rd], by rw [u₅.wr, u₄.wr, u₃.wr, u₂.wr, u₁.wr, h.wr], ?_, ?_, ?_⟩, ?_⟩ - · have : r ≠ .eax ∧ r ≠ .edi ∧ r ≠ .edx := by - simp only [List.mem_cons, List.not_mem_nil, or_false] at hr - rcases hr with rfl | rfl | rfl | rfl <;> decide - rw [u₅.other r this.1, u₄.other r this.2.1, u₃.gpr, u₂.other r this.2.2, u₁.other r this.2.2, h.keep r hr] - · rw [u₅.other _ (by decide), u₄.gpr, u₃.gpr, u₂.other _ (by decide), u₁.other _ (by decide), h.edi, - ← ofNat_succ, Nat.add_assoc] - · rw [u₅.gpr, u₄.other _ (by decide), u₃.gpr, u₂.other _ (by decide), u₁.other _ (by decide), h.eax, - ofNat_pred (by omega), Nat.sub_sub] - · rw [u₅.mem, u₄.mem, u₃.mem, u₂.mem, u₁.mem, show Reg8.cl.reg = Reg.ecx from rfl, u₂.other _ (by decide), - u₁.other _ (by decide), h.keep _ (by simp), hecx, h.mem, List.replicate_succ', - writeBytes_snoc _ _ _ _ (by simp only [List.length_replicate]; omega), List.length_replicate] - rfl - · rw [hz₅, u₄.other _ (by decide), u₃.gpr, u₂.other _ (by decide), u₁.other _ (by decide), h.eax, - ofNat_pred (by omega), ofNat_beq_zero (by omega), Nat.sub_sub, Nat.sub_sub] - -theorem zero_ok {s₀ : State} (hp : Pre s₀) {sI : State} (hC : Common s₀ sI) (hecx : sI.gpr .ecx = 0) - {n lim : Nat} (hlim : lim ≤ 128) (hn : n ≤ lim) {s : State} (h : Zero s₀ sI n lim 0 s) - (hz : s.zf = some (decide (lim - n = 0))) : - WP isa (.ite .e (.block []) (.loop (.block [.mov .edx (.reg .ebx), .alu .add .edx (.reg .edi), - .store8 (at_ .edx 64) .cl, .alu .add .edi (.imm 1), .alu .sub .eax (.imm 1)]) .ne)) s - (Zero s₀ sI n lim (lim - n)) := by - refine WP.ite (decide (lim - n = 0)) hz (fun hb => ?_) (fun hb => ?_) - · simp only [decide_eq_true_eq] at hb - exact WP.block_nil (hb ▸ h) - · simp only [decide_eq_false_iff_not] at hb - refine WP.loop (M := isa) (fun k s => ∃ j, k = lim - n - j ∧ j < lim - n ∧ Zero s₀ sI n lim j s) - ?_ (lim - n) s ⟨0, rfl, by omega, h⟩ - rintro k s ⟨j, rfl, hj, hZ⟩ - refine WP.mono (zero_step hp hC hecx hlim hj hZ) fun s' ⟨hZ', hz'⟩ => ?_ - by_cases hl : lim - n - (j + 1) = 0 - · refine .inl ⟨by show s'.zf.map (!·) = _; rw [hz']; simp [hl], ?_⟩ - rwa [show j + 1 = lim - n by omega] at hZ' - · exact .inr ⟨by show s'.zf.map (!·) = _; rw [hz']; simp [hl], _, by omega, j + 1, rfl, by omega, hZ'⟩ - -/-! ## One block -/ - -/-- What the call of the compression function needs. -/ -theorem Common.atPre {s₀ : State} (hp : Pre s₀) {s : State} (hC : Common s₀ s) : - AtPre (st s₀) (scr s₀) (esp₀ s₀) 20 s := - ⟨hC.esp, hC.ebx, hC.argIn hp (by omega) (by omega), by rw [hC.arg hp (by omega) (by omega)]; rfl, - by simp [hC.wr, hp.wr], by simp [hC.wr, hp.wr]⟩ - -/-- The call of the compression function on the buffer. -/ -theorem compress_buf {s₀ : State} (hp : Pre s₀) {s : State} (hC : Common s₀ s) {Q : State → Prop} - (hQ : ∀ s', Common s₀ s' → (∀ r ∈ [Reg.ebx, .esi, .edi, .ebp, .esp], s'.gpr r = s.gpr r) → - stateAt s'.mem (stA s₀) = compress (stateAt s.mem (stA s₀)) (blockAt s.mem (stA s₀ + 64)) → Q s') : - WP isa (compressAt 20) s Q := by - refine compressAt_ok hp.st_fit hp.scr_fit hp.sp_lo hp.st_scr hp.stk_st hp.stk_scr (hC.atPre hp) - fun s' hrd hwr hg hf hst => hQ s' ⟨hrd.trans hC.rd, hwr.trans hC.wr, by rw [hg _ (by simp)]; exact hC.ebx, - by rw [hg _ (by simp)]; exact hC.esp, hC.frame.trans (hf.sub fun r hr => ?_), fun p hp' => ?_⟩ hg hst - · simp only [List.mem_cons, List.not_mem_nil, or_false] at hr - rcases hr with rfl | rfl | rfl - · exact ⟨stR s₀, by simp, Region.sub_prefix (by omega)⟩ - · exact ⟨scR s₀, by simp, Region.sub_prefix (by omega)⟩ - · exact ⟨stkR s₀, by simp, fun _ h => h⟩ - · have hd : 224 ≤ p.2 ∧ p.2 + 4 ≤ 240 := by - simp only [VG.Impl.Sha512.X86.Stream.saved, List.mem_cons, List.not_mem_nil, or_false] at hp' - rcases hp' with rfl | rfl | rfl | rfl <;> simp - rw [← hC.saved p hp'] - exact hf.readW (r := ⟨addr (scr s₀) p.2, 4⟩) (Region.contains_self _ _) - (hp.saved_sep hd.1 (by omega)) (by decide) - -/-! ## The message length -/ - -theorem writeW_bswap (m : Mem) (a : Addr) (w : BitVec 32) : - m.writeW a (bswap w) = writeBytes m a (Spec.Sha256.wordBytes w) := by - rw [Mem.writeW, write_eq_writeBytes, ← VG.Proof.Sha256.X86.Stream.bswap_bytes]; rfl - -/-- The bytes `lenW` writes, from `count` in the argument words 1 and 2. -/ -def lenL (s₀ : State) : List Byte := - Spec.Sha256.wordBytes 0 ++ Spec.Sha256.wordBytes (arg s₀ 2 >>> 29) ++ - Spec.Sha256.wordBytes ((arg s₀ 2 <<< 3) ||| (arg s₀ 1 >>> 29)) ++ Spec.Sha256.wordBytes (arg s₀ 1 <<< 3) - -theorem lenL_eq {s₀ : State} {iv : HashValue} {m : List Byte} (hm : R₀ s₀ iv m) : lenL s₀ = lenBytes m := by - have hc := hm.2.2 - have h8 : BitVec.ofNat 64 (8 * m.length) = countX86 s₀ <<< 3 := by - rw [hc] - apply BitVec.eq_of_toNat_eq - simp only [BitVec.toNat_ofNat, BitVec.toNat_shiftLeft, Nat.shiftLeft_eq] - omega - rw [lenBytes_split m hm.2.1, ← hc, h8, wordBytes_split, wordBytes_split, hi_shr61, lo_shr61, hi_shl3, - lo_shl3] - simp only [countX86, Word64.hi_append, Word64.lo_append, lenL, List.append_assoc] - -theorem lenL_length (s₀ : State) : (lenL s₀).length = 16 := rfl +/-- The length field: `count >> 61`, then `8 count`, big-endian. -/ +theorem lenOf_eq (hi lo : BitVec 32) : + md.lenOf (hi ++ lo) = bytes32 true 0 ++ bytes32 true (hi >>> 29) ++ + bytes64 true (BitVec.ofNat 64 (8 * (hi ++ lo).toNat)) := by + have e := Proof.Sha512.lenOf_split (hi ++ lo) + rw [shr61] at e + rw [show md.lenOf (hi ++ lo) = Spec.Sha512.wordBytes ((0 : BitVec 32) ++ hi >>> 29) ++ + Spec.Sha512.wordBytes (BitVec.ofNat 64 (8 * (hi ++ lo).toNat)) from e, + show Spec.Sha512.wordBytes = bytes64 true from rfl, bytes64_halves] + rfl -/-- Writing the message length. -/ -theorem len_ok {s₀ : State} (hp : Pre s₀) {s : State} (hC : Common s₀ s) : - WP isa (.block lenW) s fun s' => +theorem len_ok (s : State) (hfit : (s.gpr .ebx).toNat + (params.N + params.B) ≤ 2 ^ 32) + (hlo : InRegions (s.rd ++ s.wr) (addr (s.gpr .ebp) (params.so + 16)) 4) + (hhi : InRegions (s.rd ++ s.wr) (addr (s.gpr .ebp) (params.so + 20)) 4) + (ho : ∀ d, params.N + params.B - params.L ≤ d → d + 4 ≤ params.N + params.B → + InRegions s.wr (addr (s.gpr .ebx) d) 4) : + WP isa (.block params.len) s fun s' => (∀ r, r ≠ .eax → r ≠ .ecx → r ≠ .edx → s'.gpr r = s.gpr r) ∧ s'.rd = s.rd ∧ s'.wr = s.wr ∧ - s'.mem = writeBytes s.mem (stA s₀ + 64 + BitVec.ofNat 64 112) (lenL s₀) := by - have hst := hp.st_fit - have hout : ∀ o, o + 4 ≤ 192 → InRegions s.wr (addr (st s₀) o) 4 := - fun o ho => ⟨stR s₀, by simp [hC.wr, hp.wr], contains_addr ho (by omega) hst⟩ - unfold lenW - refine wp_movm (a := addr (esp₀ s₀) 8) (by rw [ea_at, hC.esp]) (hC.argIn hp (by omega) (by omega)) - fun s₁ u₁ => ?_ - refine wp_movm (a := addr (esp₀ s₀) 12) (by rw [ea_at, u₁.other _ (by decide), hC.esp]) - (by rw [u₁.rd, u₁.wr]; exact hC.argIn hp (by omega) (by omega)) fun s₂ u₂ => ?_ - have a2 : s₂.gpr .eax = arg s₀ 1 := by - rw [u₂.other _ (by decide), u₁.gpr, hC.arg hp (by omega) (by omega)]; rfl - have c2 : s₂.gpr .ecx = arg s₀ 2 := by - rw [u₂.gpr, u₁.mem, hC.arg hp (by omega) (by omega)]; rfl - have b2 : s₂.gpr .ebx = st s₀ := by rw [u₂.other _ (by decide), u₁.other _ (by decide), hC.ebx] - refine wp_movi fun s₃ u₃ => wp_store (a := addr (st s₀) 176) (by rw [ea_at, u₃.other _ (by decide), b2]) - (by rw [u₃.wr, u₂.wr, u₁.wr]; exact hout 176 (by omega)) fun s₄ u₄ => ?_ + s'.mem = writeBytes s.mem ((s.gpr .ebx).setWidth 64 + BitVec.ofNat 64 (params.N + params.B - params.L)) + (md.lenOf (s.mem.readW (addr (s.gpr .ebp) (params.so + 20)) 32 ++ + s.mem.readW (addr (s.gpr .ebp) (params.so + 16)) 32)) := by + have hfit' : (s.gpr .ebx).toNat + 192 ≤ 2 ^ 32 := hfit + have ho' : ∀ d, 176 ≤ d → d + 4 ≤ 192 → InRegions s.wr (addr (s.gpr .ebx) d) 4 := ho + show WP isa (.block (Impl.MdStream.X86.loadCount 224 ++ ([.mov .edx (.imm 0), .store (at_ .ebx 176) .edx, + .mov .edx (.reg .ecx), .shift .shr .edx 29, .bswap .edx, .store (at_ .ebx 180) .edx] ++ + len64Of 184 true))) s fun s' => _ ∧ _ ∧ _ ∧ s'.mem = writeBytes s.mem ((s.gpr .ebx).setWidth 64 + + BitVec.ofNat 64 176) (md.lenOf (s.mem.readW (addr (s.gpr .ebp) 244) 32 ++ + s.mem.readW (addr (s.gpr .ebp) 240) 32)) + refine loadCount_ok hlo hhi fun s₂ g₂ m₂ rd₂ wr₂ ha hc => ?_ + generalize s.mem.readW (addr (s.gpr .ebp) (224 + 16)) 32 = lo at ha + generalize s.mem.readW (addr (s.gpr .ebp) (224 + 20)) 32 = hi at hc + have hb₂ : s₂.gpr .ebx = s.gpr .ebx := g₂ _ (by decide) (by decide) + simp only [List.cons_append, List.nil_append] + refine wp_movi fun s₃ u₃ => wp_store (a := addr (s.gpr .ebx) 176) + (by show addr (s₃.gpr .ebx) 176 = _; rw [u₃.other _ (by decide), hb₂]) (by rw [u₃.wr, wr₂]; exact ho' 176 (by omega) (by omega)) + fun s₄ u₄ => ?_ refine wp_mov fun s₅ u₅ => wp_shr (by decide) fun s₆ u₆ => wp_bswap fun s₇ u₇ => ?_ have g₇ : ∀ r, r ≠ .edx → s₇.gpr r = s₂.gpr r := fun r h => by rw [u₇.other r h, u₆.other r h, u₅.other r h, u₄.gpr, u₃.other r h] - refine wp_store (a := addr (st s₀) 180) (by rw [ea_at, g₇ _ (by decide), b2]) - (by rw [u₇.wr, u₆.wr, u₅.wr, u₄.wr, u₃.wr, u₂.wr, u₁.wr]; exact hout 180 (by omega)) fun s₈ u₈ => ?_ - refine wp_add fun s₉ u₉ => wp_add fun s₁₀ u₁₀ => wp_add fun s₁₁ u₁₁ => wp_mov fun s₁₂ u₁₂ => - wp_shr (by decide) fun s₁₃ u₁₃ => wp_or fun s₁₄ u₁₄ => wp_bswap fun s₁₅ u₁₅ => ?_ - have g₁₅ : ∀ r, r ≠ .edx → r ≠ .ecx → s₁₅.gpr r = s₂.gpr r := fun r h h' => by - rw [u₁₅.other r h', u₁₄.other r h', u₁₃.other r h, u₁₂.other r h, u₁₁.other r h', u₁₀.other r h', - u₉.other r h', u₈.gpr, g₇ r h] - refine wp_store (a := addr (st s₀) 184) (by rw [ea_at, g₁₅ _ (by decide) (by decide), b2]) - (by rw [u₁₅.wr, u₁₄.wr, u₁₃.wr, u₁₂.wr, u₁₁.wr, u₁₀.wr, u₉.wr, u₈.wr, u₇.wr, u₆.wr, u₅.wr, u₄.wr, u₃.wr, - u₂.wr, u₁.wr]; exact hout 184 (by omega)) fun s₁₆ u₁₆ => ?_ - refine wp_add fun s₁₇ u₁₇ => wp_add fun s₁₈ u₁₈ => wp_add fun s₁₉ u₁₉ => wp_bswap fun s₂₀ u₂₀ => ?_ - have g₂₀ : ∀ r, r ≠ .eax → r ≠ .edx → r ≠ .ecx → s₂₀.gpr r = s₂.gpr r := fun r h h' h'' => by - rw [u₂₀.other r h, u₁₉.other r h, u₁₈.other r h, u₁₇.other r h, u₁₆.gpr, g₁₅ r h' h''] - refine wp_store (a := addr (st s₀) 188) (by rw [ea_at, g₂₀ _ (by decide) (by decide) (by decide), b2]) - (by rw [u₂₀.wr, u₁₉.wr, u₁₈.wr, u₁₇.wr, u₁₆.wr, u₁₅.wr, u₁₄.wr, u₁₃.wr, u₁₂.wr, u₁₁.wr, u₁₀.wr, u₉.wr, u₈.wr, - u₇.wr, u₆.wr, u₅.wr, u₄.wr, u₃.wr, u₂.wr, u₁.wr]; exact hout 188 (by omega)) fun s₂₁ u₂₁ => WP.block_nil ?_ - refine ⟨fun r h1 h2 h3 => ?_, ?_, ?_, ?_⟩ - · rw [u₂₁.gpr, g₂₀ r h1 h3 h2, u₂.other r h2, u₁.other r h1] - · rw [u₂₁.rd, u₂₀.rd, u₁₉.rd, u₁₈.rd, u₁₇.rd, u₁₆.rd, u₁₅.rd, u₁₄.rd, u₁₃.rd, u₁₂.rd, u₁₁.rd, u₁₀.rd, u₉.rd, - u₈.rd, u₇.rd, u₆.rd, u₅.rd, u₄.rd, u₃.rd, u₂.rd, u₁.rd] - · rw [u₂₁.wr, u₂₀.wr, u₁₉.wr, u₁₈.wr, u₁₇.wr, u₁₆.wr, u₁₅.wr, u₁₄.wr, u₁₃.wr, u₁₂.wr, u₁₁.wr, u₁₀.wr, u₉.wr, - u₈.wr, u₇.wr, u₆.wr, u₅.wr, u₄.wr, u₃.wr, u₂.wr, u₁.wr] - -- The values stored. - have v0 : s₃.gpr .edx = bswap 0 := by rw [u₃.gpr]; decide - have v1 : s₇.gpr .edx = bswap (arg s₀ 2 >>> 29) := by - rw [u₇.gpr, u₆.gpr, u₅.gpr, u₄.gpr, u₃.other _ (by decide), c2] - have c11 : s₁₁.gpr .ecx = arg s₀ 2 <<< 3 := by - rw [u₁₁.gpr, u₁₀.gpr, u₉.gpr, u₈.gpr, g₇ _ (by decide), c2, times8] - have v2 : s₁₅.gpr .ecx = bswap ((arg s₀ 2 <<< 3) ||| (arg s₀ 1 >>> 29)) := by - rw [u₁₅.gpr, u₁₄.gpr, u₁₃.gpr, u₁₃.other _ (by decide), u₁₂.gpr, u₁₂.other _ (by decide), c11, - u₁₁.other _ (by decide), u₁₀.other _ (by decide), u₉.other _ (by decide), u₈.gpr, g₇ _ (by decide), a2] - have v3 : s₂₀.gpr .eax = bswap (arg s₀ 1 <<< 3) := by - rw [u₂₀.gpr, u₁₉.gpr, u₁₈.gpr, u₁₇.gpr, u₁₆.gpr, g₁₅ _ (by decide) (by decide), a2, times8] - have m₂ : s₂.mem = s.mem := by rw [u₂.mem, u₁.mem] - have a0 : addr (st s₀) 176 = stA s₀ + 64 + BitVec.ofNat 64 112 := by - rw [addr_eq (by omega), BitVec.add_assoc]; rfl - have a1 : addr (st s₀) 180 = stA s₀ + 64 + BitVec.ofNat 64 112 + BitVec.ofNat 64 4 := by - rw [addr_eq (by omega), BitVec.add_assoc, BitVec.add_assoc]; rfl - have a2' : addr (st s₀) 184 = stA s₀ + 64 + BitVec.ofNat 64 112 + BitVec.ofNat 64 8 := by - rw [addr_eq (by omega), BitVec.add_assoc, BitVec.add_assoc]; rfl - have a3 : addr (st s₀) 188 = stA s₀ + 64 + BitVec.ofNat 64 112 + BitVec.ofNat 64 12 := by - rw [addr_eq (by omega), BitVec.add_assoc, BitVec.add_assoc]; rfl - rw [u₂₁.mem, v3, u₂₀.mem, u₁₉.mem, u₁₈.mem, u₁₇.mem, u₁₆.mem, v2, u₁₅.mem, u₁₄.mem, u₁₃.mem, u₁₂.mem, u₁₁.mem, - u₁₀.mem, u₉.mem, u₈.mem, v1, u₇.mem, u₆.mem, u₅.mem, u₄.mem, v0, u₃.mem, m₂, writeW_bswap, writeW_bswap, - writeW_bswap, writeW_bswap, a0, a1, a2', a3, - show (4 : Nat) = (Spec.Sha256.wordBytes 0).length from rfl, - writeBytes_append _ _ _ _ (by simp [Spec.Sha256.wordBytes]), - show (8 : Nat) = (Spec.Sha256.wordBytes 0 ++ Spec.Sha256.wordBytes (arg s₀ 2 >>> 29)).length from rfl, - writeBytes_append _ _ _ _ (by simp [Spec.Sha256.wordBytes]), - show (12 : Nat) = (Spec.Sha256.wordBytes 0 ++ Spec.Sha256.wordBytes (arg s₀ 2 >>> 29) ++ - Spec.Sha256.wordBytes ((arg s₀ 2 <<< 3) ||| (arg s₀ 1 >>> 29))).length from rfl, - writeBytes_append _ _ _ _ (by simp [Spec.Sha256.wordBytes])] - rfl - -/-! ## One block -/ - -/-- The loop's postcondition for one iteration. -/ -def Step (s₀ : State) (k : Nat) (s : State) : Prop := - (eval .e s = some false ∧ k = 0 ∧ Done s₀ s) ∨ (eval .e s = some true ∧ k = 1 ∧ LInv s₀ 0 0 s) - -theorem regs2 {r : Reg} (hr : r ∈ [Reg.ebx, .esp]) : - r ≠ .eax ∧ r ≠ .ecx ∧ r ≠ .edx ∧ r ≠ .edi ∧ r ≠ .esi := by - simp only [List.mem_cons, List.not_mem_nil, or_false] at hr - rcases hr with rfl | rfl <;> decide - -/-- The loop body before the call of the compression function, and after. -/ -def bodyPre : Prog isa := - .seq (.seq (.seq (.seq (.seq (.block [.mov .eax (.imm 128), .alu .test .esi (.reg .esi)]) - (.ite .e (.block [.mov .eax (.imm 112)]) (.block []))) - (.block [.mov .ecx (.imm 0), .alu .sub .eax (.reg .edi)])) - (.ite .e (.block []) - (.loop (.block [.mov .edx (.reg .ebx), .alu .add .edx (.reg .edi), .store8 (at_ .edx 64) .cl, - .alu .add .edi (.imm 1), .alu .sub .eax (.imm 1)]) .ne))) - (.block [.alu .test .esi (.reg .esi)])) - (.ite .e (.block lenW) (.block [])) - -def bodyEnd : List Instr := [.mov .edi (.imm 0), .alu .sub .esi (.imm 1)] - -theorem pre_ok {s₀ : State} (hp : Pre s₀) {k n : Nat} {s : State} (h : LInv s₀ k n s) : - WP isa bodyPre s fun s' => Common s₀ s' ∧ WP isa (.seq (compressAt 20) (.block bodyEnd)) s' (Step s₀ k) := by - have hk := h.k_le; have hn := h.n_le; have hst := hp.st_fit - have hC := h.toCommon - unfold bodyPre - refine WP.seq (WP.seq (WP.seq (WP.seq (WP.seq ?_)))) - -- `eax := 128` or `112`: the end of the zeros. - refine (wp_movi fun s₁ u₁ => wp_test fun s₂ f₂ z₂ => WP.block_nil ?_) - have hz₂ : s₂.zf = some (decide (k = 0)) := by - rw [z₂, u₁.other _ (by decide), h.esi, BitVec.and_self, ofNat_beq_zero (by omega)] - refine (WP.mono (Q := fun (s₃ : State) => s₃.gpr .eax = BitVec.ofNat 32 (112 + 16 * k) ∧ - (∀ r, r ≠ .eax → s₃.gpr r = s.gpr r) ∧ s₃.mem = s.mem ∧ s₃.rd = s.rd ∧ s₃.wr = s.wr) ?_ - fun s₃ ⟨heax₃, g₃, m₃, rd₃, wr₃⟩ => ?_) - · refine WP.ite (decide (k = 0)) (by show s₂.zf = _; rw [hz₂]) (fun hb => ?_) (fun hb => ?_) - · simp only [decide_eq_true_eq] at hb; subst hb - refine wp_movi fun s₃ u₃ => WP.block_nil ⟨by rw [u₃.gpr]; rfl, fun r hr => ?_, ?_, ?_, ?_⟩ - · rw [u₃.other r hr, f₂.gpr, u₁.other r hr] - · rw [u₃.mem, f₂.mem, u₁.mem] - · rw [u₃.rd, f₂.rd, u₁.rd] - · rw [u₃.wr, f₂.wr, u₁.wr] - · simp only [decide_eq_false_iff_not] at hb - refine WP.block_nil ⟨by rw [f₂.gpr, u₁.gpr, show k = 1 by omega]; rfl, fun r hr => ?_, ?_, ?_, ?_⟩ - · rw [f₂.gpr, u₁.other r hr] - · rw [f₂.mem, u₁.mem] - · rw [f₂.rd, u₁.rd] - · rw [f₂.wr, u₁.wr] - -- `ecx := 0; eax -= edi`: zero the rest of the buffer, up to `lim`. - have hC₃ : Common s₀ s₃ := hC.of_gpr (fun r hr => g₃ r (regs2 hr).1) m₃ rd₃ wr₃ - refine (wp_movi fun s₄ u₄ => wp_sub fun s₅ u₅ z₅ => WP.block_nil ?_) - have hC₄ : Common s₀ s₄ := hC₃.of_gpr (fun r hr => u₄.other r (regs2 hr).2.1) u₄.mem u₄.rd u₄.wr - have hecx₄ : s₄.gpr .ecx = 0 := u₄.gpr - have hedi₄ : s₄.gpr .edi = BitVec.ofNat 32 n := by rw [u₄.other _ (by decide), g₃ _ (by decide), h.edi] - have heax₅ : s₅.gpr .eax = BitVec.ofNat 32 (112 + 16 * k - n) := by - rw [u₅.gpr, u₄.other _ (by decide), heax₃, hedi₄, sub_ofNat (a := 112 + 16 * k) (b := n) (by omega)] - have hZ : Zero s₀ s₄ n (112 + 16 * k) 0 s₅ := by - refine ⟨Nat.zero_le _, fun r hr => u₅.other r ?_, u₅.rd, u₅.wr, - by rw [u₅.other _ (by decide), hedi₄, Nat.add_zero], by rw [heax₅, Nat.sub_zero], - by rw [u₅.mem, List.replicate_zero, writeBytes_nil]⟩ - simp only [List.mem_cons, List.not_mem_nil, or_false] at hr - rcases hr with rfl | rfl | rfl | rfl <;> decide - have hz₅ : s₅.zf = some (decide (112 + 16 * k - n = 0)) := by - rw [z₅, ← u₅.gpr, heax₅, ofNat_beq_zero (by omega)] - refine (WP.mono (zero_ok hp hC₄ hecx₄ (by omega) hn hZ hz₅) fun s₆ hZ₆ => ?_) - have hm₄ : s₄.mem = s.mem := by rw [u₄.mem, m₃] - have hf₆ : Frame [stR s₀] s₄.mem s₆.mem := by - rw [hZ₆.mem]; exact buf_frame _ (by simp only [List.length_replicate]; omega) - obtain ⟨hfr₆, hsv₆⟩ := hC₄.writeSt hp hf₆ - have hC₆ : Common s₀ s₆ := ⟨hZ₆.rd.trans hC₄.rd, hZ₆.wr.trans hC₄.wr, by rw [hZ₆.keep _ (by simp), hC₄.ebx], - by rw [hZ₆.keep _ (by simp), hC₄.esp], hfr₆, hsv₆⟩ - have hst₆ : stateAt s₆.mem (stA s₀) = stateAt s.mem (stA s₀) := by - rw [hZ₆.mem, hm₄] - apply stateAt_congr - intro i hi - rw [st_add] - exact writeBytes_before _ _ _ (by omega) (by simp only [List.length_replicate]; omega) - have hby₆ : bytesAt s₆.mem (stA s₀ + 64) (112 + 16 * k) = - bytesAt s.mem (stA s₀ + 64) n ++ List.replicate (112 + 16 * k - n) 0 := by - rw [hZ₆.mem, hm₄, ← bytesAt_writeBytes _ _ _ _ (by simp only [List.length_replicate]; omega)] - congr 1; simp only [List.length_replicate]; omega - have hesi₆ : s₆.gpr .esi = BitVec.ofNat 32 k := by - rw [hZ₆.keep _ (by simp), u₄.other _ (by decide), g₃ _ (by decide), h.esi] - -- In the last block, the length. - refine (wp_test fun s₇ f₇ z₇ => WP.block_nil ?_) - have hC₇ : Common s₀ s₇ := hC₆.of_gpr (fun r _ => by rw [f₇.gpr]) f₇.mem f₇.rd f₇.wr - have hz₇ : s₇.zf = some (decide (k = 0)) := by - rw [z₇, hesi₆, BitVec.and_self, ofNat_beq_zero (by omega)] - have hesi₇ : s₇.gpr .esi = BitVec.ofNat 32 k := by rw [f₇.gpr, hesi₆] - refine (WP.mono (Q := fun (s₈ : State) => Common s₀ s₈ ∧ s₈.gpr .esi = BitVec.ofNat 32 k ∧ - stateAt s₈.mem (stA s₀) = stateAt s.mem (stA s₀) ∧ - ∀ iv m, R₀ s₀ iv m → bytesAt s₈.mem (stA s₀ + 64) 128 = bytesAt s.mem (stA s₀ + 64) n ++ - (if k = 1 then List.replicate (128 - n) 0 else List.replicate (112 - n) 0 ++ lenBytes m)) ?_ - fun s₈ ⟨hC₈, hesi₈, hst₈, hby₈⟩ => ?_) - · refine WP.ite (decide (k = 0)) (by show s₇.zf = _; rw [hz₇]) (fun hb => ?_) (fun hb => ?_) - · simp only [decide_eq_true_eq] at hb; subst hb - refine WP.mono (len_ok hp hC₇) fun s₈ ⟨g₈, rd₈, wr₈, m₈⟩ => ?_ - have hfL : Frame [stR s₀] s₇.mem s₈.mem := by - rw [m₈]; exact buf_frame _ (by rw [lenL_length]) - obtain ⟨hfr, hsv⟩ := hC₇.writeSt hp hfL - refine ⟨⟨rd₈.trans hC₇.rd, wr₈.trans hC₇.wr, by rw [g₈ _ (by decide) (by decide) (by decide), hC₇.ebx], - by rw [g₈ _ (by decide) (by decide) (by decide), hC₇.esp], hfr, hsv⟩, - by rw [g₈ _ (by decide) (by decide) (by decide), hesi₇], ?_, fun iv m hm => ?_⟩ - · rw [m₈, ← hst₆, ← f₇.mem] - apply stateAt_congr - intro i hi - rw [st_add] - exact writeBytes_before _ _ _ (by omega) (by rw [lenL_length]; omega) - · simp only [show ¬ ((0 : Nat) = 1) by decide, ite_false] - have e := bytesAt_writeBytes s₇.mem (stA s₀ + 64) 112 (lenL s₀) (by rw [lenL_length]; omega) - rw [lenL_length] at e - rw [show 112 + 16 * 0 = 112 from rfl] at hby₆ - rw [m₈, e, f₇.mem, hby₆, lenL_eq hm] - simp [List.append_assoc] - · simp only [decide_eq_false_iff_not] at hb - have hk1 : k = 1 := by omega - subst hk1 - refine WP.block_nil ⟨hC₇, hesi₇, by rw [f₇.mem, hst₆], fun iv m _ => ?_⟩ - rw [f₇.mem, show (128 : Nat) = 112 + 16 * 1 from rfl, hby₆]; simp - -- Compress the block. - refine ⟨hC₈, WP.seq (compress_buf hp hC₈ fun s₁₀ hC₁₀ cs₁₀ hst₁₀ => ?_)⟩ - have hesi₁₀ : s₁₀.gpr .esi = BitVec.ofNat 32 k := by rw [cs₁₀ _ (by simp), hesi₈] - have hblk : ∀ iv m, R₀ s₀ iv m → blockAt s₈.mem (stA s₀ + 64) = parseBlock fun t => - (bytesAt s.mem (stA s₀ + 64) n ++ - (if k = 1 then List.replicate (128 - n) 0 else List.replicate (112 - n) 0 ++ lenBytes m)).getD t 0 := - fun iv m hm => parseBlock_congr fun t ht => bytesAt_getD (hby₈ iv m hm) ht - -- Next block, if any. - refine wp_movi fun s₁₁ u₁₁ => wp_subi fun s₁₂ u₁₂ z₁₂ => WP.block_nil ?_ - have hC₁₂ : Common s₀ s₁₂ := hC₁₀.of_gpr (fun r hr => by - rw [u₁₂.other r (regs2 hr).2.2.2.2, u₁₁.other r (regs2 hr).2.2.2.1]) (by rw [u₁₂.mem, u₁₁.mem]) - (by rw [u₁₂.rd, u₁₁.rd]) (by rw [u₁₂.wr, u₁₁.wr]) - have hz : s₁₂.zf = some (decide (k = 1)) := by - rw [z₁₂, u₁₁.other _ (by decide), hesi₁₀, show (1 : BitVec 32) = BitVec.ofNat 32 1 from rfl, - sub_beq (a := k) (b := 1) (by omega) (by omega)] - have hst : ∀ iv m, R₀ s₀ iv m → stateAt s₁₂.mem (stA s₀) = compress (stateAt s.mem (stA s₀)) (parseBlock fun t => - (bytesAt s.mem (stA s₀ + 64) n ++ - (if k = 1 then List.replicate (128 - n) 0 else List.replicate (112 - n) 0 ++ lenBytes m)).getD t 0) := by - intro iv m hm - rw [u₁₂.mem, u₁₁.mem, hst₁₀, hst₈, hblk iv m hm] - by_cases hk1 : k = 1 - · subst hk1 - refine .inr ⟨by show s₁₂.zf = _; rw [hz]; rfl, rfl, ⟨hC₁₂, by omega, by omega, ?_, ?_, fun iv m hm => ?_⟩⟩ - · rw [u₁₂.other _ (by decide), u₁₁.gpr]; rfl - · rw [u₁₂.gpr, u₁₁.other _ (by decide), hesi₁₀]; rfl - · rw [h.hash iv m hm] - simp only [ite_true, show ¬ ((0 : Nat) = 1) by decide, ite_false, Fin1, Fin0, hst iv m hm] - simp [bytesAt] - · have hk0 : k = 0 := by omega - subst hk0 - refine .inl ⟨by show s₁₂.zf = _; rw [hz]; rfl, rfl, hC₁₂, fun iv m hm => ?_⟩ - rw [h.hash iv m hm, hst iv m hm] - simp only [show ¬ ((0 : Nat) = 1) by decide, ite_false, Fin0, List.append_assoc] - -theorem body_ok {s₀ : State} (hp : Pre s₀) {k n : Nat} {s : State} (h : LInv s₀ k n s) : - WP isa finalizeBody s (Step s₀ k) := by - exact WP.assoc (WP.assoc (WP.assoc (WP.assoc (WP.assoc (WP.seq (WP.mono (pre_ok hp h) fun _ h => h.2)))))) - -/-! ## Prologue -/ - -/-- The memory after saving our caller's registers. -/ -def saveMem (s₀ : State) : Mem := - (((s₀.mem.writeW (addr (scr s₀) 224) (s₀.gpr .ebx)).writeW (addr (scr s₀) 228) (s₀.gpr .esi)).writeW - (addr (scr s₀) 232) (s₀.gpr .edi)).writeW (addr (scr s₀) 236) (s₀.gpr .ebp) - -theorem saveMem_frame {s₀ : State} (hp : Pre s₀) : Frame [scR s₀] s₀.mem (saveMem s₀) := by - have c : ∀ d, d + 4 ≤ 272 → (scR s₀).Contains (addr (scr s₀) d) (32 / 8) := fun d hd => hp.scr_in hd - exact ((((Frame.refl _ _).writeW (List.mem_singleton_self _) _ (c 224 (by omega))).writeW - (List.mem_singleton_self _) _ (c 228 (by omega))).writeW (List.mem_singleton_self _) _ - (c 232 (by omega))).writeW (List.mem_singleton_self _) _ (c 236 (by omega)) - -theorem saveMem_saved {s₀ : State} (hp : Pre s₀) : Saved s₀ (saveMem s₀) := by - have hs := hp.scr_fit - have w : ∀ (m : Mem) (v : BitVec 32) (d e : Nat), d + 4 ≤ 272 → e + 4 ≤ 272 → d + 4 ≤ e ∨ e + 4 ≤ d → - (m.writeW (addr (scr s₀) e) v).readW (addr (scr s₀) d) 32 = m.readW (addr (scr s₀) d) 32 := - fun m v d e h₁ h₂ h => readW_writeW_addr m v (by omega) (by omega) h - intro p hp' - simp only [VG.Impl.Sha512.X86.Stream.saved, List.mem_cons, List.not_mem_nil, or_false] at hp' - rcases hp' with rfl | rfl | rfl | rfl <;> simp only [saveMem] - · rw [w _ _ 224 236 (by omega) (by omega) (by omega), w _ _ 224 232 (by omega) (by omega) (by omega), - w _ _ 224 228 (by omega) (by omega) (by omega), Mem.readW_writeW_self32] - · rw [w _ _ 228 236 (by omega) (by omega) (by omega), w _ _ 228 232 (by omega) (by omega) (by omega), - Mem.readW_writeW_self32] - · rw [w _ _ 232 236 (by omega) (by omega) (by omega), Mem.readW_writeW_self32] - · rw [Mem.readW_writeW_self32] - -/-- Whether the prologue pads two blocks. -/ -def kOf (s₀ : State) : Nat := if cnt s₀ % 128 + 1 < 113 then 0 else 1 - -/-- The prologue's straight-line code. -/ -def proBlock : List Instr := - [.mov .eax (.mem (at_ .esp 20)), .store (at_ .eax 224) .ebx, .store (at_ .eax 228) .esi, - .store (at_ .eax 232) .edi, .store (at_ .eax 236) .ebp, - .mov .ebx (.mem (at_ .esp 4)), .mov .edi (.mem (at_ .esp 8)), .alu .and .edi (.imm 127), - .mov .eax (.reg .ebx), .alu .add .eax (.reg .edi), .mov .ecx (.imm 0x80), - .store8 (at_ .eax 64) .cl, .alu .add .edi (.imm 1), - .mov .esi (.imm 0), .alu .cmp .edi (.imm 113)] - -theorem finalize_eq : finalize = - .seq (.block proBlock) - (.seq (.ite .ae (.block [.mov .esi (.imm 1)]) (.block [])) - (.seq (.loop finalizeBody .e) - (.block (.mov .eax (.mem (at_ .esp 16)) :: (List.range 8).flatMap outW ++ - .mov .eax (.mem (at_ .esp 20)) :: restore)))) := rfl - -theorem prologue_ok {s₀ : State} (hp : Pre s₀) : - WP isa (.seq (.block proBlock) (.ite .ae (.block [.mov .esi (.imm 1)]) (.block []))) s₀ - fun s => ∃ k, k = kOf s₀ ∧ LInv s₀ k (cnt s₀ % 128 + 1) s := by - have hsp := hp.sp_fit; have hsc := hp.scr_fit; have hst := hp.st_fit - have hr : cnt s₀ % 128 < 128 := Nat.mod_lt _ (by omega) - have ain : ∀ e, 4 ≤ e → e + 4 ≤ 24 → ∀ t : State, t.rd = s₀.rd → t.wr = s₀.wr → - InRegions (t.rd ++ t.wr) (addr (esp₀ s₀) e) 4 := - fun e h₁ h₂ t hrd hwr => ⟨argR s₀, by simp [hrd, hp.rd], hp.arg_in h₁ h₂⟩ - have sout : ∀ d, d + 4 ≤ 272 → ∀ t : State, t.wr = s₀.wr → InRegions t.wr (addr (scr s₀) d) 4 := - fun d hd t hwr => ⟨scR s₀, by simp [hwr, hp.wr], hp.scr_in hd⟩ - have ard : ∀ e, 4 ≤ e → e + 4 ≤ 24 → - (saveMem s₀).readW (addr (esp₀ s₀) e) 32 = s₀.mem.readW (addr (esp₀ s₀) e) 32 := - fun e h₁ h₂ => (saveMem_frame hp).readW (Region.contains_self _ _) - (by simpa using hp.a_scr.sub_left (hp.arg_sub h₁ h₂)) (by decide) - refine WP.seq ?_ - unfold proBlock - refine wp_movm (a := addr (esp₀ s₀) 20) (ea_at _ _ _) (ain 20 (by omega) (by omega) s₀ rfl rfl) - fun s₁ u₁ => ?_ - have e₁ : s₁.gpr .eax = scr s₀ := u₁.gpr - refine wp_store (a := addr (scr s₀) 224) (by rw [ea_at, e₁]) (sout 224 (by omega) _ u₁.wr) fun s₂ u₂ => ?_ - refine wp_store (a := addr (scr s₀) 228) (by rw [ea_at, u₂.gpr, e₁]) - (sout 228 (by omega) _ (by rw [u₂.wr, u₁.wr])) fun s₃ u₃ => ?_ - refine wp_store (a := addr (scr s₀) 232) (by rw [ea_at, u₃.gpr, u₂.gpr, e₁]) - (sout 232 (by omega) _ (by rw [u₃.wr, u₂.wr, u₁.wr])) fun s₄ u₄ => ?_ - refine wp_store (a := addr (scr s₀) 236) (by rw [ea_at, u₄.gpr, u₃.gpr, u₂.gpr, e₁]) - (sout 236 (by omega) _ (by rw [u₄.wr, u₃.wr, u₂.wr, u₁.wr])) fun s₅ u₅ => ?_ - have g₅ : s₅.gpr = s₁.gpr := by rw [u₅.gpr, u₄.gpr, u₃.gpr, u₂.gpr] - have rd₅ : s₅.rd = s₀.rd := by rw [u₅.rd, u₄.rd, u₃.rd, u₂.rd, u₁.rd] - have wr₅ : s₅.wr = s₀.wr := by rw [u₅.wr, u₄.wr, u₃.wr, u₂.wr, u₁.wr] - have sp₅ : s₅.gpr .esp = esp₀ s₀ := by rw [g₅, u₁.other _ (by decide)] - have m₅ : s₅.mem = saveMem s₀ := by - rw [u₅.mem, u₄.mem, u₃.mem, u₂.mem, u₄.gpr, u₃.gpr, u₂.gpr, u₁.mem, u₁.other .ebx (by decide), - u₁.other .esi (by decide), u₁.other .edi (by decide), u₁.other .ebp (by decide)] + refine wp_store (a := addr (s.gpr .ebx) 180) (by show addr (s₇.gpr .ebx) 180 = _; rw [g₇ _ (by decide), hb₂]) + (by rw [u₇.wr, u₆.wr, u₅.wr, u₄.wr, u₃.wr, wr₂]; exact ho' 180 (by omega) (by omega)) fun s₈ u₈ => ?_ + have g₈ : ∀ r, r ≠ .edx → s₈.gpr r = s₂.gpr r := fun r h => by rw [u₈.gpr, g₇ r h] + have wr₈ : s₈.wr = s.wr := by rw [u₈.wr, u₇.wr, u₆.wr, u₅.wr, u₄.wr, u₃.wr, wr₂] + refine (len64Of_ok (d := 184) (be := true) (hi := hi) (lo := lo) (by rw [g₈ _ (by decide), hb₂]; omega) + (by rw [g₈ _ (by decide), ha]) (by rw [g₈ _ (by decide), hc]) + (by rw [wr₈, g₈ _ (by decide), hb₂]; exact ho' 184 (by omega) (by omega)) + (by rw [wr₈, g₈ _ (by decide), hb₂]; exact ho' 188 (by omega) (by omega))).mono + fun s' ⟨g', rd', wr', m'⟩ => ⟨fun r h1 h2 h3 => by rw [g' r h1 h2 h3, g₈ r h3, g₂ r h1 h2], + by rw [rd', u₈.rd, u₇.rd, u₆.rd, u₅.rd, u₄.rd, u₃.rd, rd₂], by rw [wr', wr₈], ?_⟩ + have v₃ : s₃.gpr .edx = bswap 0 := by rw [u₃.gpr]; decide + have v₇ : s₇.gpr .edx = bswap (hi >>> 29) := by rw [u₇.gpr, u₆.gpr, u₅.gpr, u₄.gpr, u₃.other _ (by decide), hc] + have w := fun (m : Mem) (a : Addr) (x : BitVec 32) => writeW32 m a true x + simp only [ite_true] at w + have e₀ : addr (s.gpr .ebx) 176 = (s.gpr .ebx).setWidth 64 + BitVec.ofNat 64 176 := addr_eq (by omega) + have e₁ : addr (s.gpr .ebx) 180 = (s.gpr .ebx).setWidth 64 + BitVec.ofNat 64 176 + + BitVec.ofNat 64 (bytes32 true 0).length := by rw [addr_eq (by omega), bytes32_length, add_ofNat] + have e₂ : (s₈.gpr .ebx).setWidth 64 + BitVec.ofNat 64 184 = (s.gpr .ebx).setWidth 64 + BitVec.ofNat 64 176 + + BitVec.ofNat 64 (bytes32 true 0 ++ bytes32 true (hi >>> 29)).length := by + rw [g₈ _ (by decide), hb₂, List.length_append, bytes32_length, bytes32_length, add_ofNat] + rw [m', e₂, u₈.mem, v₇, u₇.mem, u₆.mem, u₅.mem, u₄.mem, v₃, u₃.mem, m₂, w, w, e₀, e₁, + writeBytes_append _ _ _ _ (by simp [bytes32_length]), + writeBytes_append _ _ _ _ (by simp [bytes32_length, bytes64_length]), lenOf_eq] + +theorem digest_eq (mem : Mem) (p : Addr) : + md.digest (md.stateAt mem p) = (List.range 8).flatMap fun k => + bytes32 true (mem.readW (p + BitVec.ofNat 64 (8 * k + 4)) 32) ++ + bytes32 true (mem.readW (p + BitVec.ofNat 64 (8 * k)) 32) := by + have h : md.digest (md.stateAt mem p) = (List.range 8).flatMap fun k => + bytes64 true (mem.readW (p + BitVec.ofNat 64 (8 * k)) 64) := by + simp [md, Spec.Sha512.stateAt, Vector.toList_ofFn, List.range_succ, List.ofFn_succ, bytes64, + Spec.Sha512.wordBytes] + have e : ∀ k, bytes64 true (mem.readW (p + BitVec.ofNat 64 (8 * k)) 64) = + bytes32 true (mem.readW (p + BitVec.ofNat 64 (8 * k + 4)) 32) ++ + bytes32 true (mem.readW (p + BitVec.ofNat 64 (8 * k)) 32) := fun k => by + rw [Proof.Sha512.Word64.readW64, bytes64_halves, ← add_ofNat] rfl - refine wp_movm (a := addr (esp₀ s₀) 4) (by rw [ea_at, sp₅]) (ain 4 (by omega) (by omega) s₅ rd₅ wr₅) - fun s₆ u₆ => ?_ - refine wp_movm (a := addr (esp₀ s₀) 8) (by rw [ea_at, u₆.other _ (by decide), sp₅]) - (ain 8 (by omega) (by omega) s₆ (by rw [u₆.rd, rd₅]) (by rw [u₆.wr, wr₅])) fun s₇ u₇ => - wp_andi fun s₈ u₈ => ?_ - have ebx₈ : s₈.gpr .ebx = st s₀ := by - rw [u₈.other _ (by decide), u₇.other _ (by decide), u₆.gpr, m₅, ard 4 (by omega) (by omega)]; rfl - have edi₈ : s₈.gpr .edi = BitVec.ofNat 32 (cnt s₀ % 128) := by - rw [u₈.gpr, u₇.gpr, u₆.mem, m₅, ard 8 (by omega) (by omega), and127, cnt_mod]; rfl - have m₈ : s₈.mem = saveMem s₀ := by rw [u₈.mem, u₇.mem, u₆.mem, m₅] - have rd₈ : s₈.rd = s₀.rd := by rw [u₈.rd, u₇.rd, u₆.rd, rd₅] - have wr₈ : s₈.wr = s₀.wr := by rw [u₈.wr, u₇.wr, u₆.wr, wr₅] - have sp₈ : s₈.gpr .esp = esp₀ s₀ := by - rw [u₈.other _ (by decide), u₇.other _ (by decide), u₆.other _ (by decide), sp₅] - -- The `0x80` byte. - refine wp_mov fun s₉ u₉ => wp_add fun s₁₀ u₁₀ => wp_movi fun s₁₁ u₁₁ => ?_ - have eax₁₁ : s₁₁.gpr .eax = st s₀ + BitVec.ofNat 32 (cnt s₀ % 128) := by - rw [u₁₁.other _ (by decide), u₁₀.gpr, u₉.gpr, u₉.other _ (by decide), ebx₈, edi₈] - have hq : addr (s₁₁.gpr .eax) 64 = stA s₀ + 64 + BitVec.ofNat 64 (cnt s₀ % 128) := by - rw [eax₁₁, addr_add_ofNat (by omega), st_add, Nat.add_comm] - have hout : InRegions s₁₁.wr (stA s₀ + 64 + BitVec.ofNat 64 (cnt s₀ % 128)) 1 := - ⟨stR s₀, by simp [u₁₁.wr, u₁₀.wr, u₉.wr, wr₈, hp.wr], by - rw [st_add]; exact contains_offset (by omega) (by omega)⟩ - refine wp_store8 (r := .cl) (a := stA s₀ + 64 + BitVec.ofNat 64 (cnt s₀ % 128)) (by rw [ea_at, hq]) hout - fun s₁₂ u₁₂ => wp_addi fun s₁₃ u₁₃ => wp_movi fun s₁₄ u₁₄ => wp_cmpi fun s₁₅ f₁₅ cf₁₅ _ => - WP.block_nil ?_ - have hm₁₂ : s₁₂.mem = writeBytes (saveMem s₀) (stA s₀ + 64 + BitVec.ofNat 64 (cnt s₀ % 128)) [0x80] := by - rw [u₁₂.mem, show Reg8.cl.reg = Reg.ecx from rfl, u₁₁.gpr, u₁₁.mem, u₁₀.mem, u₉.mem, m₈, - ← List.nil_append [(0x80 : Byte)], writeBytes_snoc _ _ _ _ (by simp), writeBytes_nil] - simp - have hm₁₅ : s₁₅.mem = s₁₂.mem := by rw [f₁₅.mem, u₁₄.mem, u₁₃.mem] - have hfb : Frame [stR s₀] (saveMem s₀) s₁₂.mem := by rw [hm₁₂]; exact buf_frame _ (by simp; omega) - have keep : ∀ r, r ≠ .ecx → r ≠ .edi → r ≠ .eax → r ≠ .esi → s₁₅.gpr r = s₈.gpr r := - fun r h1 h2 h3 h4 => by - rw [f₁₅.gpr, u₁₄.other r h4, u₁₃.other r h2, u₁₂.gpr, u₁₁.other r h1, u₁₀.other r h3, u₉.other r h3] - have hC₈ : Common s₀ s₈ := ⟨rd₈, wr₈, ebx₈, sp₈, by rw [m₈]; exact (saveMem_frame hp).mono (by simp), - by rw [m₈]; exact saveMem_saved hp⟩ - obtain ⟨hfr, hsv⟩ := hC₈.writeSt hp (m := s₁₂.mem) (by rw [m₈]; exact hfb) - have hC : Common s₀ s₁₅ := - ⟨by rw [f₁₅.rd, u₁₄.rd, u₁₃.rd, u₁₂.rd, u₁₁.rd, u₁₀.rd, u₉.rd, rd₈], - by rw [f₁₅.wr, u₁₄.wr, u₁₃.wr, u₁₂.wr, u₁₁.wr, u₁₀.wr, u₉.wr, wr₈], - by rw [keep _ (by decide) (by decide) (by decide) (by decide), ebx₈], - by rw [keep _ (by decide) (by decide) (by decide) (by decide), sp₈], - by rw [hm₁₅]; exact hfr, by rw [hm₁₅]; exact hsv⟩ - have edi₁₅ : s₁₅.gpr .edi = BitVec.ofNat 32 (cnt s₀ % 128 + 1) := by - rw [f₁₅.gpr, u₁₄.other _ (by decide), u₁₃.gpr, u₁₂.gpr, u₁₁.other _ (by decide), u₁₀.other _ (by decide), - u₉.other _ (by decide), edi₈, ofNat_succ] - have hcf : s₁₅.cf = some (decide (cnt s₀ % 128 + 1 < 113)) := by - rw [cf₁₅, ← f₁₅.gpr, edi₁₅, toNat_ofNat_lt (by omega)]; rfl - -- The facts about the buffer. - have hst' : stateAt s₁₅.mem (stA s₀) = stateAt s₀.mem (stA s₀) := by - apply stateAt_congr - intro i hi - rw [hm₁₅, hm₁₂, st_add, writeBytes_before _ _ _ (by omega) (by simp; omega)] - exact frame_bytes (saveMem_frame hp) (R := stR s₀) (by simpa using hp.st_scr) (by simp) - (by show i < 192; omega) - have hbytes : ∀ iv m, R₀ s₀ iv m → - bytesAt s₁₅.mem (stA s₀ + 64) (cnt s₀ % 128 + 1) = rest m ++ [0x80] := by - intro iv m hm - have e := bytesAt_writeBytes (saveMem s₀) (stA s₀ + 64) (cnt s₀ % 128) [0x80] (by simp; omega) - simp only [List.length_singleton] at e - rw [hm₁₅, hm₁₂, e] - refine congrArg (· ++ [0x80]) ?_ - rw [hm.length] - refine (bytesAt_congr ?_).trans hm.1.2 - intro i hi - rw [st_add] - exact frame_bytes (saveMem_frame hp) (R := stR s₀) (by simpa using hp.st_scr) (by simp) - (by show 64 + i < 192; have := hm.length; omega) - have hesi : s₁₅.gpr .esi = 0 := by rw [f₁₅.gpr, u₁₄.gpr] - refine WP.ite (!decide (cnt s₀ % 128 + 1 < 113)) (by show s₁₅.cf.map (!·) = _; rw [hcf]; rfl) - (fun hb => ?_) (fun hb => ?_) - · simp only [Bool.not_eq_true', decide_eq_false_iff_not, Nat.not_lt] at hb - refine wp_movi fun s₁₆ u₁₆ => WP.block_nil ⟨1, by simp only [kOf]; split <;> omega, hC.of_gpr (fun r hr => u₁₆.other r (regs2 hr).2.2.2.2) - u₁₆.mem u₁₆.rd u₁₆.wr, (Nat.le_refl _), by omega, by rw [u₁₆.other _ (by decide), edi₁₅], by rw [u₁₆.gpr]; rfl, - fun iv m hm => ?_⟩ - simp only [↓reduceIte] - rw [hash_two (by rw [← hm.length]; omega), Fin1, u₁₆.mem, hbytes iv m hm, hst', hm.1.1, - ← hm.length, show 128 - (cnt s₀ % 128 + 1) = 127 - cnt s₀ % 128 by omega] - · simp only [Bool.not_eq_false', decide_eq_true_eq] at hb - refine WP.block_nil ⟨0, by simp only [kOf]; split <;> omega, hC, by omega, by omega, edi₁₅, by rw [hesi]; rfl, fun iv m hm => ?_⟩ - simp only [show ((0 : Nat) = 1) = False by decide, ite_false] - rw [hash_one (by rw [← hm.length]; omega), Fin0, hbytes iv m hm, hst', hm.1.1, - ← hm.length, show 112 - (cnt s₀ % 128 + 1) = 111 - cnt s₀ % 128 by omega] - -/-! ## Output and epilogue -/ - -/-- `k` words of the digest are written. -/ -structure Out (s₀ sD : State) (k : Nat) (s : State) : Prop where - rd : s.rd = s₀.rd - wr : s.wr = s₀.wr - keep : ∀ r ∈ [Reg.ebx, .esp], s.gpr r = sD.gpr r - eax : s.gpr .eax = out s₀ - mem : s.mem = writeBytes sD.mem (outA s₀) (((stateAt sD.mem (stA s₀)).toList.take k).flatMap wordBytes) - -theorem flat_length (H : HashValue) (k : Nat) (hk : k ≤ 8) : - ((H.toList.take k).flatMap wordBytes).length = 8 * k := by - rw [List.length_flatMap] - have : ∀ w ∈ H.toList.take k, (wordBytes w).length = 8 := fun w _ => by simp [wordBytes] - rw [List.map_congr_left this, List.map_const', List.sum_replicate_nat, List.length_take] - simp; omega - -theorem out_frame (s₀ : State) (m : Mem) (xs : List Byte) (hx : xs.length ≤ 64) : - Frame [outR s₀] m (writeBytes m (outA s₀) xs) := - writeBytes_frame _ _ _ (by - rw [show outA s₀ = outA s₀ + BitVec.ofNat 64 0 by simp] - exact contains_offset (by omega) (by omega)) - -theorem out_step {s₀ : State} (hp : Pre s₀) {sD : State} (hD : Done s₀ sD) {k : Nat} (hk : k < 8) - {s : State} (h : Out s₀ sD k s) {rest : List Instr} {Q : State → Prop} - (hnext : ∀ s', Out s₀ sD (k + 1) s' → WP isa (.block rest) s' Q) : - WP isa (.block (outW k ++ rest)) s Q := by - have hC := hD.1 - have hst := hp.st_fit; have ho := hp.out_fit - have hebx : s.gpr .ebx = st s₀ := by rw [h.keep _ (by simp), hC.ebx] - have hP := flat_length (stateAt sD.mem (stA s₀)) k (Nat.le_of_lt hk) - have hin : ∀ o, o + 4 ≤ 8 → InRegions (s.rd ++ s.wr) (addr (st s₀) (8 * k + o)) 4 := fun o ho' => - ⟨stR s₀, by simp [h.rd, h.wr, hp.wr], contains_addr (by omega) (by omega) hst⟩ - -- The word's halves, unchanged since `Done`. - have hread : ∀ o, o + 4 ≤ 8 → s.mem.readW (addr (st s₀) (8 * k + o)) 32 = - sD.mem.readW (addr (st s₀) (8 * k + o)) 32 := by - intro o ho' - rw [h.mem] - refine (out_frame s₀ sD.mem _ (by omega)).readW (r := ⟨addr (st s₀) (8 * k + o), 4⟩) - (Region.contains_self _ _) ?_ (by decide) - intro r' hr' - simp only [List.mem_cons, List.not_mem_nil, or_false] at hr' - subst hr' - rw [addr_eq (by omega)] - exact hp.st_out.sub_left (sub_offset (by omega) (by omega)) - have hw := stateAt_get (st := st s₀) (by omega) sD.mem hk - have wlo : sD.mem.readW (addr (st s₀) (8 * k + 0)) 32 = lo (stateAt sD.mem (stA s₀))[k] := by - rw [hw, lo_rd64, Nat.add_zero] - have whi : sD.mem.readW (addr (st s₀) (8 * k + 4)) 32 = hi (stateAt sD.mem (stA s₀))[k] := by - rw [hw, hi_rd64] - simp only [outW, List.cons_append, List.nil_append] - refine wp_movm (a := addr (st s₀) (8 * k + 0)) (by rw [ea_at, hebx, Nat.add_zero]) (hin 0 (by omega)) - fun s₁ u₁ => ?_ - refine wp_movm (a := addr (st s₀) (8 * k + 4)) (by rw [ea_at, u₁.other _ (by decide), hebx]) - (by rw [u₁.rd, u₁.wr]; exact hin 4 (by omega)) fun s₂ u₂ => wp_bswap fun s₃ u₃ => wp_bswap fun s₄ u₄ => ?_ - have heax : s₄.gpr .eax = out s₀ := by - rw [u₄.other _ (by decide), u₃.other _ (by decide), u₂.other _ (by decide), u₁.other _ (by decide), h.eax] - have hwo : ∀ o, o + 4 ≤ 8 → ∀ t : State, t.wr = s₀.wr → InRegions t.wr (addr (out s₀) (8 * k + o)) 4 := - fun o ho' t ht => ⟨outR s₀, by simp [ht, hp.wr], contains_addr (by omega) (by omega) ho⟩ - refine wp_store (a := addr (out s₀) (8 * k + 0)) (by rw [ea_at, heax, Nat.add_zero]) - (hwo 0 (by omega) _ (by rw [u₄.wr, u₃.wr, u₂.wr, u₁.wr, h.wr])) fun s₅ u₅ => ?_ - refine wp_store (a := addr (out s₀) (8 * k + 4)) (by rw [ea_at, u₅.gpr, heax]) - (hwo 4 (by omega) _ (by rw [u₅.wr, u₄.wr, u₃.wr, u₂.wr, u₁.wr, h.wr])) fun s₆ u₆ => - hnext s₆ ⟨by rw [u₆.rd, u₅.rd, u₄.rd, u₃.rd, u₂.rd, u₁.rd, h.rd], - by rw [u₆.wr, u₅.wr, u₄.wr, u₃.wr, u₂.wr, u₁.wr, h.wr], fun r hr => ?_, - by rw [u₆.gpr, u₅.gpr, heax], ?_⟩ - · have : r ≠ .ecx ∧ r ≠ .edx := by - simp only [List.mem_cons, List.not_mem_nil, or_false] at hr - rcases hr with rfl | rfl <;> decide - rw [u₆.gpr, u₅.gpr, u₄.other r this.1, u₃.other r this.2, u₂.other r this.2, u₁.other r this.1, - h.keep r hr] - · have v2 : s₄.gpr .edx = bswap (hi (stateAt sD.mem (stA s₀))[k]) := by - rw [u₄.other _ (by decide), u₃.gpr, u₂.gpr, u₁.mem, hread 4 (by omega), whi] - have v1 : s₅.gpr .ecx = bswap (lo (stateAt sD.mem (stA s₀))[k]) := by - rw [u₅.gpr, u₄.gpr, u₃.other _ (by decide), u₂.other _ (by decide), u₁.gpr, hread 0 (by omega), wlo] - have a0 : addr (out s₀) (8 * k + 0) = outA s₀ + - BitVec.ofNat 64 (((stateAt sD.mem (stA s₀)).toList.take k).flatMap wordBytes).length := by - rw [hP, addr_eq (by omega), Nat.add_zero] - have a4 : addr (out s₀) (8 * k + 4) = outA s₀ + - BitVec.ofNat 64 (((stateAt sD.mem (stA s₀)).toList.take k).flatMap wordBytes).length + - BitVec.ofNat 64 (Spec.Sha256.wordBytes (hi (stateAt sD.mem (stA s₀))[k])).length := by - rw [hP, addr_eq (by omega), BitVec.add_assoc, ← BitVec.ofNat_add]; rfl - rw [u₆.mem, v1, u₅.mem, v2, u₄.mem, u₃.mem, u₂.mem, u₁.mem, writeW_bswap, writeW_bswap, a0, a4, - writeBytes_append _ _ _ _ (by simp [Spec.Sha256.wordBytes]), ← wordBytes_split, h.mem, - writeBytes_append _ _ _ _ (by rw [hP]; simp [wordBytes]; omega), List.take_add_one, - List.getElem?_eq_getElem (by simp; omega), Option.toList_some, List.flatMap_append, - List.flatMap_singleton, Vector.getElem_toList] - -/-- The epilogue's postcondition. -/ -def Post (s₀ s' : State) : Prop := abiPreserved s₀ s' ∧ Proof.Sha512.finalizeX86.post s₀ s' - -theorem epilogue_ok {s₀ : State} (hp : Pre s₀) {sD : State} (hD : Done s₀ sD) {s : State} - (h : Out s₀ sD 8 s) : WP isa (.block (.mov .eax (.mem (at_ .esp 20)) :: restore)) s (Post s₀) := by - have hC := hD.1 - have hsc := hp.scr_fit - have hfo := out_frame s₀ sD.mem (((stateAt sD.mem (stA s₀)).toList.take 8).flatMap wordBytes) - (by rw [flat_length _ _ (Nat.le_refl _)]) - have hesp : s.gpr .esp = esp₀ s₀ := by rw [h.keep _ (by simp), hC.esp] - have rin : ∀ d, d + 4 ≤ 272 → InRegions (s.rd ++ s.wr) (addr (scr s₀) d) 4 := - fun d hd => ⟨scR s₀, by simp [h.rd, h.wr, hp.wr], hp.scr_in hd⟩ - have sv : ∀ p ∈ saved, s.mem.readW (addr (scr s₀) p.2) 32 = s₀.gpr p.1 := by - intro p hp' - have hd : 224 ≤ p.2 ∧ p.2 + 4 ≤ 240 := by - simp only [VG.Impl.Sha512.X86.Stream.saved, List.mem_cons, List.not_mem_nil, or_false] at hp' - rcases hp' with rfl | rfl | rfl | rfl <;> simp - rw [h.mem, hfo.readW (r := ⟨addr (scr s₀) p.2, 4⟩) (Region.contains_self _ _) - (by simpa using hp.out_scr.symm.sub_left (hp.scr_sub (by omega))) (by decide)] - exact hC.saved p hp' - refine wp_movm (a := addr (esp₀ s₀) 20) (by rw [ea_at, hesp]) - ⟨argR s₀, by simp [h.rd, hp.rd], hp.arg_in (by omega) (by omega)⟩ fun s₀' u₀ => ?_ - have e₀ : s₀'.gpr .eax = scr s₀ := by - rw [u₀.gpr, h.mem, hfo.readW (r := ⟨addr (esp₀ s₀) 20, 4⟩) (Region.contains_self _ _) - (by simpa using hp.a_out.sub_left (hp.arg_sub (by omega) (by omega))) (by decide), - hC.arg hp (by omega) (by omega)] - rfl - unfold restore - simp only [saved, List.map_cons, List.map_nil] - refine wp_movm (a := addr (scr s₀) 224) (by rw [ea_at, e₀]) - (by rw [u₀.rd, u₀.wr]; exact rin 224 (by omega)) fun s₁ u₁ => ?_ - refine wp_movm (a := addr (scr s₀) 228) (by rw [ea_at, u₁.other _ (by decide), e₀]) - (by rw [u₁.rd, u₁.wr, u₀.rd, u₀.wr]; exact rin 228 (by omega)) fun s₂ u₂ => ?_ - refine wp_movm (a := addr (scr s₀) 232) (by rw [ea_at, u₂.other _ (by decide), u₁.other _ (by decide), e₀]) - (by rw [u₂.rd, u₂.wr, u₁.rd, u₁.wr, u₀.rd, u₀.wr]; exact rin 232 (by omega)) fun s₃ u₃ => ?_ - refine wp_movm (a := addr (scr s₀) 236) - (by rw [ea_at, u₃.other _ (by decide), u₂.other _ (by decide), u₁.other _ (by decide), e₀]) - (by rw [u₃.rd, u₃.wr, u₂.rd, u₂.wr, u₁.rd, u₁.wr, u₀.rd, u₀.wr]; exact rin 236 (by omega)) - fun s₄ u₄ => WP.block_nil ?_ - have hm₄ : s₄.mem = s.mem := by rw [u₄.mem, u₃.mem, u₂.mem, u₁.mem, u₀.mem] - refine ⟨⟨fun r hr => ?_, ?_⟩, fun iv m hm hl hc => ?_⟩ - · simp only [calleeSaved, List.mem_cons, List.not_mem_nil, or_false] at hr - rcases hr with rfl | rfl | rfl | rfl | rfl - · rw [u₄.other _ (by decide), u₃.other _ (by decide), u₂.other _ (by decide), u₁.gpr, u₀.mem] - exact sv (.ebx, 224) (by simp [saved]) - · rw [u₄.other _ (by decide), u₃.other _ (by decide), u₂.gpr, u₁.mem, u₀.mem] - exact sv (.esi, 228) (by simp [saved]) - · rw [u₄.other _ (by decide), u₃.gpr, u₂.mem, u₁.mem, u₀.mem] - exact sv (.edi, 232) (by simp [saved]) - · rw [u₄.gpr, u₃.mem, u₂.mem, u₁.mem, u₀.mem] - exact sv (.ebp, 236) (by simp [saved]) - · rw [u₄.other _ (by decide), u₃.other _ (by decide), u₂.other _ (by decide), u₁.other _ (by decide), - u₀.other _ (by decide), hesp] - · rw [hm₄, h.mem, hfo.readW (r := retR s₀) (Region.contains_self _ _) (by simpa using hp.ret_out) (by decide)] - refine hC.frame.readW (r := retR s₀) (Region.contains_self _ _) ?_ (by decide) - intro r hr - simp only [List.mem_cons, List.not_mem_nil, or_false] at hr - rcases hr with rfl | rfl | rfl - exacts [hp.ret_st, hp.ret_scr, hp.ret_stk] - · have e := bytesAt_writeBytes sD.mem (outA s₀) 0 (((stateAt sD.mem (stA s₀)).toList.take 8).flatMap wordBytes) - (by rw [flat_length _ _ (Nat.le_refl _)]; omega) - have e' : bytesAt (writeBytes sD.mem (outA s₀) (((stateAt sD.mem (stA s₀)).toList.take 8).flatMap wordBytes)) - (outA s₀) 64 = ((stateAt sD.mem (stA s₀)).toList.take 8).flatMap wordBytes := by - rw [flat_length _ _ (Nat.le_refl _), show outA s₀ + BitVec.ofNat 64 0 = outA s₀ by simp, - show bytesAt sD.mem (outA s₀) 0 = [] from rfl, List.nil_append] at e - exact e - rw [← h.mem, ← hm₄] at e' - show bytesAt s₄.mem (outA s₀) 64 = _ - rw [e', hD.2 iv m ⟨hm, hl, hc⟩, List.take_of_length_le (by simp)] - -theorem out_all {s₀ : State} (hp : Pre s₀) {sD : State} (hD : Done s₀ sD) : - ∀ j ≤ 8, ∀ s, Out s₀ sD (8 - j) s → - WP isa (.block (((List.range 8).drop (8 - j)).flatMap outW ++ - .mov .eax (.mem (at_ .esp 20)) :: restore)) s (Post s₀) := by - intro j - induction j with - | zero => - intro _ s h - rw [show (List.range 8).drop (8 - 0) = [] from rfl, List.flatMap_nil, List.nil_append] - exact epilogue_ok hp hD h - | succ j ih => - intro hj s h - rw [List.drop_eq_getElem_cons (by simp; omega), List.flatMap_cons, List.append_assoc, - List.getElem_range] - refine out_step hp hD (by omega) h fun s' h' => ?_ - rw [show 8 - (j + 1) + 1 = 8 - j by omega] - exact ih (by omega) s' (by rwa [show 8 - (j + 1) + 1 = 8 - j by omega] at h') - -theorem correct {s₀ : State} (hp : Pre s₀) : WP isa finalize s₀ (Post s₀) := by - rw [finalize_eq, ← Proof.Sha256.X86.Stream.Finalize.seq_assoc] - refine WP.seq (WP.mono (prologue_ok hp) fun s₁ ⟨k, _, hL⟩ => ?_) - refine WP.seq (WP.mono (Q := Done s₀) ?_ fun sD hD => ?_) - · refine WP.loop (M := isa) (fun i s => ∃ n, LInv s₀ i n s) ?_ k s₁ ⟨_, hL⟩ - rintro i s ⟨n, hL⟩ - refine WP.mono (body_ok hp hL) fun s' h => ?_ - rcases h with ⟨he, -, hD⟩ | ⟨he, rfl, hL'⟩ - · exact .inl ⟨he, hD⟩ - · exact .inr ⟨he, 0, by omega, 0, hL'⟩ - · have hC := hD.1 - refine wp_movm (a := addr (esp₀ s₀) 16) (by rw [ea_at, hC.esp]) (hC.argIn hp (by omega) (by omega)) - fun s₁ u₁ => ?_ - have := out_all hp hD 8 (Nat.le_refl _) s₁ ⟨by rw [u₁.rd, hC.rd], by rw [u₁.wr, hC.wr], - fun r hr => u₁.other r (regs2 hr).1, by rw [u₁.gpr, hC.arg hp (by omega) (by omega)]; rfl, - by simp [u₁.mem, writeBytes_nil]⟩ - rw [show 8 - 8 = 0 from rfl, List.drop_zero] at this - exact this - -/-! ## Constant time -/ - -/-- The initial taint: the stack arguments are public, the words holding -`state`, `out` and `scratch` are the base addresses of the writable regions, -and the 20 bytes below `esp` are outside them. -/ -def τ₀ : VG.X86.Taint.T := - { regs := .ofList [.esp], flags := false, lens := [192, 64, 272], argLen := 24, - argBases := [(4, 0), (16, 1), (20, 2)], room := 20 } - -theorem wf₀ {s : State} (h : Proof.Sha512.finalizeX86.pre s) : VG.X86.Taint.Wf τ₀ s := by - have hp := pre_of h - have hst := hp.st_fit; have ho := hp.out_fit; have hsc := hp.scr_fit; have hs := hp.sp_fit - have hlo := hp.sp_lo - obtain ⟨-, -, -, -, -, -, -, -, -, -, -, k1, k2, k3, -⟩ := h - refine VG.X86.Taint.Wf.entryRoom rfl ⟨fun _ => ⟨by simp [hp.wr, τ₀], ?_, ?_⟩, - fun _ h => (List.not_mem_nil h).elim, fun _ h => (List.not_mem_nil h).elim, - fun _ => ⟨hs, ?_⟩, ?_⟩ fun _ => ⟨hlo, ?_⟩ - · simp only [hp.wr, List.pairwise_cons, List.mem_cons, List.not_mem_nil, or_false, forall_eq_or_imp, - forall_eq, List.Pairwise.nil, and_true] - exact ⟨⟨hp.st_out, hp.st_scr⟩, hp.out_scr, fun _ h => h.elim⟩ - · simp only [hp.wr, List.mem_cons, List.not_mem_nil, or_false] - rintro r (rfl | rfl | rfl) <;> simp only [BitVec.toNat_setWidth] <;> omega - · simp only [hp.wr, List.mem_cons, List.not_mem_nil, or_false] - rintro r (rfl | rfl | rfl) - · exact VG.X86.Taint.frame_disjoint (n := 20) (by omega) hp.ret_st hp.a_st - · exact VG.X86.Taint.frame_disjoint (n := 20) (by omega) hp.ret_out hp.a_out - · exact VG.X86.Taint.frame_disjoint (n := 20) (by omega) hp.ret_scr hp.a_scr - · intro p hp' - simp only [τ₀, List.mem_cons, List.not_mem_nil, or_false] at hp' - rcases hp' with rfl | rfl | rfl <;> refine ⟨by decide, ?_⟩ <;> - simp [VG.X86.Taint.region, hp.wr, addr, arg, argAddr] - · simp only [hp.wr, List.mem_cons, List.not_mem_nil, or_false] - rintro r (rfl | rfl | rfl) - exacts [k1, k2, k3] - -theorem agree₀ {s₁ s₂ : State} (h₁ : Proof.Sha512.finalizeX86.pre s₁) (h₂ : Proof.Sha512.finalizeX86.pre s₂) - (hpub : Proof.Sha512.finalizeX86.pub s₁ s₂) : VG.X86.Taint.Agree τ₀ s₁ s₂ := by - obtain ⟨hesp, ha⟩ := hpub - have hp₁ := pre_of h₁; have hp₂ := pre_of h₂ - refine ⟨⟨fun r hr => ?_, fun h => nomatch h⟩, fun _ => ?_, wf₀ h₁, wf₀ h₂, - fun _ h => (List.not_mem_nil h).elim, fun _ h => (List.not_mem_nil h).elim, fun _ => hesp, - fun k h4 hk => ?_⟩ - · simp only [τ₀, RegSet.mem_ofList, List.mem_singleton] at hr - subst hr; exact hesp - · rw [hp₁.wr, hp₂.wr] - simp only [stR, outR, scR, stA, outA, scA, st, out, scr, ha 0 (by omega), ha 3 (by omega), ha 4 (by omega)] - · simp only [τ₀] at hk - rw [show VG.X86.Taint.depth τ₀.stk = 0 from rfl, Nat.zero_add] - have f₁ : (s₁.gpr .esp).toNat + 24 ≤ 2 ^ 32 := hp₁.sp_fit - have f₂ : (s₂.gpr .esp).toNat + 24 ≤ 2 ^ 32 := hp₂.sp_fit - rw [VG.X86.Taint.argByte_eq f₁ h4 hk, VG.X86.Taint.argByte_eq f₂ h4 hk, - Mem.readW_byte s₁.mem _ (Nat.mod_lt _ (by omega)), Mem.readW_byte s₂.mem _ (Nat.mod_lt _ (by omega))] - exact congrArg _ (ha _ (by omega)) - -/-- Memory holding the arguments `0x1000, 0, 0, 0x2000, 0x3000` at `0x4004`. -/ -def satMem : Mem := fun a => - if a = 0x4005 then 0x10 else if a = 0x4011 then 0x20 else if a = 0x4015 then 0x30 else 0 - -/-- A state satisfying the precondition. -/ -def sat : State where - gpr r := match r with - | .esp => 0x4000 | _ => 0 - cf := none - zf := none - sf := none - of := none - mem := satMem - rd := [⟨0x4004, 20⟩] - wr := [⟨0x1000, 192⟩, ⟨0x2000, 64⟩, ⟨0x3000, 272⟩] - -theorem sat_pre : Proof.Sha512.finalizeX86.pre sat := by - have a0 : arg sat 0 = 0x1000 := by decide - have a3 : arg sat 3 = 0x2000 := by decide - have a4 : arg sat 4 = 0x3000 := by decide - have e : argAddr sat 0 = 0x4004 := by decide - simp only [Proof.Sha512.finalizeX86, a0, a3, a4, e] - refine ⟨rfl, rfl, ?_, ?_, ?_, ?_, ?_, ?_, ?_, ?_, ?_, ?_, ?_, ?_, by decide, by decide, by decide, by decide, - by decide⟩ <;> - exact Region.disjoint_of_sep (by decide) - -/-! ## Constant time, by relating two runs - -The prologue is checked by the taint analysis from the initial taint; in the -loop, the code before the call of the compression function from the -registers that hold our variables, the call by the compression function's -contract (`compressAt_rel`); the epilogue reads the stack arguments again -(`argTaint`). Whether a second block is padded depends only on `count`, so -both runs go through the loop the same number of times, with the same -registers. -/ - -theorem args_out {s₀ : State} (hp : Pre s₀) {s : State} (hC : Common s₀ s) : ArgsOut 5 s := by - have hs := hp.sp_fit - refine ⟨by rw [hC.esp]; omega, ?_⟩ - rw [hC.wr, hp.wr, hC.esp] - simp only [List.mem_cons, List.not_mem_nil, or_false] - rintro r (rfl | rfl | rfl) - · exact VG.X86.Taint.frame_disjoint (n := 20) (by omega) hp.ret_st hp.a_st - · exact VG.X86.Taint.frame_disjoint (n := 20) (by omega) hp.ret_out hp.a_out - · exact VG.X86.Taint.frame_disjoint (n := 20) (by omega) hp.ret_scr hp.a_scr - -theorem args_kept {s₀ : State} (hp : Pre s₀) {s : State} (hC : Common s₀ s) {i : Nat} (hi : i < 5) : arg s i = arg s₀ i := by - rw [arg_eq, arg_eq, hC.esp] - exact hC.arg hp (by omega) (by omega) - -section CT -variable {s₀ s₀' : State} (hp : Pre s₀) (hp' : Pre s₀') (hesp : s₀.gpr .esp = s₀'.gpr .esp) - (ha : ∀ i < 5, arg s₀ i = arg s₀' i) - -include ha in -theorem cnt_eq : cnt s₀ = cnt s₀' := by - simp only [cnt, countX86, ha 1 (by omega), ha 2 (by omega)] - -include hesp ha in -theorem LInv.agree {k n : Nat} {s s' : State} (h : LInv s₀ k n s) (h' : LInv s₀' k n s') : - ∀ r ∈ [Reg.esp, .ebx, .edi, .esi], s.gpr r = s'.gpr r := by - intro r hr - simp only [List.mem_cons, List.not_mem_nil, or_false] at hr - rcases hr with rfl | rfl | rfl | rfl - · rw [h.esp, h'.esp]; exact hesp - · rw [h.ebx, h'.ebx]; exact ha 0 (by omega) - · rw [h.edi, h'.edi] - · rw [h.esi, h'.esi] + rw [h] + exact congrArg (fun f => (List.range 8).flatMap f) (funext e) -include hp hp' hesp ha +theorem shape : Shape (P := params) md where + len s hfit hlo hhi ho := len_ok s hfit hlo hhi ho + out _ hbx hax hin hout hd := by + refine (out64_ok (n := 8) (by decide) hbx hax hin hout hd).mono fun s' ⟨g, rd, wr, m⟩ => + ⟨g, rd, wr, ?_⟩ + rw [m, digest_eq] -theorem body_rel {k n : Nat} : - RelCT isa (fun s₁ s₂ => LInv s₀ k n s₁ ∧ LInv s₀' k n s₂) finalizeBody - fun s₁ s₂ => Step s₀ k s₁ ∧ Step s₀' k s₂ := by - have pre : RelCT isa (fun s₁ s₂ => LInv s₀ k n s₁ ∧ LInv s₀' k n s₂) bodyPre fun s₁ s₂ => - (Common s₀ s₁ ∧ WP isa (.seq (compressAt 20) (.block bodyEnd)) s₁ (Step s₀ k)) ∧ - (Common s₀' s₂ ∧ WP isa (.seq (compressAt 20) (.block bodyEnd)) s₂ (Step s₀' k)) := - ((RelCT.taint (A := taint) (τr [.esp, .ebx, .edi, .esi]) - (fun _ _ h => agree_regs (LInv.agree hesp ha h.1 h.2)) (c := bodyPre) (by taint_decide)).wp - fun _ _ h => ⟨pre_ok hp h.1, pre_ok hp' h.2⟩).mono (fun _ _ h => h) fun _ _ h => h.2 - have e0 : st s₀' = st s₀ := (ha 0 (by omega)).symm - have e4 : scr s₀' = scr s₀ := (ha 4 (by omega)).symm - have cmp : RelCT isa (fun s₁ s₂ => - (Common s₀ s₁ ∧ WP isa (.seq (compressAt 20) (.block bodyEnd)) s₁ (Step s₀ k)) ∧ - (Common s₀' s₂ ∧ WP isa (.seq (compressAt 20) (.block bodyEnd)) s₂ (Step s₀' k))) - (compressAt 20) fun s₁ s₂ => WP isa (.block bodyEnd) s₁ (Step s₀ k) ∧ - WP isa (.block bodyEnd) s₂ (Step s₀' k) := - (((compressAt_rel hp.st_fit hp.scr_fit hp.sp_lo hp.st_scr hp.stk_st hp.stk_scr ⟨_, by taint_decide⟩).mono - (fun _ _ h => ⟨h.1.1.atPre hp, by have := h.2.1.atPre hp'; rwa [e0, e4, esp₀, ← hesp] at this⟩) - fun _ _ h => h).wp fun _ _ h => ⟨WP.seq_iff.mp h.1.2, WP.seq_iff.mp h.2.2⟩).mono - (fun _ _ h => h) fun _ _ h => h.2 - have fin : RelCT isa (fun s₁ s₂ => WP isa (.block bodyEnd) s₁ (Step s₀ k) ∧ - WP isa (.block bodyEnd) s₂ (Step s₀' k)) (.block bodyEnd) - fun s₁ s₂ => Step s₀ k s₁ ∧ Step s₀' k s₂ := - ((RelCT.taint (A := taint) (τr []) (fun _ _ _ => agree_regs (by simp)) (c := .block bodyEnd) - (by taint_decide)).wp fun _ _ h => h).mono (fun _ _ h => h) fun _ _ h => h.2 - exact RelCT.assoc (RelCT.assoc (RelCT.assoc (RelCT.assoc (RelCT.assoc (pre.seq (cmp.seq fin)))))) +namespace Finalize -theorem finalize_rel (h₀ : Proof.Sha512.finalizeX86.pre s₀) (h₀' : Proof.Sha512.finalizeX86.pre s₀') : - RelCT isa (fun s₁ s₂ => s₁ = s₀ ∧ s₂ = s₀') finalize fun _ _ => True := by - have ek : kOf s₀' = kOf s₀ := by simp only [kOf, cnt_eq ha] - have pro : RelCT isa (fun s₁ s₂ => s₁ = s₀ ∧ s₂ = s₀') - (.seq (.block proBlock) (.ite .ae (.block [.mov .esi (.imm 1)]) (.block []))) fun s₁ s₂ => - ∃ n, LInv s₀ (kOf s₀) n s₁ ∧ LInv s₀' (kOf s₀) n s₂ := - ((RelCT.taint (A := taint) τ₀ (fun _ _ ⟨e, e'⟩ => by rw [e, e']; exact agree₀ h₀ h₀' ⟨hesp, ha⟩) - (c := .seq (.block proBlock) (.ite .ae (.block [.mov .esi (.imm 1)]) (.block []))) (by taint_decide)).wp - (F₁ := fun s => ∃ k, k = kOf s₀ ∧ LInv s₀ k (cnt s₀ % 128 + 1) s) - (F₂ := fun s => ∃ k, k = kOf s₀' ∧ LInv s₀' k (cnt s₀' % 128 + 1) s) - fun _ _ ⟨e, e'⟩ => by rw [e, e']; exact ⟨prologue_ok hp, prologue_ok hp'⟩).mono (fun _ _ h => h) - fun _ _ ⟨_, ⟨k, hk, L⟩, ⟨k', hk', L'⟩⟩ => ⟨_, hk ▸ L, by rw [cnt_eq ha, ← ek, ← hk']; exact L'⟩ - have lp := RelCT.loop (M := isa) (body := finalizeBody) (c := .e) - (Q := fun s₁ s₂ => Done s₀ s₁ ∧ Done s₀' s₂) - (fun m s₁ s₂ => ∃ n, LInv s₀ m n s₁ ∧ LInv s₀' m n s₂) (fun m => RelCT.exists_ fun n => - (body_rel hp hp' hesp ha).mono (fun _ _ h => h) fun s₁ s₂ ⟨h₁, h₂⟩ => by - rcases h₁ with ⟨z₁, rfl, D₁⟩ | ⟨z₁, rfl, L₁⟩ <;> - rcases h₂ with ⟨z₂, h0, D₂⟩ | ⟨z₂, h1, L₂⟩ - · exact ⟨z₁.trans z₂.symm, fun _ => ⟨D₁, D₂⟩, fun h => absurd (z₁.symm.trans h) (by simp)⟩ - · cases h1 - · cases h0 - · exact ⟨z₁.trans z₂.symm, fun h => absurd (z₁.symm.trans h) (by simp), - fun _ => ⟨0, by omega, 0, L₁, L₂⟩⟩) (kOf s₀) - have epi : RelCT isa (fun s₁ s₂ => Done s₀ s₁ ∧ Done s₀' s₂) - (.block (.mov .eax (.mem (at_ .esp 16)) :: (List.range 8).flatMap outW ++ - .mov .eax (.mem (at_ .esp 20)) :: restore)) fun _ _ => True := - RelCT.taint (A := taint) (argTaint [.ebx] (4 + 4 * 5)) (fun _ _ h => agree_argTaint - (fun r hr => by - simp only [List.mem_singleton] at hr; subst hr - rw [h.1.1.ebx, h.2.1.ebx]; exact ha 0 (by omega)) - (by rw [h.1.1.esp, h.2.1.esp]; exact hesp) (args_out hp h.1.1) (args_out hp' h.2.1) - fun i hi => by rw [args_kept hp h.1.1 hi, args_kept hp' h.2.1 hi]; exact ha i hi) (by taint_decide) - rw [finalize_eq] - exact RelCT.assoc (pro.seq (lp.seq epi)) +theorem finalize_verified : Verified X86.target Impl.Sha512.X86.Stream.finalize Proof.Sha512.finalizeX86 := + MdStream.X86.Finalize.verified_ro (name := "vg_sha512_compress") dims shape callee + (VG.Taint.constantTime (A := taint) (MdStream.X86.Finalize.τ₀ params 272) + (fun _ _ h₁ h₂ hp => MdStream.X86.Finalize.agree₀ dims h₁ h₂ hp) (by taint_decide)) -end CT +/-- A state satisfying `finalize`'s precondition. -/ +abbrev sat : State := MdStream.X86.Finalize.satR params 272 -theorem finalize_verified : Verified X86.target finalize Proof.Sha512.finalizeX86 := by - refine ⟨fun s hs => ?_, ?_, ⟨sat, sat_pre⟩⟩ - · obtain ⟨t, s', he, h⟩ := correct (pre_of hs) - exact ⟨t, s', he, h⟩ - · intro s₁ s₂ t₁ t₂ s₁' s₂' h₁ h₂ hpub e₁ e₂ - exact (finalize_rel (pre_of h₁) (pre_of h₂) hpub.1 hpub.2 h₁ h₂ _ _ _ _ _ _ ⟨rfl, rfl⟩ e₁ e₂).1 +end Finalize -end VG.Proof.Sha512.X86.Stream.Finalize +end VG.Proof.Sha512.X86.Stream diff --git a/lean/VerifiedGarbage/Proof/Sha512/X86/Stream/Update.lean b/lean/VerifiedGarbage/Proof/Sha512/X86/Stream/Update.lean index 01feee9b9..09f51c89e 100644 --- a/lean/VerifiedGarbage/Proof/Sha512/X86/Stream/Update.lean +++ b/lean/VerifiedGarbage/Proof/Sha512/X86/Stream/Update.lean @@ -1,1038 +1,43 @@ -import VerifiedGarbage.Proof.Sha512.X86.Stream.Common +import VerifiedGarbage.Proof.Sha512.Md +import VerifiedGarbage.Proof.MdStream.X86.Finalize import VerifiedGarbage.Proof.Framework.Contract -import VerifiedGarbage.Proof.Framework.RelCTAssoc -import VerifiedGarbage.Proof.Framework.X86.ArgTaint +import VerifiedGarbage.Proof.Sha512.X86.Compress +import VerifiedGarbage.Impl.Sha512.X86.Stream +import VerifiedGarbage.Proof.Sha512.X86.Lit /-! # Streaming SHA-512 on x86 (32-bit): `update` -The structure of the ARMv7 proof (`VG.Proof.Sha512.Arm.Stream.Update`), with -`state` in `ebx`, `data` in `esi`, the bytes left in `ebp` and the buffered -bytes in `edi`; every block goes through the buffer, which is compressed as -soon as it is full, by calling the compression function (`compressAt_ok`) with -the 20 bytes below `esp` for its frame. +`update` and `finalize` are the generic streaming code +(`Impl/MdStream/X86.lean`), so they are verified by the generic proofs +(`Proof/MdStream/X86/`) for the SHA-512 family's instance +(`Proof/Sha512/Md.lean`) with 272 bytes of scratch space, given that its +compression function is verified (`callee`) and that the taint analysis +accepts its code (which it checks together with the compression function's). +`Finalize.lean` adds what the family's length field and digest do. -/ -namespace VG.Proof.Sha512.X86.Stream.Update +namespace VG.Proof.Sha512.X86.Stream -open VG VG.X86 VG.Impl.Sha512.X86.Stream -open VG.Impl.Sha512.X86 (at_) -open VG.Proof.Sha256.X86 (contains_offset) -open VG.Proof.Sha256.X86.Stream (Upd Mupd Fupd wp_mov wp_movi wp_movm wp_movzx8 wp_store wp_store8 wp_add - wp_addi wp_sub wp_subi wp_andi wp_cmp wp_cmpi wp_test contains_addr sub_offset frame_bytes addr_add_ofNat - readW_writeW_addr ofNat_beq_zero sub_ofNat sub_beq ofNat_succ ofNat_pred toNat_ofNat_lt bytesAt_getD - addr_toNat) -open VG.Proof.Sha512.Stream -open VG.Spec.Sha512 (HashValue stateAt blockAt compress parseBlock bytesAt) -open VG.Proof.Sha512 (countX86) +open VG VG.X86 VG.Proof.MdStream VG.Proof.MdStream.X86 -/-! ## The precondition -/ +abbrev params := Impl.Sha512.X86.Stream.params -section -variable (s₀ : State) +theorem dims : Dims params 272 := ⟨.inr rfl, by decide, by decide, by decide, by decide⟩ -abbrev esp₀ : BitVec 32 := s₀.gpr .esp -abbrev st : BitVec 32 := arg s₀ 0 -abbrev cnt : Nat := (countX86 s₀).toNat -abbrev dp : BitVec 32 := arg s₀ 3 -abbrev len : Nat := (arg s₀ 4).toNat -abbrev scr : BitVec 32 := arg s₀ 5 -abbrev stA : Addr := (st s₀).setWidth 64 -abbrev dA : Addr := (dp s₀).setWidth 64 -abbrev scA : Addr := (scr s₀).setWidth 64 -abbrev stR : Region := ⟨stA s₀, 192⟩ -abbrev dR : Region := ⟨dA s₀, len s₀⟩ -abbrev scR : Region := ⟨scA s₀, 272⟩ -abbrev argR : Region := ⟨argAddr s₀ 0, 24⟩ -abbrev retR : Region := ⟨(esp₀ s₀).setWidth 64, 4⟩ -abbrev stkR : Region := below (esp₀ s₀) 20 -/-- The data. -/ -abbrev D : List Byte := bytesAt s₀.mem (dA s₀) (len s₀) +theorem callee : CalleeOk (P := params) md Impl.Sha512.X86.compress := + ⟨Compress.compress_verified.1, NoSp.of_all (by lit_decide), by lit_decide⟩ -/-- The messages the initial state represents, from the initial hash value `iv`. -/ -def R₀ (iv : HashValue) (m : List Byte) : Prop := - Spec.Sha512.Repr iv s₀.mem (stA s₀) m ∧ countX86 s₀ = BitVec.ofNat 64 m.length +namespace Update -/-- Our caller's registers are saved in the scratch space. -/ -def Saved (m : Mem) : Prop := ∀ p ∈ saved, m.readW (addr (scr s₀) p.2) 32 = s₀.gpr p.1 +theorem update_verified : Verified X86.target Impl.Sha512.X86.Stream.update Proof.Sha512.updateX86 := + MdStream.X86.Update.verified (name := "vg_sha512_compress") dims callee + (VG.Taint.constantTime (A := taint) (MdStream.X86.Update.τ₀ params 272) + (fun _ _ h₁ h₂ hp => MdStream.X86.Update.agree₀ dims h₁ h₂ hp) (by taint_decide)) -end +/-- A state satisfying `update`'s precondition. -/ +abbrev sat : State := MdStream.X86.Update.sat params 272 -structure Pre (s₀ : State) : Prop where - rd : s₀.rd = [dR s₀, argR s₀] - wr : s₀.wr = [stR s₀, scR s₀] - st_scr : (stR s₀).Disjoint (scR s₀) - d_st : (dR s₀).Disjoint (stR s₀) - d_scr : (dR s₀).Disjoint (scR s₀) - a_st : (argR s₀).Disjoint (stR s₀) - a_scr : (argR s₀).Disjoint (scR s₀) - ret_st : (retR s₀).Disjoint (stR s₀) - ret_scr : (retR s₀).Disjoint (scR s₀) - stk_st : (stkR s₀).Disjoint (stR s₀) - stk_scr : (stkR s₀).Disjoint (scR s₀) - stk_d : (stkR s₀).Disjoint (dR s₀) - st_fit : (st s₀).toNat + 192 ≤ 2 ^ 32 - d_fit : (dp s₀).toNat + len s₀ ≤ 2 ^ 32 - scr_fit : (scr s₀).toNat + 272 ≤ 2 ^ 32 - sp_lo : 20 ≤ (esp₀ s₀).toNat - sp_fit : (esp₀ s₀).toNat + 28 ≤ 2 ^ 32 +end Update -theorem pre_of {s₀ : State} (h : Proof.Sha512.updateX86.pre s₀) : Pre s₀ := by - obtain ⟨h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11, h12, h13, h14, h15, h16, h17⟩ := h - have e := stk_eq h16 - exact ⟨h1, h2, h3, h4, h5, h6, h7, h8, h9, by show (below _ _).Disjoint _; rw [e]; exact h10, - by show (below _ _).Disjoint _; rw [e]; exact h11, by show (below _ _).Disjoint _; rw [e]; exact h12, - h13, h14, h15, h16, h17⟩ - -theorem cnt_mod (s₀ : State) : cnt s₀ % 128 = (arg s₀ 1).toNat % 128 := by - simp only [cnt, countX86] - rw [BitVec.toNat_append, ← Nat.shiftLeft_add_eq_or_of_lt (arg s₀ 1).isLt, Nat.shiftLeft_eq] - omega - -theorem R₀.length {s₀ : State} {iv : HashValue} {m : List Byte} (h : R₀ s₀ iv m) : - cnt s₀ % 128 = m.length % 128 := by - rw [cnt, h.2, BitVec.toNat_ofNat] - omega - -theorem len_lt (s₀ : State) : len s₀ < 2 ^ 32 := (arg s₀ 4).isLt - -theorem D_length (s₀ : State) : (D s₀).length = len s₀ := by simp [bytesAt] - -namespace Pre -variable {s₀ : State} (hp : Pre s₀) -include hp - -theorem scr_in {d : Nat} (hd : d + 4 ≤ 272) : (scR s₀).Contains (addr (scr s₀) d) 4 := - contains_addr hd (by omega) hp.scr_fit - -theorem scr_sub {d : Nat} (hd : d + 4 ≤ 272) : Region.Sub ⟨addr (scr s₀) d, 4⟩ (scR s₀) := by - rw [addr_eq (by have := hp.scr_fit; omega)] - exact sub_offset hd (by omega) - -theorem arg_sub {d : Nat} (hd₁ : 4 ≤ d) (hd : d + 4 ≤ 28) : Region.Sub ⟨addr (esp₀ s₀) d, 4⟩ (argR s₀) := by - have := hp.sp_fit - show Region.Sub _ ⟨addr (esp₀ s₀) 4, 24⟩ - rw [addr_eq (by omega), addr_eq (by omega)] - exact Offset.sub _ hd₁ (by omega) - -theorem arg_in {d : Nat} (hd₁ : 4 ≤ d) (hd : d + 4 ≤ 28) : (argR s₀).Contains (addr (esp₀ s₀) d) 4 := by - have := hp.sp_fit - show (⟨addr (esp₀ s₀) 4, 24⟩ : Region).Contains _ _ - rw [addr_eq (by omega), addr_eq (by omega)] - exact Offset.contains _ hd₁ (by omega) (by omega) - -theorem a_stk : (argR s₀).Disjoint (stkR s₀) := by - have := hp.sp_fit; have := hp.sp_lo - show Region.Disjoint ⟨addr (esp₀ s₀) 4, 24⟩ (below (esp₀ s₀) 20) - rw [stk_eq hp.sp_lo, addr_eq (by omega)] - exact (Offset.disjoint_below_above (m := 20) (a := 4) _ (by omega)).symm - -theorem ret_stk : (retR s₀).Disjoint (stkR s₀) := by - have := hp.sp_fit; have := hp.sp_lo - show Region.Disjoint ⟨(esp₀ s₀).setWidth 64, 4⟩ (below (esp₀ s₀) 20) - rw [stk_eq hp.sp_lo] - have h := Offset.disjoint_below_above ((esp₀ s₀).setWidth 64) (m := 20) (a := 0) (l := 4) (by omega) - rw [show (esp₀ s₀).setWidth 64 + BitVec.ofNat 64 0 = (esp₀ s₀).setWidth 64 from BitVec.add_zero _] at h - exact h.symm - -/-- The words of the scratch space from 224 on (the saved registers) are -outside the regions the compression function writes. -/ -theorem saved_sep {d : Nat} (hd₁ : 224 ≤ d) (hd : d + 4 ≤ 272) : - ∀ r ∈ [(⟨stA s₀, 64⟩ : Region), ⟨scA s₀, 224⟩, stkR s₀], Region.Disjoint ⟨addr (scr s₀) d, 4⟩ r := by - have := hp.scr_fit - intro r hr - simp only [List.mem_cons, List.not_mem_nil, or_false] at hr - rcases hr with rfl | rfl | rfl - · exact (hp.st_scr.symm.sub_left (hp.scr_sub hd)).sub_right (Region.sub_prefix (by omega)) - · rw [addr_eq (by omega)] - exact Offset.disjoint_base _ hd₁ (by omega) - · exact (hp.stk_scr.symm.sub_left (hp.scr_sub hd)) - -end Pre - -/-! ## Invariants -/ - -/-- What holds throughout, after consuming `c` bytes of data. -/ -structure Common (s₀ : State) (c : Nat) (s : State) : Prop where - c_le : c ≤ len s₀ - rd : s.rd = s₀.rd - wr : s.wr = s₀.wr - ebx : s.gpr .ebx = st s₀ - esp : s.gpr .esp = esp₀ s₀ - esi : s.gpr .esi = dp s₀ + BitVec.ofNat 32 c - ebp : s.gpr .ebp = BitVec.ofNat 32 (len s₀ - c) - frame : Frame [stR s₀, scR s₀, stkR s₀] s₀.mem s.mem - saved : Saved s₀ s.mem - -/-- The loop invariant: the state represents the message followed by the -first `c` bytes of data. -/ -structure Inv (s₀ : State) (c : Nat) (s : State) : Prop extends Common s₀ c s where - edi : s.gpr .edi = BitVec.ofNat 32 ((cnt s₀ + c) % 128) - repr : ∀ iv m, R₀ s₀ iv m → Spec.Sha512.Repr iv s.mem (stA s₀) (m ++ (D s₀).take c) - -theorem Common.of_gpr {s₀ : State} {c : Nat} {s s' : State} (h : Common s₀ c s) - (hg : ∀ r ∈ [Reg.ebx, .esp, .esi, .ebp], s'.gpr r = s.gpr r) - (hm : s'.mem = s.mem) (hrd : s'.rd = s.rd) (hwr : s'.wr = s.wr) : Common s₀ c s' where - c_le := h.c_le - rd := hrd.trans h.rd - wr := hwr.trans h.wr - ebx := by rw [hg _ (by simp)]; exact h.ebx - esp := by rw [hg _ (by simp)]; exact h.esp - esi := by rw [hg _ (by simp)]; exact h.esi - ebp := by rw [hg _ (by simp)]; exact h.ebp - frame := by rw [hm]; exact h.frame - saved := by rw [hm]; exact h.saved - -theorem Inv.of_gpr {s₀ : State} {c : Nat} {s s' : State} (h : Inv s₀ c s) - (hg : ∀ r ∈ [Reg.ebx, .esp, .esi, .ebp, .edi], s'.gpr r = s.gpr r) - (hm : s'.mem = s.mem) (hrd : s'.rd = s.rd) (hwr : s'.wr = s.wr) : Inv s₀ c s' := - { h.toCommon.of_gpr (fun r hr => hg r (List.mem_append_left [Reg.edi] hr)) hm hrd hwr with - edi := by rw [hg _ (by simp)]; exact h.edi - repr := by rw [hm]; exact h.repr } - -theorem Inv.of_upd {s₀ : State} {c : Nat} {s s' : State} (h : Inv s₀ c s) {d : Reg} {v : BitVec 32} - (u : Upd s s' d v) (hd : d ∉ [Reg.ebx, .esp, .esi, .ebp, .edi]) : Inv s₀ c s' := - h.of_gpr (fun r hr => u.other r fun e => hd (e ▸ hr)) u.mem u.rd u.wr - -theorem Inv.of_flags {s₀ : State} {c : Nat} {s s' : State} (h : Inv s₀ c s) (u : Fupd s s') : Inv s₀ c s' := - h.of_gpr (fun r _ => by rw [u.gpr]) u.mem u.rd u.wr - -/-- The argument words are never written. -/ -theorem Common.arg {s₀ : State} (hp : Pre s₀) {c : Nat} {s : State} (h : Common s₀ c s) {d : Nat} - (h₁ : 4 ≤ d) (h₂ : d + 4 ≤ 28) : - s.mem.readW (addr (esp₀ s₀) d) 32 = s₀.mem.readW (addr (esp₀ s₀) d) 32 := by - refine h.frame.readW (r := ⟨addr (esp₀ s₀) d, 4⟩) (Region.contains_self _ _) ?_ (by decide) - intro r hr - simp only [List.mem_cons, List.not_mem_nil, or_false] at hr - rcases hr with rfl | rfl | rfl - · exact hp.a_st.sub_left (hp.arg_sub h₁ h₂) - · exact hp.a_scr.sub_left (hp.arg_sub h₁ h₂) - · exact hp.a_stk.sub_left (hp.arg_sub h₁ h₂) - -/-! ## Consuming data -/ - -theorem D_getD (s₀ : State) {i : Nat} (hi : i < len s₀) : - (D s₀).getD i 0 = s₀.mem (dA s₀ + BitVec.ofNat 64 i) := by - simp [bytesAt, List.getD_eq_getElem?_getD, hi] - -/-- The data is unchanged. -/ -theorem Common.data {s₀ : State} (hp : Pre s₀) {c : Nat} {s : State} (h : Common s₀ c s) {i : Nat} - (hi : i < len s₀) : s.mem (dA s₀ + BitVec.ofNat 64 i) = (D s₀).getD i 0 := by - rw [D_getD s₀ hi] - exact frame_bytes h.frame (R := dR s₀) (by simpa using ⟨hp.d_st, hp.d_scr, hp.stk_d.symm⟩) - (by have := len_lt s₀; show len s₀ ≤ 2 ^ 64; omega) hi - -theorem length_mid (s₀ : State) {iv : HashValue} {m : List Byte} (hm : R₀ s₀ iv m) {c : Nat} - (hc : c ≤ len s₀) : (m ++ (D s₀).take c).length % 128 = (cnt s₀ + c) % 128 := by - have := hm.length - simp only [List.length_append, List.length_take, D_length, Nat.min_eq_left hc] - omega - -theorem take_add_data (s₀ : State) (c t : Nat) (m : List Byte) : - m ++ (D s₀).take c ++ ((D s₀).drop c).take t = m ++ (D s₀).take (c + t) := by - rw [List.take_add, List.append_assoc] - -/-! ## Buffering data -/ - -section -variable (s₀ : State) (c : Nat) -/-- Bytes in the buffer before this iteration. -/ -abbrev rr : Nat := (cnt s₀ + c) % 128 -/-- Bytes copied into the buffer in this iteration. -/ -abbrev tt : Nat := min (128 - rr s₀ c) (len s₀ - c) -/-- Where they go. -/ -abbrev q : Addr := stA s₀ + 64 + BitVec.ofNat 64 (rr s₀ c) -/-- The data copied. -/ -abbrev xs : List Byte := ((D s₀).drop c).take (tt s₀ c) -end - -theorem rr_lt (s₀ : State) (c : Nat) : rr s₀ c < 128 := Nat.mod_lt _ (by omega) -theorem tt_le (s₀ : State) (c : Nat) : tt s₀ c ≤ len s₀ - c := Nat.min_le_right _ _ -theorem tt_le' (s₀ : State) (c : Nat) : tt s₀ c ≤ 128 - rr s₀ c := Nat.min_le_left _ _ -theorem rr_eq (s₀ : State) (c : Nat) : rr s₀ c = (cnt s₀ + c) % 128 := rfl -theorem tt_eq (s₀ : State) (c : Nat) : tt s₀ c = min (128 - rr s₀ c) (len s₀ - c) := rfl - -theorem q_eq (s₀ : State) (c : Nat) : q s₀ c = stA s₀ + BitVec.ofNat 64 (64 + rr s₀ c) := by - simp only [q, BitVec.ofNat_add]; rw [BitVec.add_assoc]; rfl - -theorem xs_length (s₀ : State) (c : Nat) : (xs s₀ c).length = tt s₀ c := by - have := tt_le s₀ c - simp only [xs, List.length_take, List.length_drop, D_length]; omega - -/-- The state while copying: `j` bytes copied, into memory otherwise as in `mI`. -/ -structure Copy (s₀ : State) (c : Nat) (mI : Mem) (j : Nat) (s : State) : Prop where - j_le : j ≤ tt s₀ c - rd : s.rd = s₀.rd - wr : s.wr = s₀.wr - ebx : s.gpr .ebx = st s₀ - esp : s.gpr .esp = esp₀ s₀ - esi : s.gpr .esi = dp s₀ + BitVec.ofNat 32 (c + j) - ebp : s.gpr .ebp = BitVec.ofNat 32 (len s₀ - c - tt s₀ c) - edi : s.gpr .edi = BitVec.ofNat 32 (rr s₀ c + j) - ecx : s.gpr .ecx = BitVec.ofNat 32 (tt s₀ c - j) - mem : s.mem = writeBytes mI (q s₀ c) ((xs s₀ c).take j) - -theorem write_frame (s₀ : State) (c : Nat) (mI : Mem) (j : Nat) (hj : j ≤ tt s₀ c) : - Frame [stR s₀] mI (writeBytes mI (q s₀ c) ((xs s₀ c).take j)) := by - have := tt_le' s₀ c; have := rr_lt s₀ c - refine writeBytes_frame _ _ _ ?_ - rw [q_eq] - exact contains_offset (by simp only [List.length_take]; omega) (by omega) - -/-- The copy loop's body. -/ -def copyBody : List Instr := - [.movzx8 .edx (at_ .esi 0), .mov .eax (.reg .ebx), .alu .add .eax (.reg .edi), - .store8 (at_ .eax 64) .dl, .alu .add .esi (.imm 1), .alu .add .edi (.imm 1), - .alu .sub .ecx (.imm 1)] - -theorem copy_step {s₀ : State} (hp : Pre s₀) {c : Nat} {sI : State} (hI : Inv s₀ c sI) {j : Nat} - (hj : j < tt s₀ c) {s : State} (h : Copy s₀ c sI.mem j s) : - WP isa (.block copyBody) s fun s' => - Copy s₀ c sI.mem (j + 1) s' ∧ s'.zf = some (BitVec.ofNat 32 (tt s₀ c - (j + 1)) == 0) := by - have hlen := len_lt s₀; have hd := hp.d_fit; have hst := hp.st_fit - have hc := hI.c_le - have hr := rr_lt s₀ c - have ht := tt_le s₀ c; have ht' := tt_le' s₀ c - -- The byte read. - have hin : InRegions (s.rd ++ s.wr) (dA s₀ + BitVec.ofNat 64 (c + j)) 1 := - ⟨dR s₀, by simp [h.rd, hp.rd], contains_offset (by omega) (by omega)⟩ - have hbyte : s.mem (dA s₀ + BitVec.ofNat 64 (c + j)) = (D s₀).getD (c + j) 0 := by - rw [h.mem, ← hI.data hp (by omega)] - exact frame_bytes (write_frame s₀ c sI.mem j h.j_le) (R := dR s₀) (by simpa using hp.d_st) - (by show len s₀ ≤ 2 ^ 64; omega) (by show c + j < len s₀; omega) - -- The byte written. - have hq : q s₀ c + BitVec.ofNat 64 j = stA s₀ + BitVec.ofNat 64 (rr s₀ c + j + 64) := by - rw [q_eq, BitVec.add_assoc, ← BitVec.ofNat_add]; congr 2; omega - have hout : InRegions s.wr (q s₀ c + BitVec.ofNat 64 j) 1 := - ⟨stR s₀, by simp [h.wr, hp.wr], by rw [hq]; exact contains_offset (by omega) (by omega)⟩ - have hxs := xs_length s₀ c - unfold copyBody - refine wp_movzx8 (a := dA s₀ + BitVec.ofNat 64 (c + j)) - (by rw [ea_at, h.esi, addr_add_ofNat (by omega), Nat.add_zero]) hin fun s₁ u₁ => ?_ - refine wp_mov fun s₂ u₂ => wp_add fun s₃ u₃ => ?_ - refine wp_store8 (r := .dl) (a := q s₀ c + BitVec.ofNat 64 j) ?_ - (by rw [u₃.wr, u₂.wr, u₁.wr]; exact hout) fun s₄ u₄ => ?_ - · rw [ea_at, u₃.gpr, u₂.gpr, u₂.other _ (by decide), u₁.other _ (by decide), u₁.other _ (by decide), h.ebx, - h.edi, hq, addr_add_ofNat (by omega)] - refine wp_addi fun s₅ u₅ => wp_addi fun s₆ u₆ => wp_subi fun s₇ u₇ z₇ => WP.block_nil ?_ - have g : ∀ r, r ≠ .edx → r ≠ .eax → r ≠ .esi → r ≠ .edi → r ≠ .ecx → s₇.gpr r = s.gpr r := - fun r h1 h2 h3 h4 h5 => by - rw [u₇.other r h5, u₆.other r h4, u₅.other r h3, u₄.gpr, u₃.other r h2, u₂.other r h2, u₁.other r h1] - have h8 : s₇.gpr .ecx = BitVec.ofNat 32 (tt s₀ c - (j + 1)) := by - rw [u₇.gpr, u₆.other _ (by decide), u₅.other _ (by decide), u₄.gpr, u₃.other _ (by decide), - u₂.other _ (by decide), u₁.other _ (by decide), h.ecx, ofNat_pred (by omega), Nat.sub_sub] - refine ⟨⟨by omega, ?_, ?_, ?_, ?_, ?_, ?_, ?_, h8, ?_⟩, ?_⟩ - · rw [u₇.rd, u₆.rd, u₅.rd, u₄.rd, u₃.rd, u₂.rd, u₁.rd, h.rd] - · rw [u₇.wr, u₆.wr, u₅.wr, u₄.wr, u₃.wr, u₂.wr, u₁.wr, h.wr] - · rw [g .ebx (by decide) (by decide) (by decide) (by decide) (by decide), h.ebx] - · rw [g .esp (by decide) (by decide) (by decide) (by decide) (by decide), h.esp] - · rw [u₇.other _ (by decide), u₆.other _ (by decide), u₅.gpr, u₄.gpr, u₃.other _ (by decide), - u₂.other _ (by decide), u₁.other _ (by decide), h.esi, BitVec.add_assoc, - show (1 : BitVec 32) = BitVec.ofNat 32 1 from rfl, ← BitVec.ofNat_add, Nat.add_assoc] - · rw [g .ebp (by decide) (by decide) (by decide) (by decide) (by decide), h.ebp] - · rw [u₇.other _ (by decide), u₆.gpr, u₅.other _ (by decide), u₄.gpr, u₃.other _ (by decide), - u₂.other _ (by decide), u₁.other _ (by decide), h.edi, ← ofNat_succ, Nat.add_assoc] - · have hj' : j < (xs s₀ c).length := by omega - rw [u₇.mem, u₆.mem, u₅.mem, u₄.mem, u₃.mem, u₂.mem, u₁.mem, show Reg8.dl.reg = Reg.edx from rfl, - u₃.other _ (by decide), u₂.other _ (by decide), u₁.gpr, hbyte, h.mem, - List.take_add_one, List.getElem?_eq_getElem hj', Option.toList_some, - writeBytes_snoc _ _ _ _ (by simp only [List.length_take]; omega)] - have hl : (List.take j (xs s₀ c)).length = j := by rw [List.length_take, Nat.min_eq_left (Nat.le_of_lt hj')] - rw [hl] - have e : ((List.getD (D s₀) (c + j) 0).setWidth 32).setWidth 8 = List.getD (D s₀) (c + j) 0 := by - ext i hi; simp - rw [e] - congr 1 - simp only [xs, List.getElem_take, List.getElem_drop, List.getD_eq_getElem?_getD, - List.getElem?_eq_getElem (show c + j < (D s₀).length by rw [D_length]; omega), Option.getD_some] - · rw [z₇, ← u₇.gpr, h8] - -theorem copy_loop_ok {s₀ : State} (hp : Pre s₀) {c : Nat} {sI : State} (hI : Inv s₀ c sI) {s : State} - (h : Copy s₀ c sI.mem 0 s) (ht : 0 < tt s₀ c) : - WP isa (.loop (.block copyBody) .ne) s (Copy s₀ c sI.mem (tt s₀ c)) := by - refine WP.loop (M := isa) (fun n s => ∃ j, n = tt s₀ c - j ∧ j < tt s₀ c ∧ Copy s₀ c sI.mem j s) - ?_ (tt s₀ c) s ⟨0, rfl, ht, h⟩ - rintro n s ⟨j, rfl, hj, hc⟩ - refine WP.mono (copy_step hp hI hj hc) fun s' ⟨hc', hz'⟩ => ?_ - have hz : isa.eval .ne s' = some (decide (tt s₀ c - (j + 1) ≠ 0)) := by - show s'.zf.map (!·) = _ - rw [hz', ofNat_beq_zero (by have := tt_le' s₀ c; omega)] - simp - by_cases hl : tt s₀ c - (j + 1) = 0 - · refine .inl ⟨by rw [hz, decide_eq_false fun h => h hl], ?_⟩ - rwa [show j + 1 = tt s₀ c by omega] at hc' - · exact .inr ⟨by rw [hz, decide_eq_true hl], _, by omega, j + 1, rfl, by omega, hc'⟩ - -/-- The memory after copying `tt` bytes. -/ -theorem copied_facts {s₀ : State} (hp : Pre s₀) {c : Nat} {sI : State} (hI : Inv s₀ c sI) : - let mem := writeBytes sI.mem (q s₀ c) (xs s₀ c) - Frame [stR s₀, scR s₀, stkR s₀] s₀.mem mem ∧ Saved s₀ mem ∧ - stateAt mem (stA s₀) = stateAt sI.mem (stA s₀) ∧ - bytesAt mem (stA s₀ + 64) (rr s₀ c + tt s₀ c) = bytesAt sI.mem (stA s₀ + 64) (rr s₀ c) ++ xs s₀ c := by - intro mem - have hr := rr_lt s₀ c; have ht' := tt_le' s₀ c - have hxs := xs_length s₀ c - have hf : Frame [stR s₀] sI.mem mem := by - have := write_frame s₀ c sI.mem (tt s₀ c) (Nat.le_refl _) - rwa [List.take_of_length_le (by omega)] at this - refine ⟨hI.frame.trans (hf.mono (by simp)), fun p hp' => ?_, ?_, ?_⟩ - · have hd : 224 ≤ p.2 ∧ p.2 + 4 ≤ 240 := by - simp only [VG.Impl.Sha512.X86.Stream.saved, List.mem_cons, List.not_mem_nil, or_false] at hp' - rcases hp' with rfl | rfl | rfl | rfl <;> simp - rw [← hI.saved p hp'] - refine hf.readW (r := ⟨addr (scr s₀) p.2, 4⟩) (Region.contains_self _ _) ?_ (by decide) - intro r' hr' - simp only [List.mem_singleton] at hr' - subst hr' - exact hp.st_scr.symm.sub_left (hp.scr_sub (by omega)) - · apply stateAt_congr - intro i hi - simp only [mem, q_eq] - exact writeBytes_before _ _ _ (by omega) (by omega) - · rw [← hxs] - exact bytesAt_writeBytes _ _ _ _ (by omega) - -/-- What the call of the compression function needs. -/ -theorem Common.atPre {s₀ : State} (hp : Pre s₀) {c : Nat} {s : State} (hC : Common s₀ c s) : - AtPre (st s₀) (scr s₀) (esp₀ s₀) 24 s := - ⟨hC.esp, hC.ebx, ⟨argR s₀, by simp [hC.rd, hp.rd], hp.arg_in (by omega) (by omega)⟩, - by rw [hC.arg hp (by omega) (by omega)]; rfl, by simp [hC.wr, hp.wr], by simp [hC.wr, hp.wr]⟩ - -/-- Once the bytes are copied. -/ -theorem Copy.common {s₀ : State} (hp : Pre s₀) {c : Nat} {sI : State} (hI : Inv s₀ c sI) {s : State} - (h : Copy s₀ c sI.mem (tt s₀ c) s) : Common s₀ (c + tt s₀ c) s := by - have ht := tt_le s₀ c - have hxs := xs_length s₀ c - have hc := hI.c_le - obtain ⟨hfr, hsv, -, -⟩ := copied_facts hp hI - have hmem : s.mem = writeBytes sI.mem (q s₀ c) (xs s₀ c) := by - rw [h.mem, List.take_of_length_le (by omega)] - exact ⟨by omega, h.rd, h.wr, h.ebx, h.esp, h.esi, by rw [h.ebp, Nat.sub_sub], by rw [hmem]; exact hfr, - by rw [hmem]; exact hsv⟩ - -/-- The call of the compression function on the buffer. -/ -theorem compress_buf {s₀ : State} (hp : Pre s₀) {c : Nat} {s : State} (hC : Common s₀ c s) {Q : State → Prop} - (hQ : ∀ s', Common s₀ c s' → (∀ r ∈ [Reg.ebx, .esi, .edi, .ebp, .esp], s'.gpr r = s.gpr r) → - stateAt s'.mem (stA s₀) = compress (stateAt s.mem (stA s₀)) (blockAt s.mem (stA s₀ + 64)) → Q s') : - WP isa (compressAt 24) s Q := by - refine compressAt_ok hp.st_fit hp.scr_fit hp.sp_lo hp.st_scr hp.stk_st hp.stk_scr (hC.atPre hp) - fun s' hrd hwr hg hf hst => hQ s' ⟨hC.c_le, hrd.trans hC.rd, hwr.trans hC.wr, - by rw [hg _ (by simp)]; exact hC.ebx, by rw [hg _ (by simp)]; exact hC.esp, - by rw [hg _ (by simp)]; exact hC.esi, by rw [hg _ (by simp)]; exact hC.ebp, - hC.frame.trans (hf.sub fun r hr => ?_), fun p hp' => ?_⟩ hg hst - · simp only [List.mem_cons, List.not_mem_nil, or_false] at hr - rcases hr with rfl | rfl | rfl - · exact ⟨stR s₀, by simp, Region.sub_prefix (by omega)⟩ - · exact ⟨scR s₀, by simp, Region.sub_prefix (by omega)⟩ - · exact ⟨stkR s₀, by simp, fun _ h => h⟩ - · have hd : 224 ≤ p.2 ∧ p.2 + 4 ≤ 240 := by - simp only [VG.Impl.Sha512.X86.Stream.saved, List.mem_cons, List.not_mem_nil, or_false] at hp' - rcases hp' with rfl | rfl | rfl | rfl <;> simp - rw [← hC.saved p hp'] - exact hf.readW (r := ⟨addr (scr s₀) p.2, 4⟩) (Region.contains_self _ _) - (hp.saved_sep hd.1 (by omega)) (by decide) - -/-- A full buffer: compress it. -/ -theorem fill_full {s₀ : State} (hp : Pre s₀) {c : Nat} {sI : State} (hI : Inv s₀ c sI) {s : State} - (h : Copy s₀ c sI.mem (tt s₀ c) s) (hfull : rr s₀ c + tt s₀ c = 128) : - WP isa (.seq (compressAt 24) (.block [.mov .edi (.imm 0)])) s (Inv s₀ (c + tt s₀ c)) := by - have hr := rr_lt s₀ c; have ht := tt_le s₀ c; have ht' := tt_le' s₀ c - have hxs := xs_length s₀ c - have hc := hI.c_le - obtain ⟨hfr, hsv, hstt, hby⟩ := copied_facts hp hI - have hmem : s.mem = writeBytes sI.mem (q s₀ c) (xs s₀ c) := by - rw [h.mem, List.take_of_length_le (by omega)] - have hC : Common s₀ (c + tt s₀ c) s := h.common hp hI - refine WP.seq (compress_buf hp hC fun s' hC' _ hstate => ?_) - refine wp_movi fun s'' u => WP.block_nil ?_ - refine ⟨hC'.of_gpr (fun r hr => u.other r ?_) u.mem u.rd u.wr, ?_, fun iv m hm => ?_⟩ - · simp only [List.mem_cons, List.not_mem_nil, or_false] at hr - rcases hr with rfl | rfl | rfl | rfl <;> decide - · rw [u.gpr] - show 0 = BitVec.ofNat 32 ((cnt s₀ + (c + tt s₀ c)) % 128) - rw [show (cnt s₀ + (c + tt s₀ c)) % 128 = 0 by have := rr_eq s₀ c; omega]; rfl - · rw [← take_add_data] - have hmod := length_mid s₀ hm hc - refine repr_append_block (hI.repr iv m hm) (by rw [hmod, hxs]; exact hfull) ?_ - rw [u.mem, hstate, hmem, hstt] - refine congrArg (compress _) (parseBlock_congr fun k hk => ?_) - have hb := (hI.repr iv m hm).2 - rw [hmod] at hb - rw [hb, show rr s₀ c + tt s₀ c = 128 from hfull] at hby - exact bytesAt_getD hby hk - -/-- All the data fits in the buffer. -/ -theorem fill_done {s₀ : State} (hp : Pre s₀) {c : Nat} {sI : State} (hI : Inv s₀ c sI) {s : State} - (h : Copy s₀ c sI.mem (tt s₀ c) s) (hnf : rr s₀ c + tt s₀ c ≠ 128) : Inv s₀ (len s₀) s := by - have hr := rr_lt s₀ c; have ht := tt_le s₀ c; have ht' := tt_le' s₀ c - have hrr := rr_eq s₀ c; have htt := tt_eq s₀ c - have hxs := xs_length s₀ c - have hc := hI.c_le - have htl : tt s₀ c = len s₀ - c := by omega - obtain ⟨hfr, hsv, hstt, hby⟩ := copied_facts hp hI - have hmem : s.mem = writeBytes sI.mem (q s₀ c) (xs s₀ c) := by - rw [h.mem, List.take_of_length_le (by omega)] - refine ⟨⟨(Nat.le_refl _), h.rd, h.wr, h.ebx, h.esp, ?_, ?_, by rw [hmem]; exact hfr, - by rw [hmem]; exact hsv⟩, ?_, fun iv m hm => ?_⟩ - · rw [h.esi]; congr 2; omega - · rw [h.ebp]; congr 1; omega - · rw [h.edi]; congr 1; omega - · have hmod := length_mid s₀ hm hc - rw [show len s₀ = c + tt s₀ c by omega, ← take_add_data] - refine repr_append_buf (hI.repr iv m hm) (by rw [hmod, hxs]; omega) (by rw [hmem, hstt]) ?_ - rw [hmod, hxs, hmem, hby] - have hb := (hI.repr iv m hm).2 - rw [hmod] at hb - rw [hb] - -theorem fill_eq : fill = - .seq (.block [.mov .ecx (.imm 128), .alu .sub .ecx (.reg .edi), .alu .cmp .ebp (.reg .ecx)]) - (.seq (.ite .b (.block [.mov .ecx (.reg .ebp)]) (.block [])) - (.seq (.block [.alu .sub .ebp (.reg .ecx)]) - (.seq (.loop (.block copyBody) .ne) - (.seq (.block [.alu .cmp .edi (.imm 128)]) - (.ite .e (.seq (compressAt 24) (.block [.mov .edi (.imm 0)])) (.block [])))))) := rfl - -/-- The bytes consumed after an iteration that started with `c`. -/ -def nextC (s₀ : State) (c : Nat) : Nat := if rr s₀ c + tt s₀ c = 128 then c + tt s₀ c else len s₀ - -/-- `fill` before the test of whether the buffer is full, and after. -/ -def fillPre : Prog isa := - .seq (.seq (.seq (.seq (.block [.mov .ecx (.imm 128), .alu .sub .ecx (.reg .edi), .alu .cmp .ebp (.reg .ecx)]) - (.ite .b (.block [.mov .ecx (.reg .ebp)]) (.block []))) - (.block [.alu .sub .ebp (.reg .ecx)])) - (.loop (.block copyBody) .ne)) - (.block [.alu .cmp .edi (.imm 128)]) - -def fillEnd : Prog isa := .ite .e (.seq (compressAt 24) (.block [.mov .edi (.imm 0)])) (.block []) - -theorem nextC_gt (s₀ : State) {c : Nat} (hcl : c < len s₀) : c < nextC s₀ c := by - have := tt_eq s₀ c; have := rr_lt s₀ c - simp only [nextC]; split <;> omega - -theorem pre_ok {s₀ : State} (hp : Pre s₀) {c : Nat} {s : State} (hI : Inv s₀ c s) (hcl : c < len s₀) : - WP isa fillPre s fun s' => AtPre (st s₀) (scr s₀) (esp₀ s₀) 24 s' ∧ - s'.zf = some (decide (rr s₀ c + tt s₀ c = 128)) ∧ WP isa fillEnd s' (Inv s₀ (nextC s₀ c)) := by - have hr := rr_lt s₀ c; have ht := tt_le s₀ c; have ht' := tt_le' s₀ c - have hrr := rr_eq s₀ c; have htt := tt_eq s₀ c - have hc := hI.c_le; have hlen := len_lt s₀ - unfold fillPre - refine WP.seq (WP.seq (WP.seq (WP.seq ?_))) - -- `ecx := 128 - r`, compared with the bytes left. - refine (wp_movi fun s₁ u₁ => wp_sub fun s₂ u₂ _ => wp_cmp fun s₃ f₃ cf₃ _ => WP.block_nil ?_) - have hI₃ : Inv s₀ c s₃ := ((hI.of_upd u₁ (by decide)).of_upd u₂ (by decide)).of_flags f₃ - have hecx₂ : s₂.gpr .ecx = BitVec.ofNat 32 (128 - rr s₀ c) := by - rw [u₂.gpr, u₁.gpr, u₁.other _ (by decide), hI.edi, - show (128 : BitVec 32) = BitVec.ofNat 32 128 from rfl, sub_ofNat (by omega)] - have hecx₃ : s₃.gpr .ecx = BitVec.ofNat 32 (128 - rr s₀ c) := by rw [f₃.gpr, hecx₂] - have hm₃ : s₃.mem = s.mem := by rw [f₃.mem, u₂.mem, u₁.mem] - have hcf : s₃.cf = some (decide (len s₀ - c < 128 - rr s₀ c)) := by - rw [cf₃, u₂.other _ (by decide), u₁.other _ (by decide), hI.ebp, hecx₂, toNat_ofNat_lt (by omega), - toNat_ofNat_lt (by omega)] - -- `ecx := min(ecx, len)` - refine (WP.mono (Q := fun (s₅ : State) => Inv s₀ c s₅ ∧ s₅.gpr .ecx = BitVec.ofNat 32 (tt s₀ c) ∧ - s₅.mem = s.mem) ?_ fun s₅ ⟨hI₅, h8₅, hm₅⟩ => ?_) - · refine WP.ite (decide (len s₀ - c < 128 - rr s₀ c)) (by show s₃.cf = _; exact hcf) - (fun hb => ?_) (fun hb => ?_) - · simp only [decide_eq_true_eq] at hb - refine wp_mov fun s₄ u₄ => WP.block_nil ⟨hI₃.of_upd u₄ (by decide), ?_, by rw [u₄.mem, hm₃]⟩ - rw [u₄.gpr, hI₃.ebp]; congr 1; omega - · simp only [decide_eq_false_iff_not] at hb - refine WP.block_nil ⟨hI₃, ?_, hm₃⟩ - rw [hecx₃]; congr 1; omega - -- `ebp -= ecx` - refine (wp_sub fun s₆ u₆ _ => WP.block_nil ?_) - have hC₀ : Copy s₀ c s.mem 0 s₆ := by - have e : ∀ r, r ≠ .ebp → s₆.gpr r = s₅.gpr r := fun r h => u₆.other r h - refine ⟨Nat.zero_le _, by rw [u₆.rd, hI₅.rd], by rw [u₆.wr, hI₅.wr], - by rw [e _ (by decide), hI₅.ebx], by rw [e _ (by decide), hI₅.esp], - by rw [e _ (by decide), hI₅.esi, Nat.add_zero], ?_, - by rw [e _ (by decide), hI₅.edi, Nat.add_zero], by rw [e _ (by decide), h8₅, Nat.sub_zero], ?_⟩ - · rw [u₆.gpr, hI₅.ebp, h8₅, sub_ofNat (by omega), Nat.sub_sub] - · rw [u₆.mem, hm₅, List.take_zero, writeBytes_nil] - -- Copy the bytes. - refine (WP.mono (copy_loop_ok hp hI hC₀ (by omega)) fun s₇ hC => ?_) - -- Is the buffer full? - refine (wp_cmpi fun s₈ f₈ _ z₈ => WP.block_nil ?_) - have hC₈ : Copy s₀ c s.mem (tt s₀ c) s₈ := - ⟨hC.j_le, by rw [f₈.rd, hC.rd], by rw [f₈.wr, hC.wr], by rw [f₈.gpr, hC.ebx], by rw [f₈.gpr, hC.esp], - by rw [f₈.gpr, hC.esi], by rw [f₈.gpr, hC.ebp], by rw [f₈.gpr, hC.edi], by rw [f₈.gpr, hC.ecx], - by rw [f₈.mem, hC.mem]⟩ - have hz : s₈.zf = some (decide (rr s₀ c + tt s₀ c = 128)) := by - rw [z₈, hC.edi, show (128 : BitVec 32) = BitVec.ofNat 32 128 from rfl, sub_beq (by omega) (by omega)] - refine ⟨(hC₈.common hp hI).atPre hp, hz, - WP.ite (decide (rr s₀ c + tt s₀ c = 128)) (by show s₈.zf = _; exact hz) (fun hb => ?_) (fun hb => ?_)⟩ - · simp only [decide_eq_true_eq] at hb - have e : nextC s₀ c = c + tt s₀ c := by simp only [nextC]; split <;> omega - rw [e] - exact fill_full hp hI hC₈ hb - · simp only [decide_eq_false_iff_not] at hb - have e : nextC s₀ c = len s₀ := by simp only [nextC]; split <;> omega - rw [e] - exact WP.block_nil (fill_done hp hI hC₈ hb) - -theorem fill_ok {s₀ : State} (hp : Pre s₀) {c : Nat} {s : State} (hI : Inv s₀ c s) (hcl : c < len s₀) : - WP isa fill s fun s' => ∃ c', c < c' ∧ Inv s₀ c' s' := by - rw [fill_eq] - exact WP.assoc (WP.assoc (WP.assoc (WP.assoc (WP.seq (WP.mono (pre_ok hp hI hcl) - fun _ h => WP.mono h.2.2 fun _ h => ⟨_, nextC_gt s₀ hcl, h⟩))))) - -/-! ## One iteration -/ - -/-- The loop's test: bytes left? -/ -theorem test_ok {s₀ : State} {c : Nat} {s : State} (hI : Inv s₀ c s) : - WP isa (.block [.alu .test .ebp (.reg .ebp)]) s fun s' => - Inv s₀ c s' ∧ s'.zf = some (decide (len s₀ - c = 0)) := by - have hlen := len_lt s₀ - have hc'' := hI.c_le - refine wp_test fun s'' f'' z'' => WP.block_nil ⟨hI.of_flags f'', ?_⟩ - rw [z'', hI.ebp, BitVec.and_self, ofNat_beq_zero (by omega)] - -theorem body_ok {s₀ : State} (hp : Pre s₀) {c : Nat} {s : State} (hI : Inv s₀ c s) (hcl : c < len s₀) : - WP isa updateBody s fun s' => ∃ c', c < c' ∧ Inv s₀ c' s' ∧ s'.zf = some (decide (len s₀ - c' = 0)) := - WP.seq (WP.mono (fill_ok hp hI hcl) fun _ ⟨c', hc', hI'⟩ => - WP.mono (test_ok hI') fun _ h => ⟨c', hc', h⟩) - -/-! ## Prologue and epilogue -/ - -/-- The memory after saving our caller's registers. -/ -def saveMem (s₀ : State) : Mem := - (((s₀.mem.writeW (addr (scr s₀) 224) (s₀.gpr .ebx)).writeW (addr (scr s₀) 228) (s₀.gpr .esi)).writeW - (addr (scr s₀) 232) (s₀.gpr .edi)).writeW (addr (scr s₀) 236) (s₀.gpr .ebp) - -theorem saveMem_frame {s₀ : State} (hp : Pre s₀) : Frame [scR s₀] s₀.mem (saveMem s₀) := by - have c : ∀ d, d + 4 ≤ 272 → (scR s₀).Contains (addr (scr s₀) d) (32 / 8) := fun d hd => hp.scr_in hd - exact ((((Frame.refl _ _).writeW (List.mem_singleton_self _) _ (c 224 (by omega))).writeW - (List.mem_singleton_self _) _ (c 228 (by omega))).writeW (List.mem_singleton_self _) _ - (c 232 (by omega))).writeW (List.mem_singleton_self _) _ (c 236 (by omega)) - -theorem saveMem_saved {s₀ : State} (hp : Pre s₀) : Saved s₀ (saveMem s₀) := by - have hs := hp.scr_fit - have w : ∀ (m : Mem) (v : BitVec 32) (d e : Nat), d + 4 ≤ 272 → e + 4 ≤ 272 → d + 4 ≤ e ∨ e + 4 ≤ d → - (m.writeW (addr (scr s₀) e) v).readW (addr (scr s₀) d) 32 = m.readW (addr (scr s₀) d) 32 := - fun m v d e h₁ h₂ h => readW_writeW_addr m v (by omega) (by omega) h - intro p hp' - simp only [VG.Impl.Sha512.X86.Stream.saved, List.mem_cons, List.not_mem_nil, or_false] at hp' - rcases hp' with rfl | rfl | rfl | rfl <;> simp only [saveMem] - · rw [w _ _ 224 236 (by omega) (by omega) (by omega), w _ _ 224 232 (by omega) (by omega) (by omega), - w _ _ 224 228 (by omega) (by omega) (by omega), Mem.readW_writeW_self32] - · rw [w _ _ 228 236 (by omega) (by omega) (by omega), w _ _ 228 232 (by omega) (by omega) (by omega), - Mem.readW_writeW_self32] - · rw [w _ _ 232 236 (by omega) (by omega) (by omega), Mem.readW_writeW_self32] - · rw [Mem.readW_writeW_self32] - -/-- The prologue. -/ -def proBlock : List Instr := - [.mov .eax (.mem (at_ .esp 24)), .store (at_ .eax 224) .ebx, .store (at_ .eax 228) .esi, - .store (at_ .eax 232) .edi, .store (at_ .eax 236) .ebp, - .mov .ebx (.mem (at_ .esp 4)), .mov .edi (.mem (at_ .esp 8)), .alu .and .edi (.imm 127), - .mov .esi (.mem (at_ .esp 16)), .mov .ebp (.mem (at_ .esp 20)), .alu .test .ebp (.reg .ebp)] - -theorem update_eq : update = .seq (.block proBlock) - (.seq (.ite .e (.block []) (.loop updateBody .ne)) (.block (.mov .eax (.mem (at_ .esp 24)) :: restore))) := - rfl - -theorem beq_zero (x : BitVec 32) : (x == 0) = decide (x.toNat = 0) := by - rw [← ofNat_beq_zero x.isLt, BitVec.ofNat_toNat, BitVec.setWidth_eq] - -theorem prologue_ok {s₀ : State} (hp : Pre s₀) : - WP isa (.block proBlock) s₀ fun s => Inv s₀ 0 s ∧ s.zf = some (decide (len s₀ = 0)) := by - have hsp := hp.sp_fit; have hsc := hp.scr_fit; have hst := hp.st_fit - have ain : ∀ e, 4 ≤ e → e + 4 ≤ 28 → ∀ t : State, t.rd = s₀.rd → t.wr = s₀.wr → - InRegions (t.rd ++ t.wr) (addr (esp₀ s₀) e) 4 := - fun e h₁ h₂ t hrd hwr => ⟨argR s₀, by simp [hrd, hp.rd], hp.arg_in h₁ h₂⟩ - have sout : ∀ d, d + 4 ≤ 272 → ∀ t : State, t.wr = s₀.wr → InRegions t.wr (addr (scr s₀) d) 4 := - fun d hd t hwr => ⟨scR s₀, by simp [hwr, hp.wr], hp.scr_in hd⟩ - have ard : ∀ e, 4 ≤ e → e + 4 ≤ 28 → - (saveMem s₀).readW (addr (esp₀ s₀) e) 32 = s₀.mem.readW (addr (esp₀ s₀) e) 32 := - fun e h₁ h₂ => (saveMem_frame hp).readW (Region.contains_self _ _) - (by simpa using hp.a_scr.sub_left (hp.arg_sub h₁ h₂)) (by decide) - unfold proBlock - refine wp_movm (a := addr (esp₀ s₀) 24) (ea_at _ _ _) (ain 24 (by omega) (by omega) s₀ rfl rfl) - fun s₁ u₁ => ?_ - have e₁ : s₁.gpr .eax = scr s₀ := u₁.gpr - refine wp_store (a := addr (scr s₀) 224) (by rw [ea_at, e₁]) (sout 224 (by omega) _ u₁.wr) fun s₂ u₂ => ?_ - refine wp_store (a := addr (scr s₀) 228) (by rw [ea_at, u₂.gpr, e₁]) - (sout 228 (by omega) _ (by rw [u₂.wr, u₁.wr])) fun s₃ u₃ => ?_ - refine wp_store (a := addr (scr s₀) 232) (by rw [ea_at, u₃.gpr, u₂.gpr, e₁]) - (sout 232 (by omega) _ (by rw [u₃.wr, u₂.wr, u₁.wr])) fun s₄ u₄ => ?_ - refine wp_store (a := addr (scr s₀) 236) (by rw [ea_at, u₄.gpr, u₃.gpr, u₂.gpr, e₁]) - (sout 236 (by omega) _ (by rw [u₄.wr, u₃.wr, u₂.wr, u₁.wr])) fun s₅ u₅ => ?_ - have g₅ : s₅.gpr = s₁.gpr := by rw [u₅.gpr, u₄.gpr, u₃.gpr, u₂.gpr] - have rd₅ : s₅.rd = s₀.rd := by rw [u₅.rd, u₄.rd, u₃.rd, u₂.rd, u₁.rd] - have wr₅ : s₅.wr = s₀.wr := by rw [u₅.wr, u₄.wr, u₃.wr, u₂.wr, u₁.wr] - have sp₅ : s₅.gpr .esp = esp₀ s₀ := by rw [g₅, u₁.other _ (by decide)] - have m₅ : s₅.mem = saveMem s₀ := by - rw [u₅.mem, u₄.mem, u₃.mem, u₂.mem, u₄.gpr, u₃.gpr, u₂.gpr, u₁.mem, u₁.other .ebx (by decide), - u₁.other .esi (by decide), u₁.other .edi (by decide), u₁.other .ebp (by decide)] - rfl - refine wp_movm (a := addr (esp₀ s₀) 4) (by rw [ea_at, sp₅]) (ain 4 (by omega) (by omega) s₅ rd₅ wr₅) - fun s₆ u₆ => ?_ - refine wp_movm (a := addr (esp₀ s₀) 8) (by rw [ea_at, u₆.other _ (by decide), sp₅]) - (ain 8 (by omega) (by omega) s₆ (by rw [u₆.rd, rd₅]) (by rw [u₆.wr, wr₅])) fun s₇ u₇ => - wp_andi fun s₈ u₈ => ?_ - have m₈ : s₈.mem = saveMem s₀ := by rw [u₈.mem, u₇.mem, u₆.mem, m₅] - have rd₈ : s₈.rd = s₀.rd := by rw [u₈.rd, u₇.rd, u₆.rd, rd₅] - have wr₈ : s₈.wr = s₀.wr := by rw [u₈.wr, u₇.wr, u₆.wr, wr₅] - have sp₈ : s₈.gpr .esp = esp₀ s₀ := by - rw [u₈.other _ (by decide), u₇.other _ (by decide), u₆.other _ (by decide), sp₅] - refine wp_movm (a := addr (esp₀ s₀) 16) (by rw [ea_at, sp₈]) (ain 16 (by omega) (by omega) s₈ rd₈ wr₈) - fun s₉ u₉ => ?_ - refine wp_movm (a := addr (esp₀ s₀) 20) (by rw [ea_at, u₉.other _ (by decide), sp₈]) - (ain 20 (by omega) (by omega) s₉ (by rw [u₉.rd, rd₈]) (by rw [u₉.wr, wr₈])) fun s₁₀ u₁₀ => - wp_test fun s₁₁ f₁₁ z₁₁ => WP.block_nil ?_ - have m₁₁ : s₁₁.mem = saveMem s₀ := by rw [f₁₁.mem, u₁₀.mem, u₉.mem, m₈] - have ebp₁₁ : s₁₁.gpr .ebp = arg s₀ 4 := by - rw [f₁₁.gpr, u₁₀.gpr, u₉.mem, m₈, ard 20 (by omega) (by omega)]; rfl - refine ⟨⟨⟨Nat.zero_le _, by rw [f₁₁.rd, u₁₀.rd, u₉.rd, rd₈], by rw [f₁₁.wr, u₁₀.wr, u₉.wr, wr₈], ?_, - by rw [f₁₁.gpr, u₁₀.other _ (by decide), u₉.other _ (by decide), sp₈], ?_, ?_, - by rw [m₁₁]; exact (saveMem_frame hp).mono (by simp), by rw [m₁₁]; exact saveMem_saved hp⟩, ?_, - fun iv m hm => ?_⟩, ?_⟩ - · rw [f₁₁.gpr, u₁₀.other _ (by decide), u₉.other _ (by decide), u₈.other _ (by decide), - u₇.other _ (by decide), u₆.gpr, m₅, ard 4 (by omega) (by omega)]; rfl - · rw [f₁₁.gpr, u₁₀.other _ (by decide), u₉.gpr, m₈, ard 16 (by omega) (by omega)] - exact (BitVec.add_zero (dp s₀)).symm - · rw [ebp₁₁, Nat.sub_zero, BitVec.ofNat_toNat, BitVec.setWidth_eq] - · rw [f₁₁.gpr, u₁₀.other _ (by decide), u₉.other _ (by decide), u₈.gpr, u₇.gpr, u₆.mem, m₅, - ard 8 (by omega) (by omega), and127, Nat.add_zero, cnt_mod]; rfl - · rw [List.take_zero, List.append_nil, m₁₁] - exact repr_congr (fun i hi => frame_bytes (saveMem_frame hp) (R := stR s₀) (by simpa using hp.st_scr) - (by simp) hi) hm.1 - · rw [z₁₁, BitVec.and_self, beq_zero, ← f₁₁.gpr, ebp₁₁] - -/-- The epilogue's postcondition. -/ -def Post (s₀ s' : State) : Prop := abiPreserved s₀ s' ∧ Proof.Sha512.updateX86.post s₀ s' - -theorem epilogue_ok {s₀ : State} (hp : Pre s₀) {s : State} (hI : Inv s₀ (len s₀) s) : - WP isa (.block (.mov .eax (.mem (at_ .esp 24)) :: restore)) s (Post s₀) := by - have hsc := hp.scr_fit - have rin : ∀ d, d + 4 ≤ 272 → InRegions (s.rd ++ s.wr) (addr (scr s₀) d) 4 := - fun d hd => ⟨scR s₀, by simp [hI.rd, hI.wr, hp.wr], hp.scr_in hd⟩ - have sv : ∀ p ∈ saved, s.mem.readW (addr (scr s₀) p.2) 32 = s₀.gpr p.1 := hI.saved - refine wp_movm (a := addr (esp₀ s₀) 24) (by rw [ea_at, hI.esp]) - ⟨argR s₀, by simp [hI.rd, hp.rd], hp.arg_in (by omega) (by omega)⟩ fun s₀' u₀ => ?_ - have e₀ : s₀'.gpr .eax = scr s₀ := by - rw [u₀.gpr, hI.arg hp (by omega) (by omega)] - rfl - unfold restore - simp only [saved, List.map_cons, List.map_nil] - refine wp_movm (a := addr (scr s₀) 224) (by rw [ea_at, e₀]) - (by rw [u₀.rd, u₀.wr]; exact rin 224 (by omega)) fun s₁ u₁ => ?_ - refine wp_movm (a := addr (scr s₀) 228) (by rw [ea_at, u₁.other _ (by decide), e₀]) - (by rw [u₁.rd, u₁.wr, u₀.rd, u₀.wr]; exact rin 228 (by omega)) fun s₂ u₂ => ?_ - refine wp_movm (a := addr (scr s₀) 232) (by rw [ea_at, u₂.other _ (by decide), u₁.other _ (by decide), e₀]) - (by rw [u₂.rd, u₂.wr, u₁.rd, u₁.wr, u₀.rd, u₀.wr]; exact rin 232 (by omega)) fun s₃ u₃ => ?_ - refine wp_movm (a := addr (scr s₀) 236) - (by rw [ea_at, u₃.other _ (by decide), u₂.other _ (by decide), u₁.other _ (by decide), e₀]) - (by rw [u₃.rd, u₃.wr, u₂.rd, u₂.wr, u₁.rd, u₁.wr, u₀.rd, u₀.wr]; exact rin 236 (by omega)) - fun s₄ u₄ => WP.block_nil ?_ - have hm₄ : s₄.mem = s.mem := by rw [u₄.mem, u₃.mem, u₂.mem, u₁.mem, u₀.mem] - refine ⟨⟨fun r hr => ?_, ?_⟩, fun iv m hm hc => ?_⟩ - · simp only [calleeSaved, List.mem_cons, List.not_mem_nil, or_false] at hr - rcases hr with rfl | rfl | rfl | rfl | rfl - · rw [u₄.other _ (by decide), u₃.other _ (by decide), u₂.other _ (by decide), u₁.gpr, u₀.mem] - exact sv (.ebx, 224) (by simp [saved]) - · rw [u₄.other _ (by decide), u₃.other _ (by decide), u₂.gpr, u₁.mem, u₀.mem] - exact sv (.esi, 228) (by simp [saved]) - · rw [u₄.other _ (by decide), u₃.gpr, u₂.mem, u₁.mem, u₀.mem] - exact sv (.edi, 232) (by simp [saved]) - · rw [u₄.gpr, u₃.mem, u₂.mem, u₁.mem, u₀.mem] - exact sv (.ebp, 236) (by simp [saved]) - · rw [u₄.other _ (by decide), u₃.other _ (by decide), u₂.other _ (by decide), u₁.other _ (by decide), - u₀.other _ (by decide), hI.esp] - · rw [hm₄] - refine hI.frame.readW (r := retR s₀) (Region.contains_self _ _) ?_ (by decide) - intro r hr - simp only [List.mem_cons, List.not_mem_nil, or_false] at hr - rcases hr with rfl | rfl | rfl - exacts [hp.ret_st, hp.ret_scr, hp.ret_stk] - · have := hI.repr iv m ⟨hm, hc⟩ - rw [List.take_of_length_le (by rw [D_length]), ← hm₄] at this - exact this - -theorem correct {s₀ : State} (hp : Pre s₀) : WP isa update s₀ (Post s₀) := by - have hlen := len_lt s₀ - rw [update_eq] - refine WP.seq (WP.mono (prologue_ok hp) fun s₁ ⟨hI, hz⟩ => ?_) - refine WP.seq (WP.mono (Q := Inv s₀ (len s₀)) ?_ fun s₂ hI₂ => epilogue_ok hp hI₂) - refine WP.ite (decide (len s₀ = 0)) (by show s₁.zf = _; exact hz) (fun hb => ?_) (fun hb => ?_) - · simp only [decide_eq_true_eq] at hb - exact WP.block_nil (hb ▸ hI) - · simp only [decide_eq_false_iff_not] at hb - refine WP.loop (M := isa) (fun n s => ∃ c, n = len s₀ - c ∧ c < len s₀ ∧ Inv s₀ c s) ?_ (len s₀) s₁ - ⟨0, rfl, by omega, hI⟩ - rintro n s ⟨c, rfl, hcl, hI⟩ - refine WP.mono (body_ok hp hI hcl) fun s' ⟨c', hc, hI', hz'⟩ => ?_ - have hc' := hI'.c_le - have hz : isa.eval .ne s' = some (decide (len s₀ - c' ≠ 0)) := by - show s'.zf.map (!·) = _ - rw [hz'] - simp - by_cases hl : len s₀ - c' = 0 - · refine .inl ⟨by rw [hz, decide_eq_false fun h => h hl], ?_⟩ - rwa [show c' = len s₀ by omega] at hI' - · exact .inr ⟨by rw [hz, decide_eq_true hl], len s₀ - c', by omega, c', rfl, by omega, hI'⟩ - -/-! ## Constant time -/ - -/-- The initial taint: the stack arguments are public, the words holding -`state` and `scratch` are the base addresses of the writable regions, and the -20 bytes below `esp` are outside them. -/ -def τ₀ : VG.X86.Taint.T := - { regs := .ofList [.esp], flags := false, lens := [192, 272], argLen := 28, - argBases := [(4, 0), (24, 1)], room := 20 } - -theorem wf₀ {s : State} (h : Proof.Sha512.updateX86.pre s) : VG.X86.Taint.Wf τ₀ s := by - have hp := pre_of h - have hst := hp.st_fit; have hsc := hp.scr_fit; have hs := hp.sp_fit - have hlo := hp.sp_lo - obtain ⟨-, -, -, -, -, -, -, -, -, k1, k2, -⟩ := h - refine VG.X86.Taint.Wf.entryRoom rfl ⟨fun _ => ⟨by simp [hp.wr, τ₀], ?_, ?_⟩, - fun _ h => (List.not_mem_nil h).elim, fun _ h => (List.not_mem_nil h).elim, - fun _ => ⟨hs, ?_⟩, ?_⟩ fun _ => ⟨hlo, ?_⟩ - · simp only [hp.wr, List.pairwise_cons, List.mem_cons, List.not_mem_nil, or_false, forall_eq, - List.Pairwise.nil, and_true] - exact ⟨hp.st_scr, fun _ h => h.elim⟩ - · simp only [hp.wr, List.mem_cons, List.not_mem_nil, or_false] - rintro r (rfl | rfl) <;> simp only [BitVec.toNat_setWidth] <;> omega - · simp only [hp.wr, List.mem_cons, List.not_mem_nil, or_false] - rintro r (rfl | rfl) - · exact VG.X86.Taint.frame_disjoint (n := 24) (by omega) hp.ret_st hp.a_st - · exact VG.X86.Taint.frame_disjoint (n := 24) (by omega) hp.ret_scr hp.a_scr - · intro p hp' - simp only [τ₀, List.mem_cons, List.not_mem_nil, or_false] at hp' - rcases hp' with rfl | rfl <;> refine ⟨by decide, ?_⟩ <;> - simp [VG.X86.Taint.region, hp.wr, addr, arg, argAddr] - · simp only [hp.wr, List.mem_cons, List.not_mem_nil, or_false] - rintro r (rfl | rfl) - exacts [k1, k2] - -theorem agree₀ {s₁ s₂ : State} (h₁ : Proof.Sha512.updateX86.pre s₁) (h₂ : Proof.Sha512.updateX86.pre s₂) - (hpub : Proof.Sha512.updateX86.pub s₁ s₂) : VG.X86.Taint.Agree τ₀ s₁ s₂ := by - obtain ⟨hesp, ha⟩ := hpub - have hp₁ := pre_of h₁; have hp₂ := pre_of h₂ - refine ⟨⟨fun r hr => ?_, fun h => nomatch h⟩, fun _ => ?_, wf₀ h₁, wf₀ h₂, - fun _ h => (List.not_mem_nil h).elim, fun _ h => (List.not_mem_nil h).elim, fun _ => hesp, - fun k h4 hk => ?_⟩ - · simp only [τ₀, RegSet.mem_ofList, List.mem_singleton] at hr - subst hr; exact hesp - · rw [hp₁.wr, hp₂.wr] - simp only [stR, scR, stA, scA, st, scr, ha 0 (by omega), ha 5 (by omega)] - · simp only [τ₀] at hk - rw [show VG.X86.Taint.depth τ₀.stk = 0 from rfl, Nat.zero_add] - have f₁ : (s₁.gpr .esp).toNat + 28 ≤ 2 ^ 32 := hp₁.sp_fit - have f₂ : (s₂.gpr .esp).toNat + 28 ≤ 2 ^ 32 := hp₂.sp_fit - rw [VG.X86.Taint.argByte_eq f₁ h4 hk, VG.X86.Taint.argByte_eq f₂ h4 hk, - Mem.readW_byte s₁.mem _ (Nat.mod_lt _ (by omega)), Mem.readW_byte s₂.mem _ (Nat.mod_lt _ (by omega))] - exact congrArg _ (ha _ (by omega)) - -/-- Memory holding the arguments `0x1000, 0, 0, 0x2000, 0, 0x3000` at `0x4004`. -/ -def satMem : Mem := fun a => - if a = 0x4005 then 0x10 else if a = 0x4011 then 0x20 else if a = 0x4019 then 0x30 else 0 - -/-- A state satisfying the precondition. -/ -def sat : State where - gpr r := match r with - | .esp => 0x4000 | _ => 0 - cf := none - zf := none - sf := none - of := none - mem := satMem - rd := [⟨0x2000, 0⟩, ⟨0x4004, 24⟩] - wr := [⟨0x1000, 192⟩, ⟨0x3000, 272⟩] - -theorem sat_pre : Proof.Sha512.updateX86.pre sat := by - have a0 : arg sat 0 = 0x1000 := by decide - have a3 : arg sat 3 = 0x2000 := by decide - have a4 : arg sat 4 = 0 := by decide - have a5 : arg sat 5 = 0x3000 := by decide - have e : argAddr sat 0 = 0x4004 := by decide - simp only [Proof.Sha512.updateX86, a0, a3, a4, a5, e] - refine ⟨rfl, rfl, ?_, ?_, ?_, ?_, ?_, ?_, ?_, ?_, ?_, ?_, by decide, by decide, by decide, by decide, - by decide⟩ <;> - exact Region.disjoint_of_sep (by decide) - -/-! ## Constant time, by relating two runs - -The prologue is checked by the taint analysis from the initial taint; in the -loop, `fill` up to the test of whether the buffer is full from the registers -that hold our variables, the call of the compression function by its -contract (`compressAt_rel`); the epilogue reads the stack arguments again -(`argTaint`). How many bytes each iteration consumes depends only on `count` -and `len`, so both runs go through the loop the same number of times, with -the same registers. -/ - -theorem args_out {s₀ : State} (hp : Pre s₀) {c : Nat} {s : State} (hC : Common s₀ c s) : ArgsOut 6 s := by - have hs := hp.sp_fit - refine ⟨by rw [hC.esp]; omega, ?_⟩ - rw [hC.wr, hp.wr, hC.esp] - simp only [List.mem_cons, List.not_mem_nil, or_false] - rintro r (rfl | rfl) - · exact VG.X86.Taint.frame_disjoint (n := 24) (by omega) hp.ret_st hp.a_st - · exact VG.X86.Taint.frame_disjoint (n := 24) (by omega) hp.ret_scr hp.a_scr - -theorem arg_eq (s : State) (i : Nat) : arg s i = s.mem.readW (addr (s.gpr .esp) (4 + 4 * i)) 32 := rfl - -theorem args_kept {s₀ : State} (hp : Pre s₀) {c : Nat} {s : State} (hC : Common s₀ c s) {i : Nat} (hi : i < 6) : - arg s i = arg s₀ i := by - rw [arg_eq, arg_eq, hC.esp] - exact hC.arg hp (by omega) (by omega) - -/-- Where `fill` tests whether the buffer is full. -/ -def Mid (s₀ : State) (c : Nat) (s : State) : Prop := AtPre (st s₀) (scr s₀) (esp₀ s₀) 24 s ∧ - s.zf = some (decide (rr s₀ c + tt s₀ c = 128)) ∧ WP isa fillEnd s (Inv s₀ (nextC s₀ c)) - -section CT -variable {s₀ s₀' : State} (hp : Pre s₀) (hp' : Pre s₀') (hesp : s₀.gpr .esp = s₀'.gpr .esp) - (ha : ∀ i < 6, arg s₀ i = arg s₀' i) - -include ha - -theorem cnt_eq : cnt s₀ = cnt s₀' := by - simp only [cnt, countX86, ha 1 (by omega), ha 2 (by omega)] - -theorem len_eq : len s₀ = len s₀' := by - simp only [len, ha 4 (by omega)] - -theorem nextC_eq (c : Nat) : nextC s₀' c = nextC s₀ c := by - unfold nextC tt rr - rw [cnt_eq ha, len_eq ha] - -include hesp in -theorem Inv.agree {c : Nat} {s s' : State} (h : Inv s₀ c s) (h' : Inv s₀' c s') : - ∀ r ∈ [Reg.esp, .ebx, .esi, .ebp, .edi], s.gpr r = s'.gpr r := by - intro r hr - simp only [List.mem_cons, List.not_mem_nil, or_false] at hr - rcases hr with rfl | rfl | rfl | rfl | rfl - · rw [h.esp, h'.esp]; exact hesp - · rw [h.ebx, h'.ebx]; exact ha 0 (by omega) - · rw [h.esi, h'.esi, dp, dp, ha 3 (by omega)] - · rw [h.ebp, h'.ebp, len_eq ha] - · rw [h.edi, h'.edi, cnt_eq ha] - -include hp hp' hesp - -theorem fill_rel {c : Nat} (hcl : c < len s₀) : - RelCT isa (fun s₁ s₂ => Inv s₀ c s₁ ∧ Inv s₀' c s₂) fill - fun s₁ s₂ => Inv s₀ (nextC s₀ c) s₁ ∧ Inv s₀' (nextC s₀ c) s₂ := by - have hcl' : c < len s₀' := len_eq ha ▸ hcl - have e0 : st s₀' = st s₀ := (ha 0 (by omega)).symm - have e5 : scr s₀' = scr s₀ := (ha 5 (by omega)).symm - have ez : rr s₀' c + tt s₀' c = rr s₀ c + tt s₀ c := by unfold tt rr; rw [cnt_eq ha, len_eq ha] - have pre : RelCT isa (fun s₁ s₂ => Inv s₀ c s₁ ∧ Inv s₀' c s₂) fillPre fun s₁ s₂ => Mid s₀ c s₁ ∧ Mid s₀' c s₂ := - ((RelCT.taint (A := taint) (τr [.esp, .ebx, .esi, .ebp, .edi]) - (fun _ _ h => agree_regs (Inv.agree hesp ha h.1 h.2)) (c := fillPre) (by taint_decide)).wp - (F₁ := Mid s₀ c) (F₂ := Mid s₀' c) fun _ _ h => ⟨pre_ok hp h.1 hcl, pre_ok hp' h.2 hcl'⟩).mono - (fun _ _ h => h) fun _ _ h => h.2 - have hat : ∀ s, Mid s₀' c s → AtPre (st s₀) (scr s₀) (esp₀ s₀) 24 s := fun s h => by - have := h.1; rwa [e0, e5, esp₀, ← hesp] at this - have cmp : RelCT isa (fun s₁ s₂ => (Mid s₀ c s₁ ∧ Mid s₀' c s₂) ∧ isa.eval .e s₁ = some true) - (.seq (compressAt 24) (.block [.mov .edi (.imm 0)])) - fun s₁ s₂ => Inv s₀ (nextC s₀ c) s₁ ∧ Inv s₀' (nextC s₀ c) s₂ := by - have hz : ∀ s₁ s₂, (Mid s₀ c s₁ ∧ Mid s₀' c s₂) ∧ isa.eval .e s₁ = some true → isa.eval .e s₂ = some true := - fun s₁ s₂ ⟨⟨m₁, m₂⟩, h⟩ => by - have e₁ : isa.eval .e s₁ = some (decide (rr s₀ c + tt s₀ c = 128)) := m₁.2.1 - have e₂ : isa.eval .e s₂ = some (decide (rr s₀ c + tt s₀ c = 128)) := by rw [← ez]; exact m₂.2.1 - rw [e₂, ← e₁, h] - refine RelCT.seq (R := fun s₁ s₂ => WP isa (.block [.mov .edi (.imm 0)]) s₁ (Inv s₀ (nextC s₀ c)) ∧ - WP isa (.block [.mov .edi (.imm 0)]) s₂ (Inv s₀' (nextC s₀' c))) ?_ ?_ - · exact (((compressAt_rel hp.st_fit hp.scr_fit hp.sp_lo hp.st_scr hp.stk_st hp.stk_scr - ⟨_, by taint_decide⟩).mono (fun _ _ h => ⟨h.1.1.1, hat _ h.1.2⟩) fun _ _ h => h).wp - fun s₁ s₂ h => ⟨WP.seq_iff.mp (WP.ite_true h.1.1.2.2 h.2), - WP.seq_iff.mp (WP.ite_true h.1.2.2.2 (hz _ _ h))⟩).mono (fun _ _ h => h) fun _ _ h => h.2 - · refine ((RelCT.taint (A := taint) (τr []) (fun _ _ _ => agree_regs (by simp)) - (c := .block [.mov .edi (.imm 0)]) (by taint_decide)).wp fun _ _ h => h).mono (fun _ _ h => h) - fun _ _ h => ⟨h.2.1, ?_⟩ - rw [← nextC_eq ha]; exact h.2.2 - have fend : RelCT isa (fun s₁ s₂ => Mid s₀ c s₁ ∧ Mid s₀' c s₂) fillEnd - fun s₁ s₂ => Inv s₀ (nextC s₀ c) s₁ ∧ Inv s₀' (nextC s₀ c) s₂ := by - refine RelCT.ite (fun s₁ s₂ h => ?_) cmp (RelCT.nil fun s₁ s₂ ⟨⟨m₁, m₂⟩, hf⟩ => ?_) - · have e₁ : isa.eval .e s₁ = some (decide (rr s₀ c + tt s₀ c = 128)) := h.1.2.1 - have e₂ : isa.eval .e s₂ = some (decide (rr s₀ c + tt s₀ c = 128)) := by rw [← ez]; exact h.2.2.1 - rw [e₁, e₂] - · have e₁ : isa.eval .e s₁ = some (decide (rr s₀ c + tt s₀ c = 128)) := m₁.2.1 - have e₂ : isa.eval .e s₂ = some false := by - have : isa.eval .e s₂ = some (decide (rr s₀ c + tt s₀ c = 128)) := by rw [← ez]; exact m₂.2.1 - rw [this, ← e₁, hf] - refine ⟨WP.block_nil_iff.mp (WP.ite_false m₁.2.2 hf), ?_⟩ - rw [← nextC_eq ha]; exact WP.block_nil_iff.mp (WP.ite_false m₂.2.2 e₂) - rw [fill_eq] - exact RelCT.assoc (RelCT.assoc (RelCT.assoc (RelCT.assoc (pre.seq fend)))) - -theorem update_rel (h₀ : Proof.Sha512.updateX86.pre s₀) (h₀' : Proof.Sha512.updateX86.pre s₀') : - RelCT isa (fun s₁ s₂ => s₁ = s₀ ∧ s₂ = s₀') update fun _ _ => True := by - have pro : RelCT isa (fun s₁ s₂ => s₁ = s₀ ∧ s₂ = s₀') (.block proBlock) fun s₁ s₂ => - (Inv s₀ 0 s₁ ∧ s₁.zf = some (decide (len s₀ = 0))) ∧ - (Inv s₀' 0 s₂ ∧ s₂.zf = some (decide (len s₀' = 0))) := - ((RelCT.taint (A := taint) τ₀ (fun _ _ ⟨e, e'⟩ => by rw [e, e']; exact agree₀ h₀ h₀' ⟨hesp, ha⟩) - (c := .block proBlock) (by taint_decide)).wp - (F₁ := fun (s : State) => Inv s₀ 0 s ∧ s.zf = some (decide (len s₀ = 0))) - (F₂ := fun (s : State) => Inv s₀' 0 s ∧ s.zf = some (decide (len s₀' = 0))) - fun _ _ ⟨e, e'⟩ => by rw [e, e']; exact ⟨prologue_ok hp, prologue_ok hp'⟩).mono (fun _ _ h => h) - fun _ _ h => h.2 - have lp := RelCT.loop (M := isa) (body := updateBody) (c := .ne) - (Q := fun s₁ s₂ => Inv s₀ (len s₀) s₁ ∧ Inv s₀' (len s₀') s₂) - (fun n s₁ s₂ => ∃ c, n = len s₀ - c ∧ c < len s₀ ∧ Inv s₀ c s₁ ∧ Inv s₀' c s₂) (fun n => RelCT.exists_ fun c => by - by_cases hcn : c < len s₀ ∧ n = len s₀ - c - · obtain ⟨hcl, rfl⟩ := hcn - have hn := nextC_gt s₀ hcl - have tst : RelCT isa (fun s₁ s₂ => Inv s₀ (nextC s₀ c) s₁ ∧ Inv s₀' (nextC s₀ c) s₂) - (.block [.alu .test .ebp (.reg .ebp)]) fun s₁ s₂ => - (Inv s₀ (nextC s₀ c) s₁ ∧ s₁.zf = some (decide (len s₀ - nextC s₀ c = 0))) ∧ - (Inv s₀' (nextC s₀ c) s₂ ∧ s₂.zf = some (decide (len s₀' - nextC s₀ c = 0))) := - ((RelCT.taint (A := taint) (τr []) (fun _ _ _ => agree_regs (by simp)) - (c := .block [.alu .test .ebp (.reg .ebp)]) (by taint_decide)).wp - (F₁ := fun (s : State) => Inv s₀ (nextC s₀ c) s ∧ s.zf = some (decide (len s₀ - nextC s₀ c = 0))) - (F₂ := fun (s : State) => Inv s₀' (nextC s₀ c) s ∧ s.zf = some (decide (len s₀' - nextC s₀ c = 0))) - fun _ _ h => ⟨test_ok h.1, test_ok h.2⟩).mono (fun _ _ h => h) fun _ _ h => h.2 - refine ((fill_rel hp hp' hesp ha hcl).seq tst).mono (fun _ _ h => ⟨h.2.2.1, h.2.2.2⟩) fun s₁ s₂ h => ?_ - · obtain ⟨⟨I₁, z₁⟩, ⟨I₂, z₂⟩⟩ := h - have hc' := I₁.c_le - have e₁ : isa.eval .ne s₁ = some (decide (len s₀ - nextC s₀ c ≠ 0)) := by - show Option.map (!·) _ = _; rw [z₁]; simp - have e₂ : isa.eval .ne s₂ = some (decide (len s₀ - nextC s₀ c ≠ 0)) := by - show Option.map (!·) _ = _; rw [z₂, ← len_eq ha]; simp - refine ⟨e₁.trans e₂.symm, fun hf => ?_, fun ht => ⟨len s₀ - nextC s₀ c, by omega, nextC s₀ c, rfl, - ?_, I₁, I₂⟩⟩ - · have : len s₀ - nextC s₀ c = 0 := by - rw [e₁] at hf; simpa using hf - have e : nextC s₀ c = len s₀ := by omega - rw [e] at I₁ I₂; rw [← len_eq ha]; exact ⟨I₁, I₂⟩ - · rw [e₁] at ht; simp at ht; omega - · exact RelCT.of_false fun _ _ h => hcn ⟨h.2.1, h.1⟩) (len s₀) - have ite : RelCT isa (fun s₁ s₂ => - (Inv s₀ 0 s₁ ∧ s₁.zf = some (decide (len s₀ = 0))) ∧ - (Inv s₀' 0 s₂ ∧ s₂.zf = some (decide (len s₀' = 0)))) - (.ite .e (.block []) (.loop updateBody .ne)) - fun s₁ s₂ => Inv s₀ (len s₀) s₁ ∧ Inv s₀' (len s₀') s₂ := by - refine RelCT.ite (fun s₁ s₂ h => ?_) (RelCT.nil fun s₁ s₂ ⟨⟨⟨I₁, z₁⟩, ⟨I₂, _⟩⟩, ht⟩ => ?_) - (lp.mono (fun s₁ s₂ ⟨⟨⟨I₁, z₁⟩, ⟨I₂, _⟩⟩, hf⟩ => ⟨0, by omega, ?_, I₁, I₂⟩) fun _ _ h => h) - · show s₁.zf = s₂.zf - rw [h.1.2, h.2.2, len_eq ha] - · have : len s₀ = 0 := by - have : s₁.zf = some true := ht - rw [z₁] at this; simpa using this - rw [← len_eq ha, this]; exact ⟨I₁, I₂⟩ - · have : s₁.zf = some false := hf - rw [z₁] at this; simp at this; omega - have epi : RelCT isa (fun s₁ s₂ => Inv s₀ (len s₀) s₁ ∧ Inv s₀' (len s₀') s₂) - (.block (.mov .eax (.mem (at_ .esp 24)) :: restore)) fun _ _ => True := - RelCT.taint (A := taint) (argTaint [] (4 + 4 * 6)) (fun _ _ h => agree_argTaint - (fun r hr => nomatch hr) (by rw [h.1.esp, h.2.esp]; exact hesp) - (args_out hp h.1.toCommon) (args_out hp' h.2.toCommon) - fun i hi => by rw [args_kept hp h.1.toCommon hi, args_kept hp' h.2.toCommon hi]; exact ha i hi) - (by taint_decide) - rw [update_eq] - exact pro.seq (ite.seq epi) - -end CT - -theorem update_verified : Verified X86.target update Proof.Sha512.updateX86 := by - refine ⟨fun s hs => ?_, ?_, ⟨sat, sat_pre⟩⟩ - · obtain ⟨t, s', he, h⟩ := correct (pre_of hs) - exact ⟨t, s', he, h⟩ - · intro s₁ s₂ t₁ t₂ s₁' s₂' h₁ h₂ hpub e₁ e₂ - exact (update_rel (pre_of h₁) (pre_of h₂) hpub.1 hpub.2 h₁ h₂ _ _ _ _ _ _ ⟨rfl, rfl⟩ e₁ e₂).1 - -end VG.Proof.Sha512.X86.Stream.Update +end VG.Proof.Sha512.X86.Stream diff --git a/src/asm/x86/hmac_sha384.rs b/src/asm/x86/hmac_sha384.rs index b2e5f98c6..6fe33cc81 100644 --- a/src/asm/x86/hmac_sha384.rs +++ b/src/asm/x86/hmac_sha384.rs @@ -370,53 +370,53 @@ pub(crate) unsafe extern "C" fn vg_hmac_sha384_finalize(inner: *mut [u8; 192], o "pop eax", "mov eax, ebx", "add eax, 64", + "mov ecx, DWORD PTR [ebx+4]", + "bswap ecx", + "mov DWORD PTR [eax], ecx", "mov ecx, DWORD PTR [ebx]", - "mov edx, DWORD PTR [ebx+4]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax], edx", "mov DWORD PTR [eax+4], ecx", + "mov ecx, DWORD PTR [ebx+12]", + "bswap ecx", + "mov DWORD PTR [eax+8], ecx", "mov ecx, DWORD PTR [ebx+8]", - "mov edx, DWORD PTR [ebx+12]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+8], edx", "mov DWORD PTR [eax+12], ecx", + "mov ecx, DWORD PTR [ebx+20]", + "bswap ecx", + "mov DWORD PTR [eax+16], ecx", "mov ecx, DWORD PTR [ebx+16]", - "mov edx, DWORD PTR [ebx+20]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+16], edx", "mov DWORD PTR [eax+20], ecx", + "mov ecx, DWORD PTR [ebx+28]", + "bswap ecx", + "mov DWORD PTR [eax+24], ecx", "mov ecx, DWORD PTR [ebx+24]", - "mov edx, DWORD PTR [ebx+28]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+24], edx", "mov DWORD PTR [eax+28], ecx", + "mov ecx, DWORD PTR [ebx+36]", + "bswap ecx", + "mov DWORD PTR [eax+32], ecx", "mov ecx, DWORD PTR [ebx+32]", - "mov edx, DWORD PTR [ebx+36]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+32], edx", "mov DWORD PTR [eax+36], ecx", + "mov ecx, DWORD PTR [ebx+44]", + "bswap ecx", + "mov DWORD PTR [eax+40], ecx", "mov ecx, DWORD PTR [ebx+40]", - "mov edx, DWORD PTR [ebx+44]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+40], edx", "mov DWORD PTR [eax+44], ecx", + "mov ecx, DWORD PTR [ebx+52]", + "bswap ecx", + "mov DWORD PTR [eax+48], ecx", "mov ecx, DWORD PTR [ebx+48]", - "mov edx, DWORD PTR [ebx+52]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+48], edx", "mov DWORD PTR [eax+52], ecx", + "mov ecx, DWORD PTR [ebx+60]", + "bswap ecx", + "mov DWORD PTR [eax+56], ecx", "mov ecx, DWORD PTR [ebx+56]", - "mov edx, DWORD PTR [ebx+60]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+56], edx", "mov DWORD PTR [eax+60], ecx", "mov ecx, DWORD PTR [ebx+64]", "mov DWORD PTR [edi], ecx", diff --git a/src/asm/x86/hmac_sha512.rs b/src/asm/x86/hmac_sha512.rs index f0e1d83b7..b020ad6bd 100644 --- a/src/asm/x86/hmac_sha512.rs +++ b/src/asm/x86/hmac_sha512.rs @@ -369,53 +369,53 @@ pub(crate) unsafe extern "C" fn vg_hmac_sha512_finalize(inner: *mut [u8; 192], o "pop eax", "pop eax", "mov eax, edi", + "mov ecx, DWORD PTR [ebx+4]", + "bswap ecx", + "mov DWORD PTR [eax], ecx", "mov ecx, DWORD PTR [ebx]", - "mov edx, DWORD PTR [ebx+4]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax], edx", "mov DWORD PTR [eax+4], ecx", + "mov ecx, DWORD PTR [ebx+12]", + "bswap ecx", + "mov DWORD PTR [eax+8], ecx", "mov ecx, DWORD PTR [ebx+8]", - "mov edx, DWORD PTR [ebx+12]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+8], edx", "mov DWORD PTR [eax+12], ecx", + "mov ecx, DWORD PTR [ebx+20]", + "bswap ecx", + "mov DWORD PTR [eax+16], ecx", "mov ecx, DWORD PTR [ebx+16]", - "mov edx, DWORD PTR [ebx+20]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+16], edx", "mov DWORD PTR [eax+20], ecx", + "mov ecx, DWORD PTR [ebx+28]", + "bswap ecx", + "mov DWORD PTR [eax+24], ecx", "mov ecx, DWORD PTR [ebx+24]", - "mov edx, DWORD PTR [ebx+28]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+24], edx", "mov DWORD PTR [eax+28], ecx", + "mov ecx, DWORD PTR [ebx+36]", + "bswap ecx", + "mov DWORD PTR [eax+32], ecx", "mov ecx, DWORD PTR [ebx+32]", - "mov edx, DWORD PTR [ebx+36]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+32], edx", "mov DWORD PTR [eax+36], ecx", + "mov ecx, DWORD PTR [ebx+44]", + "bswap ecx", + "mov DWORD PTR [eax+40], ecx", "mov ecx, DWORD PTR [ebx+40]", - "mov edx, DWORD PTR [ebx+44]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+40], edx", "mov DWORD PTR [eax+44], ecx", + "mov ecx, DWORD PTR [ebx+52]", + "bswap ecx", + "mov DWORD PTR [eax+48], ecx", "mov ecx, DWORD PTR [ebx+48]", - "mov edx, DWORD PTR [ebx+52]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+48], edx", "mov DWORD PTR [eax+52], ecx", + "mov ecx, DWORD PTR [ebx+60]", + "bswap ecx", + "mov DWORD PTR [eax+56], ecx", "mov ecx, DWORD PTR [ebx+56]", - "mov edx, DWORD PTR [ebx+60]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+56], edx", "mov DWORD PTR [eax+60], ecx", "mov eax, ebp", "mov ebx, DWORD PTR [eax+272]", diff --git a/src/asm/x86/hmac_sha512_224.rs b/src/asm/x86/hmac_sha512_224.rs index fce59562d..861bf1eb1 100644 --- a/src/asm/x86/hmac_sha512_224.rs +++ b/src/asm/x86/hmac_sha512_224.rs @@ -370,53 +370,53 @@ pub(crate) unsafe extern "C" fn vg_hmac_sha512_224_finalize(inner: *mut [u8; 192 "pop eax", "mov eax, ebx", "add eax, 64", + "mov ecx, DWORD PTR [ebx+4]", + "bswap ecx", + "mov DWORD PTR [eax], ecx", "mov ecx, DWORD PTR [ebx]", - "mov edx, DWORD PTR [ebx+4]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax], edx", "mov DWORD PTR [eax+4], ecx", + "mov ecx, DWORD PTR [ebx+12]", + "bswap ecx", + "mov DWORD PTR [eax+8], ecx", "mov ecx, DWORD PTR [ebx+8]", - "mov edx, DWORD PTR [ebx+12]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+8], edx", "mov DWORD PTR [eax+12], ecx", + "mov ecx, DWORD PTR [ebx+20]", + "bswap ecx", + "mov DWORD PTR [eax+16], ecx", "mov ecx, DWORD PTR [ebx+16]", - "mov edx, DWORD PTR [ebx+20]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+16], edx", "mov DWORD PTR [eax+20], ecx", + "mov ecx, DWORD PTR [ebx+28]", + "bswap ecx", + "mov DWORD PTR [eax+24], ecx", "mov ecx, DWORD PTR [ebx+24]", - "mov edx, DWORD PTR [ebx+28]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+24], edx", "mov DWORD PTR [eax+28], ecx", + "mov ecx, DWORD PTR [ebx+36]", + "bswap ecx", + "mov DWORD PTR [eax+32], ecx", "mov ecx, DWORD PTR [ebx+32]", - "mov edx, DWORD PTR [ebx+36]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+32], edx", "mov DWORD PTR [eax+36], ecx", + "mov ecx, DWORD PTR [ebx+44]", + "bswap ecx", + "mov DWORD PTR [eax+40], ecx", "mov ecx, DWORD PTR [ebx+40]", - "mov edx, DWORD PTR [ebx+44]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+40], edx", "mov DWORD PTR [eax+44], ecx", + "mov ecx, DWORD PTR [ebx+52]", + "bswap ecx", + "mov DWORD PTR [eax+48], ecx", "mov ecx, DWORD PTR [ebx+48]", - "mov edx, DWORD PTR [ebx+52]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+48], edx", "mov DWORD PTR [eax+52], ecx", + "mov ecx, DWORD PTR [ebx+60]", + "bswap ecx", + "mov DWORD PTR [eax+56], ecx", "mov ecx, DWORD PTR [ebx+56]", - "mov edx, DWORD PTR [ebx+60]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+56], edx", "mov DWORD PTR [eax+60], ecx", "mov ecx, DWORD PTR [ebx+64]", "mov DWORD PTR [edi], ecx", diff --git a/src/asm/x86/hmac_sha512_256.rs b/src/asm/x86/hmac_sha512_256.rs index 439790f10..34c05b4ee 100644 --- a/src/asm/x86/hmac_sha512_256.rs +++ b/src/asm/x86/hmac_sha512_256.rs @@ -370,53 +370,53 @@ pub(crate) unsafe extern "C" fn vg_hmac_sha512_256_finalize(inner: *mut [u8; 192 "pop eax", "mov eax, ebx", "add eax, 64", + "mov ecx, DWORD PTR [ebx+4]", + "bswap ecx", + "mov DWORD PTR [eax], ecx", "mov ecx, DWORD PTR [ebx]", - "mov edx, DWORD PTR [ebx+4]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax], edx", "mov DWORD PTR [eax+4], ecx", + "mov ecx, DWORD PTR [ebx+12]", + "bswap ecx", + "mov DWORD PTR [eax+8], ecx", "mov ecx, DWORD PTR [ebx+8]", - "mov edx, DWORD PTR [ebx+12]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+8], edx", "mov DWORD PTR [eax+12], ecx", + "mov ecx, DWORD PTR [ebx+20]", + "bswap ecx", + "mov DWORD PTR [eax+16], ecx", "mov ecx, DWORD PTR [ebx+16]", - "mov edx, DWORD PTR [ebx+20]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+16], edx", "mov DWORD PTR [eax+20], ecx", + "mov ecx, DWORD PTR [ebx+28]", + "bswap ecx", + "mov DWORD PTR [eax+24], ecx", "mov ecx, DWORD PTR [ebx+24]", - "mov edx, DWORD PTR [ebx+28]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+24], edx", "mov DWORD PTR [eax+28], ecx", + "mov ecx, DWORD PTR [ebx+36]", + "bswap ecx", + "mov DWORD PTR [eax+32], ecx", "mov ecx, DWORD PTR [ebx+32]", - "mov edx, DWORD PTR [ebx+36]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+32], edx", "mov DWORD PTR [eax+36], ecx", + "mov ecx, DWORD PTR [ebx+44]", + "bswap ecx", + "mov DWORD PTR [eax+40], ecx", "mov ecx, DWORD PTR [ebx+40]", - "mov edx, DWORD PTR [ebx+44]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+40], edx", "mov DWORD PTR [eax+44], ecx", + "mov ecx, DWORD PTR [ebx+52]", + "bswap ecx", + "mov DWORD PTR [eax+48], ecx", "mov ecx, DWORD PTR [ebx+48]", - "mov edx, DWORD PTR [ebx+52]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+48], edx", "mov DWORD PTR [eax+52], ecx", + "mov ecx, DWORD PTR [ebx+60]", + "bswap ecx", + "mov DWORD PTR [eax+56], ecx", "mov ecx, DWORD PTR [ebx+56]", - "mov edx, DWORD PTR [ebx+60]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+56], edx", "mov DWORD PTR [eax+60], ecx", "mov ecx, DWORD PTR [ebx+64]", "mov DWORD PTR [edi], ecx", diff --git a/src/asm/x86/pbkdf2_sha384.rs b/src/asm/x86/pbkdf2_sha384.rs index b144b967e..5ce4047aa 100644 --- a/src/asm/x86/pbkdf2_sha384.rs +++ b/src/asm/x86/pbkdf2_sha384.rs @@ -144,53 +144,53 @@ pub(crate) unsafe extern "C" fn vg_pbkdf2_hmac_sha384_iterate(key: *const [u8; 3 "pop eax", "mov eax, ebx", "add eax, 64", + "mov ecx, DWORD PTR [ebx+4]", + "bswap ecx", + "mov DWORD PTR [eax], ecx", "mov ecx, DWORD PTR [ebx]", - "mov edx, DWORD PTR [ebx+4]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax], edx", "mov DWORD PTR [eax+4], ecx", + "mov ecx, DWORD PTR [ebx+12]", + "bswap ecx", + "mov DWORD PTR [eax+8], ecx", "mov ecx, DWORD PTR [ebx+8]", - "mov edx, DWORD PTR [ebx+12]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+8], edx", "mov DWORD PTR [eax+12], ecx", + "mov ecx, DWORD PTR [ebx+20]", + "bswap ecx", + "mov DWORD PTR [eax+16], ecx", "mov ecx, DWORD PTR [ebx+16]", - "mov edx, DWORD PTR [ebx+20]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+16], edx", "mov DWORD PTR [eax+20], ecx", + "mov ecx, DWORD PTR [ebx+28]", + "bswap ecx", + "mov DWORD PTR [eax+24], ecx", "mov ecx, DWORD PTR [ebx+24]", - "mov edx, DWORD PTR [ebx+28]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+24], edx", "mov DWORD PTR [eax+28], ecx", + "mov ecx, DWORD PTR [ebx+36]", + "bswap ecx", + "mov DWORD PTR [eax+32], ecx", "mov ecx, DWORD PTR [ebx+32]", - "mov edx, DWORD PTR [ebx+36]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+32], edx", "mov DWORD PTR [eax+36], ecx", + "mov ecx, DWORD PTR [ebx+44]", + "bswap ecx", + "mov DWORD PTR [eax+40], ecx", "mov ecx, DWORD PTR [ebx+40]", - "mov edx, DWORD PTR [ebx+44]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+40], edx", "mov DWORD PTR [eax+44], ecx", + "mov ecx, DWORD PTR [ebx+52]", + "bswap ecx", + "mov DWORD PTR [eax+48], ecx", "mov ecx, DWORD PTR [ebx+48]", - "mov edx, DWORD PTR [ebx+52]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+48], edx", "mov DWORD PTR [eax+52], ecx", + "mov ecx, DWORD PTR [ebx+60]", + "bswap ecx", + "mov DWORD PTR [eax+56], ecx", "mov ecx, DWORD PTR [ebx+56]", - "mov edx, DWORD PTR [ebx+60]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+56], edx", "mov DWORD PTR [eax+60], ecx", "mov ecx, 128", "mov DWORD PTR [ebx+112], ecx", @@ -246,53 +246,53 @@ pub(crate) unsafe extern "C" fn vg_pbkdf2_hmac_sha384_iterate(key: *const [u8; 3 "pop eax", "mov eax, ebx", "add eax, 64", + "mov ecx, DWORD PTR [ebx+4]", + "bswap ecx", + "mov DWORD PTR [eax], ecx", "mov ecx, DWORD PTR [ebx]", - "mov edx, DWORD PTR [ebx+4]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax], edx", "mov DWORD PTR [eax+4], ecx", + "mov ecx, DWORD PTR [ebx+12]", + "bswap ecx", + "mov DWORD PTR [eax+8], ecx", "mov ecx, DWORD PTR [ebx+8]", - "mov edx, DWORD PTR [ebx+12]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+8], edx", "mov DWORD PTR [eax+12], ecx", + "mov ecx, DWORD PTR [ebx+20]", + "bswap ecx", + "mov DWORD PTR [eax+16], ecx", "mov ecx, DWORD PTR [ebx+16]", - "mov edx, DWORD PTR [ebx+20]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+16], edx", "mov DWORD PTR [eax+20], ecx", + "mov ecx, DWORD PTR [ebx+28]", + "bswap ecx", + "mov DWORD PTR [eax+24], ecx", "mov ecx, DWORD PTR [ebx+24]", - "mov edx, DWORD PTR [ebx+28]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+24], edx", "mov DWORD PTR [eax+28], ecx", + "mov ecx, DWORD PTR [ebx+36]", + "bswap ecx", + "mov DWORD PTR [eax+32], ecx", "mov ecx, DWORD PTR [ebx+32]", - "mov edx, DWORD PTR [ebx+36]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+32], edx", "mov DWORD PTR [eax+36], ecx", + "mov ecx, DWORD PTR [ebx+44]", + "bswap ecx", + "mov DWORD PTR [eax+40], ecx", "mov ecx, DWORD PTR [ebx+40]", - "mov edx, DWORD PTR [ebx+44]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+40], edx", "mov DWORD PTR [eax+44], ecx", + "mov ecx, DWORD PTR [ebx+52]", + "bswap ecx", + "mov DWORD PTR [eax+48], ecx", "mov ecx, DWORD PTR [ebx+48]", - "mov edx, DWORD PTR [ebx+52]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+48], edx", "mov DWORD PTR [eax+52], ecx", + "mov ecx, DWORD PTR [ebx+60]", + "bswap ecx", + "mov DWORD PTR [eax+56], ecx", "mov ecx, DWORD PTR [ebx+56]", - "mov edx, DWORD PTR [ebx+60]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+56], edx", "mov DWORD PTR [eax+60], ecx", "mov ecx, 128", "mov DWORD PTR [ebx+112], ecx", diff --git a/src/asm/x86/pbkdf2_sha512.rs b/src/asm/x86/pbkdf2_sha512.rs index 3d2b15ff2..edad9dc39 100644 --- a/src/asm/x86/pbkdf2_sha512.rs +++ b/src/asm/x86/pbkdf2_sha512.rs @@ -144,53 +144,53 @@ pub(crate) unsafe extern "C" fn vg_pbkdf2_hmac_sha512_iterate(key: *const [u8; 3 "pop eax", "mov eax, ebx", "add eax, 64", + "mov ecx, DWORD PTR [ebx+4]", + "bswap ecx", + "mov DWORD PTR [eax], ecx", "mov ecx, DWORD PTR [ebx]", - "mov edx, DWORD PTR [ebx+4]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax], edx", "mov DWORD PTR [eax+4], ecx", + "mov ecx, DWORD PTR [ebx+12]", + "bswap ecx", + "mov DWORD PTR [eax+8], ecx", "mov ecx, DWORD PTR [ebx+8]", - "mov edx, DWORD PTR [ebx+12]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+8], edx", "mov DWORD PTR [eax+12], ecx", + "mov ecx, DWORD PTR [ebx+20]", + "bswap ecx", + "mov DWORD PTR [eax+16], ecx", "mov ecx, DWORD PTR [ebx+16]", - "mov edx, DWORD PTR [ebx+20]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+16], edx", "mov DWORD PTR [eax+20], ecx", + "mov ecx, DWORD PTR [ebx+28]", + "bswap ecx", + "mov DWORD PTR [eax+24], ecx", "mov ecx, DWORD PTR [ebx+24]", - "mov edx, DWORD PTR [ebx+28]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+24], edx", "mov DWORD PTR [eax+28], ecx", + "mov ecx, DWORD PTR [ebx+36]", + "bswap ecx", + "mov DWORD PTR [eax+32], ecx", "mov ecx, DWORD PTR [ebx+32]", - "mov edx, DWORD PTR [ebx+36]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+32], edx", "mov DWORD PTR [eax+36], ecx", + "mov ecx, DWORD PTR [ebx+44]", + "bswap ecx", + "mov DWORD PTR [eax+40], ecx", "mov ecx, DWORD PTR [ebx+40]", - "mov edx, DWORD PTR [ebx+44]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+40], edx", "mov DWORD PTR [eax+44], ecx", + "mov ecx, DWORD PTR [ebx+52]", + "bswap ecx", + "mov DWORD PTR [eax+48], ecx", "mov ecx, DWORD PTR [ebx+48]", - "mov edx, DWORD PTR [ebx+52]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+48], edx", "mov DWORD PTR [eax+52], ecx", + "mov ecx, DWORD PTR [ebx+60]", + "bswap ecx", + "mov DWORD PTR [eax+56], ecx", "mov ecx, DWORD PTR [ebx+56]", - "mov edx, DWORD PTR [ebx+60]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+56], edx", "mov DWORD PTR [eax+60], ecx", "mov ecx, DWORD PTR [esi+192]", "mov DWORD PTR [ebx], ecx", @@ -238,53 +238,53 @@ pub(crate) unsafe extern "C" fn vg_pbkdf2_hmac_sha512_iterate(key: *const [u8; 3 "pop eax", "mov eax, ebx", "add eax, 64", + "mov ecx, DWORD PTR [ebx+4]", + "bswap ecx", + "mov DWORD PTR [eax], ecx", "mov ecx, DWORD PTR [ebx]", - "mov edx, DWORD PTR [ebx+4]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax], edx", "mov DWORD PTR [eax+4], ecx", + "mov ecx, DWORD PTR [ebx+12]", + "bswap ecx", + "mov DWORD PTR [eax+8], ecx", "mov ecx, DWORD PTR [ebx+8]", - "mov edx, DWORD PTR [ebx+12]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+8], edx", "mov DWORD PTR [eax+12], ecx", + "mov ecx, DWORD PTR [ebx+20]", + "bswap ecx", + "mov DWORD PTR [eax+16], ecx", "mov ecx, DWORD PTR [ebx+16]", - "mov edx, DWORD PTR [ebx+20]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+16], edx", "mov DWORD PTR [eax+20], ecx", + "mov ecx, DWORD PTR [ebx+28]", + "bswap ecx", + "mov DWORD PTR [eax+24], ecx", "mov ecx, DWORD PTR [ebx+24]", - "mov edx, DWORD PTR [ebx+28]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+24], edx", "mov DWORD PTR [eax+28], ecx", + "mov ecx, DWORD PTR [ebx+36]", + "bswap ecx", + "mov DWORD PTR [eax+32], ecx", "mov ecx, DWORD PTR [ebx+32]", - "mov edx, DWORD PTR [ebx+36]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+32], edx", "mov DWORD PTR [eax+36], ecx", + "mov ecx, DWORD PTR [ebx+44]", + "bswap ecx", + "mov DWORD PTR [eax+40], ecx", "mov ecx, DWORD PTR [ebx+40]", - "mov edx, DWORD PTR [ebx+44]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+40], edx", "mov DWORD PTR [eax+44], ecx", + "mov ecx, DWORD PTR [ebx+52]", + "bswap ecx", + "mov DWORD PTR [eax+48], ecx", "mov ecx, DWORD PTR [ebx+48]", - "mov edx, DWORD PTR [ebx+52]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+48], edx", "mov DWORD PTR [eax+52], ecx", + "mov ecx, DWORD PTR [ebx+60]", + "bswap ecx", + "mov DWORD PTR [eax+56], ecx", "mov ecx, DWORD PTR [ebx+56]", - "mov edx, DWORD PTR [ebx+60]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+56], edx", "mov DWORD PTR [eax+60], ecx", "mov edx, DWORD PTR [esp+16]", "mov ecx, DWORD PTR [ebx+64]", diff --git a/src/asm/x86/pbkdf2_sha512_224.rs b/src/asm/x86/pbkdf2_sha512_224.rs index 29b23dd7a..35481f432 100644 --- a/src/asm/x86/pbkdf2_sha512_224.rs +++ b/src/asm/x86/pbkdf2_sha512_224.rs @@ -144,53 +144,53 @@ pub(crate) unsafe extern "C" fn vg_pbkdf2_hmac_sha512_224_iterate(key: *const [u "pop eax", "mov eax, ebx", "add eax, 64", + "mov ecx, DWORD PTR [ebx+4]", + "bswap ecx", + "mov DWORD PTR [eax], ecx", "mov ecx, DWORD PTR [ebx]", - "mov edx, DWORD PTR [ebx+4]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax], edx", "mov DWORD PTR [eax+4], ecx", + "mov ecx, DWORD PTR [ebx+12]", + "bswap ecx", + "mov DWORD PTR [eax+8], ecx", "mov ecx, DWORD PTR [ebx+8]", - "mov edx, DWORD PTR [ebx+12]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+8], edx", "mov DWORD PTR [eax+12], ecx", + "mov ecx, DWORD PTR [ebx+20]", + "bswap ecx", + "mov DWORD PTR [eax+16], ecx", "mov ecx, DWORD PTR [ebx+16]", - "mov edx, DWORD PTR [ebx+20]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+16], edx", "mov DWORD PTR [eax+20], ecx", + "mov ecx, DWORD PTR [ebx+28]", + "bswap ecx", + "mov DWORD PTR [eax+24], ecx", "mov ecx, DWORD PTR [ebx+24]", - "mov edx, DWORD PTR [ebx+28]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+24], edx", "mov DWORD PTR [eax+28], ecx", + "mov ecx, DWORD PTR [ebx+36]", + "bswap ecx", + "mov DWORD PTR [eax+32], ecx", "mov ecx, DWORD PTR [ebx+32]", - "mov edx, DWORD PTR [ebx+36]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+32], edx", "mov DWORD PTR [eax+36], ecx", + "mov ecx, DWORD PTR [ebx+44]", + "bswap ecx", + "mov DWORD PTR [eax+40], ecx", "mov ecx, DWORD PTR [ebx+40]", - "mov edx, DWORD PTR [ebx+44]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+40], edx", "mov DWORD PTR [eax+44], ecx", + "mov ecx, DWORD PTR [ebx+52]", + "bswap ecx", + "mov DWORD PTR [eax+48], ecx", "mov ecx, DWORD PTR [ebx+48]", - "mov edx, DWORD PTR [ebx+52]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+48], edx", "mov DWORD PTR [eax+52], ecx", + "mov ecx, DWORD PTR [ebx+60]", + "bswap ecx", + "mov DWORD PTR [eax+56], ecx", "mov ecx, DWORD PTR [ebx+56]", - "mov edx, DWORD PTR [ebx+60]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+56], edx", "mov DWORD PTR [eax+60], ecx", "mov ecx, 128", "mov DWORD PTR [ebx+92], ecx", @@ -256,53 +256,53 @@ pub(crate) unsafe extern "C" fn vg_pbkdf2_hmac_sha512_224_iterate(key: *const [u "pop eax", "mov eax, ebx", "add eax, 64", + "mov ecx, DWORD PTR [ebx+4]", + "bswap ecx", + "mov DWORD PTR [eax], ecx", "mov ecx, DWORD PTR [ebx]", - "mov edx, DWORD PTR [ebx+4]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax], edx", "mov DWORD PTR [eax+4], ecx", + "mov ecx, DWORD PTR [ebx+12]", + "bswap ecx", + "mov DWORD PTR [eax+8], ecx", "mov ecx, DWORD PTR [ebx+8]", - "mov edx, DWORD PTR [ebx+12]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+8], edx", "mov DWORD PTR [eax+12], ecx", + "mov ecx, DWORD PTR [ebx+20]", + "bswap ecx", + "mov DWORD PTR [eax+16], ecx", "mov ecx, DWORD PTR [ebx+16]", - "mov edx, DWORD PTR [ebx+20]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+16], edx", "mov DWORD PTR [eax+20], ecx", + "mov ecx, DWORD PTR [ebx+28]", + "bswap ecx", + "mov DWORD PTR [eax+24], ecx", "mov ecx, DWORD PTR [ebx+24]", - "mov edx, DWORD PTR [ebx+28]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+24], edx", "mov DWORD PTR [eax+28], ecx", + "mov ecx, DWORD PTR [ebx+36]", + "bswap ecx", + "mov DWORD PTR [eax+32], ecx", "mov ecx, DWORD PTR [ebx+32]", - "mov edx, DWORD PTR [ebx+36]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+32], edx", "mov DWORD PTR [eax+36], ecx", + "mov ecx, DWORD PTR [ebx+44]", + "bswap ecx", + "mov DWORD PTR [eax+40], ecx", "mov ecx, DWORD PTR [ebx+40]", - "mov edx, DWORD PTR [ebx+44]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+40], edx", "mov DWORD PTR [eax+44], ecx", + "mov ecx, DWORD PTR [ebx+52]", + "bswap ecx", + "mov DWORD PTR [eax+48], ecx", "mov ecx, DWORD PTR [ebx+48]", - "mov edx, DWORD PTR [ebx+52]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+48], edx", "mov DWORD PTR [eax+52], ecx", + "mov ecx, DWORD PTR [ebx+60]", + "bswap ecx", + "mov DWORD PTR [eax+56], ecx", "mov ecx, DWORD PTR [ebx+56]", - "mov edx, DWORD PTR [ebx+60]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+56], edx", "mov DWORD PTR [eax+60], ecx", "mov ecx, 128", "mov DWORD PTR [ebx+92], ecx", diff --git a/src/asm/x86/pbkdf2_sha512_256.rs b/src/asm/x86/pbkdf2_sha512_256.rs index 24d398dd4..aa399e6d6 100644 --- a/src/asm/x86/pbkdf2_sha512_256.rs +++ b/src/asm/x86/pbkdf2_sha512_256.rs @@ -144,53 +144,53 @@ pub(crate) unsafe extern "C" fn vg_pbkdf2_hmac_sha512_256_iterate(key: *const [u "pop eax", "mov eax, ebx", "add eax, 64", + "mov ecx, DWORD PTR [ebx+4]", + "bswap ecx", + "mov DWORD PTR [eax], ecx", "mov ecx, DWORD PTR [ebx]", - "mov edx, DWORD PTR [ebx+4]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax], edx", "mov DWORD PTR [eax+4], ecx", + "mov ecx, DWORD PTR [ebx+12]", + "bswap ecx", + "mov DWORD PTR [eax+8], ecx", "mov ecx, DWORD PTR [ebx+8]", - "mov edx, DWORD PTR [ebx+12]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+8], edx", "mov DWORD PTR [eax+12], ecx", + "mov ecx, DWORD PTR [ebx+20]", + "bswap ecx", + "mov DWORD PTR [eax+16], ecx", "mov ecx, DWORD PTR [ebx+16]", - "mov edx, DWORD PTR [ebx+20]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+16], edx", "mov DWORD PTR [eax+20], ecx", + "mov ecx, DWORD PTR [ebx+28]", + "bswap ecx", + "mov DWORD PTR [eax+24], ecx", "mov ecx, DWORD PTR [ebx+24]", - "mov edx, DWORD PTR [ebx+28]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+24], edx", "mov DWORD PTR [eax+28], ecx", + "mov ecx, DWORD PTR [ebx+36]", + "bswap ecx", + "mov DWORD PTR [eax+32], ecx", "mov ecx, DWORD PTR [ebx+32]", - "mov edx, DWORD PTR [ebx+36]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+32], edx", "mov DWORD PTR [eax+36], ecx", + "mov ecx, DWORD PTR [ebx+44]", + "bswap ecx", + "mov DWORD PTR [eax+40], ecx", "mov ecx, DWORD PTR [ebx+40]", - "mov edx, DWORD PTR [ebx+44]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+40], edx", "mov DWORD PTR [eax+44], ecx", + "mov ecx, DWORD PTR [ebx+52]", + "bswap ecx", + "mov DWORD PTR [eax+48], ecx", "mov ecx, DWORD PTR [ebx+48]", - "mov edx, DWORD PTR [ebx+52]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+48], edx", "mov DWORD PTR [eax+52], ecx", + "mov ecx, DWORD PTR [ebx+60]", + "bswap ecx", + "mov DWORD PTR [eax+56], ecx", "mov ecx, DWORD PTR [ebx+56]", - "mov edx, DWORD PTR [ebx+60]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+56], edx", "mov DWORD PTR [eax+60], ecx", "mov ecx, 128", "mov DWORD PTR [ebx+96], ecx", @@ -254,53 +254,53 @@ pub(crate) unsafe extern "C" fn vg_pbkdf2_hmac_sha512_256_iterate(key: *const [u "pop eax", "mov eax, ebx", "add eax, 64", + "mov ecx, DWORD PTR [ebx+4]", + "bswap ecx", + "mov DWORD PTR [eax], ecx", "mov ecx, DWORD PTR [ebx]", - "mov edx, DWORD PTR [ebx+4]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax], edx", "mov DWORD PTR [eax+4], ecx", + "mov ecx, DWORD PTR [ebx+12]", + "bswap ecx", + "mov DWORD PTR [eax+8], ecx", "mov ecx, DWORD PTR [ebx+8]", - "mov edx, DWORD PTR [ebx+12]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+8], edx", "mov DWORD PTR [eax+12], ecx", + "mov ecx, DWORD PTR [ebx+20]", + "bswap ecx", + "mov DWORD PTR [eax+16], ecx", "mov ecx, DWORD PTR [ebx+16]", - "mov edx, DWORD PTR [ebx+20]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+16], edx", "mov DWORD PTR [eax+20], ecx", + "mov ecx, DWORD PTR [ebx+28]", + "bswap ecx", + "mov DWORD PTR [eax+24], ecx", "mov ecx, DWORD PTR [ebx+24]", - "mov edx, DWORD PTR [ebx+28]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+24], edx", "mov DWORD PTR [eax+28], ecx", + "mov ecx, DWORD PTR [ebx+36]", + "bswap ecx", + "mov DWORD PTR [eax+32], ecx", "mov ecx, DWORD PTR [ebx+32]", - "mov edx, DWORD PTR [ebx+36]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+32], edx", "mov DWORD PTR [eax+36], ecx", + "mov ecx, DWORD PTR [ebx+44]", + "bswap ecx", + "mov DWORD PTR [eax+40], ecx", "mov ecx, DWORD PTR [ebx+40]", - "mov edx, DWORD PTR [ebx+44]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+40], edx", "mov DWORD PTR [eax+44], ecx", + "mov ecx, DWORD PTR [ebx+52]", + "bswap ecx", + "mov DWORD PTR [eax+48], ecx", "mov ecx, DWORD PTR [ebx+48]", - "mov edx, DWORD PTR [ebx+52]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+48], edx", "mov DWORD PTR [eax+52], ecx", + "mov ecx, DWORD PTR [ebx+60]", + "bswap ecx", + "mov DWORD PTR [eax+56], ecx", "mov ecx, DWORD PTR [ebx+56]", - "mov edx, DWORD PTR [ebx+60]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+56], edx", "mov DWORD PTR [eax+60], ecx", "mov ecx, 128", "mov DWORD PTR [ebx+96], ecx", diff --git a/src/asm/x86/sha512.rs b/src/asm/x86/sha512.rs index 1327b8603..b1eec3baf 100644 --- a/src/asm/x86/sha512.rs +++ b/src/asm/x86/sha512.rs @@ -15320,38 +15320,100 @@ pub(crate) unsafe extern "C" fn vg_sha512_update(state: *mut [u8; 192], count: u "mov DWORD PTR [eax+232], edi", "mov DWORD PTR [eax+236], ebp", "mov ebx, DWORD PTR [esp+4]", + "mov ebp, DWORD PTR [esp+16]", + "mov esi, DWORD PTR [esp+20]", "mov edi, DWORD PTR [esp+8]", "and edi, 127", - "mov esi, DWORD PTR [esp+16]", - "mov ebp, DWORD PTR [esp+20]", - "test ebp, ebp", - "je 20f", - "22:", - "mov ecx, 128", - "sub ecx, edi", - "cmp ebp, ecx", + "20:", + "test edi, edi", + "je 21f", + "mov eax, 128", + "sub eax, edi", + "cmp esi, eax", "jb 23f", "jmp 24f", "23:", - "mov ecx, ebp", + "mov eax, esi", "24:", - "sub ebp, ecx", + "sub esi, eax", + "add edi, ebx", + "test eax, eax", + "je 25f", + "27:", + "movzx ecx, BYTE PTR [ebp]", + "mov BYTE PTR [edi+64], cl", + "add ebp, 1", + "add edi, 1", + "sub eax, 1", + "jne 27b", + "jmp 26f", "25:", - "movzx edx, BYTE PTR [esi]", + "26:", + "sub edi, ebx", + "mov ecx, 0", + "cmp edi, 128", + "je 28f", + "jmp 29f", + "28:", "mov eax, ebx", - "add eax, edi", - "mov BYTE PTR [eax+64], dl", - "add esi, 1", + "add eax, 64", + "mov edi, 0", + "mov ecx, 1", + "29:", + "jmp 22f", + "21:", + "cmp esi, 128", + "jae 210f", + "mov eax, 128", + "sub eax, edi", + "cmp esi, eax", + "jb 212f", + "jmp 213f", + "212:", + "mov eax, esi", + "213:", + "sub esi, eax", + "add edi, ebx", + "test eax, eax", + "je 214f", + "216:", + "movzx ecx, BYTE PTR [ebp]", + "mov BYTE PTR [edi+64], cl", + "add ebp, 1", "add edi, 1", - "sub ecx, 1", - "jne 25b", + "sub eax, 1", + "jne 216b", + "jmp 215f", + "214:", + "215:", + "sub edi, ebx", + "mov ecx, 0", "cmp edi, 128", - "je 26f", - "jmp 27f", - "26:", + "je 217f", + "jmp 218f", + "217:", "mov eax, ebx", "add eax, 64", + "mov edi, 0", "mov ecx, 1", + "218:", + "jmp 211f", + "210:", + "mov eax, ebp", + "mov ecx, esi", + "and ecx, 127", + "mov edx, esi", + "sub edx, ecx", + "add ebp, edx", + "mov esi, ecx", + "mov ecx, edx", + "shr ecx, 7", + "211:", + "22:", + "test ecx, ecx", + "jne 219f", + "jmp 220f", + "219:", "mov edx, DWORD PTR [esp+24]", "push edx", "push ecx", @@ -15362,13 +15424,10 @@ pub(crate) unsafe extern "C" fn vg_sha512_update(state: *mut [u8; 192], count: u "pop eax", "pop eax", "pop eax", - "mov edi, 0", - "27:", - "test ebp, ebp", - "jne 22b", - "jmp 21f", - "20:", - "21:", + "mov ecx, 1", + "test ecx, ecx", + "220:", + "jne 20b", "mov eax, DWORD PTR [esp+24]", "mov ebx, DWORD PTR [eax+224]", "mov esi, DWORD PTR [eax+228]", @@ -15401,13 +15460,20 @@ pub(crate) unsafe extern "C" fn vg_sha512_finalize(state: *mut [u8; 192], count: "mov DWORD PTR [eax+228], esi", "mov DWORD PTR [eax+232], edi", "mov DWORD PTR [eax+236], ebp", + "mov ebp, eax", "mov ebx, DWORD PTR [esp+4]", + "mov ecx, DWORD PTR [esp+8]", + "mov DWORD PTR [ebp+240], ecx", + "mov ecx, DWORD PTR [esp+12]", + "mov DWORD PTR [ebp+244], ecx", + "mov ecx, DWORD PTR [esp+16]", + "mov DWORD PTR [ebp+248], ecx", "mov edi, DWORD PTR [esp+8]", "and edi, 127", - "mov eax, ebx", - "add eax, edi", + "mov edx, ebx", + "add edx, edi", "mov ecx, 128", - "mov BYTE PTR [eax+64], cl", + "mov BYTE PTR [edx+64], cl", "add edi, 1", "mov esi, 0", "cmp edi, 113", @@ -15441,8 +15507,8 @@ pub(crate) unsafe extern "C" fn vg_sha512_finalize(state: *mut [u8; 192], count: "je 28f", "jmp 29f", "28:", - "mov eax, DWORD PTR [esp+8]", - "mov ecx, DWORD PTR [esp+12]", + "mov eax, DWORD PTR [ebp+240]", + "mov ecx, DWORD PTR [ebp+244]", "mov edx, 0", "mov DWORD PTR [ebx+176], edx", "mov edx, ecx", @@ -15455,19 +15521,18 @@ pub(crate) unsafe extern "C" fn vg_sha512_finalize(state: *mut [u8; 192], count: "mov edx, eax", "shr edx, 29", "or ecx, edx", - "bswap ecx", - "mov DWORD PTR [ebx+184], ecx", "add eax, eax", "add eax, eax", "add eax, eax", + "bswap ecx", + "mov DWORD PTR [ebx+184], ecx", "bswap eax", "mov DWORD PTR [ebx+188], eax", "29:", "mov eax, ebx", "add eax, 64", "mov ecx, 1", - "mov edx, DWORD PTR [esp+20]", - "push edx", + "push ebp", "push ecx", "push eax", "push ebx", @@ -15479,60 +15544,59 @@ pub(crate) unsafe extern "C" fn vg_sha512_finalize(state: *mut [u8; 192], count: "mov edi, 0", "sub esi, 1", "je 22b", - "mov eax, DWORD PTR [esp+16]", + "mov eax, DWORD PTR [ebp+248]", + "mov ecx, DWORD PTR [ebx+4]", + "bswap ecx", + "mov DWORD PTR [eax], ecx", "mov ecx, DWORD PTR [ebx]", - "mov edx, DWORD PTR [ebx+4]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax], edx", "mov DWORD PTR [eax+4], ecx", + "mov ecx, DWORD PTR [ebx+12]", + "bswap ecx", + "mov DWORD PTR [eax+8], ecx", "mov ecx, DWORD PTR [ebx+8]", - "mov edx, DWORD PTR [ebx+12]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+8], edx", "mov DWORD PTR [eax+12], ecx", + "mov ecx, DWORD PTR [ebx+20]", + "bswap ecx", + "mov DWORD PTR [eax+16], ecx", "mov ecx, DWORD PTR [ebx+16]", - "mov edx, DWORD PTR [ebx+20]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+16], edx", "mov DWORD PTR [eax+20], ecx", + "mov ecx, DWORD PTR [ebx+28]", + "bswap ecx", + "mov DWORD PTR [eax+24], ecx", "mov ecx, DWORD PTR [ebx+24]", - "mov edx, DWORD PTR [ebx+28]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+24], edx", "mov DWORD PTR [eax+28], ecx", + "mov ecx, DWORD PTR [ebx+36]", + "bswap ecx", + "mov DWORD PTR [eax+32], ecx", "mov ecx, DWORD PTR [ebx+32]", - "mov edx, DWORD PTR [ebx+36]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+32], edx", "mov DWORD PTR [eax+36], ecx", + "mov ecx, DWORD PTR [ebx+44]", + "bswap ecx", + "mov DWORD PTR [eax+40], ecx", "mov ecx, DWORD PTR [ebx+40]", - "mov edx, DWORD PTR [ebx+44]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+40], edx", "mov DWORD PTR [eax+44], ecx", + "mov ecx, DWORD PTR [ebx+52]", + "bswap ecx", + "mov DWORD PTR [eax+48], ecx", "mov ecx, DWORD PTR [ebx+48]", - "mov edx, DWORD PTR [ebx+52]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+48], edx", "mov DWORD PTR [eax+52], ecx", + "mov ecx, DWORD PTR [ebx+60]", + "bswap ecx", + "mov DWORD PTR [eax+56], ecx", "mov ecx, DWORD PTR [ebx+56]", - "mov edx, DWORD PTR [ebx+60]", - "bswap edx", "bswap ecx", - "mov DWORD PTR [eax+56], edx", "mov DWORD PTR [eax+60], ecx", - "mov eax, DWORD PTR [esp+20]", - "mov ebx, DWORD PTR [eax+224]", - "mov esi, DWORD PTR [eax+228]", - "mov edi, DWORD PTR [eax+232]", - "mov ebp, DWORD PTR [eax+236]", + "mov ebx, DWORD PTR [ebp+224]", + "mov esi, DWORD PTR [ebp+228]", + "mov edi, DWORD PTR [ebp+232]", + "mov ebp, DWORD PTR [ebp+236]", "ret", vg_sha512_compress = sym super::sha512::vg_sha512_compress, )