From c989d1f82599ed365d7f65482f7c51866746b609 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 2 Oct 2026 06:44:53 +0000 Subject: [PATCH] x86: HMAC finalize and PBKDF2 iterate over the compression function On 32-bit x86, HMAC's `finalize` and PBKDF2's `iterate` for MD5, SHA-1, SHA-384, SHA-512, SHA-512/224 and SHA-512/256 are now written once over a description of a Merkle-Damgard hash function (`Impl/Pbkdf2/Md/X86.lean`: its streaming functions, hash value and length-field sizes, byte order, compression function and digest code), proven once against `Proof.MdStream.Md` and instantiated per hash. * `iterate` lays the block out once (U, 0x80, zeros, the length of a B + D-byte message), and each step is two compressions: the key's inner hash value with that block, then the outer one with the digest written word by word into it. The padding a truncated digest overwrites is written back, and T ^= U is computed word by word. * HMAC `finalize` calls the streaming `finalize` for the inner hash, then computes the outer hash with one compression of a fixed-layout block: the outer hash value and the digest copied word by word, the padding and length written as word stores, the MAC written to `out` (or, truncated, to scratch and copied). The whole PBKDF2 derivation calls the new functions. The streaming-level x86 `iterate` (`Impl/Pbkdf2/Generic/X86.lean`) and HMAC `finalize`, and their proofs, are removed; HMAC's `init` is unchanged. No change to TCB/ or Spec/, to the contracts, or to other targets. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01RjfTK5YMk2jDsiKRYs2dbn --- .../Artifacts/HmacMd5/X86.lean | 16 +- .../Artifacts/HmacSha1/X86.lean | 16 +- .../Artifacts/HmacSha384/X86.lean | 16 +- .../Artifacts/HmacSha512/X86.lean | 16 +- .../Artifacts/HmacSha512_224/X86.lean | 16 +- .../Artifacts/HmacSha512_256/X86.lean | 16 +- .../Artifacts/Pbkdf2Md5/X86.lean | 14 +- .../Artifacts/Pbkdf2Sha1/X86.lean | 14 +- .../Artifacts/Pbkdf2Sha384/X86.lean | 14 +- .../Artifacts/Pbkdf2Sha512/X86.lean | 14 +- .../Artifacts/Pbkdf2Sha512_224/X86.lean | 14 +- .../Artifacts/Pbkdf2Sha512_256/X86.lean | 14 +- .../Impl/Hmac/Generic/X86.lean | 28 +- .../Impl/Pbkdf2/Generic/X86.lean | 79 -- lean/VerifiedGarbage/Impl/Pbkdf2/Md/X86.lean | 192 ++++ .../Proof/Hmac/Generic/X86/Finalize.lean | 218 +---- .../Proof/Hmac/Generic/X86/FinalizeCT.lean | 479 ---------- .../Proof/Hmac/Generic/X86/Hash.lean | 2 +- .../Proof/Hmac/Generic/X86/InitCT.lean | 225 +++++ .../Proof/Hmac/Generic/X86/Instances.lean | 142 +-- .../Proof/Hmac/Generic/X86/Lit.lean | 24 +- .../Proof/Pbkdf2/Generic/X86/Instances.lean | 219 ----- .../Proof/Pbkdf2/Generic/X86/Iterate.lean | 770 ---------------- .../Proof/Pbkdf2/Generic/X86/IterateCT.lean | 329 ------- .../Proof/Pbkdf2/Md/X86/Block.lean | 540 ++++++++++++ .../Proof/Pbkdf2/Md/X86/Hashes.lean | 247 ++++++ .../Proof/Pbkdf2/Md/X86/HmacFin.lean | 370 ++++++++ .../Proof/Pbkdf2/Md/X86/HmacFinCT.lean | 213 +++++ .../Proof/Pbkdf2/Md/X86/Instances.lean | 291 +++++++ .../Proof/Pbkdf2/Md/X86/Iterate.lean | 819 ++++++++++++++++++ .../Proof/Pbkdf2/Md/X86/IterateCT.lean | 289 ++++++ .../Proof/Pbkdf2/Md/X86/Lit.lean | 30 + lean/VerifiedGarbage/Proof/Pbkdf2/MdHmac.lean | 54 ++ .../Proof/Pbkdf2/Whole/X86/CT.lean | 2 +- .../Proof/Pbkdf2/Whole/X86/Instances.lean | 28 +- .../Proof/Pbkdf2/Whole/X86/Lit.lean | 36 +- src/asm/x86/hmac_md5.rs | 96 +- src/asm/x86/hmac_sha1.rs | 105 ++- src/asm/x86/hmac_sha384.rs | 219 ++++- src/asm/x86/hmac_sha512.rs | 192 +++- src/asm/x86/hmac_sha512_224.rs | 209 ++++- src/asm/x86/hmac_sha512_256.rs | 211 ++++- src/asm/x86/pbkdf2_md5.rs | 224 +++-- src/asm/x86/pbkdf2_sha1.rs | 245 +++--- src/asm/x86/pbkdf2_sha384.rs | 420 ++++++--- src/asm/x86/pbkdf2_sha512.rs | 420 ++++++--- src/asm/x86/pbkdf2_sha512_224.rs | 425 ++++++--- src/asm/x86/pbkdf2_sha512_256.rs | 424 ++++++--- 48 files changed, 5653 insertions(+), 3343 deletions(-) delete mode 100644 lean/VerifiedGarbage/Impl/Pbkdf2/Generic/X86.lean create mode 100644 lean/VerifiedGarbage/Impl/Pbkdf2/Md/X86.lean delete mode 100644 lean/VerifiedGarbage/Proof/Hmac/Generic/X86/FinalizeCT.lean create mode 100644 lean/VerifiedGarbage/Proof/Hmac/Generic/X86/InitCT.lean delete mode 100644 lean/VerifiedGarbage/Proof/Pbkdf2/Generic/X86/Instances.lean delete mode 100644 lean/VerifiedGarbage/Proof/Pbkdf2/Generic/X86/Iterate.lean delete mode 100644 lean/VerifiedGarbage/Proof/Pbkdf2/Generic/X86/IterateCT.lean create mode 100644 lean/VerifiedGarbage/Proof/Pbkdf2/Md/X86/Block.lean create mode 100644 lean/VerifiedGarbage/Proof/Pbkdf2/Md/X86/Hashes.lean create mode 100644 lean/VerifiedGarbage/Proof/Pbkdf2/Md/X86/HmacFin.lean create mode 100644 lean/VerifiedGarbage/Proof/Pbkdf2/Md/X86/HmacFinCT.lean create mode 100644 lean/VerifiedGarbage/Proof/Pbkdf2/Md/X86/Instances.lean create mode 100644 lean/VerifiedGarbage/Proof/Pbkdf2/Md/X86/Iterate.lean create mode 100644 lean/VerifiedGarbage/Proof/Pbkdf2/Md/X86/IterateCT.lean create mode 100644 lean/VerifiedGarbage/Proof/Pbkdf2/Md/X86/Lit.lean create mode 100644 lean/VerifiedGarbage/Proof/Pbkdf2/MdHmac.lean diff --git a/lean/VerifiedGarbage/Artifacts/HmacMd5/X86.lean b/lean/VerifiedGarbage/Artifacts/HmacMd5/X86.lean index 9fecdc4eb..7525f3565 100644 --- a/lean/VerifiedGarbage/Artifacts/HmacMd5/X86.lean +++ b/lean/VerifiedGarbage/Artifacts/HmacMd5/X86.lean @@ -1,5 +1,6 @@ import VerifiedGarbage.TCB.X86.Target import VerifiedGarbage.Proof.Hmac.Generic.X86.Instances +import VerifiedGarbage.Proof.Pbkdf2.Md.X86.Instances /-! # HMAC-MD5 (RFC 2104) on x86 @@ -14,9 +15,14 @@ target (`Sig.layoutDoc`), from `stack` and `writeArgs`, which `ofSig` checks against the contract (after unfolding the `Instance`'s contract to the generic one, which is a `Sig.contract`). -The code is the one HMAC implementation for every streaming hash function -(`Impl/Hmac/Generic/X86.lean`), calling MD5's verified `init`, `update` -and `finalize`. +`init` is the one HMAC implementation for every streaming hash function +(`Impl/Hmac/Generic/X86.lean`), calling MD5's verified `init` and `update`. +`finalize` is the one for every Merkle–Damgård hash function +(`Impl/Pbkdf2/Md/X86.lean`): it calls MD5's verified streaming `finalize` +for the inner hash, then computes the outer hash with one call of MD5's +verified compression function, on a block it lays out word by word in +`scratch`: the outer key's hash value, the inner digest, its padding and +length. -/ namespace VG.Artifacts.HmacMd5.X86 @@ -36,11 +42,11 @@ def artifacts : List Artifact := [ { Spec.Hmac.md5I.finalizeApi with target := X86.target doc := Spec.Hmac.md5I.finalizeApi.doc - code := md5H.finalize + code := Proof.Pbkdf2.Md.X86.md5M.hmacFin contract := Spec.Hmac.md5I.finalizeContract X86.abi 48 ofSig := ⟨_, _, _, by unfold Spec.Hmac.Instance.finalizeContract; rfl⟩ stack := 48 - verified := Instances.md5_finalize + verified := Proof.Pbkdf2.Md.X86.Instances.md5_finalize spSafe := Code.all_of_allInstrs (by lit_decide) }] end VG.Artifacts.HmacMd5.X86 diff --git a/lean/VerifiedGarbage/Artifacts/HmacSha1/X86.lean b/lean/VerifiedGarbage/Artifacts/HmacSha1/X86.lean index 09f482a4b..96dccccf4 100644 --- a/lean/VerifiedGarbage/Artifacts/HmacSha1/X86.lean +++ b/lean/VerifiedGarbage/Artifacts/HmacSha1/X86.lean @@ -1,5 +1,6 @@ import VerifiedGarbage.TCB.X86.Target import VerifiedGarbage.Proof.Hmac.Generic.X86.Instances +import VerifiedGarbage.Proof.Pbkdf2.Md.X86.Instances /-! # HMAC-SHA-1 (RFC 2104) on x86 @@ -14,9 +15,14 @@ target (`Sig.layoutDoc`), from `stack` and `writeArgs`, which `ofSig` checks against the contract (after unfolding the `Instance`'s contract to the generic one, which is a `Sig.contract`). -The code is the one HMAC implementation for every streaming hash function -(`Impl/Hmac/Generic/X86.lean`), calling SHA-1's verified `init`, `update` -and `finalize`. +`init` is the one HMAC implementation for every streaming hash function +(`Impl/Hmac/Generic/X86.lean`), calling SHA-1's verified `init` and `update`. +`finalize` is the one for every Merkle–Damgård hash function +(`Impl/Pbkdf2/Md/X86.lean`): it calls SHA-1's verified streaming `finalize` +for the inner hash, then computes the outer hash with one call of SHA-1's +verified compression function, on a block it lays out word by word in +`scratch`: the outer key's hash value, the inner digest, its padding and +length. -/ namespace VG.Artifacts.HmacSha1.X86 @@ -36,11 +42,11 @@ def artifacts : List Artifact := [ { Spec.Hmac.sha1I.finalizeApi with target := X86.target doc := Spec.Hmac.sha1I.finalizeApi.doc - code := sha1H.finalize + code := Proof.Pbkdf2.Md.X86.sha1M.hmacFin contract := Spec.Hmac.sha1I.finalizeContract X86.abi 48 ofSig := ⟨_, _, _, by unfold Spec.Hmac.Instance.finalizeContract; rfl⟩ stack := 48 - verified := Instances.sha1_finalize + verified := Proof.Pbkdf2.Md.X86.Instances.sha1_finalize spSafe := Code.all_of_allInstrs (by lit_decide) }] end VG.Artifacts.HmacSha1.X86 diff --git a/lean/VerifiedGarbage/Artifacts/HmacSha384/X86.lean b/lean/VerifiedGarbage/Artifacts/HmacSha384/X86.lean index 32bbcdedc..22d0319ec 100644 --- a/lean/VerifiedGarbage/Artifacts/HmacSha384/X86.lean +++ b/lean/VerifiedGarbage/Artifacts/HmacSha384/X86.lean @@ -1,5 +1,6 @@ import VerifiedGarbage.TCB.X86.Target import VerifiedGarbage.Proof.Hmac.Generic.X86.Instances +import VerifiedGarbage.Proof.Pbkdf2.Md.X86.Instances /-! # HMAC-SHA-384 (RFC 2104) on x86 @@ -14,9 +15,14 @@ target (`Sig.layoutDoc`), from `stack` and `writeArgs`, which `ofSig` checks against the contract (after unfolding the `Instance`'s contract to the generic one, which is a `Sig.contract`). -The code is the one HMAC implementation for every streaming hash function -(`Impl/Hmac/Generic/X86.lean`), calling SHA-384's verified `init`, `update` -and `finalize`. +`init` is the one HMAC implementation for every streaming hash function +(`Impl/Hmac/Generic/X86.lean`), calling SHA-384's verified `init` and `update`. +`finalize` is the one for every Merkle–Damgård hash function +(`Impl/Pbkdf2/Md/X86.lean`): it calls SHA-384's verified streaming `finalize` +for the inner hash, then computes the outer hash with one call of SHA-384's +verified compression function, on a block it lays out word by word in +`scratch`: the outer key's hash value, the inner digest, its padding and +length. -/ namespace VG.Artifacts.HmacSha384.X86 @@ -36,11 +42,11 @@ def artifacts : List Artifact := [ { Spec.Hmac.sha384I.finalizeApi with target := X86.target doc := Spec.Hmac.sha384I.finalizeApi.doc - code := sha384H.finalize + code := Proof.Pbkdf2.Md.X86.sha384M.hmacFin contract := Spec.Hmac.sha384I.finalizeContract X86.abi 48 ofSig := ⟨_, _, _, by unfold Spec.Hmac.Instance.finalizeContract; rfl⟩ stack := 48 - verified := Instances.sha384_finalize + verified := Proof.Pbkdf2.Md.X86.Instances.sha384_finalize spSafe := Code.all_of_allInstrs (by lit_decide) }] end VG.Artifacts.HmacSha384.X86 diff --git a/lean/VerifiedGarbage/Artifacts/HmacSha512/X86.lean b/lean/VerifiedGarbage/Artifacts/HmacSha512/X86.lean index 6667e2bb8..74d619afb 100644 --- a/lean/VerifiedGarbage/Artifacts/HmacSha512/X86.lean +++ b/lean/VerifiedGarbage/Artifacts/HmacSha512/X86.lean @@ -1,5 +1,6 @@ import VerifiedGarbage.TCB.X86.Target import VerifiedGarbage.Proof.Hmac.Generic.X86.Instances +import VerifiedGarbage.Proof.Pbkdf2.Md.X86.Instances /-! # HMAC-SHA-512 (RFC 2104) on x86 @@ -14,9 +15,14 @@ target (`Sig.layoutDoc`), from `stack` and `writeArgs`, which `ofSig` checks against the contract (after unfolding the `Instance`'s contract to the generic one, which is a `Sig.contract`). -The code is the one HMAC implementation for every streaming hash function -(`Impl/Hmac/Generic/X86.lean`), calling SHA-512's verified `init`, `update` -and `finalize`. +`init` is the one HMAC implementation for every streaming hash function +(`Impl/Hmac/Generic/X86.lean`), calling SHA-512's verified `init` and `update`. +`finalize` is the one for every Merkle–Damgård hash function +(`Impl/Pbkdf2/Md/X86.lean`): it calls SHA-512's verified streaming `finalize` +for the inner hash, then computes the outer hash with one call of SHA-512's +verified compression function, on a block it lays out word by word in +`scratch`: the outer key's hash value, the inner digest, its padding and +length. -/ namespace VG.Artifacts.HmacSha512.X86 @@ -36,11 +42,11 @@ def artifacts : List Artifact := [ { Spec.Hmac.sha512I.finalizeApi with target := X86.target doc := Spec.Hmac.sha512I.finalizeApi.doc - code := sha512H'.finalize + code := Proof.Pbkdf2.Md.X86.sha512M'.hmacFin contract := Spec.Hmac.sha512I.finalizeContract X86.abi 48 ofSig := ⟨_, _, _, by unfold Spec.Hmac.Instance.finalizeContract; rfl⟩ stack := 48 - verified := Instances.sha512_finalize + verified := Proof.Pbkdf2.Md.X86.Instances.sha512_finalize spSafe := Code.all_of_allInstrs (by lit_decide) }] end VG.Artifacts.HmacSha512.X86 diff --git a/lean/VerifiedGarbage/Artifacts/HmacSha512_224/X86.lean b/lean/VerifiedGarbage/Artifacts/HmacSha512_224/X86.lean index e561e729b..f094f463c 100644 --- a/lean/VerifiedGarbage/Artifacts/HmacSha512_224/X86.lean +++ b/lean/VerifiedGarbage/Artifacts/HmacSha512_224/X86.lean @@ -1,5 +1,6 @@ import VerifiedGarbage.TCB.X86.Target import VerifiedGarbage.Proof.Hmac.Generic.X86.Instances +import VerifiedGarbage.Proof.Pbkdf2.Md.X86.Instances /-! # HMAC-SHA-512/224 (RFC 2104) on x86 @@ -14,9 +15,14 @@ target (`Sig.layoutDoc`), from `stack` and `writeArgs`, which `ofSig` checks against the contract (after unfolding the `Instance`'s contract to the generic one, which is a `Sig.contract`). -The code is the one HMAC implementation for every streaming hash function -(`Impl/Hmac/Generic/X86.lean`), calling SHA-512/224's verified `init`, `update` -and `finalize`. +`init` is the one HMAC implementation for every streaming hash function +(`Impl/Hmac/Generic/X86.lean`), calling SHA-512/224's verified `init` and `update`. +`finalize` is the one for every Merkle–Damgård hash function +(`Impl/Pbkdf2/Md/X86.lean`): it calls SHA-512/224's verified streaming `finalize` +for the inner hash, then computes the outer hash with one call of SHA-512/224's +verified compression function, on a block it lays out word by word in +`scratch`: the outer key's hash value, the inner digest, its padding and +length. -/ namespace VG.Artifacts.HmacSha512_224.X86 @@ -36,11 +42,11 @@ def artifacts : List Artifact := [ { Spec.Hmac.sha512_224I.finalizeApi with target := X86.target doc := Spec.Hmac.sha512_224I.finalizeApi.doc - code := sha512_224H.finalize + code := Proof.Pbkdf2.Md.X86.sha512_224M.hmacFin contract := Spec.Hmac.sha512_224I.finalizeContract X86.abi 48 ofSig := ⟨_, _, _, by unfold Spec.Hmac.Instance.finalizeContract; rfl⟩ stack := 48 - verified := Instances.sha512_224_finalize + verified := Proof.Pbkdf2.Md.X86.Instances.sha512_224_finalize spSafe := Code.all_of_allInstrs (by lit_decide) }] end VG.Artifacts.HmacSha512_224.X86 diff --git a/lean/VerifiedGarbage/Artifacts/HmacSha512_256/X86.lean b/lean/VerifiedGarbage/Artifacts/HmacSha512_256/X86.lean index 56b84ccb6..bd842e001 100644 --- a/lean/VerifiedGarbage/Artifacts/HmacSha512_256/X86.lean +++ b/lean/VerifiedGarbage/Artifacts/HmacSha512_256/X86.lean @@ -1,5 +1,6 @@ import VerifiedGarbage.TCB.X86.Target import VerifiedGarbage.Proof.Hmac.Generic.X86.Instances +import VerifiedGarbage.Proof.Pbkdf2.Md.X86.Instances /-! # HMAC-SHA-512/256 (RFC 2104) on x86 @@ -14,9 +15,14 @@ target (`Sig.layoutDoc`), from `stack` and `writeArgs`, which `ofSig` checks against the contract (after unfolding the `Instance`'s contract to the generic one, which is a `Sig.contract`). -The code is the one HMAC implementation for every streaming hash function -(`Impl/Hmac/Generic/X86.lean`), calling SHA-512/256's verified `init`, `update` -and `finalize`. +`init` is the one HMAC implementation for every streaming hash function +(`Impl/Hmac/Generic/X86.lean`), calling SHA-512/256's verified `init` and `update`. +`finalize` is the one for every Merkle–Damgård hash function +(`Impl/Pbkdf2/Md/X86.lean`): it calls SHA-512/256's verified streaming `finalize` +for the inner hash, then computes the outer hash with one call of SHA-512/256's +verified compression function, on a block it lays out word by word in +`scratch`: the outer key's hash value, the inner digest, its padding and +length. -/ namespace VG.Artifacts.HmacSha512_256.X86 @@ -36,11 +42,11 @@ def artifacts : List Artifact := [ { Spec.Hmac.sha512_256I.finalizeApi with target := X86.target doc := Spec.Hmac.sha512_256I.finalizeApi.doc - code := sha512_256H.finalize + code := Proof.Pbkdf2.Md.X86.sha512_256M.hmacFin contract := Spec.Hmac.sha512_256I.finalizeContract X86.abi 48 ofSig := ⟨_, _, _, by unfold Spec.Hmac.Instance.finalizeContract; rfl⟩ stack := 48 - verified := Instances.sha512_256_finalize + verified := Proof.Pbkdf2.Md.X86.Instances.sha512_256_finalize spSafe := Code.all_of_allInstrs (by lit_decide) }] end VG.Artifacts.HmacSha512_256.X86 diff --git a/lean/VerifiedGarbage/Artifacts/Pbkdf2Md5/X86.lean b/lean/VerifiedGarbage/Artifacts/Pbkdf2Md5/X86.lean index 97f1bd8b1..db1877915 100644 --- a/lean/VerifiedGarbage/Artifacts/Pbkdf2Md5/X86.lean +++ b/lean/VerifiedGarbage/Artifacts/Pbkdf2Md5/X86.lean @@ -1,5 +1,5 @@ import VerifiedGarbage.TCB.X86.Target -import VerifiedGarbage.Proof.Pbkdf2.Generic.X86.Instances +import VerifiedGarbage.Proof.Pbkdf2.Md.X86.Instances import VerifiedGarbage.Proof.Pbkdf2.Whole.X86.Instances /-! @@ -15,9 +15,11 @@ target (`Sig.layoutDoc`), from `stack` and `writeArgs`, which `ofSig` checks against the contract (after unfolding the `Instance`'s contract to the generic one, which is a `Sig.contract`). -The code is the one PBKDF2 iteration for every streaming hash function -(`Impl/Pbkdf2/Generic/X86.lean`), calling MD5's verified `update` and -`finalize`. +The iteration is the one for every Merkle–Damgård hash function +(`Impl/Pbkdf2/Md/X86.lean`): each step is two calls of MD5's verified +compression function, on a block laid out once, word by word, in `scratch` +(`U`, its padding and length), starting from the key's inner and outer hash +values. The whole derivation, `pbkdf2`, is the one for every streaming hash function (`Impl/Pbkdf2/Whole/X86.lean`), calling the hash function's streaming @@ -35,11 +37,11 @@ def artifacts : List Artifact := [ { Spec.Hmac.md5I.iterateApi with target := X86.target doc := Spec.Hmac.md5I.iterateApi.doc - code := Impl.Pbkdf2.Generic.X86.iterate md5H + code := Proof.Pbkdf2.Md.X86.md5M.iterate contract := Spec.Hmac.md5I.iterateContract X86.abi 48 ofSig := ⟨_, _, _, by unfold Spec.Hmac.Instance.iterateContract; rfl⟩ stack := 48 - verified := Proof.Pbkdf2.Generic.X86.Instances.md5 + verified := Proof.Pbkdf2.Md.X86.Instances.md5_iterate spSafe := Code.all_of_allInstrs (by lit_decide) }, { Spec.Hmac.md5I.pbkdf2Api with target := X86.target diff --git a/lean/VerifiedGarbage/Artifacts/Pbkdf2Sha1/X86.lean b/lean/VerifiedGarbage/Artifacts/Pbkdf2Sha1/X86.lean index 11102a37f..83c493eb3 100644 --- a/lean/VerifiedGarbage/Artifacts/Pbkdf2Sha1/X86.lean +++ b/lean/VerifiedGarbage/Artifacts/Pbkdf2Sha1/X86.lean @@ -1,5 +1,5 @@ import VerifiedGarbage.TCB.X86.Target -import VerifiedGarbage.Proof.Pbkdf2.Generic.X86.Instances +import VerifiedGarbage.Proof.Pbkdf2.Md.X86.Instances import VerifiedGarbage.Proof.Pbkdf2.Whole.X86.Instances /-! @@ -15,9 +15,11 @@ target (`Sig.layoutDoc`), from `stack` and `writeArgs`, which `ofSig` checks against the contract (after unfolding the `Instance`'s contract to the generic one, which is a `Sig.contract`). -The code is the one PBKDF2 iteration for every streaming hash function -(`Impl/Pbkdf2/Generic/X86.lean`), calling SHA-1's verified `update` and -`finalize`. +The iteration is the one for every Merkle–Damgård hash function +(`Impl/Pbkdf2/Md/X86.lean`): each step is two calls of SHA-1's verified +compression function, on a block laid out once, word by word, in `scratch` +(`U`, its padding and length), starting from the key's inner and outer hash +values. The whole derivation, `pbkdf2`, is the one for every streaming hash function (`Impl/Pbkdf2/Whole/X86.lean`), calling the hash function's streaming @@ -35,11 +37,11 @@ def artifacts : List Artifact := [ { Spec.Hmac.sha1I.iterateApi with target := X86.target doc := Spec.Hmac.sha1I.iterateApi.doc - code := Impl.Pbkdf2.Generic.X86.iterate sha1H + code := Proof.Pbkdf2.Md.X86.sha1M.iterate contract := Spec.Hmac.sha1I.iterateContract X86.abi 48 ofSig := ⟨_, _, _, by unfold Spec.Hmac.Instance.iterateContract; rfl⟩ stack := 48 - verified := Proof.Pbkdf2.Generic.X86.Instances.sha1 + verified := Proof.Pbkdf2.Md.X86.Instances.sha1_iterate spSafe := Code.all_of_allInstrs (by lit_decide) }, { Spec.Hmac.sha1I.pbkdf2Api with target := X86.target diff --git a/lean/VerifiedGarbage/Artifacts/Pbkdf2Sha384/X86.lean b/lean/VerifiedGarbage/Artifacts/Pbkdf2Sha384/X86.lean index 71b7c68ba..e8d132e2d 100644 --- a/lean/VerifiedGarbage/Artifacts/Pbkdf2Sha384/X86.lean +++ b/lean/VerifiedGarbage/Artifacts/Pbkdf2Sha384/X86.lean @@ -1,5 +1,5 @@ import VerifiedGarbage.TCB.X86.Target -import VerifiedGarbage.Proof.Pbkdf2.Generic.X86.Instances +import VerifiedGarbage.Proof.Pbkdf2.Md.X86.Instances import VerifiedGarbage.Proof.Pbkdf2.Whole.X86.Instances /-! @@ -15,9 +15,11 @@ target (`Sig.layoutDoc`), from `stack` and `writeArgs`, which `ofSig` checks against the contract (after unfolding the `Instance`'s contract to the generic one, which is a `Sig.contract`). -The code is the one PBKDF2 iteration for every streaming hash function -(`Impl/Pbkdf2/Generic/X86.lean`), calling SHA-384's verified `update` and -`finalize`. +The iteration is the one for every Merkle–Damgård hash function +(`Impl/Pbkdf2/Md/X86.lean`): each step is two calls of SHA-384's verified +compression function, on a block laid out once, word by word, in `scratch` +(`U`, its padding and length), starting from the key's inner and outer hash +values. The whole derivation, `pbkdf2`, is the one for every streaming hash function (`Impl/Pbkdf2/Whole/X86.lean`), calling the hash function's streaming @@ -35,11 +37,11 @@ def artifacts : List Artifact := [ { Spec.Hmac.sha384I.iterateApi with target := X86.target doc := Spec.Hmac.sha384I.iterateApi.doc - code := Impl.Pbkdf2.Generic.X86.iterate sha384H + code := Proof.Pbkdf2.Md.X86.sha384M.iterate contract := Spec.Hmac.sha384I.iterateContract X86.abi 48 ofSig := ⟨_, _, _, by unfold Spec.Hmac.Instance.iterateContract; rfl⟩ stack := 48 - verified := Proof.Pbkdf2.Generic.X86.Instances.sha384 + verified := Proof.Pbkdf2.Md.X86.Instances.sha384_iterate spSafe := Code.all_of_allInstrs (by lit_decide) }, { Spec.Hmac.sha384I.pbkdf2Api with target := X86.target diff --git a/lean/VerifiedGarbage/Artifacts/Pbkdf2Sha512/X86.lean b/lean/VerifiedGarbage/Artifacts/Pbkdf2Sha512/X86.lean index 4418aac75..7ffded97a 100644 --- a/lean/VerifiedGarbage/Artifacts/Pbkdf2Sha512/X86.lean +++ b/lean/VerifiedGarbage/Artifacts/Pbkdf2Sha512/X86.lean @@ -1,5 +1,5 @@ import VerifiedGarbage.TCB.X86.Target -import VerifiedGarbage.Proof.Pbkdf2.Generic.X86.Instances +import VerifiedGarbage.Proof.Pbkdf2.Md.X86.Instances import VerifiedGarbage.Proof.Pbkdf2.Whole.X86.Instances /-! @@ -15,9 +15,11 @@ target (`Sig.layoutDoc`), from `stack` and `writeArgs`, which `ofSig` checks against the contract (after unfolding the `Instance`'s contract to the generic one, which is a `Sig.contract`). -The code is the one PBKDF2 iteration for every streaming hash function -(`Impl/Pbkdf2/Generic/X86.lean`), calling SHA-512's verified `update` and -`finalize`. +The iteration is the one for every Merkle–Damgård hash function +(`Impl/Pbkdf2/Md/X86.lean`): each step is two calls of SHA-512's verified +compression function, on a block laid out once, word by word, in `scratch` +(`U`, its padding and length), starting from the key's inner and outer hash +values. The whole derivation, `pbkdf2`, is the one for every streaming hash function (`Impl/Pbkdf2/Whole/X86.lean`), calling the hash function's streaming @@ -35,11 +37,11 @@ def artifacts : List Artifact := [ { Spec.Hmac.sha512I.iterateApi with target := X86.target doc := Spec.Hmac.sha512I.iterateApi.doc - code := Impl.Pbkdf2.Generic.X86.iterate sha512H' + code := Proof.Pbkdf2.Md.X86.sha512M'.iterate contract := Spec.Hmac.sha512I.iterateContract X86.abi 48 ofSig := ⟨_, _, _, by unfold Spec.Hmac.Instance.iterateContract; rfl⟩ stack := 48 - verified := Proof.Pbkdf2.Generic.X86.Instances.sha512 + verified := Proof.Pbkdf2.Md.X86.Instances.sha512_iterate spSafe := Code.all_of_allInstrs (by lit_decide) }, { Spec.Hmac.sha512I.pbkdf2Api with target := X86.target diff --git a/lean/VerifiedGarbage/Artifacts/Pbkdf2Sha512_224/X86.lean b/lean/VerifiedGarbage/Artifacts/Pbkdf2Sha512_224/X86.lean index acf971a6c..f65bee898 100644 --- a/lean/VerifiedGarbage/Artifacts/Pbkdf2Sha512_224/X86.lean +++ b/lean/VerifiedGarbage/Artifacts/Pbkdf2Sha512_224/X86.lean @@ -1,5 +1,5 @@ import VerifiedGarbage.TCB.X86.Target -import VerifiedGarbage.Proof.Pbkdf2.Generic.X86.Instances +import VerifiedGarbage.Proof.Pbkdf2.Md.X86.Instances import VerifiedGarbage.Proof.Pbkdf2.Whole.X86.Instances /-! @@ -15,9 +15,11 @@ target (`Sig.layoutDoc`), from `stack` and `writeArgs`, which `ofSig` checks against the contract (after unfolding the `Instance`'s contract to the generic one, which is a `Sig.contract`). -The code is the one PBKDF2 iteration for every streaming hash function -(`Impl/Pbkdf2/Generic/X86.lean`), calling SHA-512/224's verified `update` and -`finalize`. +The iteration is the one for every Merkle–Damgård hash function +(`Impl/Pbkdf2/Md/X86.lean`): each step is two calls of SHA-512/224's verified +compression function, on a block laid out once, word by word, in `scratch` +(`U`, its padding and length), starting from the key's inner and outer hash +values. The whole derivation, `pbkdf2`, is the one for every streaming hash function (`Impl/Pbkdf2/Whole/X86.lean`), calling the hash function's streaming @@ -35,11 +37,11 @@ def artifacts : List Artifact := [ { Spec.Hmac.sha512_224I.iterateApi with target := X86.target doc := Spec.Hmac.sha512_224I.iterateApi.doc - code := Impl.Pbkdf2.Generic.X86.iterate sha512_224H + code := Proof.Pbkdf2.Md.X86.sha512_224M.iterate contract := Spec.Hmac.sha512_224I.iterateContract X86.abi 48 ofSig := ⟨_, _, _, by unfold Spec.Hmac.Instance.iterateContract; rfl⟩ stack := 48 - verified := Proof.Pbkdf2.Generic.X86.Instances.sha512_224 + verified := Proof.Pbkdf2.Md.X86.Instances.sha512_224_iterate spSafe := Code.all_of_allInstrs (by lit_decide) }, { Spec.Hmac.sha512_224I.pbkdf2Api with target := X86.target diff --git a/lean/VerifiedGarbage/Artifacts/Pbkdf2Sha512_256/X86.lean b/lean/VerifiedGarbage/Artifacts/Pbkdf2Sha512_256/X86.lean index 0f91cac3d..f1c67fe66 100644 --- a/lean/VerifiedGarbage/Artifacts/Pbkdf2Sha512_256/X86.lean +++ b/lean/VerifiedGarbage/Artifacts/Pbkdf2Sha512_256/X86.lean @@ -1,5 +1,5 @@ import VerifiedGarbage.TCB.X86.Target -import VerifiedGarbage.Proof.Pbkdf2.Generic.X86.Instances +import VerifiedGarbage.Proof.Pbkdf2.Md.X86.Instances import VerifiedGarbage.Proof.Pbkdf2.Whole.X86.Instances /-! @@ -15,9 +15,11 @@ target (`Sig.layoutDoc`), from `stack` and `writeArgs`, which `ofSig` checks against the contract (after unfolding the `Instance`'s contract to the generic one, which is a `Sig.contract`). -The code is the one PBKDF2 iteration for every streaming hash function -(`Impl/Pbkdf2/Generic/X86.lean`), calling SHA-512/256's verified `update` and -`finalize`. +The iteration is the one for every Merkle–Damgård hash function +(`Impl/Pbkdf2/Md/X86.lean`): each step is two calls of SHA-512/256's verified +compression function, on a block laid out once, word by word, in `scratch` +(`U`, its padding and length), starting from the key's inner and outer hash +values. The whole derivation, `pbkdf2`, is the one for every streaming hash function (`Impl/Pbkdf2/Whole/X86.lean`), calling the hash function's streaming @@ -35,11 +37,11 @@ def artifacts : List Artifact := [ { Spec.Hmac.sha512_256I.iterateApi with target := X86.target doc := Spec.Hmac.sha512_256I.iterateApi.doc - code := Impl.Pbkdf2.Generic.X86.iterate sha512_256H + code := Proof.Pbkdf2.Md.X86.sha512_256M.iterate contract := Spec.Hmac.sha512_256I.iterateContract X86.abi 48 ofSig := ⟨_, _, _, by unfold Spec.Hmac.Instance.iterateContract; rfl⟩ stack := 48 - verified := Proof.Pbkdf2.Generic.X86.Instances.sha512_256 + verified := Proof.Pbkdf2.Md.X86.Instances.sha512_256_iterate spSafe := Code.all_of_allInstrs (by lit_decide) }, { Spec.Hmac.sha512_256I.pbkdf2Api with target := X86.target diff --git a/lean/VerifiedGarbage/Impl/Hmac/Generic/X86.lean b/lean/VerifiedGarbage/Impl/Hmac/Generic/X86.lean index e8f514a2b..771743cc9 100644 --- a/lean/VerifiedGarbage/Impl/Hmac/Generic/X86.lean +++ b/lean/VerifiedGarbage/Impl/Hmac/Generic/X86.lean @@ -10,10 +10,11 @@ calls (`Hash`). Every argument is on the stack (cdecl). * `init(inner, outer, key, key_len, scratch)` writes `K₀ ⊕ ipad` and `K₀ ⊕ opad` into `scratch`, then makes the inner state absorb the first and the outer state the second, with `init` and `update`. -* `finalize(inner, outer, count, out, scratch)` finalizes the inner state - into `scratch`, copies the outer state over the inner one, absorbs the - inner digest into it with `update`, and finalizes it again; the MAC is - copied to `out`. +* `finalize(inner, outer, count, out, scratch)` starts with `finPrologue` + and a call of the streaming `finalize` on the inner state (`callFin`, + `count1`); the rest of it, the outer hash, is one call of the compression + function on a block laid out in `scratch`, written over the hash function's + compression function (`VG.Impl.Pbkdf2.Md.X86`). Each call passes its arguments in a frame of their own, pushed last to first (`push`), which the pop loads into `eax` when the call returns: every @@ -149,11 +150,10 @@ def init : Prog isa := (.seq (H.callUpd [] .esi .edi 0 (H.buf + H.B) H.B) (.block H.restore)))))) -/-! ## `finalize` +/-! ## The start of `finalize` -Registers: `ebx` = `inner`, `esi` = `outer` (then the low word of -`update`'s count), `edi` = `out`, `ebp` = `scratch`. The digests are -written to `scratch + buf`. -/ +Registers: `ebx` = `inner`, `esi` = `outer`, `edi` = `out`, `ebp` = +`scratch`. The inner digest is written to `scratch + buf`. -/ def finPrologue : List Instr := [.mov .eax (.mem (at_ .esp 24))] ++ H.save ++ [.mov .ebp (.reg .eax), .mov .ebx (.mem (at_ .esp 4)), @@ -162,18 +162,6 @@ def finPrologue : List Instr := /-- Our `count` argument, as `finalize`'s. -/ def count1 : List Instr := [.mov .eax (.mem (at_ .esp 12)), .mov .ecx (.mem (at_ .esp 16))] -/-- The count of a state that has absorbed a block and a digest, `B + D`. -/ -def count2 : List Instr := [.mov .eax (.imm (BitVec.ofNat 32 (H.B + H.D))), .mov .ecx (.imm 0)] - -def finalize : Prog isa := - .seq (.block H.finPrologue) - (.seq (H.callFin [] count1 .ebx H.buf) - (.seq (copy .esi 0 .ebx 0 H.S) - (.seq (H.callUpd [] .ebx .esi H.B H.buf H.D) - (.seq (H.callFin [] H.count2 .ebx H.buf) - (.seq (copy .ebp H.buf .edi 0 H.D) - (.block H.restore)))))) - end Hash end VG.Impl.Hmac.Generic.X86 diff --git a/lean/VerifiedGarbage/Impl/Pbkdf2/Generic/X86.lean b/lean/VerifiedGarbage/Impl/Pbkdf2/Generic/X86.lean deleted file mode 100644 index 067f30af0..000000000 --- a/lean/VerifiedGarbage/Impl/Pbkdf2/Generic/X86.lean +++ /dev/null @@ -1,79 +0,0 @@ -import VerifiedGarbage.Impl.Hmac.Generic.X86 - -/-! -# PBKDF2-HMAC over any streaming hash function: x86 (32-bit) implementation - -`iterate(key, u, n, t, scratch)`, every argument on the stack (cdecl), runs -`n` steps `U ← HMAC (K₀, U)`, `T ← T ⊕ U` (`VG.Spec.Pbkdf2.iterate`), for -the key whose inner and outer streaming states are at `key` and `key + S`: -the same design as on 32-bit ARM (`VG.Impl.Pbkdf2.Generic.Arm`). -Each step copies the inner state into `scratch`, absorbs `U` into it with -`update` and finalizes it; then does the same with the outer state and that -digest, which gives the next `U`. - -`scratch` is laid out as for HMAC (`VG.Impl.Hmac.Generic.X86`): the working -space of the functions we call, our caller's registers, then the state (`S` -bytes), the inner digest and `U` (`F` bytes each). Registers: `ebp` = -`scratch`, `edi` = the steps left; `key` and `t` are read from the stack -into `esi` when needed, which leaves `ebx` for the address of the state -being hashed and `esi` for the low word of `update`'s count. --/ - -namespace VG.Impl.Pbkdf2.Generic.X86 - -open VG.X86 -open VG.Impl.Hmac.Generic.X86 (Hash copy scr at_) - -variable (H : Hash) - -/-- Where the state being hashed is in `scratch`. -/ -def stO : Nat := H.buf - -/-- Where the inner digest is. -/ -def tmpO : Nat := H.buf + H.S - -/-- Where `U` is. -/ -def uO : Nat := H.buf + H.S + H.F - -/-- `T ← T ⊕ U`, byte by byte, with `T` at `esi`. -/ -def xorLoop : Prog isa := - .seq (.block [.mov .ecx (.imm 0)]) - (.loop (.block [.mov .eax (.reg .ebp), .alu .add .eax (.reg .ecx), .movzx8 .edx (at_ .eax (uO H)), - .mov .eax (.reg .esi), .alu .add .eax (.reg .ecx), .movzx8 .ebx (at_ .eax 0), .alu .xor .edx (.reg .ebx), - .store8 (at_ .eax 0) .dl, .alu .add .ecx (.imm 1), .alu .cmp .ecx (.imm (BitVec.ofNat 32 H.D))]) .ne) - -/-- `ebx ← scratch + stO`: the state being hashed. -/ -def atSt : List Instr := scr .ebx (stO H) - -/-- `key`, from the stack. -/ -def ldKey : List Instr := [.mov .esi (.mem (at_ .esp 4))] - -/-- `t`, from the stack. -/ -def ldT : List Instr := [.mov .esi (.mem (at_ .esp 16))] - -/-- One step. -/ -def body : Prog isa := - .seq (.block ldKey) - (.seq (copy .esi 0 .ebp (stO H) H.S) - (.seq (H.callUpd (atSt H) .ebx .esi H.B (uO H) H.D) - (.seq (H.callFin (atSt H) H.count2 .ebx (tmpO H)) - (.seq (.block ldKey) - (.seq (copy .esi H.S .ebp (stO H) H.S) - (.seq (H.callUpd (atSt H) .ebx .esi H.B (tmpO H) H.D) - (.seq (H.callFin (atSt H) H.count2 .ebx (uO H)) - (.seq (.block ldT) - (.seq (xorLoop H) - (.block [.alu .sub .edi (.imm 1)])))))))))) - -def prologue : List Instr := - [.mov .eax (.mem (at_ .esp 20))] ++ H.save ++ [.mov .ebp (.reg .eax), .mov .edi (.mem (at_ .esp 12)), - .mov .esi (.mem (at_ .esp 8))] - -def iterate : Prog isa := - .seq (.block (prologue H)) - (.seq (copy .esi 0 .ebp (uO H) H.D) - (.seq (.block [.alu .test .edi (.reg .edi)]) - (.seq (.ite .e (.block []) (.loop (body H) .ne)) - (.block H.restore)))) - -end VG.Impl.Pbkdf2.Generic.X86 diff --git a/lean/VerifiedGarbage/Impl/Pbkdf2/Md/X86.lean b/lean/VerifiedGarbage/Impl/Pbkdf2/Md/X86.lean new file mode 100644 index 000000000..7a3658b4c --- /dev/null +++ b/lean/VerifiedGarbage/Impl/Pbkdf2/Md/X86.lean @@ -0,0 +1,192 @@ +import VerifiedGarbage.Impl.Hmac.Generic.X86 +import VerifiedGarbage.Impl.MdStream.X86 + +/-! +# HMAC and PBKDF2-HMAC over any Merkle–Damgård hash function: x86 (32-bit) implementation + +One implementation of HMAC's `finalize` and of PBKDF2's iteration for every +hash function that x86 has streaming functions and a compression function +for, with blocks of 64 bytes (MD5, SHA-1: `Impl/MdStream/X86.lean`) or 128 +(the SHA-512 family: `Impl/Sha512/X86/Stream.lean`). A `Hash` is what the +code needs of one of them: its streaming functions, as HMAC's `init` calls +them (`Impl/Hmac/Generic/X86.lean`, with the sizes of the block, the state +and the digest), the size of its hash value and of its length field, the +byte order of the length field, the compression function (its name, code +and scratch space), and the code writing the digest of a hash value. + +Both functions compress a block that is `D` bytes of message followed by the +padding of a `B + D`-byte message, into a hash value at `ebx` with the block +right after it, at `ebx + N` (a streaming state's layout): + +* `iterate(key, u, n, t, scratch)` runs `n` steps `U ← HMAC (K₀, U)`, + `T ← T ⊕ U` (`VG.Spec.Pbkdf2.iterate`), for the key whose inner and outer + streaming states are at `key` and `key + S`. Those have each absorbed one + block, so HMAC of the `D`-byte `U` is two compressions: the inner hash + value with the block `U ‖ pad`, then the outer hash value with the block + `digest ‖ pad`. The padding is written once, before the loop; the + digest's `N - D` bytes past `D` (for a truncated hash function), which + overwrite its start, are written back after each. `T ← T ⊕ U` is computed + in `t` itself, word by word. +* `finalize(inner, outer, count, out, scratch)` finalizes the inner state + into `scratch` with the hash function's streaming `finalize` (its + message has a variable length). The outer hash, of the outer block and + that digest, is then one compression: the inner state is no longer + needed, so it gets the outer hash value and, in its buffer, the digest + followed by the padding. The MAC is written to `out`: directly, or for a + digest shorter than the hash value, into the buffer and its first `D` + bytes copied. + +`scratch` holds the compression function's scratch space (`[0..so)`, within +the working space of the streaming functions, `8 W` bytes), our caller's +`ebx`, `esi`, `edi` and `ebp` (`Impl.Hmac.Generic.X86.Hash.saved`), then our +buffers: `iterate`'s hash value and block, `finalize`'s digest. The +compression function is called as by the streaming functions, with its +arguments pushed in a frame of their own (`Impl.MdStream.X86.compressAt`), +using the 20 bytes below `esp`; it preserves `ebx`, `esi`, `edi` and `ebp`, +so our variables live there. Every copy and every write of the padding is a +32-bit word at a fixed offset. Every address and branch depends only on +`esp`, the pointers, `count` and `n`. +-/ + +namespace VG.Impl.Pbkdf2.Md.X86 + +open VG.X86 +open VG.Impl.Hmac.Generic.X86 (at_) + +/-- Word `k` from `[src + o₁]` to `[dst + o₂]`, through `ecx`. -/ +def cpW (src dst : Reg) (o₁ o₂ k : Nat) : List Instr := + [.mov .ecx (.mem (at_ src (o₁ + 4 * k))), .store (at_ dst (o₂ + 4 * k)) .ecx] + +/-- `n` words from `[src + o₁]` to `[dst + o₂]`. -/ +def copyW (src : Reg) (o₁ : Nat) (dst : Reg) (o₂ n : Nat) : List Instr := + (List.range n).flatMap (cpW src dst o₁ o₂) + +/-- The little-endian 32-bit word of bytes `4 k … 4 k + 3` of `xs`. -/ +def wordOf (xs : List Byte) (k : Nat) : BitVec 32 := + xs.getD (4 * k + 3) 0 ++ xs.getD (4 * k + 2) 0 ++ xs.getD (4 * k + 1) 0 ++ xs.getD (4 * k) 0 + +/-- The first `4 n` bytes of `xs` at `[dst + o]`, a word at a time through `ecx`. -/ +def storeW (dst : Reg) (o : Nat) (xs : List Byte) (n : Nat) : List Instr := + (List.range n).flatMap fun k => [.mov .ecx (.imm (wordOf xs k)), .store (at_ dst (o + 4 * k)) .ecx] + +/-- The end of the last block of a `B + D`-byte message, after its last `D` +bytes: `0x80`, zeros, and the `L`-byte length field, the length in bits, +big-endian if `be` and little-endian otherwise. -/ +def tail (B D L : Nat) (be : Bool) : List Byte := + [0x80] ++ List.replicate (B - L - 1 - D) 0 ++ + (List.range L).map fun i => BitVec.ofNat 8 ((8 * (B + D)) >>> (8 * (if be then L - 1 - i else i))) + +/-- A Merkle–Damgård hash function's x86 functions, as HMAC and PBKDF2 use +them. -/ +structure Hash where + /-- The streaming functions HMAC's `init` and `finalize` call, with the + sizes of the block, the state and the digest. -/ + st : Impl.Hmac.Generic.X86.Hash + /-- The size of the hash value (where a state's buffer starts). -/ + N : Nat + /-- The size of the length field. -/ + L : Nat + /-- Whether the length field is big-endian. -/ + be : Bool + /-- The bytes of scratch space of the compression function. -/ + so : Nat + /-- The compression function `compress(state, blocks, n, scratch)`, and its name. -/ + compN : String + compC : Prog isa + /-- Writes the digest of the `N`-byte hash value at `ebx` to `eax`; writes + only `ecx` and `edx` (and the flags). -/ + out : List Instr + +namespace Hash + +variable (H : Hash) + +/-- The block size, and the sizes of the state and of the digest. -/ +abbrev B : Nat := H.st.B +abbrev S : Nat := H.st.S +abbrev D : Nat := H.st.D + +/-- The end of the block after the digest. -/ +def tailB : List Byte := tail H.B H.D H.L H.be + +/-! ## The block after the hash value at `ebx` -/ + +/-- `eax ← ebx + N`: the block. -/ +def atBlk : List Instr := [.mov .eax (.reg .ebx), .alu .add .eax (.imm (BitVec.ofNat 32 H.N))] + +/-- The padding after the block's first `D` bytes. -/ +def pad : List Instr := storeW .ebx (H.N + H.D) H.tailB ((H.B - H.D) / 4) + +/-- The digest of the hash value into the block, and the padding it +overwrote (for a digest shorter than the hash value) written back. -/ +def digest : List Instr := H.atBlk ++ H.out ++ storeW .ebx (H.N + H.D) H.tailB ((H.N - H.D) / 4) + +/-- One compression of the block (at `eax`) into the hash value, with the +scratch space at `ebp`. -/ +def cmp : Prog isa := Impl.MdStream.X86.compressAt H.compN H.compC .ebx .ebp + +/-! ## `iterate` + +Registers: `ebp` = `scratch`, `ebx` = the hash value being compressed (at +`scratch + buf`, the block right after it), `esi` = `key`, `edi` = the steps +left; `t` is read from the stack into `edx` for `T ← T ⊕ U`. -/ + +/-- The hash value at `key + o` into the one at `ebx`. -/ +def loadKey (o : Nat) : List Instr := copyW .esi o .ebx 0 (H.N / 4) + +/-- `T ← T ⊕ U` for word `k`, with `T` at `edx` and `U` the block's first `D` bytes. -/ +def xorW (k : Nat) : List Instr := + [.mov .ecx (.mem (at_ .ebx (H.N + 4 * k))), .alu .xor .ecx (.mem (at_ .edx (4 * k))), + .store (at_ .edx (4 * k)) .ecx] + +/-- `t`, then `T ← T ⊕ U` and the count. -/ +def tStep : List Instr := + [.mov .edx (.mem (at_ .esp 16))] ++ (List.range (H.D / 4)).flatMap H.xorW ++ [.alu .sub .edi (.imm 1)] + +/-- One step. -/ +def body : Prog isa := + .seq (.block (H.loadKey 0 ++ H.atBlk)) + (.seq H.cmp + (.seq (.block (H.digest ++ H.loadKey H.S ++ H.atBlk)) + (.seq H.cmp + (.block (H.digest ++ H.tStep))))) + +/-- Saving our caller's registers, setting up ours, and writing `U` and the +padding into the block. -/ +def prologue : List Instr := + [.mov .eax (.mem (at_ .esp 20))] ++ H.st.save ++ + [.mov .ebp (.reg .eax), .mov .esi (.mem (at_ .esp 4)), .mov .edi (.mem (at_ .esp 12)), + .mov .ebx (.reg .ebp), .alu .add .ebx (.imm (BitVec.ofNat 32 H.st.buf)), .mov .edx (.mem (at_ .esp 8))] ++ + copyW .edx 0 .ebx H.N (H.D / 4) ++ H.pad ++ [.alu .test .edi (.reg .edi)] + +def iterate : Prog isa := + .seq (.block H.prologue) + (.seq (.ite .e (.block []) (.loop H.body .ne)) + (.block H.st.restore)) + +/-! ## HMAC's `finalize` + +Registers as in the streaming-level design (`Impl.Hmac.Generic.X86.Hash.finPrologue`): +`ebx` = `inner`, `esi` = `outer`, `edi` = `out`, `ebp` = `scratch`. The +streaming `finalize` writes the inner digest to `scratch + buf`. -/ + +/-- The outer hash value over the inner state's, the inner digest into its +buffer and the padding after it, and `eax` at the buffer. -/ +def finMid : List Instr := + copyW .esi 0 .ebx 0 (H.N / 4) ++ copyW .ebp H.st.buf .ebx H.N (H.D / 4) ++ H.pad ++ H.atBlk + +/-- The MAC to `out`, and our caller's registers back. -/ +def finOut : List Instr := + (if H.D < H.N then H.atBlk ++ H.out ++ copyW .ebx H.N .edi 0 (H.D / 4) else .mov .eax (.reg .edi) :: H.out) ++ + H.st.restore + +def hmacFin : Prog isa := + .seq (.block H.st.finPrologue) + (.seq (H.st.callFin [] Impl.Hmac.Generic.X86.Hash.count1 .ebx H.st.buf) + (.seq (.block H.finMid) + (.seq H.cmp + (.block H.finOut)))) + +end Hash + +end VG.Impl.Pbkdf2.Md.X86 diff --git a/lean/VerifiedGarbage/Proof/Hmac/Generic/X86/Finalize.lean b/lean/VerifiedGarbage/Proof/Hmac/Generic/X86/Finalize.lean index f7baf6062..a70bb2d87 100644 --- a/lean/VerifiedGarbage/Proof/Hmac/Generic/X86/Finalize.lean +++ b/lean/VerifiedGarbage/Proof/Hmac/Generic/X86/Finalize.lean @@ -3,13 +3,16 @@ import VerifiedGarbage.Proof.Hmac.Generic.Common import VerifiedGarbage.Proof.Framework.OmegaLit /-! -# HMAC over any streaming hash function on x86 (32-bit): `finalize`, correct - -Untrusted: everything here is checked by Lean. As on the other targets -(`Proof/Hmac/Generic/Arm/Finalize.lean`). The arguments are on the stack: -`scratch`, `inner`, `outer` and `out` are loaded first (after our caller's -registers are saved in `scratch`), and the count just before the first -call, which passes it on. +# HMAC on x86 (32-bit): the start of `finalize` + +Untrusted: everything here is checked by Lean. HMAC's `finalize` +(`Impl/Pbkdf2/Md/X86.lean`) starts by finalizing the inner state with the +hash function's streaming `finalize`, called with the code of the +streaming-level design (`Impl/Hmac/Generic/X86.lean`): the prologue +(`pro_ok`) loads `scratch`, `inner`, `outer` and `out` (after our caller's +registers are saved in `scratch`), and the count just before the call, +which passes it on (`fin1Args_ok`, `finCall_ok`). What the rest keeps is +`KR`; `Proof/Pbkdf2/Md/X86/HmacFin.lean` continues from there. -/ namespace VG.Proof.Hmac.Generic.X86.Finalize @@ -332,20 +335,6 @@ theorem fin1Args_ok {s : State} (hk : KR (H := H) sc s₀ s) : · rw [u₄.gpr, u₃.gpr, u₂.other _ (by decide), u₁.other _ (by decide), hk.ebp] · rw [u₄.other _ (by decide), u₃.other _ (by decide), u₂.other _ (by decide), u₁.other _ (by decide)] -/-- The second call's arguments: the count `B + D`. -/ -theorem fin2Args_ok {s : State} (hk : KR (H := H) sc s₀ s) : - WP isa (.block ([] ++ H.count2 ++ Impl.Hmac.Generic.X86.scr .edx H.buf)) s fun t => - KR (H := H) sc s₀ t ∧ - FinArgs hH t .ebx (inn s₀) (tO (H := H) s₀) (scr s₀) (BitVec.ofNat 32 (H.B + H.D)) 0 ∧ t.mem = s.mem := by - simp only [Hash.count2, Impl.Hmac.Generic.X86.scr, List.cons_append, List.nil_append] - refine wp_movi fun s₁ u₁ => wp_movi fun s₂ u₂ => wp_mov fun s₃ u₃ => wp_addi fun s₄ u₄ => WP.block_nil ?_ - have k₄ : KR (H := H) sc s₀ s₄ := (((hk.upd (by decide) u₁).upd (by decide) u₂).upd (by decide) u₃).upd - (by decide) u₄ - refine ⟨k₄, finArgs hH hp k₄ ?_ ?_ ?_, by rw [u₄.mem, u₃.mem, u₂.mem, u₁.mem]⟩ - · rw [u₄.other _ (by decide), u₃.other _ (by decide), u₂.other _ (by decide), u₁.gpr] - · rw [u₄.other _ (by decide), u₃.other _ (by decide), u₂.gpr] - · rw [u₄.gpr, u₃.gpr, u₂.other _ (by decide), u₁.other _ (by decide), hk.ebp] - theorem finCall_ok {t : State} (hk : KR (H := H) sc s₀ t) {lo hi : BitVec 32} (ha : FinArgs hH t .ebx (inn s₀) (tO (H := H) s₀) (scr s₀) lo hi) {Q : State → Prop} (hQ : ∀ s', KR (H := H) sc s₀ s' → s'.gpr .esi = t.gpr .esi → @@ -371,193 +360,6 @@ theorem finCall_ok {t : State} (hk : KR (H := H) sc s₀ t) {lo hi : BitVec 32} · exact .inl (t_sub hp) · exact .inl (cal_sub hH hp) -/-- `update`'s arguments: the digest at `T`, and the count `B`. -/ -theorem updArgs_ok {s : State} (hk : KR (H := H) sc s₀ s) : - WP isa (.block ([] ++ ([.mov .eax (.imm 0), .mov .esi (.imm (BitVec.ofNat 32 H.B)), - .mov .ecx (.imm (BitVec.ofNat 32 H.D))] : List Instr) ++ Impl.Hmac.Generic.X86.scr .edx H.buf)) s fun t => - KR (H := H) sc s₀ t ∧ - UpdArgs hH t .esi .ebx (inn s₀) (tO (H := H) s₀) (scr s₀) (BitVec.ofNat 32 H.B) H.D ∧ t.mem = s.mem := by - have hf := hp.fits; have hW := hp.hW; have hB := hp.hB; have hD := hp.hD; have hwb := hH.hWb - have nw := hp.nw; have hf2 := hp.fits; simp only [Hash.buf] at hf2 - obtain ⟨sR, iR, _⟩ := wr_mem hp - simp only [Impl.Hmac.Generic.X86.scr, List.cons_append, List.nil_append] - refine wp_movi fun s₁ u₁ => wp_movi fun s₂ u₂ => wp_movi fun s₃ u₃ => wp_mov fun s₄ u₄ => - wp_addi fun s₅ u₅ => WP.block_nil ?_ - have k₅ : KR (H := H) sc s₀ s₅ := - ((((hk.upd (by decide) u₁).upd (by decide) u₂).upd (by decide) u₃).upd (by decide) u₄).upd (by decide) u₅ - have tsub : Region.Sub ⟨T (H := H) s₀, H.D⟩ (tR (H := H) s₀) := Region.sub_prefix hD.2.1 - refine ⟨k₅, ?_, by rw [u₅.mem, u₄.mem, u₃.mem, u₂.mem, u₁.mem]⟩ - exact - { hst := k₅.ebx - hlo := by rw [u₅.other _ (by decide), u₄.other _ (by decide), u₃.other _ (by decide), u₂.gpr] - eax := by rw [u₅.other _ (by decide), u₄.other _ (by decide), u₃.other _ (by decide), - u₂.other _ (by decide), u₁.gpr] - ecx := by rw [u₅.other _ (by decide), u₄.other _ (by decide), u₃.gpr] - edx := by rw [u₅.gpr, u₄.gpr, u₃.other _ (by decide), u₂.other _ (by decide), u₁.other _ (by decide), - hk.ebp] - ebp := k₅.ebp - hr := by decide - hl := by decide - hlen := by omega_nat - sp48 := by rw [k₅.esp]; exact hp.sp48 - cd := by - rw [k₅.rd, k₅.wr, addr_tO hp] - exact Covers.of_sub fun r hr => by - simp only [List.mem_singleton] at hr; subst hr - exact sub_of_off (List.mem_append_right _ sR) (by omega_nat) - cw := by - rw [k₅.wr] - exact Covers.of_sub fun r hr => by - simp only [List.mem_cons, List.not_mem_nil, or_false] at hr - rcases hr with rfl | rfl - · exact sub_of_self iR (Nat.le_refl _) - · exact sub_of_self (r := scR sc s₀) sR (by show hH.Wb ≤ 8 * sc; simp only [Hash.buf] at hf; omega_nat) - st_sc := hp.i_s.sub_right (cal_sub hH hp) - d_st := by rw [addr_tO hp]; exact (hp.i_s.sub_right (fun a h => t_sub hp a (tsub a h))).symm - d_sc := by rw [addr_tO hp]; exact (cal_t hH hp).symm.sub_left tsub - b_st := by rw [stk_eq k₅]; exact hp.b_i - b_d := by rw [stk_eq k₅, addr_tO hp]; exact hp.b_s.sub_right (fun a h => t_sub hp a (tsub a h)) - b_sc := by rw [stk_eq k₅]; exact hp.b_s.sub_right (cal_sub hH hp) - nst := hp.ni - nd := by rw [toNat_tO hp]; omega_nat - nsc := by omega_nat } - -theorem updCall_ok {t : State} (hk : KR (H := H) sc s₀ t) - (ha : UpdArgs hH t .esi .ebx (inn s₀) (tO (H := H) s₀) (scr s₀) (BitVec.ofNat 32 H.B) H.D) {Q : State → Prop} - (hQ : ∀ s', KR (H := H) sc s₀ s' → Frame [inR (H := H) s₀, calR hH s₀, stkR s₀] t.mem s'.mem → - (∀ m, hH.SH.Repr t.mem ((inn s₀).setWidth 64) m → BitVec.ofNat 64 H.B = BitVec.ofNat 64 m.length → - hH.SH.Repr s'.mem ((inn s₀).setWidth 64) (m ++ bytesAt t.mem (T (H := H) s₀) H.D)) → Q s') : - WP isa (.frame (.push (upd6 .esi .ebx)) (.call H.updN H.updC) (.pop .eax (upd6 .esi .ebx).length)) t Q := - upd_frame hH ha fun s' ha' hpost => by - have f := ha'.frame - rw [stk_eq hk] at f - rw [addr_tO hp] at hpost - refine hQ s' (hk.call hp ha' ?_ ?_) f fun m hr hc => hpost m hr (by - rw [zero_append_ofNat (by have := hp.hB; omega_nat)]; exact hc) - · simp only [List.mem_cons, List.not_mem_nil, or_false] - rintro r (rfl | rfl) - · exact hp.i_s.symm.sub_left (save_sub hp) - · exact (cal_save hH hp).symm - · simp only [List.mem_cons, List.not_mem_nil, or_false] - rintro r (rfl | rfl) - · exact .inr rfl - · exact .inl (cal_sub hH hp) - -/-! ## The copies -/ - -omit hp in -theorem add_zero' (p : Addr) : p + BitVec.ofNat 64 0 = p := BitVec.add_zero p - -/-- The outer state over the inner one. -/ -theorem copy1_ok {s : State} (hk : KR (H := H) sc s₀ s) (hsi : s.gpr .esi = outer s₀) : - WP isa (copy .esi 0 .ebx 0 H.S) s fun t => KR (H := H) sc s₀ t ∧ - t.mem = writeBytes s.mem ((inn s₀).setWidth 64) (bytesAt s.mem ((outer s₀).setWidth 64) H.S) := by - have hS := hp.hS; have ni := hp.ni; have no := hp.no - obtain ⟨_, iR, _⟩ := wr_mem hp - have oR : outerR (H := H) s₀ ∈ s.rd ++ s.wr := by rw [hk.rd, hp.rd]; simp - refine WP.mono (copy_ok (so := 0) (d := 0) (n := H.S) (by decide) (by decide) hS.1 - (by omega_nat) (by rw [hsi]; omega_nat) (by rw [hk.ebx]; omega_nat) - (fun k hk' => by rw [hsi, add_zero']; exact inRegions_of_sub oR (fun _ h => h) (by omega_nat) hk') - (fun k hk' => by rw [hk.ebx, add_zero', hk.wr]; exact inRegions_of_sub iR (fun _ h => h) (by omega_nat) hk') - (by rw [hsi, hk.ebx, add_zero', add_zero']; exact hp.i_o.symm)) fun t c => ?_ - rw [hk.ebx, hsi, add_zero', add_zero'] at c - refine ⟨hk.keep c.rd c.wr (fun r hr => ?_) - (c.mem ▸ Proof.Sha256.Stream.writeBytes_frame _ _ _ (R := inR (H := H) s₀) (by - rw [bytesAt_length]; exact Region.contains_self _ _)) (by - simp only [List.mem_singleton]; rintro r rfl; exact hp.i_s.symm.sub_left (save_sub hp)) - (by simp only [List.mem_singleton]; rintro r rfl; exact ⟨inR (H := H) s₀, by simp, fun _ h => h⟩), c.mem⟩ - refine c.other r fun h => ?_ - simp only [List.mem_cons, List.not_mem_nil, or_false] at hr h - rcases hr with rfl | rfl | rfl | rfl <;> rcases h with h | h | h <;> cases h - -/-- The MAC to `out`. -/ -theorem copy2_ok {s : State} (hk : KR (H := H) sc s₀ s) : - WP isa (copy .ebp H.buf .edi 0 H.D) s fun t => KR (H := H) sc s₀ t ∧ - t.mem = writeBytes s.mem ((op s₀).setWidth 64) (bytesAt s.mem (T (H := H) s₀) H.D) := by - have hD := hp.hD; have np := hp.np; have nw := hp.nw; have hf := hp.fits - obtain ⟨sR, _, pR⟩ := wr_mem hp - have tsub : Region.Sub ⟨T (H := H) s₀, H.D⟩ (scR sc s₀) := fun a h => t_sub hp a (Region.sub_prefix hD.2.1 a h) - refine WP.mono (copy_ok (so := H.buf) (d := 0) (n := H.D) (by decide) (by decide) - hD.1 (by omega_nat) (by rw [hk.ebp]; omega_nat) (by rw [hk.edi]; omega_nat) - (fun k hk' => by - rw [hk.ebp, hk.rd, hk.wr]; exact inRegions_of_sub (List.mem_append_right _ sR) tsub (by omega_nat) hk') - (fun k hk' => by rw [hk.edi, add_zero', hk.wr]; exact inRegions_of_sub pR (fun _ h => h) (by omega_nat) hk') - (by rw [hk.ebp, hk.edi, add_zero']; exact hp.p_s.symm.sub_left tsub)) fun t c => ?_ - rw [hk.edi, hk.ebp, add_zero'] at c - refine ⟨hk.keep c.rd c.wr (fun r hr => ?_) - (c.mem ▸ Proof.Sha256.Stream.writeBytes_frame _ _ _ (R := opR (H := H) s₀) (by - rw [bytesAt_length]; exact Region.contains_self _ _)) (by - simp only [List.mem_singleton]; rintro r rfl; exact hp.p_s.symm.sub_left (save_sub hp)) - (by simp only [List.mem_singleton]; rintro r rfl; exact ⟨opR (H := H) s₀, by simp, fun _ h => h⟩), c.mem⟩ - refine c.other r fun h => ?_ - simp only [List.mem_cons, List.not_mem_nil, or_false] at hr h - rcases hr with rfl | rfl | rfl | rfl <;> rcases h with h | h | h <;> cases h - -/-! ## Correctness -/ - -theorem correct : WP isa H.finalize s₀ fun s' => abiPreserved s₀ s' ∧ (finG hH.SH sc).post s₀ s' := by - have hD := hp.hD; have hS := hp.hS; have hB := hp.hB - have hS' := hH.hS; have hD' := hH.hD; have hB' := hH.hB - obtain ⟨sR, iR, pR⟩ := wr_mem hp - have tsub : Region.Sub ⟨T (H := H) s₀, H.D⟩ (tR (H := H) s₀) := Region.sub_prefix hD.2.1 - refine WP.seq (WP.mono (pro_ok hp) fun s₁ ⟨k₁, si₁, f₁⟩ => ?_) - refine WP.seq (WP.seq (WP.mono (fin1Args_ok hH hp k₁) fun t₁ ⟨kt₁, a₁, st₁, m₁⟩ => - finCall_ok hH hp kt₁ a₁ fun s₂ k₂ si₂ f₂ d₂ => ?_)) - refine WP.seq (WP.mono (copy1_ok hp k₂ (by rw [si₂, st₁, si₁])) fun s₃ ⟨k₃, m₃⟩ => ?_) - refine WP.seq (WP.seq (WP.mono (updArgs_ok hH hp k₃) fun t₃ ⟨kt₃, a₃, mt₃⟩ => - updCall_ok hH hp kt₃ a₃ fun s₄ k₄ f₄ r₄ => ?_)) - refine WP.seq (WP.seq (WP.mono (fin2Args_ok hH hp k₄) fun t₄ ⟨kt₄, a₄, mt₄⟩ => - finCall_ok hH hp kt₄ a₄ fun s₅ k₅ _ f₅ d₅ => ?_)) - refine WP.seq (WP.mono (copy2_ok hp k₅) fun s₆ ⟨k₆, m₆⟩ => ?_) - have hL : 8 * H.W + 16 ≤ 8 * sc := by have := hp.fits; simp only [Hash.buf] at this; omega_nat - refine WP.mono (restore_ok H k₆.ebp k₆.saved (by rw [k₆.wr]; exact sR) hL hp.nw) - fun s' ⟨hm, _, _, hg, ho⟩ => ⟨⟨fun r hr => ?_, by rw [hm]; exact k₆.ret hp⟩, ?_⟩ - · by_cases he : r = .esp - · subst he; rw [ho _ (by decide) (by decide), k₆.esp] - · exact hg r (callee_saved r hr he) - -- The functional part. - intro k0 text hk0 hlen hrI hcnt hrO - rw [hH.hB] at hk0 hcnt - have hl0 : (xorPad k0 ipad ++ text).length = H.B + text.length := by - rw [List.length_append, xorPad_length, hk0] - -- The outer state is untouched until it is copied. - have oI : ∀ r ∈ [saveR H (scr s₀)], Region.Disjoint (outerR (H := H) s₀) r := by - simp only [List.mem_singleton]; rintro r rfl; exact hp.o_s.sub_right (save_sub hp) - have o₂ : ∀ r ∈ [inR (H := H) s₀, tR (H := H) s₀, calR hH s₀, stkR s₀], - Region.Disjoint (outerR (H := H) s₀) r := by - simp only [List.mem_cons, List.not_mem_nil, or_false] - rintro r (rfl | rfl | rfl | rfl) - · exact hp.i_o.symm - · exact hp.o_s.sub_right (t_sub hp) - · exact hp.o_s.sub_right (cal_sub hH hp) - · exact hp.b_o.symm - have rO₂ := Init.repr_keep hH f₂ o₂ (m₁ ▸ Init.repr_keep hH f₁ oI hrO) - -- The inner digest. - have dig := d₂ _ (m₁ ▸ Init.repr_keep hH f₁ (by - simp only [List.mem_singleton]; rintro r rfl; exact hp.i_s.sub_right (save_sub hp)) hrI) - (by rw [hl0]; rw [hk0] at hlen; exact hlen) - (by rw [show arg s₀ 3 ++ arg s₀ 2 = countF s₀ from rfl, hcnt, hl0]) - -- The copy of the outer state. - have rI₃ : hH.SH.Repr s₃.mem ((inn s₀).setWidth 64) (xorPad k0 opad) := by - refine hH.repr _ _ _ _ _ (fun i hi => ?_) rO₂ - rw [m₃, writeBytes_at _ _ _ (by rw [bytesAt_length]; exact hi) (by rw [bytesAt_length]; omega_nat), - bytesAt_getD' _ _ hi] - have t₃ : bytesAt s₃.mem (T (H := H) s₀) H.D = bytesAt s₂.mem (T (H := H) s₀) H.D := by - rw [m₃] - exact bytes_keep (Proof.Sha256.Stream.writeBytes_frame _ _ _ (R := inR (H := H) s₀) (by - rw [bytesAt_length]; exact Region.contains_self _ _)) (by - simp only [List.mem_singleton]; rintro r rfl - exact (hp.i_s.sub_right (t_sub hp)).symm.sub_left tsub) (by omega_nat) - have rI₄ := r₄ _ (mt₃ ▸ rI₃) (by rw [xorPad_length, hk0]) - rw [mt₃, t₃] at rI₄ - have hl₄ : (xorPad k0 opad ++ bytesAt s₂.mem (T (H := H) s₀) H.D).length = H.B + H.D := by - rw [List.length_append, xorPad_length, hk0, bytesAt_length] - have dig₂ := d₅ _ (mt₄ ▸ rI₄) (by rw [hl₄]; omega_nat) (by rw [hl₄, zero_append_ofNat (by omega_nat)]) - show bytesAt s'.mem ((op s₀).setWidth 64) hH.SH.digestBytes = hmacBlockKey hH.SH.H k0 text - rw [hD', hm, m₆, bytesAt_writeBytes_self' (bytesAt_length _ _ _) (by omega_nat), bytesAt_take _ _ hD.2.1, dig₂, - bytesAt_take _ _ hD.2.1, dig] - rfl - end end VG.Proof.Hmac.Generic.X86.Finalize diff --git a/lean/VerifiedGarbage/Proof/Hmac/Generic/X86/FinalizeCT.lean b/lean/VerifiedGarbage/Proof/Hmac/Generic/X86/FinalizeCT.lean deleted file mode 100644 index cc92741d2..000000000 --- a/lean/VerifiedGarbage/Proof/Hmac/Generic/X86/FinalizeCT.lean +++ /dev/null @@ -1,479 +0,0 @@ -import VerifiedGarbage.Proof.Hmac.Generic.X86.Init -import VerifiedGarbage.Proof.Hmac.Generic.X86.Finalize -import VerifiedGarbage.Proof.Framework.OmegaLit - -/-! -# HMAC over any streaming hash function on x86 (32-bit): constant time - -Untrusted: everything here is checked by Lean. `init`, then `finalize`. --/ - -/-! -## `init` - -As on the other targets -(`Proof/Hmac/Generic/Arm/Instances.lean`): the pieces between the calls are -checked by the taint analysis, from the registers that hold our variables -and, where they read them, the arguments on the stack (`argTaint`); the -calls are related by `init_rel` and `upd_rel`. --/ - -namespace VG.Proof.Hmac.Generic.X86.Init - -open VG.X86 -open VG.Impl.Hmac.Generic.X86 (Hash) -open VG.Proof.Hmac.Generic.X86 - -/-- The taint checks of the pieces of `init` between its calls. -/ -structure Checks (H : Hash) : Prop where - keys : ∃ hc, (VG.Taint.check taint (argTaint [] (4 + 4 * 5)) H.initKeys hc).isSome = true - states : ∃ hc, (VG.Taint.check taint (argTaint [.ebp] (4 + 4 * 5)) (.block Hash.initStates) hc).isSome = true - upd : ∀ o ∈ [H.buf, H.buf + H.B], ∃ hc, - (VG.Taint.check taint (τr [.esp, .ebp, .ebx, .esi]) (.block (updBlock H o)) hc).isSome = true - restore : ∃ hc, (VG.Taint.check taint (τr [.ebp]) (.block H.restore) hc).isSome = true - -/-- The public arguments are the same. -/ -structure PubEq (s₀ s₀' : State) : Prop where - esp : s₀.gpr .esp = s₀'.gpr .esp - args : ∀ i < 5, arg s₀ i = arg s₀' i - -variable {H : Hash} (hH : HashOK H) {sc : Nat} (hc : Checks H) -variable {s₀ s₀' : State} (hp : Pre (H := H) sc s₀) (hp' : Pre (H := H) sc s₀') (hq : PubEq s₀ s₀') - -/-- The arguments lie outside the writable regions. -/ -theorem args_out {t : State} (h : Pre (H := H) sc t) {s : State} (hsp : s.gpr .esp = E t) (hwr : s.wr = t.wr) : - ArgsOut 5 s := by - have e : (⟨(s.gpr .esp).setWidth 64, 4 + 4 * 5⟩ : Region) = ⟨(E t).setWidth 64, 4 + 20⟩ := by rw [hsp] - refine ⟨by rw [hsp]; exact h.spf, ?_⟩ - rw [e, hwr, h.wr] - simp only [List.mem_cons, List.not_mem_nil, or_false] - rintro r (rfl | rfl | rfl) - · exact Taint.frame_disjoint (by have := h.spf; omega_nat) h.r_i h.a_i - · exact Taint.frame_disjoint (by have := h.spf; omega_nat) h.r_o h.a_o - · exact Taint.frame_disjoint (by have := h.spf; omega_nat) h.r_s h.a_s - -include hH hp hp' hq - -omit hH hp hp' hq in -theorem hpR {st : Reg} {p : BitVec 32} {t : State} (hst : st = .ebx ∧ p = inn t ∨ st = .esi ∧ p = out t) : - p = inn t ∨ p = out t := by - rcases hst with ⟨_, h⟩ | ⟨_, h⟩ <;> simp [h] - -omit hH hp hp' in -theorem kr_agree {s s' : State} (h : KR (H := H) sc s₀ s) (h' : KR (H := H) sc s₀' s') : - ∀ r ∈ [Reg.ebp], s.gpr r = s'.gpr r := by - intro r hr - simp only [List.mem_singleton] at hr; subst hr - rw [h.ebp, h'.ebp, scr, scr, hq.args 4 (by decide)] - -omit hH hp hp' in -theorem ks_agree {s s' : State} (h : KS (H := H) sc s₀ s) (h' : KS (H := H) sc s₀' s') : - ∀ r ∈ [Reg.esp, .ebp, .ebx, .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, E, E, hq.esp] - · rw [h.ebp, h'.ebp, scr, scr, hq.args 4 (by decide)] - · rw [h.ebx, h'.ebx, inn, inn, hq.args 0 (by decide)] - · rw [h.esi, h'.esi, out, out, hq.args 1 (by decide)] - -/-- A call of `init` on the state in `st` (`ebx` for `inner`, `esi` for `outer`). -/ -theorem callInit_rel {st : Reg} {p : BitVec 32} (hst : st = .ebx ∧ p = inn s₀ ∨ st = .esi ∧ p = out s₀) : - RelCT isa (fun s s' => KS (H := H) sc s₀ s ∧ KS (H := H) sc s₀' s') (H.callInit st) - fun s s' => KS (H := H) sc s₀ s ∧ KS (H := H) sc s₀' s' := by - have hst' : st = .ebx ∧ p = inn s₀' ∨ st = .esi ∧ p = out s₀' := by - rcases hst with ⟨h1, h2⟩ | ⟨h1, h2⟩ - · exact .inl ⟨h1, by rw [h2, inn, inn, hq.args 0 (by decide)]⟩ - · exact .inr ⟨h1, by rw [h2, out, out, hq.args 1 (by decide)]⟩ - have hpR : p = inn s₀ ∨ p = out s₀ := by rcases hst with ⟨_, h⟩ | ⟨_, h⟩ <;> simp [h] - have hpR' : p = inn s₀' ∨ p = out s₀' := by rcases hst' with ⟨_, h⟩ | ⟨_, h⟩ <;> simp [h] - refine rel_wp (F := KS (H := H) sc s₀) (F' := KS (H := H) sc s₀') - (init_rel hH (sp := E s₀) (r := st) (st := p) fun s s' ⟨k, k'⟩ => ?_) - (fun _ k => callInit_ok hH hp k hst fun _ k' _ _ => k') - (fun _ k => callInit_ok hH hp' k hst' fun _ k' _ _ => k') - obtain ⟨_, dK, _, np⟩ := state_disj hp hpR - obtain ⟨_, dK', _, np'⟩ := state_disj hp' hpR' - refine ⟨{ hst := ?_, hr := ?_, sp48 := ?_, cw := ?_, b_st := ?_, nst := np }, - { hst := ?_, hr := ?_, sp48 := ?_, cw := ?_, b_st := ?_, nst := np' }, k.esp, by rw [k'.esp, E, E, hq.esp]⟩ - · rcases hst with ⟨rfl, rfl⟩ | ⟨rfl, rfl⟩; exacts [k.ebx, k.esi] - · rcases hst with ⟨rfl, _⟩ | ⟨rfl, _⟩ <;> decide - · rw [k.esp]; exact hp.sp48 - · rw [k.wr]; exact covers_one (state_in hp hpR) - · rw [stk_eq k.toKR]; exact dK - · rcases hst' with ⟨rfl, rfl⟩ | ⟨rfl, rfl⟩; exacts [k'.ebx, k'.esi] - · rcases hst with ⟨rfl, _⟩ | ⟨rfl, _⟩ <;> decide - · rw [k'.esp]; exact hp'.sp48 - · rw [k'.wr]; exact covers_one (state_in hp' hpR') - · rw [stk_eq k'.toKR]; exact dK' - -omit hc in -/-- A call of `update` on the state in `st`, with the bytes at `scratch + o`. -/ -theorem callUpd_rel {st : Reg} {p : BitVec 32} (hst : st = .ebx ∧ p = inn s₀ ∨ st = .esi ∧ p = out s₀) {o : Nat} - (ho : o = H.buf ∨ o = H.buf + H.B) - (hck : ∃ hc, (VG.Taint.check taint (τr [.esp, .ebp, .ebx, .esi]) (.block (updBlock H o)) hc).isSome = true) : - RelCT isa (fun s s' => KS (H := H) sc s₀ s ∧ KS (H := H) sc s₀' s') (H.callUpd [] st .edi 0 o H.B) - fun s s' => KS (H := H) sc s₀ s ∧ KS (H := H) sc s₀' s' := by - have hst' : st = .ebx ∧ p = inn s₀' ∨ st = .esi ∧ p = out s₀' := by - rcases hst with ⟨h1, h2⟩ | ⟨h1, h2⟩ - · exact .inl ⟨h1, by rw [h2, inn, inn, hq.args 0 (by decide)]⟩ - · exact .inr ⟨h1, by rw [h2, out, out, hq.args 1 (by decide)]⟩ - have e4 : scr s₀' = scr s₀ := (hq.args 4 (by decide)).symm - have e8 : dO s₀' o = dO s₀ o := by rw [dO, dO, e4] - have ha : RelCT isa (fun s s' => KS (H := H) sc s₀ s ∧ KS (H := H) sc s₀' s') (.block (updBlock H o)) - fun s s' => (KS (H := H) sc s₀ s ∧ UpdArgs hH s .edi st p (dO s₀ o) (scr s₀) (BitVec.ofNat 32 0) H.B) ∧ - (KS (H := H) sc s₀' s' ∧ UpdArgs hH s' .edi st p (dO s₀ o) (scr s₀) (BitVec.ofNat 32 0) H.B) := - rel_agree (τr [.esp, .ebp, .ebx, .esi]) (fun _ _ h h' => agree_regs (ks_agree hq h h')) hck - (fun _ h => WP.mono (updArgs_ok hH hp h hst ho) fun _ ⟨k, a, _⟩ => ⟨k, a⟩) - (fun _ h => WP.mono (updArgs_ok hH hp' h hst' ho) fun _ ⟨k, a, _⟩ => ⟨k, e8 ▸ e4 ▸ a⟩) - refine ha.seq (rel_wp - (F := fun s => KS (H := H) sc s₀ s ∧ UpdArgs hH s .edi st p (dO s₀ o) (scr s₀) (BitVec.ofNat 32 0) H.B) - (F' := fun s => KS (H := H) sc s₀' s ∧ UpdArgs hH s .edi st p (dO s₀ o) (scr s₀) (BitVec.ofNat 32 0) H.B) - (upd_rel hH (sp := E s₀) fun s s' ⟨⟨k, a⟩, ⟨k', a'⟩⟩ => ⟨a, a', k.esp, by rw [k'.esp, E, E, hq.esp]⟩) - (fun _ ⟨k, a⟩ => updCall_ok hH hp k (hpR hst) a fun _ k' _ _ => k') - (fun _ ⟨k, a⟩ => updCall_ok hH hp' k (hpR hst') (e4.symm ▸ a) fun _ k' _ _ => k')) - -include hc in -theorem ct : RelCT isa (fun s s' => s = s₀ ∧ s' = s₀') H.init fun _ _ => True := by - have keys : RelCT isa (fun s s' => s = s₀ ∧ s' = s₀') H.initKeys - fun s s' => KR (H := H) sc s₀ s ∧ KR (H := H) sc s₀' s' := - rel_agree (argTaint [] (4 + 4 * 5)) (fun s s' e e' => by - subst e e' - exact agree_argTaint (fun r hr => nomatch hr) hq.esp (args_out hp rfl rfl) (args_out hp' rfl rfl) - hq.args) hc.keys - (fun _ e => by subst e; exact WP.mono (keys_ok sc hp) fun _ h => h.kr) - (fun _ e => by subst e; exact WP.mono (keys_ok sc hp') fun _ h => h.kr) - have states : RelCT isa (fun s s' => KR (H := H) sc s₀ s ∧ KR (H := H) sc s₀' s') (.block Hash.initStates) - fun s s' => KS (H := H) sc s₀ s ∧ KS (H := H) sc s₀' s' := - rel_agree (argTaint [.ebp] (4 + 4 * 5)) (fun s s' k k' => - agree_argTaint (kr_agree hq k k') (by rw [k.esp, k'.esp, E, E, hq.esp]) (args_out hp k.esp k.wr) - (args_out hp' k'.esp k'.wr) fun i hi => by rw [k.argEq hp hi, k'.argEq hp' hi, hq.args i hi]) hc.states - (fun _ k => WP.mono (states_ok hp k) fun _ h => h.1) - (fun _ k => WP.mono (states_ok hp' k) fun _ h => h.1) - obtain ⟨_, hr⟩ := hc.restore - have restore : RelCT isa (fun s s' => KS (H := H) sc s₀ s ∧ KS (H := H) sc s₀' s') (.block H.restore) - fun _ _ => True := - RelCT.taint (A := taint) (τr [.ebp]) (fun _ _ h => agree_regs (kr_agree hq h.1.toKR h.2.toKR)) hr - exact keys.seq (states.seq ((callInit_rel hH hp hp' hq (.inl ⟨rfl, rfl⟩)).seq - ((callUpd_rel hH hp hp' hq (.inl ⟨rfl, rfl⟩) (.inl rfl) (hc.upd _ (by simp))).seq - ((callInit_rel hH hp hp' hq (.inr ⟨rfl, rfl⟩)).seq - ((callUpd_rel hH hp hp' hq (.inr ⟨rfl, rfl⟩) (.inr rfl) (hc.upd _ (by simp))).seq restore))))) - -end VG.Proof.Hmac.Generic.X86.Init - -namespace VG.Proof.Hmac.Generic.X86.Init - -open VG.X86 -open VG.Impl.Hmac.Generic.X86 (Hash) -open VG.Proof.Hmac.Generic.X86 - -/-- `init` is verified against `initG`, given the taint checks, which the -kernel evaluates for each hash function. -/ -theorem verified {H : Hash} (hH : HashOK H) {sc : Nat} (hc : Checks H) - (hfit : H.buf + 2 * H.B ≤ 8 * sc) (hsat : ∃ s, (initG hH.SH sc).pre s) : - Verified X86.target H.init (initG hH.SH sc) := by - refine ⟨fun s hs => ?_, fun s₁ s₂ t₁ t₂ s₁' s₂' h₁ h₂ hpub e₁ e₂ => ?_, hsat⟩ - · obtain ⟨t, s', he, hg, hpost⟩ := correct hH (pre_of hH sc hs hfit) - exact ⟨t, s', he, hg, hpost⟩ - · obtain ⟨h1, h2⟩ := hpub - exact (ct hH hc (pre_of hH sc h₁ hfit) (pre_of hH sc h₂ hfit) ⟨h1, h2⟩ - _ _ _ _ _ _ ⟨rfl, rfl⟩ e₁ e₂).1 - -/-- The regions `init` reads and writes, of those `initW` gives it. -/ -def narrowRd (s : State) : List Region := - [⟨(arg s 2).setWidth 64, (arg s 3).toNat⟩, ⟨argAddr s 0, 20⟩] -def narrowWr (S sc : Nat) (s : State) : List Region := - [⟨(arg s 0).setWidth 64, S⟩, ⟨(arg s 1).setWidth 64, S⟩, ⟨(arg s 4).setWidth 64, 8 * sc⟩] - -/-- `init` is verified against `initW`, which lets it write its arguments: -the code only reads them. -/ -theorem verifiedW {H : Hash} (hH : HashOK H) {sc : Nat} (hc : Checks H) - (hfit : H.buf + 2 * H.B ≤ 8 * sc) (hsat : ∃ s, (initW hH.SH sc).pre s) : - Verified X86.target H.init (initW hH.SH sc) := by - have pre : ∀ s, (initW hH.SH sc).pre s → - (initG hH.SH sc).pre (s.withRegions (narrowRd s) (narrowWr hH.SH.stateBytes sc s)) := by - intro s h - obtain ⟨h0, _, _, h3, h4, h5, h6, h7, h8, h9, h10, h11, h12, h13, h14, h15, h16, h17, h18, h19, h20, h21, - h22, h23, h24⟩ := h - simp only [initG, narrowRd, narrowWr, arg_withRegions, argAddr_withRegions, State.withRegions_gpr, - State.withRegions_rd, State.withRegions_wr] - exact ⟨h0, trivial, trivial, h3, h4, h5, h6, h7, h8, h9, h10, h11, h12, h13, h14, h15, h16, h17, h18, h19, h20, h21, - h22, h23, h24⟩ - refine Verified.narrowTo (verified hH hc hfit (hsat.elim fun s hs => ⟨_, pre s hs⟩)) - (narrowRd) (narrowWr hH.SH.stateBytes sc) pre (fun s h => ?_) (fun s h => ?_) - (fun _ _ _ h => h) (fun _ _ _ _ h => h) hsat - · obtain ⟨_, h1, h2, _⟩ := h - rw [h1, h2] - refine Covers.of_sub fun r hr => ?_ - simp only [narrowRd, narrowWr, List.cons_append, List.nil_append, List.mem_cons, List.not_mem_nil, - or_false] at hr - rcases hr with rfl | rfl | rfl | rfl | rfl - · exact ⟨_, List.mem_append_left _ List.mem_cons_self, 0, by simp, by simp⟩ - · exact ⟨_, List.mem_append_right _ (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_append_right _ List.mem_cons_self, 0, by simp, by simp⟩ - · exact ⟨_, List.mem_append_right _ (List.mem_cons_of_mem _ List.mem_cons_self), 0, by simp, by simp⟩ - · exact ⟨_, List.mem_append_right _ (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 [narrowWr, 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 VG.Proof.Hmac.Generic.X86.Init - -/-! -## `finalize` - -As for `init` (above): the pieces between the calls are -checked by the taint analysis, the prologue and the first call's arguments -reading the arguments on the stack (`argTaint`); the calls are related by -`fin_rel` and `upd_rel`. --/ - -namespace VG.Proof.Hmac.Generic.X86.Finalize - -open VG.X86 -open VG.Impl.Hmac.Generic.X86 (Hash copy) -open VG.Proof.Hmac.Generic.X86 - -/-- The taint checks of the pieces of `finalize` between its calls. -/ -structure Checks (H : Hash) : Prop where - pro : ∃ hc, (VG.Taint.check taint (argTaint [] (4 + 4 * 6)) (.block H.finPrologue) hc).isSome = true - fin1 : ∃ hc, (VG.Taint.check taint (argTaint [.ebp, .ebx, .edi] (4 + 4 * 6)) - (.block ([] ++ Hash.count1 ++ Impl.Hmac.Generic.X86.scr .edx H.buf)) hc).isSome = true - copy1 : ∃ hc, (VG.Taint.check taint (τr [.esp, .ebp, .ebx, .edi, .esi]) (copy .esi 0 .ebx 0 H.S) hc).isSome = true - upd : ∃ hc, (VG.Taint.check taint (τr [.esp, .ebp, .ebx, .edi]) - (.block ([] ++ ([.mov .eax (.imm 0), .mov .esi (.imm (BitVec.ofNat 32 H.B)), - .mov .ecx (.imm (BitVec.ofNat 32 H.D))] : List Instr) ++ Impl.Hmac.Generic.X86.scr .edx H.buf)) hc).isSome = true - fin2 : ∃ hc, (VG.Taint.check taint (τr [.esp, .ebp, .ebx, .edi]) - (.block ([] ++ H.count2 ++ Impl.Hmac.Generic.X86.scr .edx H.buf)) hc).isSome = true - copy2 : ∃ hc, (VG.Taint.check taint (τr [.esp, .ebp, .ebx, .edi]) (copy .ebp H.buf .edi 0 H.D) hc).isSome = true - restore : ∃ hc, (VG.Taint.check taint (τr [.ebp]) (.block H.restore) hc).isSome = true - -/-- The checks of the parts of `finalize` that do not depend on the size of -the digest carry over to a hash function of the same sizes but that one. -/ -theorem Checks.of_sizes {H H' : Hash} (hB : H.B = H'.B) (hS : H.S = H'.S) (hW : H.W = H'.W) (h : Checks H) - (upd : ∃ hc, (VG.Taint.check taint (τr [.esp, .ebp, .ebx, .edi]) - (.block ([] ++ ([.mov .eax (.imm 0), .mov .esi (.imm (BitVec.ofNat 32 H'.B)), - .mov .ecx (.imm (BitVec.ofNat 32 H'.D))] : List Instr) ++ Impl.Hmac.Generic.X86.scr .edx H'.buf)) hc).isSome = true) - (fin2 : ∃ hc, (VG.Taint.check taint (τr [.esp, .ebp, .ebx, .edi]) - (.block ([] ++ H'.count2 ++ Impl.Hmac.Generic.X86.scr .edx H'.buf)) hc).isSome = true) - (copy2 : ∃ hc, (VG.Taint.check taint (τr [.esp, .ebp, .ebx, .edi]) (copy .ebp H'.buf .edi 0 H'.D) hc).isSome = true) : - Checks H' := by - obtain ⟨B, S, D, F, W, iN, iC, uN, uC, fN, fC⟩ := H - obtain ⟨B', S', D', F', W', iN', iC', uN', uC', fN', fC'⟩ := H' - dsimp only at hB hS hW; subst hB hS hW - exact ⟨h.pro, h.fin1, h.copy1, upd, fin2, copy2, h.restore⟩ - -/-- The public arguments are the same. -/ -structure PubEq (s₀ s₀' : State) : Prop where - esp : s₀.gpr .esp = s₀'.gpr .esp - args : ∀ i < 6, arg s₀ i = arg s₀' i - -variable {H : Hash} (hH : HashOK H) {sc : Nat} (hc : Checks H) -variable {s₀ s₀' : State} (hp : Pre (H := H) sc s₀) (hp' : Pre (H := H) sc s₀') (hq : PubEq s₀ s₀') - -/-- The arguments lie outside the writable regions. -/ -theorem args_out {t : State} (h : Pre (H := H) sc t) {s : State} (hsp : s.gpr .esp = E t) (hwr : s.wr = t.wr) : - ArgsOut 6 s := by - have e : (⟨(s.gpr .esp).setWidth 64, 4 + 4 * 6⟩ : Region) = ⟨(E t).setWidth 64, 4 + 24⟩ := by rw [hsp] - refine ⟨by rw [hsp]; exact h.spf, ?_⟩ - rw [e, hwr, h.wr] - simp only [List.mem_cons, List.not_mem_nil, or_false] - rintro r (rfl | rfl | rfl) - · exact Taint.frame_disjoint (by have := h.spf; omega_nat) h.r_i h.a_i - · exact Taint.frame_disjoint (by have := h.spf; omega_nat) h.r_p h.a_p - · exact Taint.frame_disjoint (by have := h.spf; omega_nat) h.r_s h.a_s - -include hq in -theorem kr_agree {s s' : State} (h : KR (H := H) sc s₀ s) (h' : KR (H := H) sc s₀' s') : - ∀ r ∈ [Reg.esp, .ebp, .ebx, .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 - · rw [h.esp, h'.esp, E, E, hq.esp] - · rw [h.ebp, h'.ebp, scr, scr, hq.args 5 (by decide)] - · rw [h.ebx, h'.ebx, inn, inn, hq.args 0 (by decide)] - · rw [h.edi, h'.edi, op, op, hq.args 4 (by decide)] - -theorem sub_regs {l l' : List Reg} (h : ∀ r ∈ l, r ∈ l') {s s' : State} (hs : ∀ r ∈ l', s.gpr r = s'.gpr r) : - ∀ r ∈ l, s.gpr r = s'.gpr r := fun r hr => hs r (h r hr) - -include hH hc hp hp' hq - -theorem ct : RelCT isa (fun s s' => s = s₀ ∧ s' = s₀') H.finalize fun _ _ => True := by - have e5 : scr s₀' = scr s₀ := (hq.args 5 (by decide)).symm - have e0 : inn s₀' = inn s₀ := (hq.args 0 (by decide)).symm - have eT : tO (H := H) s₀' = tO (H := H) s₀ := by rw [tO, tO, e5] - have e2 : arg s₀' 2 = arg s₀ 2 := (hq.args 2 (by decide)).symm - have e3 : arg s₀' 3 = arg s₀ 3 := (hq.args 3 (by decide)).symm - -- The prologue. - have pro : RelCT isa (fun s s' => s = s₀ ∧ s' = s₀') (.block H.finPrologue) - fun s s' => (KR (H := H) sc s₀ s ∧ s.gpr .esi = outer s₀) ∧ (KR (H := H) sc s₀' s' ∧ s'.gpr .esi = outer s₀') := - rel_agree (argTaint [] (4 + 4 * 6)) (fun s s' e e' => by - subst e e' - exact agree_argTaint (fun r hr => nomatch hr) hq.esp (args_out hp rfl rfl) (args_out hp' rfl rfl) - hq.args) hc.pro - (fun _ e => by subst e; exact WP.mono (pro_ok hp) fun _ h => ⟨h.1, h.2.1⟩) - (fun _ e => by subst e; exact WP.mono (pro_ok hp') fun _ h => ⟨h.1, h.2.1⟩) - -- The first call. - have a1 : RelCT isa (fun s s' => (KR (H := H) sc s₀ s ∧ s.gpr .esi = outer s₀) ∧ - (KR (H := H) sc s₀' s' ∧ s'.gpr .esi = outer s₀')) - (.block ([] ++ Hash.count1 ++ Impl.Hmac.Generic.X86.scr .edx H.buf)) - fun s s' => (KR (H := H) sc s₀ s ∧ FinArgs hH s .ebx (inn s₀) (tO (H := H) s₀) (scr s₀) (arg s₀ 2) (arg s₀ 3) ∧ - s.gpr .esi = outer s₀) ∧ - (KR (H := H) sc s₀' s' ∧ FinArgs hH s' .ebx (inn s₀) (tO (H := H) s₀) (scr s₀) (arg s₀ 2) (arg s₀ 3) ∧ - s'.gpr .esi = outer s₀') := - rel_agree (argTaint [.ebp, .ebx, .edi] (4 + 4 * 6)) (fun s s' ⟨k, _⟩ ⟨k', _⟩ => - agree_argTaint (sub_regs (by decide) (kr_agree hq k k')) (by rw [k.esp, k'.esp, E, E, hq.esp]) - (args_out hp k.esp k.wr) (args_out hp' k'.esp k'.wr) - fun i hi => by rw [k.argEq hp hi, k'.argEq hp' hi, hq.args i hi]) hc.fin1 - (fun _ ⟨k, si⟩ => WP.mono (fin1Args_ok hH hp k) fun _ ⟨k₁, a, s₁, _⟩ => ⟨k₁, a, s₁.trans si⟩) - (fun _ ⟨k, si⟩ => WP.mono (fin1Args_ok hH hp' k) fun _ ⟨k₁, a, s₁, _⟩ => - ⟨k₁, by rw [← e0, ← eT, ← e5, ← e2, ← e3]; exact a, s₁.trans si⟩) - have c1 : RelCT isa (fun s s' => (KR (H := H) sc s₀ s ∧ - FinArgs hH s .ebx (inn s₀) (tO (H := H) s₀) (scr s₀) (arg s₀ 2) (arg s₀ 3) ∧ s.gpr .esi = outer s₀) ∧ - (KR (H := H) sc s₀' s' ∧ FinArgs hH s' .ebx (inn s₀) (tO (H := H) s₀) (scr s₀) (arg s₀ 2) (arg s₀ 3) ∧ - s'.gpr .esi = outer s₀')) - (.frame (.push (fin5 .ebx)) (.call H.finN H.finC) (.pop .eax (fin5 .ebx).length)) - fun s s' => (KR (H := H) sc s₀ s ∧ s.gpr .esi = outer s₀) ∧ (KR (H := H) sc s₀' s' ∧ s'.gpr .esi = outer s₀') := - rel_wp (fin_rel hH (sp := E s₀) fun s s' ⟨⟨k, a, _⟩, ⟨k', a', _⟩⟩ => - ⟨a, a', k.esp, by rw [k'.esp, E, E, hq.esp]⟩) - (fun _ ⟨k, a, si⟩ => finCall_ok hH hp k a fun _ k' si' _ _ => ⟨k', si'.trans si⟩) - (fun _ ⟨k, a, si⟩ => finCall_ok hH hp' k (by rw [e0, eT, e5]; exact a) - fun _ k' si' _ _ => ⟨k', si'.trans si⟩) - -- The copy of the outer state. - have cp1 : RelCT isa (fun s s' => (KR (H := H) sc s₀ s ∧ s.gpr .esi = outer s₀) ∧ - (KR (H := H) sc s₀' s' ∧ s'.gpr .esi = outer s₀')) (copy .esi 0 .ebx 0 H.S) - fun s s' => KR (H := H) sc s₀ s ∧ KR (H := H) sc s₀' s' := - rel_agree (τr [.esp, .ebp, .ebx, .edi, .esi]) (fun s s' ⟨k, si⟩ ⟨k', si'⟩ => agree_regs fun r hr => by - simp only [List.mem_cons, List.not_mem_nil, or_false] at hr - rcases hr with rfl | rfl | rfl | rfl | rfl - · exact kr_agree hq k k' _ (by simp) - · exact kr_agree hq k k' _ (by simp) - · exact kr_agree hq k k' _ (by simp) - · exact kr_agree hq k k' _ (by simp) - · rw [si, si', outer, outer, hq.args 1 (by decide)]) hc.copy1 - (fun _ ⟨k, si⟩ => WP.mono (copy1_ok hp k si) fun _ h => h.1) - (fun _ ⟨k, si⟩ => WP.mono (copy1_ok hp' k si) fun _ h => h.1) - -- The call of `update`. - have au : RelCT isa (fun s s' => KR (H := H) sc s₀ s ∧ KR (H := H) sc s₀' s') - (.block ([] ++ ([.mov .eax (.imm 0), .mov .esi (.imm (BitVec.ofNat 32 H.B)), - .mov .ecx (.imm (BitVec.ofNat 32 H.D))] : List Instr) ++ Impl.Hmac.Generic.X86.scr .edx H.buf)) - fun s s' => (KR (H := H) sc s₀ s ∧ - UpdArgs hH s .esi .ebx (inn s₀) (tO (H := H) s₀) (scr s₀) (BitVec.ofNat 32 H.B) H.D) ∧ - (KR (H := H) sc s₀' s' ∧ - UpdArgs hH s' .esi .ebx (inn s₀) (tO (H := H) s₀) (scr s₀) (BitVec.ofNat 32 H.B) H.D) := - rel_agree (τr [.esp, .ebp, .ebx, .edi]) (fun s s' k k' => agree_regs (kr_agree hq k k')) hc.upd - (fun _ k => WP.mono (updArgs_ok hH hp k) fun _ ⟨k₁, a, _⟩ => ⟨k₁, a⟩) - (fun _ k => WP.mono (updArgs_ok hH hp' k) fun _ ⟨k₁, a, _⟩ => ⟨k₁, by rw [← e0, ← eT, ← e5]; exact a⟩) - have cu : RelCT isa (fun s s' => (KR (H := H) sc s₀ s ∧ - UpdArgs hH s .esi .ebx (inn s₀) (tO (H := H) s₀) (scr s₀) (BitVec.ofNat 32 H.B) H.D) ∧ - (KR (H := H) sc s₀' s' ∧ - UpdArgs hH s' .esi .ebx (inn s₀) (tO (H := H) s₀) (scr s₀) (BitVec.ofNat 32 H.B) H.D)) - (.frame (.push (upd6 .esi .ebx)) (.call H.updN H.updC) (.pop .eax (upd6 .esi .ebx).length)) - fun s s' => KR (H := H) sc s₀ s ∧ KR (H := H) sc s₀' s' := - rel_wp (upd_rel hH (sp := E s₀) fun s s' ⟨⟨k, a⟩, ⟨k', a'⟩⟩ => ⟨a, a', k.esp, by rw [k'.esp, E, E, hq.esp]⟩) - (fun _ ⟨k, a⟩ => updCall_ok hH hp k a fun _ k' _ _ => k') - (fun _ ⟨k, a⟩ => updCall_ok hH hp' k (by rw [e0, eT, e5]; exact a) fun _ k' _ _ => k') - -- The second call of `finalize`. - have a2 : RelCT isa (fun s s' => KR (H := H) sc s₀ s ∧ KR (H := H) sc s₀' s') - (.block ([] ++ H.count2 ++ Impl.Hmac.Generic.X86.scr .edx H.buf)) - fun s s' => (KR (H := H) sc s₀ s ∧ - FinArgs hH s .ebx (inn s₀) (tO (H := H) s₀) (scr s₀) (BitVec.ofNat 32 (H.B + H.D)) 0) ∧ - (KR (H := H) sc s₀' s' ∧ - FinArgs hH s' .ebx (inn s₀) (tO (H := H) s₀) (scr s₀) (BitVec.ofNat 32 (H.B + H.D)) 0) := - rel_agree (τr [.esp, .ebp, .ebx, .edi]) (fun s s' k k' => agree_regs (kr_agree hq k k')) hc.fin2 - (fun _ k => WP.mono (fin2Args_ok hH hp k) fun _ ⟨k₁, a, _⟩ => ⟨k₁, a⟩) - (fun _ k => WP.mono (fin2Args_ok hH hp' k) fun _ ⟨k₁, a, _⟩ => ⟨k₁, by rw [← e0, ← eT, ← e5]; exact a⟩) - have c2 : RelCT isa (fun s s' => (KR (H := H) sc s₀ s ∧ - FinArgs hH s .ebx (inn s₀) (tO (H := H) s₀) (scr s₀) (BitVec.ofNat 32 (H.B + H.D)) 0) ∧ - (KR (H := H) sc s₀' s' ∧ - FinArgs hH s' .ebx (inn s₀) (tO (H := H) s₀) (scr s₀) (BitVec.ofNat 32 (H.B + H.D)) 0)) - (.frame (.push (fin5 .ebx)) (.call H.finN H.finC) (.pop .eax (fin5 .ebx).length)) - fun s s' => KR (H := H) sc s₀ s ∧ KR (H := H) sc s₀' s' := - rel_wp (fin_rel hH (sp := E s₀) fun s s' ⟨⟨k, a⟩, ⟨k', a'⟩⟩ => ⟨a, a', k.esp, by rw [k'.esp, E, E, hq.esp]⟩) - (fun _ ⟨k, a⟩ => finCall_ok hH hp k a fun _ k' _ _ _ => k') - (fun _ ⟨k, a⟩ => finCall_ok hH hp' k (by rw [e0, eT, e5]; exact a) fun _ k' _ _ _ => k') - -- The copy of the MAC, and the end. - have cp2 : RelCT isa (fun s s' => KR (H := H) sc s₀ s ∧ KR (H := H) sc s₀' s') (copy .ebp H.buf .edi 0 H.D) - fun s s' => KR (H := H) sc s₀ s ∧ KR (H := H) sc s₀' s' := - rel_agree (τr [.esp, .ebp, .ebx, .edi]) (fun s s' k k' => agree_regs (kr_agree hq k k')) hc.copy2 - (fun _ k => WP.mono (copy2_ok hp k) fun _ h => h.1) - (fun _ k => WP.mono (copy2_ok hp' k) fun _ h => h.1) - obtain ⟨_, hr⟩ := hc.restore - have restore : RelCT isa (fun s s' => KR (H := H) sc s₀ s ∧ KR (H := H) sc s₀' s') (.block H.restore) - fun _ _ => True := - RelCT.taint (A := taint) (τr [.ebp]) (fun _ _ h => - agree_regs (sub_regs (by decide) (kr_agree hq h.1 h.2))) hr - exact pro.seq ((a1.seq c1).seq (cp1.seq ((au.seq cu).seq ((a2.seq c2).seq (cp2.seq restore))))) - -end VG.Proof.Hmac.Generic.X86.Finalize - -namespace VG.Proof.Hmac.Generic.X86.Finalize - -open VG.X86 -open VG.Impl.Hmac.Generic.X86 (Hash) -open VG.Proof.Hmac.Generic.X86 - -/-- `finalize` is verified against `finG`, given the taint checks, which the -kernel evaluates for each hash function. -/ -theorem verified {H : Hash} (hH : HashOK H) {sc : Nat} (hc : Checks H) - (hfit : H.buf + H.F ≤ 8 * sc) (hsat : ∃ s, (finG hH.SH sc).pre s) : - Verified X86.target H.finalize (finG hH.SH sc) := by - refine ⟨fun s hs => ?_, fun s₁ s₂ t₁ t₂ s₁' s₂' h₁ h₂ hpub e₁ e₂ => ?_, hsat⟩ - · obtain ⟨t, s', he, hg, hpost⟩ := correct hH (pre_of hH sc hs hfit) - exact ⟨t, s', he, hg, hpost⟩ - · obtain ⟨h1, h2⟩ := hpub - exact (ct hH hc (pre_of hH sc h₁ hfit) (pre_of hH sc h₂ hfit) ⟨h1, h2⟩ - _ _ _ _ _ _ ⟨rfl, rfl⟩ e₁ e₂).1 - -/-- The regions `finalize` reads and writes, of those `finW` gives it. -/ -def narrowRd (S : Nat) (s : State) : List Region := [⟨(arg s 1).setWidth 64, S⟩, ⟨argAddr s 0, 24⟩] -def narrowWr (S D sc : Nat) (s : State) : List Region := - [⟨(arg s 0).setWidth 64, S⟩, ⟨(arg s 4).setWidth 64, D⟩, ⟨(arg s 5).setWidth 64, 8 * sc⟩] - -/-- `finalize` is verified against `finW`, which lets it write its arguments: -the code only reads them. -/ -theorem verifiedW {H : Hash} (hH : HashOK H) {sc : Nat} (hc : Checks H) - (hfit : H.buf + H.F ≤ 8 * sc) (hsat : ∃ s, (finW hH.SH sc).pre s) : - Verified X86.target H.finalize (finW hH.SH sc) := by - have pre : ∀ s, (finW hH.SH sc).pre s → (finG hH.SH sc).pre - (s.withRegions (narrowRd hH.SH.stateBytes s) (narrowWr hH.SH.stateBytes hH.SH.digestBytes sc s)) := by - intro s h - obtain ⟨_, _, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11, h12, h13, h14, h15, h16, h17, h18, h19, h20, h21, - h22, h23⟩ := h - simp only [finG, narrowRd, narrowWr, 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, h19, h20, - h21, h22, h23⟩ - refine Verified.narrowTo (verified hH hc hfit (hsat.elim fun s hs => ⟨_, pre s hs⟩)) - (narrowRd hH.SH.stateBytes) (narrowWr hH.SH.stateBytes hH.SH.digestBytes sc) pre (fun s h => ?_) - (fun s h => ?_) (fun _ _ _ h => h) (fun _ _ _ _ h => h) hsat - · obtain ⟨h1, h2, _⟩ := h - rw [h1, h2] - refine Covers.of_sub fun r hr => ?_ - simp only [narrowRd, narrowWr, List.cons_append, List.nil_append, List.mem_cons, List.not_mem_nil, - or_false] at hr - rcases hr with rfl | rfl | rfl | rfl | rfl - · exact ⟨_, List.mem_append_left _ List.mem_cons_self, 0, by simp, by simp⟩ - · exact ⟨_, List.mem_append_right _ (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_append_right _ List.mem_cons_self, 0, by simp, by simp⟩ - · exact ⟨_, List.mem_append_right _ (List.mem_cons_of_mem _ List.mem_cons_self), 0, by simp, by simp⟩ - · exact ⟨_, List.mem_append_right _ (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 [narrowWr, 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 VG.Proof.Hmac.Generic.X86.Finalize diff --git a/lean/VerifiedGarbage/Proof/Hmac/Generic/X86/Hash.lean b/lean/VerifiedGarbage/Proof/Hmac/Generic/X86/Hash.lean index 2e4e384d8..e9805433f 100644 --- a/lean/VerifiedGarbage/Proof/Hmac/Generic/X86/Hash.lean +++ b/lean/VerifiedGarbage/Proof/Hmac/Generic/X86/Hash.lean @@ -4,7 +4,7 @@ import VerifiedGarbage.Proof.Framework.RelCT import VerifiedGarbage.Proof.Framework.Contract import VerifiedGarbage.Proof.Framework.X86.RelCT import VerifiedGarbage.Proof.Sha256.X86.Stream.Common -import VerifiedGarbage.Impl.Pbkdf2.Generic.X86 +import VerifiedGarbage.Impl.Hmac.Generic.X86 import VerifiedGarbage.Proof.Framework.OmegaLit /-! diff --git a/lean/VerifiedGarbage/Proof/Hmac/Generic/X86/InitCT.lean b/lean/VerifiedGarbage/Proof/Hmac/Generic/X86/InitCT.lean new file mode 100644 index 000000000..7c00b5ae0 --- /dev/null +++ b/lean/VerifiedGarbage/Proof/Hmac/Generic/X86/InitCT.lean @@ -0,0 +1,225 @@ +import VerifiedGarbage.Proof.Hmac.Generic.X86.Init +import VerifiedGarbage.Proof.Framework.OmegaLit + +/-! +# HMAC over any streaming hash function on x86 (32-bit): `init`, constant time + +Untrusted: everything here is checked by Lean. +-/ + +/-! +## `init` + +As on the other targets +(`Proof/Hmac/Generic/Arm/Instances.lean`): the pieces between the calls are +checked by the taint analysis, from the registers that hold our variables +and, where they read them, the arguments on the stack (`argTaint`); the +calls are related by `init_rel` and `upd_rel`. +-/ + +namespace VG.Proof.Hmac.Generic.X86.Init + +open VG.X86 +open VG.Impl.Hmac.Generic.X86 (Hash) +open VG.Proof.Hmac.Generic.X86 + +/-- The taint checks of the pieces of `init` between its calls. -/ +structure Checks (H : Hash) : Prop where + keys : ∃ hc, (VG.Taint.check taint (argTaint [] (4 + 4 * 5)) H.initKeys hc).isSome = true + states : ∃ hc, (VG.Taint.check taint (argTaint [.ebp] (4 + 4 * 5)) (.block Hash.initStates) hc).isSome = true + upd : ∀ o ∈ [H.buf, H.buf + H.B], ∃ hc, + (VG.Taint.check taint (τr [.esp, .ebp, .ebx, .esi]) (.block (updBlock H o)) hc).isSome = true + restore : ∃ hc, (VG.Taint.check taint (τr [.ebp]) (.block H.restore) hc).isSome = true + +/-- The public arguments are the same. -/ +structure PubEq (s₀ s₀' : State) : Prop where + esp : s₀.gpr .esp = s₀'.gpr .esp + args : ∀ i < 5, arg s₀ i = arg s₀' i + +variable {H : Hash} (hH : HashOK H) {sc : Nat} (hc : Checks H) +variable {s₀ s₀' : State} (hp : Pre (H := H) sc s₀) (hp' : Pre (H := H) sc s₀') (hq : PubEq s₀ s₀') + +/-- The arguments lie outside the writable regions. -/ +theorem args_out {t : State} (h : Pre (H := H) sc t) {s : State} (hsp : s.gpr .esp = E t) (hwr : s.wr = t.wr) : + ArgsOut 5 s := by + have e : (⟨(s.gpr .esp).setWidth 64, 4 + 4 * 5⟩ : Region) = ⟨(E t).setWidth 64, 4 + 20⟩ := by rw [hsp] + refine ⟨by rw [hsp]; exact h.spf, ?_⟩ + rw [e, hwr, h.wr] + simp only [List.mem_cons, List.not_mem_nil, or_false] + rintro r (rfl | rfl | rfl) + · exact Taint.frame_disjoint (by have := h.spf; omega_nat) h.r_i h.a_i + · exact Taint.frame_disjoint (by have := h.spf; omega_nat) h.r_o h.a_o + · exact Taint.frame_disjoint (by have := h.spf; omega_nat) h.r_s h.a_s + +include hH hp hp' hq + +omit hH hp hp' hq in +theorem hpR {st : Reg} {p : BitVec 32} {t : State} (hst : st = .ebx ∧ p = inn t ∨ st = .esi ∧ p = out t) : + p = inn t ∨ p = out t := by + rcases hst with ⟨_, h⟩ | ⟨_, h⟩ <;> simp [h] + +omit hH hp hp' in +theorem kr_agree {s s' : State} (h : KR (H := H) sc s₀ s) (h' : KR (H := H) sc s₀' s') : + ∀ r ∈ [Reg.ebp], s.gpr r = s'.gpr r := by + intro r hr + simp only [List.mem_singleton] at hr; subst hr + rw [h.ebp, h'.ebp, scr, scr, hq.args 4 (by decide)] + +omit hH hp hp' in +theorem ks_agree {s s' : State} (h : KS (H := H) sc s₀ s) (h' : KS (H := H) sc s₀' s') : + ∀ r ∈ [Reg.esp, .ebp, .ebx, .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, E, E, hq.esp] + · rw [h.ebp, h'.ebp, scr, scr, hq.args 4 (by decide)] + · rw [h.ebx, h'.ebx, inn, inn, hq.args 0 (by decide)] + · rw [h.esi, h'.esi, out, out, hq.args 1 (by decide)] + +/-- A call of `init` on the state in `st` (`ebx` for `inner`, `esi` for `outer`). -/ +theorem callInit_rel {st : Reg} {p : BitVec 32} (hst : st = .ebx ∧ p = inn s₀ ∨ st = .esi ∧ p = out s₀) : + RelCT isa (fun s s' => KS (H := H) sc s₀ s ∧ KS (H := H) sc s₀' s') (H.callInit st) + fun s s' => KS (H := H) sc s₀ s ∧ KS (H := H) sc s₀' s' := by + have hst' : st = .ebx ∧ p = inn s₀' ∨ st = .esi ∧ p = out s₀' := by + rcases hst with ⟨h1, h2⟩ | ⟨h1, h2⟩ + · exact .inl ⟨h1, by rw [h2, inn, inn, hq.args 0 (by decide)]⟩ + · exact .inr ⟨h1, by rw [h2, out, out, hq.args 1 (by decide)]⟩ + have hpR : p = inn s₀ ∨ p = out s₀ := by rcases hst with ⟨_, h⟩ | ⟨_, h⟩ <;> simp [h] + have hpR' : p = inn s₀' ∨ p = out s₀' := by rcases hst' with ⟨_, h⟩ | ⟨_, h⟩ <;> simp [h] + refine rel_wp (F := KS (H := H) sc s₀) (F' := KS (H := H) sc s₀') + (init_rel hH (sp := E s₀) (r := st) (st := p) fun s s' ⟨k, k'⟩ => ?_) + (fun _ k => callInit_ok hH hp k hst fun _ k' _ _ => k') + (fun _ k => callInit_ok hH hp' k hst' fun _ k' _ _ => k') + obtain ⟨_, dK, _, np⟩ := state_disj hp hpR + obtain ⟨_, dK', _, np'⟩ := state_disj hp' hpR' + refine ⟨{ hst := ?_, hr := ?_, sp48 := ?_, cw := ?_, b_st := ?_, nst := np }, + { hst := ?_, hr := ?_, sp48 := ?_, cw := ?_, b_st := ?_, nst := np' }, k.esp, by rw [k'.esp, E, E, hq.esp]⟩ + · rcases hst with ⟨rfl, rfl⟩ | ⟨rfl, rfl⟩; exacts [k.ebx, k.esi] + · rcases hst with ⟨rfl, _⟩ | ⟨rfl, _⟩ <;> decide + · rw [k.esp]; exact hp.sp48 + · rw [k.wr]; exact covers_one (state_in hp hpR) + · rw [stk_eq k.toKR]; exact dK + · rcases hst' with ⟨rfl, rfl⟩ | ⟨rfl, rfl⟩; exacts [k'.ebx, k'.esi] + · rcases hst with ⟨rfl, _⟩ | ⟨rfl, _⟩ <;> decide + · rw [k'.esp]; exact hp'.sp48 + · rw [k'.wr]; exact covers_one (state_in hp' hpR') + · rw [stk_eq k'.toKR]; exact dK' + +omit hc in +/-- A call of `update` on the state in `st`, with the bytes at `scratch + o`. -/ +theorem callUpd_rel {st : Reg} {p : BitVec 32} (hst : st = .ebx ∧ p = inn s₀ ∨ st = .esi ∧ p = out s₀) {o : Nat} + (ho : o = H.buf ∨ o = H.buf + H.B) + (hck : ∃ hc, (VG.Taint.check taint (τr [.esp, .ebp, .ebx, .esi]) (.block (updBlock H o)) hc).isSome = true) : + RelCT isa (fun s s' => KS (H := H) sc s₀ s ∧ KS (H := H) sc s₀' s') (H.callUpd [] st .edi 0 o H.B) + fun s s' => KS (H := H) sc s₀ s ∧ KS (H := H) sc s₀' s' := by + have hst' : st = .ebx ∧ p = inn s₀' ∨ st = .esi ∧ p = out s₀' := by + rcases hst with ⟨h1, h2⟩ | ⟨h1, h2⟩ + · exact .inl ⟨h1, by rw [h2, inn, inn, hq.args 0 (by decide)]⟩ + · exact .inr ⟨h1, by rw [h2, out, out, hq.args 1 (by decide)]⟩ + have e4 : scr s₀' = scr s₀ := (hq.args 4 (by decide)).symm + have e8 : dO s₀' o = dO s₀ o := by rw [dO, dO, e4] + have ha : RelCT isa (fun s s' => KS (H := H) sc s₀ s ∧ KS (H := H) sc s₀' s') (.block (updBlock H o)) + fun s s' => (KS (H := H) sc s₀ s ∧ UpdArgs hH s .edi st p (dO s₀ o) (scr s₀) (BitVec.ofNat 32 0) H.B) ∧ + (KS (H := H) sc s₀' s' ∧ UpdArgs hH s' .edi st p (dO s₀ o) (scr s₀) (BitVec.ofNat 32 0) H.B) := + rel_agree (τr [.esp, .ebp, .ebx, .esi]) (fun _ _ h h' => agree_regs (ks_agree hq h h')) hck + (fun _ h => WP.mono (updArgs_ok hH hp h hst ho) fun _ ⟨k, a, _⟩ => ⟨k, a⟩) + (fun _ h => WP.mono (updArgs_ok hH hp' h hst' ho) fun _ ⟨k, a, _⟩ => ⟨k, e8 ▸ e4 ▸ a⟩) + refine ha.seq (rel_wp + (F := fun s => KS (H := H) sc s₀ s ∧ UpdArgs hH s .edi st p (dO s₀ o) (scr s₀) (BitVec.ofNat 32 0) H.B) + (F' := fun s => KS (H := H) sc s₀' s ∧ UpdArgs hH s .edi st p (dO s₀ o) (scr s₀) (BitVec.ofNat 32 0) H.B) + (upd_rel hH (sp := E s₀) fun s s' ⟨⟨k, a⟩, ⟨k', a'⟩⟩ => ⟨a, a', k.esp, by rw [k'.esp, E, E, hq.esp]⟩) + (fun _ ⟨k, a⟩ => updCall_ok hH hp k (hpR hst) a fun _ k' _ _ => k') + (fun _ ⟨k, a⟩ => updCall_ok hH hp' k (hpR hst') (e4.symm ▸ a) fun _ k' _ _ => k')) + +include hc in +theorem ct : RelCT isa (fun s s' => s = s₀ ∧ s' = s₀') H.init fun _ _ => True := by + have keys : RelCT isa (fun s s' => s = s₀ ∧ s' = s₀') H.initKeys + fun s s' => KR (H := H) sc s₀ s ∧ KR (H := H) sc s₀' s' := + rel_agree (argTaint [] (4 + 4 * 5)) (fun s s' e e' => by + subst e e' + exact agree_argTaint (fun r hr => nomatch hr) hq.esp (args_out hp rfl rfl) (args_out hp' rfl rfl) + hq.args) hc.keys + (fun _ e => by subst e; exact WP.mono (keys_ok sc hp) fun _ h => h.kr) + (fun _ e => by subst e; exact WP.mono (keys_ok sc hp') fun _ h => h.kr) + have states : RelCT isa (fun s s' => KR (H := H) sc s₀ s ∧ KR (H := H) sc s₀' s') (.block Hash.initStates) + fun s s' => KS (H := H) sc s₀ s ∧ KS (H := H) sc s₀' s' := + rel_agree (argTaint [.ebp] (4 + 4 * 5)) (fun s s' k k' => + agree_argTaint (kr_agree hq k k') (by rw [k.esp, k'.esp, E, E, hq.esp]) (args_out hp k.esp k.wr) + (args_out hp' k'.esp k'.wr) fun i hi => by rw [k.argEq hp hi, k'.argEq hp' hi, hq.args i hi]) hc.states + (fun _ k => WP.mono (states_ok hp k) fun _ h => h.1) + (fun _ k => WP.mono (states_ok hp' k) fun _ h => h.1) + obtain ⟨_, hr⟩ := hc.restore + have restore : RelCT isa (fun s s' => KS (H := H) sc s₀ s ∧ KS (H := H) sc s₀' s') (.block H.restore) + fun _ _ => True := + RelCT.taint (A := taint) (τr [.ebp]) (fun _ _ h => agree_regs (kr_agree hq h.1.toKR h.2.toKR)) hr + exact keys.seq (states.seq ((callInit_rel hH hp hp' hq (.inl ⟨rfl, rfl⟩)).seq + ((callUpd_rel hH hp hp' hq (.inl ⟨rfl, rfl⟩) (.inl rfl) (hc.upd _ (by simp))).seq + ((callInit_rel hH hp hp' hq (.inr ⟨rfl, rfl⟩)).seq + ((callUpd_rel hH hp hp' hq (.inr ⟨rfl, rfl⟩) (.inr rfl) (hc.upd _ (by simp))).seq restore))))) + +end VG.Proof.Hmac.Generic.X86.Init + +namespace VG.Proof.Hmac.Generic.X86.Init + +open VG.X86 +open VG.Impl.Hmac.Generic.X86 (Hash) +open VG.Proof.Hmac.Generic.X86 + +/-- `init` is verified against `initG`, given the taint checks, which the +kernel evaluates for each hash function. -/ +theorem verified {H : Hash} (hH : HashOK H) {sc : Nat} (hc : Checks H) + (hfit : H.buf + 2 * H.B ≤ 8 * sc) (hsat : ∃ s, (initG hH.SH sc).pre s) : + Verified X86.target H.init (initG hH.SH sc) := by + refine ⟨fun s hs => ?_, fun s₁ s₂ t₁ t₂ s₁' s₂' h₁ h₂ hpub e₁ e₂ => ?_, hsat⟩ + · obtain ⟨t, s', he, hg, hpost⟩ := correct hH (pre_of hH sc hs hfit) + exact ⟨t, s', he, hg, hpost⟩ + · obtain ⟨h1, h2⟩ := hpub + exact (ct hH hc (pre_of hH sc h₁ hfit) (pre_of hH sc h₂ hfit) ⟨h1, h2⟩ + _ _ _ _ _ _ ⟨rfl, rfl⟩ e₁ e₂).1 + +/-- The regions `init` reads and writes, of those `initW` gives it. -/ +def narrowRd (s : State) : List Region := + [⟨(arg s 2).setWidth 64, (arg s 3).toNat⟩, ⟨argAddr s 0, 20⟩] +def narrowWr (S sc : Nat) (s : State) : List Region := + [⟨(arg s 0).setWidth 64, S⟩, ⟨(arg s 1).setWidth 64, S⟩, ⟨(arg s 4).setWidth 64, 8 * sc⟩] + +/-- `init` is verified against `initW`, which lets it write its arguments: +the code only reads them. -/ +theorem verifiedW {H : Hash} (hH : HashOK H) {sc : Nat} (hc : Checks H) + (hfit : H.buf + 2 * H.B ≤ 8 * sc) (hsat : ∃ s, (initW hH.SH sc).pre s) : + Verified X86.target H.init (initW hH.SH sc) := by + have pre : ∀ s, (initW hH.SH sc).pre s → + (initG hH.SH sc).pre (s.withRegions (narrowRd s) (narrowWr hH.SH.stateBytes sc s)) := by + intro s h + obtain ⟨h0, _, _, h3, h4, h5, h6, h7, h8, h9, h10, h11, h12, h13, h14, h15, h16, h17, h18, h19, h20, h21, + h22, h23, h24⟩ := h + simp only [initG, narrowRd, narrowWr, arg_withRegions, argAddr_withRegions, State.withRegions_gpr, + State.withRegions_rd, State.withRegions_wr] + exact ⟨h0, trivial, trivial, h3, h4, h5, h6, h7, h8, h9, h10, h11, h12, h13, h14, h15, h16, h17, h18, h19, h20, h21, + h22, h23, h24⟩ + refine Verified.narrowTo (verified hH hc hfit (hsat.elim fun s hs => ⟨_, pre s hs⟩)) + (narrowRd) (narrowWr hH.SH.stateBytes sc) pre (fun s h => ?_) (fun s h => ?_) + (fun _ _ _ h => h) (fun _ _ _ _ h => h) hsat + · obtain ⟨_, h1, h2, _⟩ := h + rw [h1, h2] + refine Covers.of_sub fun r hr => ?_ + simp only [narrowRd, narrowWr, List.cons_append, List.nil_append, List.mem_cons, List.not_mem_nil, + or_false] at hr + rcases hr with rfl | rfl | rfl | rfl | rfl + · exact ⟨_, List.mem_append_left _ List.mem_cons_self, 0, by simp, by simp⟩ + · exact ⟨_, List.mem_append_right _ (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_append_right _ List.mem_cons_self, 0, by simp, by simp⟩ + · exact ⟨_, List.mem_append_right _ (List.mem_cons_of_mem _ List.mem_cons_self), 0, by simp, by simp⟩ + · exact ⟨_, List.mem_append_right _ (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 [narrowWr, 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 VG.Proof.Hmac.Generic.X86.Init diff --git a/lean/VerifiedGarbage/Proof/Hmac/Generic/X86/Instances.lean b/lean/VerifiedGarbage/Proof/Hmac/Generic/X86/Instances.lean index f449a7b02..4f95c297c 100644 --- a/lean/VerifiedGarbage/Proof/Hmac/Generic/X86/Instances.lean +++ b/lean/VerifiedGarbage/Proof/Hmac/Generic/X86/Instances.lean @@ -1,16 +1,16 @@ import VerifiedGarbage.Proof.Framework.Contract import VerifiedGarbage.Proof.Hmac.Generic.X86.Lit -import VerifiedGarbage.Proof.Hmac.Generic.X86.FinalizeCT +import VerifiedGarbage.Proof.Hmac.Generic.X86.InitCT import VerifiedGarbage.Proof.Hmac.Generic.X86.Hashes /-! -# HMAC over the streaming hash functions on x86 (32-bit): the instances +# HMAC over the streaming hash functions on x86 (32-bit): the instances of `init` -Untrusted: everything here is checked by Lean. As on the other targets -(`Proof/Hmac/Generic/Arm/Instances.lean`): the generic proofs at each hash -function of `Hashes.lean`, moved to the shared contracts of -`Spec/Hmac/Generic.lean` (`sig_implies`), which the artifacts are emitted -with. +Untrusted: everything here is checked by Lean. The generic proof of `init` +(`InitCT.lean`) at each hash function of `Hashes.lean`, moved to the shared +contract of `Spec/Hmac/Generic.lean` (`sig_implies`), which the artifacts +are emitted with. `finalize` is written over the compression function +instead: `Proof/Pbkdf2/Md/X86/Instances.lean`. -/ namespace VG.Proof.Hmac.Generic.X86.Instances @@ -37,26 +37,6 @@ def initSat (S sc : Nat) : State where rd := [⟨0x1800, 0⟩] wr := [⟨0x1000, S⟩, ⟨0x1400, S⟩, ⟨0x2000, 8 * sc⟩, ⟨0x6004, 20⟩] -/-- Memory holding the arguments `0x1000, 0x1400, 0, 0, 0x1800, 0x2000` of -`finalize` at `0x6004`. -/ -def finMem : Mem := fun a => - if a = 0x6005 then 0x10 else if a = 0x6009 then 0x14 else if a = 0x6015 then 0x18 else - if a = 0x6019 then 0x20 else 0 - -/-- A state satisfying `finalize`'s precondition, with states of `S` bytes, -a digest of `D` bytes and `8 sc` bytes of scratch space, with the arguments -writable. -/ -def finSat (S D sc : Nat) : State where - gpr r := match r with - | .esp => 0x6000 | _ => 0 - cf := none - zf := none - sf := none - of := none - mem := finMem - rd := [⟨0x1400, S⟩] - wr := [⟨0x1000, S⟩, ⟨0x1800, D⟩, ⟨0x2000, 8 * sc⟩, ⟨0x6004, 24⟩] - theorem initSat_args (S sc : Nat) : arg (initSat S sc) 0 = 0x1000 ∧ arg (initSat S sc) 1 = 0x1400 ∧ arg (initSat S sc) 2 = 0x1800 ∧ arg (initSat S sc) 3 = 0 ∧ arg (initSat S sc) 4 = 0x2000 ∧ argAddr (initSat S sc) 0 = 0x6004 ∧ @@ -66,15 +46,6 @@ theorem initSat_args (S sc : Nat) : rw [e, e, e, e, e, e'] refine ⟨?_, ?_, ?_, ?_, ?_, ?_, rfl⟩ <;> decide -theorem finSat_args (S D sc : Nat) : - arg (finSat S D sc) 0 = 0x1000 ∧ arg (finSat S D sc) 1 = 0x1400 ∧ arg (finSat S D sc) 2 = 0 ∧ - arg (finSat S D sc) 3 = 0 ∧ arg (finSat S D sc) 4 = 0x1800 ∧ arg (finSat S D sc) 5 = 0x2000 ∧ - argAddr (finSat S D sc) 0 = 0x6004 ∧ (finSat S D sc).gpr .esp = 0x6000 := by - have e : ∀ i, arg (finSat S D sc) i = arg (finSat 0 0 0) i := fun _ => rfl - have e' : argAddr (finSat S D sc) 0 = argAddr (finSat 0 0 0) 0 := rfl - rw [e, e, e, e, e, e, e'] - refine ⟨?_, ?_, ?_, ?_, ?_, ?_, ?_, rfl⟩ <;> decide - /-! ## SHA-1 -/ theorem sha1_initChecks : Init.Checks sha1H where @@ -85,15 +56,6 @@ theorem sha1_initChecks : Init.Checks sha1H where rintro o (rfl | rfl) <;> exact ⟨_, by taint_decide⟩ restore := ⟨_, by taint_decide⟩ -theorem sha1_finChecks : Finalize.Checks sha1H where - pro := ⟨_, by taint_decide⟩ - fin1 := ⟨_, by taint_decide⟩ - copy1 := ⟨_, by taint_decide⟩ - upd := ⟨_, by taint_decide⟩ - fin2 := ⟨_, by taint_decide⟩ - copy2 := ⟨_, by taint_decide⟩ - restore := ⟨_, by taint_decide⟩ - theorem sha1_initImp : (initW Spec.Hmac.sha1S 56).Implies (Spec.Hmac.sha1I.initContract X86.abi 48) := by obtain ⟨a0, a1, a2, a3, a4, e, esp⟩ := initSat_args 84 56 sig_implies [Spec.Hmac.Instance.initContract, Spec.Hmac.initContract, Spec.Hmac.initSig, @@ -101,19 +63,9 @@ theorem sha1_initImp : (initW Spec.Hmac.sha1S 56).Implies (Spec.Hmac.sha1I.initC X86.argBytes] [a0, a1, a2, a3, a4, e, esp, initSat] using initSat 84 56 -theorem sha1_finImp : (finW Spec.Hmac.sha1S 56).Implies (Spec.Hmac.sha1I.finalizeContract X86.abi 48) := by - obtain ⟨a0, a1, a2, a3, a4, a5, e, esp⟩ := finSat_args 84 20 56 - sig_implies [Spec.Hmac.Instance.finalizeContract, Spec.Hmac.finalizeContract, Spec.Hmac.finalizeSig, - Spec.Hmac.sha1I, Spec.Hmac.sha1S, Spec.Hmac.sha1, finW, finG, countF, X86.abi, X86.argSlots, - X86.argVal, X86.argBytes] - [a0, a1, a2, a3, a4, a5, e, esp, finSat] using finSat 84 20 56 - theorem sha1_init : Verified X86.target sha1H.init (Spec.Hmac.sha1I.initContract X86.abi 48) := (Init.verifiedW sha1OK sha1_initChecks (by decide) sha1_initImp.sat_left).of_implies sha1_initImp -theorem sha1_finalize : Verified X86.target sha1H.finalize (Spec.Hmac.sha1I.finalizeContract X86.abi 48) := - (Finalize.verifiedW sha1OK sha1_finChecks (by decide) sha1_finImp.sat_left).of_implies sha1_finImp - /-! ## MD5 -/ theorem md5_initChecks : Init.Checks md5H where @@ -124,15 +76,6 @@ theorem md5_initChecks : Init.Checks md5H where rintro o (rfl | rfl) <;> exact ⟨_, by taint_decide⟩ restore := ⟨_, by taint_decide⟩ -theorem md5_finChecks : Finalize.Checks md5H where - pro := ⟨_, by taint_decide⟩ - fin1 := ⟨_, by taint_decide⟩ - copy1 := ⟨_, by taint_decide⟩ - upd := ⟨_, by taint_decide⟩ - fin2 := ⟨_, by taint_decide⟩ - copy2 := ⟨_, by taint_decide⟩ - restore := ⟨_, by taint_decide⟩ - theorem md5_initImp : (initW Spec.Hmac.md5S 48).Implies (Spec.Hmac.md5I.initContract X86.abi 48) := by obtain ⟨a0, a1, a2, a3, a4, e, esp⟩ := initSat_args 80 48 sig_implies [Spec.Hmac.Instance.initContract, Spec.Hmac.initContract, Spec.Hmac.initSig, @@ -140,19 +83,9 @@ theorem md5_initImp : (initW Spec.Hmac.md5S 48).Implies (Spec.Hmac.md5I.initCont X86.argBytes] [a0, a1, a2, a3, a4, e, esp, initSat] using initSat 80 48 -theorem md5_finImp : (finW Spec.Hmac.md5S 48).Implies (Spec.Hmac.md5I.finalizeContract X86.abi 48) := by - obtain ⟨a0, a1, a2, a3, a4, a5, e, esp⟩ := finSat_args 80 16 48 - sig_implies [Spec.Hmac.Instance.finalizeContract, Spec.Hmac.finalizeContract, Spec.Hmac.finalizeSig, - Spec.Hmac.md5I, Spec.Hmac.md5S, Spec.Hmac.md5, finW, finG, countF, X86.abi, X86.argSlots, - X86.argVal, X86.argBytes] - [a0, a1, a2, a3, a4, a5, e, esp, finSat] using finSat 80 16 48 - theorem md5_init : Verified X86.target md5H.init (Spec.Hmac.md5I.initContract X86.abi 48) := (Init.verifiedW md5OK md5_initChecks (by decide) md5_initImp.sat_left).of_implies md5_initImp -theorem md5_finalize : Verified X86.target md5H.finalize (Spec.Hmac.md5I.finalizeContract X86.abi 48) := - (Finalize.verifiedW md5OK md5_finChecks (by decide) md5_finImp.sat_left).of_implies md5_finImp - /-- `Init.Checks` looks at the sizes of a hash function but its digest's. -/ theorem Init.Checks.of_eq {H H' : Impl.Hmac.Generic.X86.Hash} (hB : H.B = H'.B) (hS : H.S = H'.S) (hW : H.W = H'.W) (h : Init.Checks H) : Init.Checks H' := by @@ -171,15 +104,6 @@ theorem sha384_initChecks : Init.Checks sha384H where rintro o (rfl | rfl) <;> exact ⟨_, by taint_decide⟩ restore := ⟨_, by taint_decide⟩ -theorem sha384_finChecks : Finalize.Checks sha384H where - pro := ⟨_, by taint_decide⟩ - fin1 := ⟨_, by taint_decide⟩ - copy1 := ⟨_, by taint_decide⟩ - upd := ⟨_, by taint_decide⟩ - fin2 := ⟨_, by taint_decide⟩ - copy2 := ⟨_, by taint_decide⟩ - restore := ⟨_, by taint_decide⟩ - theorem sha384_initImp : (initW Spec.Hmac.sha384S 234).Implies (Spec.Hmac.sha384I.initContract X86.abi 48) := by obtain ⟨a0, a1, a2, a3, a4, e, esp⟩ := initSat_args 192 234 sig_implies [Spec.Hmac.Instance.initContract, Spec.Hmac.initContract, Spec.Hmac.initSig, @@ -187,28 +111,14 @@ theorem sha384_initImp : (initW Spec.Hmac.sha384S 234).Implies (Spec.Hmac.sha384 X86.argBytes] [a0, a1, a2, a3, a4, e, esp, initSat] using initSat 192 234 -theorem sha384_finImp : (finW Spec.Hmac.sha384S 234).Implies (Spec.Hmac.sha384I.finalizeContract X86.abi 48) := by - obtain ⟨a0, a1, a2, a3, a4, a5, e, esp⟩ := finSat_args 192 48 234 - sig_implies [Spec.Hmac.Instance.finalizeContract, Spec.Hmac.finalizeContract, Spec.Hmac.finalizeSig, - Spec.Hmac.sha384I, Spec.Hmac.sha384S, Spec.Hmac.sha384, finW, finG, countF, X86.abi, X86.argSlots, - X86.argVal, X86.argBytes] - [a0, a1, a2, a3, a4, a5, e, esp, finSat] using finSat 192 48 234 - theorem sha384_init : Verified X86.target sha384H.init (Spec.Hmac.sha384I.initContract X86.abi 48) := (Init.verifiedW sha384OK sha384_initChecks (by decide) sha384_initImp.sat_left).of_implies sha384_initImp -theorem sha384_finalize : Verified X86.target sha384H.finalize (Spec.Hmac.sha384I.finalizeContract X86.abi 48) := - (Finalize.verifiedW sha384OK sha384_finChecks (by decide) sha384_finImp.sat_left).of_implies sha384_finImp - /-! ## SHA-512 -/ theorem sha512_initChecks : Init.Checks sha512H' := Init.Checks.of_eq (H := sha384H) rfl rfl rfl sha384_initChecks -theorem sha512_finChecks : Finalize.Checks sha512H' := - Finalize.Checks.of_sizes (H := sha384H) rfl rfl rfl sha384_finChecks ⟨_, by taint_decide⟩ ⟨_, by taint_decide⟩ - ⟨_, by taint_decide⟩ - theorem sha512_initImp : (initW Spec.Hmac.sha512S 234).Implies (Spec.Hmac.sha512I.initContract X86.abi 48) := by obtain ⟨a0, a1, a2, a3, a4, e, esp⟩ := initSat_args 192 234 sig_implies [Spec.Hmac.Instance.initContract, Spec.Hmac.initContract, Spec.Hmac.initSig, @@ -216,28 +126,14 @@ theorem sha512_initImp : (initW Spec.Hmac.sha512S 234).Implies (Spec.Hmac.sha512 X86.argBytes] [a0, a1, a2, a3, a4, e, esp, initSat] using initSat 192 234 -theorem sha512_finImp : (finW Spec.Hmac.sha512S 234).Implies (Spec.Hmac.sha512I.finalizeContract X86.abi 48) := by - obtain ⟨a0, a1, a2, a3, a4, a5, e, esp⟩ := finSat_args 192 64 234 - sig_implies [Spec.Hmac.Instance.finalizeContract, Spec.Hmac.finalizeContract, Spec.Hmac.finalizeSig, - Spec.Hmac.sha512I, Spec.Hmac.sha512S, Spec.Hmac.sha512, finW, finG, countF, X86.abi, X86.argSlots, - X86.argVal, X86.argBytes] - [a0, a1, a2, a3, a4, a5, e, esp, finSat] using finSat 192 64 234 - theorem sha512_init : Verified X86.target sha512H'.init (Spec.Hmac.sha512I.initContract X86.abi 48) := (Init.verifiedW sha512OK sha512_initChecks (by decide) sha512_initImp.sat_left).of_implies sha512_initImp -theorem sha512_finalize : Verified X86.target sha512H'.finalize (Spec.Hmac.sha512I.finalizeContract X86.abi 48) := - (Finalize.verifiedW sha512OK sha512_finChecks (by decide) sha512_finImp.sat_left).of_implies sha512_finImp - /-! ## SHA-512/224 -/ theorem sha512_224_initChecks : Init.Checks sha512_224H := Init.Checks.of_eq (H := sha384H) rfl rfl rfl sha384_initChecks -theorem sha512_224_finChecks : Finalize.Checks sha512_224H := - Finalize.Checks.of_sizes (H := sha384H) rfl rfl rfl sha384_finChecks ⟨_, by taint_decide⟩ ⟨_, by taint_decide⟩ - ⟨_, by taint_decide⟩ - theorem sha512_224_initImp : (initW Spec.Hmac.sha512_224S 234).Implies (Spec.Hmac.sha512_224I.initContract X86.abi 48) := by obtain ⟨a0, a1, a2, a3, a4, e, esp⟩ := initSat_args 192 234 sig_implies [Spec.Hmac.Instance.initContract, Spec.Hmac.initContract, Spec.Hmac.initSig, @@ -245,28 +141,14 @@ theorem sha512_224_initImp : (initW Spec.Hmac.sha512_224S 234).Implies (Spec.Hma X86.argBytes] [a0, a1, a2, a3, a4, e, esp, initSat] using initSat 192 234 -theorem sha512_224_finImp : (finW Spec.Hmac.sha512_224S 234).Implies (Spec.Hmac.sha512_224I.finalizeContract X86.abi 48) := by - obtain ⟨a0, a1, a2, a3, a4, a5, e, esp⟩ := finSat_args 192 28 234 - sig_implies [Spec.Hmac.Instance.finalizeContract, Spec.Hmac.finalizeContract, Spec.Hmac.finalizeSig, - Spec.Hmac.sha512_224I, Spec.Hmac.sha512_224S, Spec.Hmac.sha512_224, finW, finG, countF, X86.abi, X86.argSlots, - X86.argVal, X86.argBytes] - [a0, a1, a2, a3, a4, a5, e, esp, finSat] using finSat 192 28 234 - theorem sha512_224_init : Verified X86.target sha512_224H.init (Spec.Hmac.sha512_224I.initContract X86.abi 48) := (Init.verifiedW sha512_224OK sha512_224_initChecks (by decide) sha512_224_initImp.sat_left).of_implies sha512_224_initImp -theorem sha512_224_finalize : Verified X86.target sha512_224H.finalize (Spec.Hmac.sha512_224I.finalizeContract X86.abi 48) := - (Finalize.verifiedW sha512_224OK sha512_224_finChecks (by decide) sha512_224_finImp.sat_left).of_implies sha512_224_finImp - /-! ## SHA-512/256 -/ theorem sha512_256_initChecks : Init.Checks sha512_256H := Init.Checks.of_eq (H := sha384H) rfl rfl rfl sha384_initChecks -theorem sha512_256_finChecks : Finalize.Checks sha512_256H := - Finalize.Checks.of_sizes (H := sha384H) rfl rfl rfl sha384_finChecks ⟨_, by taint_decide⟩ ⟨_, by taint_decide⟩ - ⟨_, by taint_decide⟩ - theorem sha512_256_initImp : (initW Spec.Hmac.sha512_256S 234).Implies (Spec.Hmac.sha512_256I.initContract X86.abi 48) := by obtain ⟨a0, a1, a2, a3, a4, e, esp⟩ := initSat_args 192 234 sig_implies [Spec.Hmac.Instance.initContract, Spec.Hmac.initContract, Spec.Hmac.initSig, @@ -274,17 +156,7 @@ theorem sha512_256_initImp : (initW Spec.Hmac.sha512_256S 234).Implies (Spec.Hma X86.argBytes] [a0, a1, a2, a3, a4, e, esp, initSat] using initSat 192 234 -theorem sha512_256_finImp : (finW Spec.Hmac.sha512_256S 234).Implies (Spec.Hmac.sha512_256I.finalizeContract X86.abi 48) := by - obtain ⟨a0, a1, a2, a3, a4, a5, e, esp⟩ := finSat_args 192 32 234 - sig_implies [Spec.Hmac.Instance.finalizeContract, Spec.Hmac.finalizeContract, Spec.Hmac.finalizeSig, - Spec.Hmac.sha512_256I, Spec.Hmac.sha512_256S, Spec.Hmac.sha512_256, finW, finG, countF, X86.abi, X86.argSlots, - X86.argVal, X86.argBytes] - [a0, a1, a2, a3, a4, a5, e, esp, finSat] using finSat 192 32 234 - theorem sha512_256_init : Verified X86.target sha512_256H.init (Spec.Hmac.sha512_256I.initContract X86.abi 48) := (Init.verifiedW sha512_256OK sha512_256_initChecks (by decide) sha512_256_initImp.sat_left).of_implies sha512_256_initImp -theorem sha512_256_finalize : Verified X86.target sha512_256H.finalize (Spec.Hmac.sha512_256I.finalizeContract X86.abi 48) := - (Finalize.verifiedW sha512_256OK sha512_256_finChecks (by decide) sha512_256_finImp.sat_left).of_implies sha512_256_finImp - end VG.Proof.Hmac.Generic.X86.Instances diff --git a/lean/VerifiedGarbage/Proof/Hmac/Generic/X86/Lit.lean b/lean/VerifiedGarbage/Proof/Hmac/Generic/X86/Lit.lean index 9a51fef8f..bd55c79c0 100644 --- a/lean/VerifiedGarbage/Proof/Hmac/Generic/X86/Lit.lean +++ b/lean/VerifiedGarbage/Proof/Hmac/Generic/X86/Lit.lean @@ -1,35 +1,23 @@ import VerifiedGarbage.Proof.Framework.X86.Lit import VerifiedGarbage.Proof.Hmac.Generic.X86.Hashes -import VerifiedGarbage.Impl.Pbkdf2.Generic.X86 /-! -# HMAC and PBKDF2 over every hash on X86: the code as literals +# HMAC over every hash on X86: `init` as literals -Untrusted: everything here is checked by Lean. HMAC's `init` and `finalize` -and PBKDF2's `iterate` at each hash function, as literals (`materialize_code`, -`Proof/Framework/Lit.lean`) that refer to the hash functions' literals: the -registration files' `spSafe` checks evaluate them. +Untrusted: everything here is checked by Lean. HMAC's `init` at each hash +function, as literals (`materialize_code`, `Proof/Framework/Lit.lean`) that +refer to the hash functions' literals: the registration files' `spSafe` +checks evaluate them. `finalize` and PBKDF2's `iterate`, written over the +compression function, are in `Proof/Pbkdf2/Md/X86/Lit.lean`. -/ namespace VG.Proof.Hmac.Generic.X86 materialize_code sha1HInit := sha1H.init -materialize_code sha1HFinalize := sha1H.finalize materialize_code md5HInit := md5H.init -materialize_code md5HFinalize := md5H.finalize materialize_code sha384HInit := sha384H.init -materialize_code sha384HFinalize := sha384H.finalize materialize_code sha512HInit := sha512H'.init -materialize_code sha512HFinalize := sha512H'.finalize materialize_code sha512_224HInit := sha512_224H.init -materialize_code sha512_224HFinalize := sha512_224H.finalize materialize_code sha512_256HInit := sha512_256H.init -materialize_code sha512_256HFinalize := sha512_256H.finalize -materialize_code sha1HIterate := Impl.Pbkdf2.Generic.X86.iterate sha1H -materialize_code md5HIterate := Impl.Pbkdf2.Generic.X86.iterate md5H -materialize_code sha384HIterate := Impl.Pbkdf2.Generic.X86.iterate sha384H -materialize_code sha512HIterate := Impl.Pbkdf2.Generic.X86.iterate sha512H' -materialize_code sha512_224HIterate := Impl.Pbkdf2.Generic.X86.iterate sha512_224H -materialize_code sha512_256HIterate := Impl.Pbkdf2.Generic.X86.iterate sha512_256H end VG.Proof.Hmac.Generic.X86 diff --git a/lean/VerifiedGarbage/Proof/Pbkdf2/Generic/X86/Instances.lean b/lean/VerifiedGarbage/Proof/Pbkdf2/Generic/X86/Instances.lean deleted file mode 100644 index 46c82e8df..000000000 --- a/lean/VerifiedGarbage/Proof/Pbkdf2/Generic/X86/Instances.lean +++ /dev/null @@ -1,219 +0,0 @@ -import VerifiedGarbage.Proof.Framework.Contract -import VerifiedGarbage.Proof.Hmac.Generic.X86.Lit -import VerifiedGarbage.Proof.Pbkdf2.Generic.X86.IterateCT -import VerifiedGarbage.Proof.Hmac.Generic.X86.Hashes - -/-! -# PBKDF2-HMAC over the streaming hash functions on x86 (32-bit): the instances - -Untrusted: everything here is checked by Lean. As on 32-bit ARM -(`Proof/Pbkdf2/Generic/Arm/Instances.lean`): the generic proof -(`IterateCT.lean`) at each hash function of -`Proof/Hmac/Generic/X86/Hashes.lean`, moved to the shared contract of -`Spec/Pbkdf2/Generic.lean` (`sig_implies`), which the artifacts are emitted with. --/ - -namespace VG.Proof.Pbkdf2.Generic.X86.Instances - -open VG.X86 -open VG.Proof.Hmac.Generic.X86 -open VG.Proof.Pbkdf2.Generic.X86 - -/-- Memory holding the arguments `0x1000, 0x1400, 0, 0x1800, 0x2000` of -`iterate` at `0x6004`. -/ -def iterMem : Mem := fun a => - if a = 0x6005 then 0x10 else if a = 0x6009 then 0x14 else if a = 0x6011 then 0x18 else - if a = 0x6015 then 0x20 else 0 - -/-- A state satisfying `iterate`'s precondition, with states of `S` bytes, a -digest of `D` bytes and `8 sc` bytes of scratch space, with the arguments -writable. -/ -def iterSat (S D sc : Nat) : State where - gpr r := match r with - | .esp => 0x6000 | _ => 0 - cf := none - zf := none - sf := none - of := none - mem := iterMem - rd := [⟨0x1000, 2 * S⟩, ⟨0x1400, D⟩] - wr := [⟨0x1800, D⟩, ⟨0x2000, 8 * sc⟩, ⟨0x6004, 20⟩] - -theorem iterSat_args (S D sc : Nat) : - arg (iterSat S D sc) 0 = 0x1000 ∧ arg (iterSat S D sc) 1 = 0x1400 ∧ arg (iterSat S D sc) 2 = 0 ∧ - arg (iterSat S D sc) 3 = 0x1800 ∧ arg (iterSat S D sc) 4 = 0x2000 ∧ argAddr (iterSat S D sc) 0 = 0x6004 ∧ - (iterSat S D sc).gpr .esp = 0x6000 := by - have e : ∀ i, arg (iterSat S D sc) i = arg (iterSat 0 0 0) i := fun _ => rfl - have e' : argAddr (iterSat S D sc) 0 = argAddr (iterSat 0 0 0) 0 := rfl - rw [e, e, e, e, e, e'] - refine ⟨?_, ?_, ?_, ?_, ?_, ?_, rfl⟩ <;> decide - -/-! ## SHA-1 -/ - -theorem sha1_checks : Checks sha1H where - pro := ⟨_, by taint_decide⟩ - copyU := ⟨_, by taint_decide⟩ - copyK := by - simp only [List.mem_cons, List.not_mem_nil, or_false] - rintro o (rfl | rfl) <;> exact ⟨_, by taint_decide⟩ - upd := by - simp only [List.mem_cons, List.not_mem_nil, or_false] - rintro o (rfl | rfl) <;> exact ⟨_, by taint_decide⟩ - fin := by - simp only [List.mem_cons, List.not_mem_nil, or_false] - rintro o (rfl | rfl) <;> exact ⟨_, by taint_decide⟩ - xor := ⟨_, by taint_decide⟩ - restore := ⟨_, by taint_decide⟩ - -theorem sha1_imp : (iterW Spec.Hmac.sha1S 56).Implies (Spec.Hmac.sha1I.iterateContract X86.abi 48) := by - obtain ⟨a0, a1, a2, a3, a4, e, esp⟩ := iterSat_args 84 20 56 - sig_implies [Spec.Hmac.Instance.iterateContract, Spec.Pbkdf2.iterateContract, Spec.Pbkdf2.iterateSig, - Spec.Hmac.sha1I, Spec.Hmac.sha1S, Spec.Hmac.sha1, iterW, iterG, X86.abi, X86.argSlots, X86.argVal, - X86.argBytes] - [a0, a1, a2, a3, a4, e, esp, iterSat] using iterSat 84 20 56 - -theorem sha1 : Verified X86.target (Impl.Pbkdf2.Generic.X86.iterate sha1H) - (Spec.Hmac.sha1I.iterateContract X86.abi 48) := - (verifiedW sha1OK sha1_checks (by decide) sha1_imp.sat_left).of_implies sha1_imp - -/-! ## MD5 -/ - -theorem md5_checks : Checks md5H where - pro := ⟨_, by taint_decide⟩ - copyU := ⟨_, by taint_decide⟩ - copyK := by - simp only [List.mem_cons, List.not_mem_nil, or_false] - rintro o (rfl | rfl) <;> exact ⟨_, by taint_decide⟩ - upd := by - simp only [List.mem_cons, List.not_mem_nil, or_false] - rintro o (rfl | rfl) <;> exact ⟨_, by taint_decide⟩ - fin := by - simp only [List.mem_cons, List.not_mem_nil, or_false] - rintro o (rfl | rfl) <;> exact ⟨_, by taint_decide⟩ - xor := ⟨_, by taint_decide⟩ - restore := ⟨_, by taint_decide⟩ - -theorem md5_imp : (iterW Spec.Hmac.md5S 48).Implies (Spec.Hmac.md5I.iterateContract X86.abi 48) := by - obtain ⟨a0, a1, a2, a3, a4, e, esp⟩ := iterSat_args 80 16 48 - sig_implies [Spec.Hmac.Instance.iterateContract, Spec.Pbkdf2.iterateContract, Spec.Pbkdf2.iterateSig, - Spec.Hmac.md5I, Spec.Hmac.md5S, Spec.Hmac.md5, iterW, iterG, X86.abi, X86.argSlots, X86.argVal, - X86.argBytes] - [a0, a1, a2, a3, a4, e, esp, iterSat] using iterSat 80 16 48 - -theorem md5 : Verified X86.target (Impl.Pbkdf2.Generic.X86.iterate md5H) - (Spec.Hmac.md5I.iterateContract X86.abi 48) := - (verifiedW md5OK md5_checks (by decide) md5_imp.sat_left).of_implies md5_imp - -/-! ## SHA-384 -/ - -theorem sha384_checks : Checks sha384H where - pro := ⟨_, by taint_decide⟩ - copyU := ⟨_, by taint_decide⟩ - copyK := by - simp only [List.mem_cons, List.not_mem_nil, or_false] - rintro o (rfl | rfl) <;> exact ⟨_, by taint_decide⟩ - upd := by - simp only [List.mem_cons, List.not_mem_nil, or_false] - rintro o (rfl | rfl) <;> exact ⟨_, by taint_decide⟩ - fin := by - simp only [List.mem_cons, List.not_mem_nil, or_false] - rintro o (rfl | rfl) <;> exact ⟨_, by taint_decide⟩ - xor := ⟨_, by taint_decide⟩ - restore := ⟨_, by taint_decide⟩ - -theorem sha384_imp : (iterW Spec.Hmac.sha384S 234).Implies (Spec.Hmac.sha384I.iterateContract X86.abi 48) := by - obtain ⟨a0, a1, a2, a3, a4, e, esp⟩ := iterSat_args 192 48 234 - sig_implies [Spec.Hmac.Instance.iterateContract, Spec.Pbkdf2.iterateContract, Spec.Pbkdf2.iterateSig, - Spec.Hmac.sha384I, Spec.Hmac.sha384S, Spec.Hmac.sha384, iterW, iterG, X86.abi, X86.argSlots, X86.argVal, - X86.argBytes] - [a0, a1, a2, a3, a4, e, esp, iterSat] using iterSat 192 48 234 - -theorem sha384 : Verified X86.target (Impl.Pbkdf2.Generic.X86.iterate sha384H) - (Spec.Hmac.sha384I.iterateContract X86.abi 48) := - (verifiedW sha384OK sha384_checks (by decide) sha384_imp.sat_left).of_implies sha384_imp - -/-! ## SHA-512 -/ - -theorem sha512_checks : Checks sha512H' where - pro := ⟨_, by taint_decide⟩ - copyU := ⟨_, by taint_decide⟩ - copyK := by - simp only [List.mem_cons, List.not_mem_nil, or_false] - rintro o (rfl | rfl) <;> exact ⟨_, by taint_decide⟩ - upd := by - simp only [List.mem_cons, List.not_mem_nil, or_false] - rintro o (rfl | rfl) <;> exact ⟨_, by taint_decide⟩ - fin := by - simp only [List.mem_cons, List.not_mem_nil, or_false] - rintro o (rfl | rfl) <;> exact ⟨_, by taint_decide⟩ - xor := ⟨_, by taint_decide⟩ - restore := ⟨_, by taint_decide⟩ - -theorem sha512_imp : (iterW Spec.Hmac.sha512S 234).Implies (Spec.Hmac.sha512I.iterateContract X86.abi 48) := by - obtain ⟨a0, a1, a2, a3, a4, e, esp⟩ := iterSat_args 192 64 234 - sig_implies [Spec.Hmac.Instance.iterateContract, Spec.Pbkdf2.iterateContract, Spec.Pbkdf2.iterateSig, - Spec.Hmac.sha512I, Spec.Hmac.sha512S, Spec.Hmac.sha512, iterW, iterG, X86.abi, X86.argSlots, X86.argVal, - X86.argBytes] - [a0, a1, a2, a3, a4, e, esp, iterSat] using iterSat 192 64 234 - -theorem sha512 : Verified X86.target (Impl.Pbkdf2.Generic.X86.iterate sha512H') - (Spec.Hmac.sha512I.iterateContract X86.abi 48) := - (verifiedW sha512OK sha512_checks (by decide) sha512_imp.sat_left).of_implies sha512_imp - -/-! ## SHA-512/224 -/ - -theorem sha512_224_checks : Checks sha512_224H where - pro := ⟨_, by taint_decide⟩ - copyU := ⟨_, by taint_decide⟩ - copyK := by - simp only [List.mem_cons, List.not_mem_nil, or_false] - rintro o (rfl | rfl) <;> exact ⟨_, by taint_decide⟩ - upd := by - simp only [List.mem_cons, List.not_mem_nil, or_false] - rintro o (rfl | rfl) <;> exact ⟨_, by taint_decide⟩ - fin := by - simp only [List.mem_cons, List.not_mem_nil, or_false] - rintro o (rfl | rfl) <;> exact ⟨_, by taint_decide⟩ - xor := ⟨_, by taint_decide⟩ - restore := ⟨_, by taint_decide⟩ - -theorem sha512_224_imp : (iterW Spec.Hmac.sha512_224S 234).Implies (Spec.Hmac.sha512_224I.iterateContract X86.abi 48) := by - obtain ⟨a0, a1, a2, a3, a4, e, esp⟩ := iterSat_args 192 28 234 - sig_implies [Spec.Hmac.Instance.iterateContract, Spec.Pbkdf2.iterateContract, Spec.Pbkdf2.iterateSig, - Spec.Hmac.sha512_224I, Spec.Hmac.sha512_224S, Spec.Hmac.sha512_224, iterW, iterG, X86.abi, X86.argSlots, X86.argVal, - X86.argBytes] - [a0, a1, a2, a3, a4, e, esp, iterSat] using iterSat 192 28 234 - -theorem sha512_224 : Verified X86.target (Impl.Pbkdf2.Generic.X86.iterate sha512_224H) - (Spec.Hmac.sha512_224I.iterateContract X86.abi 48) := - (verifiedW sha512_224OK sha512_224_checks (by decide) sha512_224_imp.sat_left).of_implies sha512_224_imp - -/-! ## SHA-512/256 -/ - -theorem sha512_256_checks : Checks sha512_256H where - pro := ⟨_, by taint_decide⟩ - copyU := ⟨_, by taint_decide⟩ - copyK := by - simp only [List.mem_cons, List.not_mem_nil, or_false] - rintro o (rfl | rfl) <;> exact ⟨_, by taint_decide⟩ - upd := by - simp only [List.mem_cons, List.not_mem_nil, or_false] - rintro o (rfl | rfl) <;> exact ⟨_, by taint_decide⟩ - fin := by - simp only [List.mem_cons, List.not_mem_nil, or_false] - rintro o (rfl | rfl) <;> exact ⟨_, by taint_decide⟩ - xor := ⟨_, by taint_decide⟩ - restore := ⟨_, by taint_decide⟩ - -theorem sha512_256_imp : (iterW Spec.Hmac.sha512_256S 234).Implies (Spec.Hmac.sha512_256I.iterateContract X86.abi 48) := by - obtain ⟨a0, a1, a2, a3, a4, e, esp⟩ := iterSat_args 192 32 234 - sig_implies [Spec.Hmac.Instance.iterateContract, Spec.Pbkdf2.iterateContract, Spec.Pbkdf2.iterateSig, - Spec.Hmac.sha512_256I, Spec.Hmac.sha512_256S, Spec.Hmac.sha512_256, iterW, iterG, X86.abi, X86.argSlots, X86.argVal, - X86.argBytes] - [a0, a1, a2, a3, a4, e, esp, iterSat] using iterSat 192 32 234 - -theorem sha512_256 : Verified X86.target (Impl.Pbkdf2.Generic.X86.iterate sha512_256H) - (Spec.Hmac.sha512_256I.iterateContract X86.abi 48) := - (verifiedW sha512_256OK sha512_256_checks (by decide) sha512_256_imp.sat_left).of_implies sha512_256_imp - -end VG.Proof.Pbkdf2.Generic.X86.Instances diff --git a/lean/VerifiedGarbage/Proof/Pbkdf2/Generic/X86/Iterate.lean b/lean/VerifiedGarbage/Proof/Pbkdf2/Generic/X86/Iterate.lean deleted file mode 100644 index 86a6ad8e6..000000000 --- a/lean/VerifiedGarbage/Proof/Pbkdf2/Generic/X86/Iterate.lean +++ /dev/null @@ -1,770 +0,0 @@ -import VerifiedGarbage.Impl.Pbkdf2.Generic.X86 -import VerifiedGarbage.Proof.Hmac.Generic.X86.Finalize - -/-! -# PBKDF2-HMAC over any streaming hash function on x86 (32-bit): `iterate`, correct - -Untrusted: everything here is checked by Lean. As on 32-bit ARM -(`Proof/Pbkdf2/Generic/Arm/Instances.lean`). The arguments are on the stack: -`scratch`, `n` and `u` are loaded first (after our caller's registers are -saved in `scratch`), and `key` and `t` again in each step, when needed. The -loop counts the steps left in `edi` down with `sub`, and branches on its -result. --/ - -namespace VG.Proof.Pbkdf2.Generic.X86 - -open VG.X86 -open VG.Impl.Hmac.Generic.X86 (Hash copy at_) -open VG.Impl.Pbkdf2.Generic.X86 (stO tmpO uO xorLoop atSt ldKey ldT body prologue iterate) -open VG.Proof.Hmac.Generic.X86 -open VG.Proof.Hmac.Generic.X86.Finalize (add_zero') -open VG.Proof.Hmac.Generic.X86.Init (argW) -open VG.Proof.Hmac.Generic.Common (inRegions_of_sub xorBytes_length' sub_of_off sub_of_self bytes_keep - bytesAt_take bytesAt_writeBytes_self') -open VG.Proof.Sha256.X86.Stream (Upd Fupd wp_mov wp_movi wp_movm wp_add wp_addi wp_subi wp_test sub_offset - ofNat_beq_zero sub_ofNat eval_e eval_ne) -open VG.Proof.Hmac.Common (bytesAt_length writeBytes_at bytesAt_getD' xorPad_length) -open VG.Proof.Sha256.Stream (writeBytes) -open Spec.Sha256 (bytesAt) -open Spec.Hmac (xorPad ipad opad hmacBlockKey) - -variable {H : Hash} (hH : HashOK H) (sc : Nat) - -section -variable (s₀ : State) - -abbrev E : BitVec 32 := s₀.gpr .esp -abbrev key : BitVec 32 := arg s₀ 0 -abbrev up : BitVec 32 := arg s₀ 1 -abbrev tp : BitVec 32 := arg s₀ 3 -abbrev scr : BitVec 32 := arg s₀ 4 -/-- The number of steps. -/ -abbrev nn : Nat := (arg s₀ 2).toNat -abbrev keyR : Region := ⟨(key s₀).setWidth 64, 2 * H.S⟩ -abbrev uR : Region := ⟨(up s₀).setWidth 64, H.D⟩ -abbrev tR : Region := ⟨(tp s₀).setWidth 64, H.D⟩ -abbrev scR : Region := ⟨(scr s₀).setWidth 64, 8 * sc⟩ -abbrev argR : Region := ⟨addr (E s₀) 4, 20⟩ -abbrev retR : Region := ⟨(E s₀).setWidth 64, 4⟩ -abbrev stkR : Region := below (E s₀) 48 -/-- Byte `o` of `scratch`, and its address as a register holds it. -/ -abbrev SA (o : Nat) : Addr := (scr s₀).setWidth 64 + BitVec.ofNat 64 o -abbrev sO (o : Nat) : BitVec 32 := scr s₀ + BitVec.ofNat 32 o -/-- The state being hashed, the inner digest and `U`, in `scratch`. -/ -abbrev ST : Addr := SA s₀ (stO H) -abbrev TM : Addr := SA s₀ (tmpO H) -abbrev UA : Addr := SA s₀ (uO H) -abbrev calR : Region := ⟨(scr s₀).setWidth 64, hH.Wb⟩ - -end - -/-- The precondition, with the sizes of `H`. -/ -structure Pre (s₀ : State) : Prop where - rd : s₀.rd = [keyR (H := H) s₀, uR (H := H) s₀, argR s₀] - wr : s₀.wr = [tR (H := H) s₀, scR sc s₀] - k_t : (keyR (H := H) s₀).Disjoint (tR (H := H) s₀) - k_s : (keyR (H := H) s₀).Disjoint (scR sc s₀) - u_t : (uR (H := H) s₀).Disjoint (tR (H := H) s₀) - u_s : (uR (H := H) s₀).Disjoint (scR sc s₀) - t_s : (tR (H := H) s₀).Disjoint (scR sc s₀) - a_t : (argR s₀).Disjoint (tR (H := H) s₀) - a_s : (argR s₀).Disjoint (scR sc s₀) - r_t : (retR s₀).Disjoint (tR (H := H) s₀) - r_s : (retR s₀).Disjoint (scR sc s₀) - b_k : (stkR s₀).Disjoint (keyR (H := H) s₀) - b_u : (stkR s₀).Disjoint (uR (H := H) s₀) - b_t : (stkR s₀).Disjoint (tR (H := H) s₀) - b_s : (stkR s₀).Disjoint (scR sc s₀) - nk : (key s₀).toNat + 2 * H.S ≤ 2 ^ 32 - nu : (up s₀).toNat + H.D ≤ 2 ^ 32 - nt : (tp s₀).toNat + H.D ≤ 2 ^ 32 - nw : (scr s₀).toNat + 8 * sc ≤ 2 ^ 32 - sp48 : 48 ≤ (E s₀).toNat - spf : (E s₀).toNat + 24 ≤ 2 ^ 32 - fits : H.buf + H.S + 2 * H.F ≤ 8 * sc - hB : 0 < H.B ∧ H.B ≤ 128 - hW : H.W ≤ 64 - hS : 0 < H.S ∧ H.S ≤ 256 - hD : 0 < H.D ∧ H.D ≤ H.F ∧ H.F ≤ 64 - -theorem pre_of {s₀ : State} (h : (iterG hH.SH sc).pre s₀) (hfit : H.buf + H.S + 2 * H.F ≤ 8 * sc) : - Pre (H := H) sc s₀ := by - obtain ⟨h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11, h12, h13, h14, h15, h16, h17, h18, h19, h20⟩ := h - have hS := hH.hS - have hD := hH.hD - have e : (⟨(s₀.gpr .esp).setWidth 64 - 48, 48⟩ : Region) = stkR s₀ := by - simp only [stkR, below]; rw [Taint.sub_setWidth h19]; rfl - simp only [hS, hD, e] at * - exact ⟨h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11, h12, h13, h14, h15, h16, h17, h18, h19, h20, hfit, - ⟨hH.hB0, hH.hBB⟩, hH.hW, ⟨hH.hS0, hH.hSB⟩, ⟨hH.hD0, hH.hDF, hH.hF⟩⟩ - -/-! ## The parts of `scratch` -/ - -section -variable {sc : Nat} {s₀ : State} (hp : Pre (H := H) sc s₀) -include hp - -theorem bounds : H.buf = 8 * H.W + 16 ∧ H.buf + H.S + 2 * H.F ≤ 8 * sc ∧ (scr s₀).toNat + 8 * sc ≤ 2 ^ 32 ∧ - H.W ≤ 64 ∧ 0 < H.S ∧ H.S ≤ 256 ∧ 0 < H.D ∧ H.D ≤ H.F ∧ H.F ≤ 64 ∧ 0 < H.B ∧ H.B ≤ 128 := - ⟨rfl, hp.fits, hp.nw, hp.hW, hp.hS.1, hp.hS.2, hp.hD.1, hp.hD.2.1, hp.hD.2.2, hp.hB.1, hp.hB.2⟩ - -theorem off_sub {o n : Nat} (h : o + n ≤ 8 * sc) : - Region.Sub ⟨SA s₀ o, n⟩ (scR sc s₀) := - sub_offset h (by have := hp.nw; omega) - -theorem addr_sO {o : Nat} (h : o < 8 * sc) : (sO s₀ o).setWidth 64 = SA s₀ o := - setWidth_add (by have := hp.nw; omega) - -theorem toNat_sO {o : Nat} (h : o < 8 * sc) : (sO s₀ o).toNat = (scr s₀).toNat + o := - toNat_add_ofNat (by have := hp.nw; omega) - -theorem save_sub : Region.Sub (saveR H (scr s₀)) (scR sc s₀) := by - obtain ⟨hb, hf, -⟩ := bounds hp; exact off_sub hp (by omega) - -theorem st_sub : Region.Sub ⟨ST (H := H) s₀, H.S⟩ (scR sc s₀) := by - obtain ⟨hb, hf, -⟩ := bounds hp; exact off_sub hp (by simp only [stO]; omega) - -theorem tm_sub : Region.Sub ⟨TM (H := H) s₀, H.F⟩ (scR sc s₀) := by - obtain ⟨hb, hf, -⟩ := bounds hp; exact off_sub hp (by simp only [tmpO]; omega) - -theorem ua_sub : Region.Sub ⟨UA (H := H) s₀, H.F⟩ (scR sc s₀) := by - obtain ⟨hb, hf, -⟩ := bounds hp; exact off_sub hp (by simp only [uO]; omega) - -include hH in -theorem cal_sub : Region.Sub (calR hH s₀) (scR sc s₀) := by - have := hH.hWb; obtain ⟨hb, hf, -⟩ := bounds hp - exact Region.sub_prefix (by omega) - -/-- The parts of `scratch` do not overlap. -/ -theorem part_disj {a m b n : Nat} (h : a + m ≤ b ∨ b + n ≤ a) (ha : a + m ≤ 8 * sc) (hb : b + n ≤ 8 * sc) : - Region.Disjoint ⟨SA s₀ a, m⟩ ⟨SA s₀ b, n⟩ := - VG.Proof.Hmac.Generic.Common.off_disj _ h (by have := hp.nw; omega) (by have := hp.nw; omega) - -include hH in -theorem cal_disj {b n : Nat} (h : 8 * H.W ≤ b) (hb : b + n ≤ 8 * sc) : - (calR hH s₀).Disjoint ⟨SA s₀ b, n⟩ := by - have := hH.hWb; have := hp.nw - exact VG.Proof.Hmac.Generic.Common.off_disj0 _ (by omega) (by omega) - -theorem stk_arg : (stkR s₀).Disjoint (argR s₀) := stk_args hp.sp48 (by have := hp.spf; omega) - -theorem stk_ret' : (stkR s₀).Disjoint (retR s₀) := stk_ret hp.sp48 (by have := hp.spf; omega) - -end - -/-! ## What the pieces keep -/ - -/-- The regions everything writes: `T`, `scratch` and the stack below `esp`. -/ -abbrev wrs (s₀ : State) : List Region := [tR (H := H) s₀, scR sc s₀, stkR s₀] - -/-- The registers and memory kept from the prologue on, with `m` steps left. -/ -structure KR (s₀ : State) (m : Nat) (s : State) : Prop where - rd : s.rd = s₀.rd - wr : s.wr = s₀.wr - esp : s.gpr .esp = E s₀ - ebp : s.gpr .ebp = scr s₀ - edi : s.gpr .edi = BitVec.ofNat 32 m - saved : SavedRegs H (scr s₀) s₀ s.mem - frame : Frame (wrs (H := H) sc s₀) s₀.mem s.mem - -/-- The registers `KR` fixes. -/ -abbrev kregs : List Reg := [.esp, .ebp, .edi] - -theorem kregs_callee : ∀ r ∈ kregs, r ∈ calleeSaved := by decide -theorem kregs_clob : ∀ r ∈ kregs, r ∉ clob := by decide - -section -variable {sc : Nat} - -theorem KR.keep {s₀ : State} {m : Nat} {s s' : State} (h : KR (H := H) sc s₀ m s) (hrd : s'.rd = s.rd) - (hwr : s'.wr = s.wr) (hg : ∀ r ∈ kregs, s'.gpr r = s.gpr r) {rs : List Region} - (hf : Frame rs s.mem s'.mem) (hs : ∀ r ∈ rs, (saveR H (scr s₀)).Disjoint r) - (hsub : ∀ r ∈ rs, ∃ r' ∈ wrs (H := H) sc s₀, Region.Sub r r') : - KR (H := H) sc s₀ m s' := - ⟨hrd.trans h.rd, hwr.trans h.wr, (hg _ (by simp)).trans h.esp, (hg _ (by simp)).trans h.ebp, - (hg _ (by simp)).trans h.edi, h.saved.frame H hf hs, h.frame.trans (hf.sub hsub)⟩ - -theorem KR.upd {s₀ : State} {m : Nat} {s s' : State} (h : KR (H := H) sc s₀ m s) {d : Reg} (hd : d ∉ kregs) - {v : BitVec 32} (u : Upd s s' d v) : KR (H := H) sc s₀ m s' := - h.keep u.rd u.wr (fun r hr => u.other r fun e => hd (e ▸ hr)) (rs := []) (by rw [u.mem]; exact Frame.refl _ _) - (by simp) (by simp) - -theorem stk_eq {s₀ : State} {m : Nat} {s : State} (hk : KR (H := H) sc s₀ m s) : stk s = stkR s₀ := by - rw [stk, hk.esp] - -end - -section -variable {sc : Nat} {s₀ : State} (hp : Pre (H := H) sc s₀) -include hp - -theorem mem_wr : scR sc s₀ ∈ s₀.wr ∧ tR (H := H) s₀ ∈ s₀.wr := by rw [hp.wr]; simp - -theorem argR_in : argR s₀ ∈ s₀.rd ++ s₀.wr := by rw [hp.rd]; simp - -theorem argIn {s : State} (hrd : s.rd = s₀.rd) (hwr : s.wr = s₀.wr) {i : Nat} (hi : i < 5) : - InRegions (s.rd ++ s.wr) (argAddr s₀ i) 4 := by - rw [hrd, hwr] - exact ⟨argR s₀, argR_in hp, arg_contains rfl (by omega) (by have := hp.spf; omega)⟩ - -theorem KR.argEq {m : Nat} {s : State} (hk : KR (H := H) sc s₀ m s) {i : Nat} (hi : i < 5) : - VG.X86.arg s i = VG.X86.arg s₀ i := - arg_keep rfl hk.esp (n := 20) (by have := hp.spf; omega) hk.frame (by - simp only [List.mem_cons, List.not_mem_nil, or_false] - rintro r (rfl | rfl | rfl) - · exact hp.a_t - · exact hp.a_s - · exact (stk_arg hp).symm) (by omega) - -theorem KR.readArg {m : Nat} {s : State} (hk : KR (H := H) sc s₀ m s) {i : Nat} (hi : i < 5) : - s.mem.readW (argAddr s₀ i) 32 = VG.X86.arg s₀ i := by - have := hk.argEq hp hi - simp only [VG.X86.arg] at this ⊢ - rwa [show argAddr s i = argAddr s₀ i by rw [argAddr_eq, argAddr_eq, hk.esp]] at this - -theorem KR.ret {m : Nat} {s : State} (hk : KR (H := H) sc s₀ m s) : - s.mem.readW ((E s₀).setWidth 64) 32 = s₀.mem.readW ((E s₀).setWidth 64) 32 := - hk.frame.readW (r := retR s₀) (Region.contains_self _ _) (by - simp only [List.mem_cons, List.not_mem_nil, or_false] - rintro r (rfl | rfl | rfl) - · exact hp.r_t - · exact hp.r_s - · exact (stk_ret' hp).symm) (by decide) - -theorem KR.call {m : Nat} {s s' : State} (h : KR (H := H) sc s₀ m s) {ws : List Region} (ha : After s ws s') - (hs : ∀ r ∈ ws, (saveR H (scr s₀)).Disjoint r) (hsub : ∀ r ∈ ws, Region.Sub r (scR sc s₀)) : - KR (H := H) sc s₀ m s' := by - have f := ha.frame - rw [stk_eq h] at f - refine h.keep ha.rd ha.wr (fun r hr => ha.cs r (kregs_callee r hr)) f (fun r hr => ?_) (fun r hr => ?_) - · rcases List.mem_append.mp hr with hr | hr - · exact hs r hr - · simp only [List.mem_singleton] at hr; subst hr; exact hp.b_s.symm.sub_left (save_sub hp) - · rcases List.mem_append.mp hr with hr | hr - · exact ⟨scR sc s₀, by simp, hsub r hr⟩ - · simp only [List.mem_singleton] at hr; subst hr; exact ⟨stkR s₀, by simp, fun _ h => h⟩ - -theorem save_off {o n : Nat} (ho : 8 * H.W + 16 ≤ o) (h : o + n ≤ 8 * sc) : - (saveR H (scr s₀)).Disjoint ⟨SA s₀ o, n⟩ := - part_disj hp (a := 8 * H.W) (m := 16) (by omega) (by have := hp.fits; simp only [Hash.buf] at this; omega) h - -/-! ## The loads of `key` and `t` -/ - -theorem ld_ok {m : Nat} {s : State} (hk : KR (H := H) sc s₀ m s) {i : Nat} (hi : i = 0 ∨ i = 3) : - WP isa (.block [.mov .esi (.mem (at_ .esp (4 + 4 * i)))]) s fun t => - KR (H := H) sc s₀ m t ∧ t.gpr .esi = arg s₀ i ∧ t.mem = s.mem := by - have hi' : i < 5 := by omega - refine wp_movm (a := argAddr s₀ i) (by rw [ea_at, hk.esp]; rfl) (argIn hp hk.rd hk.wr hi') fun t u => ?_ - exact WP.block_nil ⟨hk.upd (by decide) u, by rw [u.gpr, hk.readArg hp hi'], u.mem⟩ - -/-! ## The copies of the key's states -/ - -theorem copyKey_ok {m : Nat} {s : State} (hk : KR (H := H) sc s₀ m s) (hsi : s.gpr .esi = key s₀) {o : Nat} - (ho : o = 0 ∨ o = H.S) : - WP isa (copy .esi o .ebp (stO H) H.S) s fun t => KR (H := H) sc s₀ m t ∧ - Frame [⟨ST (H := H) s₀, H.S⟩] s.mem t.mem ∧ - ∀ msg, hH.SH.Repr s₀.mem ((key s₀).setWidth 64 + BitVec.ofNat 64 o) msg → - hH.SH.Repr t.mem (ST (H := H) s₀) msg := by - obtain ⟨hb, hf, hnw, hW, hS0, hS, -⟩ := bounds hp - have hkn := hp.nk - have ksub : Region.Sub ⟨(key s₀).setWidth 64 + BitVec.ofNat 64 o, H.S⟩ (keyR (H := H) s₀) := - sub_offset (by rcases ho with rfl | rfl <;> omega) (by rcases ho with rfl | rfl <;> omega) - have kR : keyR (H := H) s₀ ∈ s.rd ++ s.wr := by rw [hk.rd, hp.rd]; simp - have sR : scR sc s₀ ∈ s.wr := by rw [hk.wr]; exact (mem_wr hp).1 - have stsub := st_sub hp - refine WP.mono (copy_ok (so := o) (d := stO H) (n := H.S) (by decide) (by decide) hS0 (by omega) - (by rw [hsi]; rcases ho with rfl | rfl <;> omega) (by rw [hk.ebp]; simp only [stO]; omega) - (fun k hk' => by rw [hsi]; exact inRegions_of_sub kR ksub (by omega) hk') - (fun k hk' => by rw [hk.ebp]; exact inRegions_of_sub sR stsub (by omega) hk') - (by rw [hsi, hk.ebp]; exact (hp.k_s.sub_left ksub).sub_right stsub)) fun t c => ?_ - rw [hsi, hk.ebp] at c - have fr : Frame [⟨ST (H := H) s₀, H.S⟩] s.mem t.mem := - c.mem ▸ Proof.Sha256.Stream.writeBytes_frame _ _ _ (by rw [bytesAt_length]; exact Region.contains_self _ _) - have sd : (saveR H (scr s₀)).Disjoint ⟨ST (H := H) s₀, H.S⟩ := - save_off hp (by simp only [stO]; omega) (by simp only [stO]; omega) - refine ⟨hk.keep c.rd c.wr (fun r hr => c.other r (not_cclob (kregs_clob r hr))) - fr (fun r hr => by simp only [List.mem_singleton] at hr; subst hr; exact sd) - (fun r hr => by simp only [List.mem_singleton] at hr; subst hr; exact ⟨_, by simp, stsub⟩), - fr, fun msg hr => ?_⟩ - refine hH.repr _ _ _ _ _ (fun i hi => ?_) hr - rw [c.mem, writeBytes_at _ _ _ (by rw [bytesAt_length]; exact hi) (by rw [bytesAt_length]; omega), - bytesAt_getD' _ _ hi] - -- The key's bytes are those of the initial memory. - refine hk.frame.bytes (R := ⟨(key s₀).setWidth 64 + BitVec.ofNat 64 o, H.S⟩) ?_ (by show H.S ≤ 2 ^ 64; omega) hi - simp only [List.mem_cons, List.not_mem_nil, or_false] - rintro r (rfl | rfl | rfl) - · exact hp.k_t.sub_left ksub - · exact hp.k_s.sub_left ksub - · exact hp.b_k.symm.sub_left ksub - -/-! ## The calls -/ - -/-- The block before `update`'s frame, from the state, with `D` bytes at `scratch + o`. -/ -abbrev updBlock (H : Hash) (o : Nat) : List Instr := - atSt H ++ [.mov .eax (.imm 0), .mov .esi (.imm (BitVec.ofNat 32 H.B)), .mov .ecx (.imm (BitVec.ofNat 32 H.D))] ++ - Impl.Hmac.Generic.X86.scr .edx o - -/-- The block before `finalize`'s frame, from the state, into `scratch + o`. -/ -abbrev finBlock (H : Hash) (o : Nat) : List Instr := - atSt H ++ H.count2 ++ Impl.Hmac.Generic.X86.scr .edx o - -theorem updArgs_ok {m : Nat} {s : State} (hk : KR (H := H) sc s₀ m s) {o : Nat} (ho : o = uO H ∨ o = tmpO H) : - WP isa (.block (updBlock H o)) s fun t => - KR (H := H) sc s₀ m t ∧ - UpdArgs hH t .esi .ebx (sO s₀ (stO H)) (sO s₀ o) (scr s₀) (BitVec.ofNat 32 H.B) H.D ∧ t.mem = s.mem := by - obtain ⟨hb, hf, hnw, hW, hS0, hS, hD0, hDF, hF, hB0, hB⟩ := bounds hp - have hwb := hH.hWb - have eu : uO H = H.buf + H.S + H.F := rfl - have et : tmpO H = H.buf + H.S := rfl - have es : stO H = H.buf := rfl - have ho' : stO H + H.S ≤ o ∧ o + H.F ≤ 8 * sc := by rcases ho with rfl | rfl <;> omega - have sR : scR sc s₀ ∈ s₀.wr := (mem_wr hp).1 - have dsub : Region.Sub ⟨SA s₀ o, H.D⟩ (scR sc s₀) := off_sub hp (by omega) - have eS := addr_sO hp (o := stO H) (by omega) - have eO := addr_sO hp (o := o) (by omega) - simp only [updBlock, atSt, Impl.Hmac.Generic.X86.scr, List.cons_append, List.nil_append] - refine wp_mov fun s₁ u₁ => wp_addi fun s₂ u₂ => wp_movi fun s₃ u₃ => wp_movi fun s₄ u₄ => - wp_movi fun s₅ u₅ => wp_mov fun s₆ u₆ => wp_addi fun s₇ u₇ => WP.block_nil ?_ - have k₇ : KR (H := H) sc s₀ m s₇ := - ((((((hk.upd (by decide) u₁).upd (by decide) u₂).upd (by decide) u₃).upd (by decide) u₄).upd - (by decide) u₅).upd (by decide) u₆).upd (by decide) u₇ - refine ⟨k₇, ?_, by rw [u₇.mem, u₆.mem, u₅.mem, u₄.mem, u₃.mem, u₂.mem, u₁.mem]⟩ - exact - { hst := by rw [u₇.other _ (by decide), u₆.other _ (by decide), u₅.other _ (by decide), - u₄.other _ (by decide), u₃.other _ (by decide), u₂.gpr, u₁.gpr, hk.ebp] - hlo := by rw [u₇.other _ (by decide), u₆.other _ (by decide), u₅.other _ (by decide), u₄.gpr] - eax := by rw [u₇.other _ (by decide), u₆.other _ (by decide), u₅.other _ (by decide), - u₄.other _ (by decide), u₃.gpr] - ecx := by rw [u₇.other _ (by decide), u₆.other _ (by decide), u₅.gpr] - edx := by rw [u₇.gpr, u₆.gpr, u₅.other _ (by decide), u₄.other _ (by decide), u₃.other _ (by decide), - u₂.other _ (by decide), u₁.other _ (by decide), hk.ebp] - ebp := k₇.ebp - hr := by decide - hl := by decide - hlen := by omega - sp48 := by rw [k₇.esp]; exact hp.sp48 - cd := by - rw [k₇.rd, k₇.wr, eO] - exact Covers.of_sub fun r hr => by - simp only [List.mem_singleton] at hr; subst hr - exact sub_of_off (List.mem_append_right _ sR) (by omega) - cw := by - rw [k₇.wr, eS] - exact Covers.of_sub fun r hr => by - simp only [List.mem_cons, List.not_mem_nil, or_false] at hr - rcases hr with rfl | rfl - · exact sub_of_off sR (by omega) - · exact sub_of_self (r := scR sc s₀) sR (by show hH.Wb ≤ 8 * sc; omega) - st_sc := by rw [eS]; exact (cal_disj hH hp (by omega) (by omega)).symm - d_st := by rw [eO, eS]; exact part_disj hp (by omega) (by omega) (by omega) - d_sc := by rw [eO]; exact (cal_disj hH hp (by omega) (by omega)).symm - b_st := by rw [stk_eq k₇, eS]; exact hp.b_s.sub_right (st_sub hp) - b_d := by rw [stk_eq k₇, eO]; exact hp.b_s.sub_right dsub - b_sc := by rw [stk_eq k₇]; exact hp.b_s.sub_right (cal_sub hH hp) - nst := by rw [toNat_sO hp (by omega)]; omega - nd := by rw [toNat_sO hp (by omega)]; omega - nsc := by omega } - -theorem updCall_ok {m : Nat} {t : State} (hk : KR (H := H) sc s₀ m t) {o : Nat} (ho : o = uO H ∨ o = tmpO H) - (ha : UpdArgs hH t .esi .ebx (sO s₀ (stO H)) (sO s₀ o) (scr s₀) (BitVec.ofNat 32 H.B) H.D) {Q : State → Prop} - (hQ : ∀ s', KR (H := H) sc s₀ m s' → Frame [⟨ST (H := H) s₀, H.S⟩, calR hH s₀, stkR s₀] t.mem s'.mem → - (∀ msg, hH.SH.Repr t.mem (ST (H := H) s₀) msg → BitVec.ofNat 64 H.B = BitVec.ofNat 64 msg.length → - hH.SH.Repr s'.mem (ST (H := H) s₀) (msg ++ bytesAt t.mem (SA s₀ o) H.D)) → Q s') : - WP isa (.frame (.push (upd6 .esi .ebx)) (.call H.updN H.updC) (.pop .eax (upd6 .esi .ebx).length)) t Q := by - obtain ⟨hb, hf, hnw, hW, hS0, hS, hD0, hDF, hF, hB0, hB⟩ := bounds hp - have hwb := hH.hWb - have eu : uO H = H.buf + H.S + H.F := rfl - have et : tmpO H = H.buf + H.S := rfl - have es : stO H = H.buf := rfl - have ho' : stO H + H.S ≤ o ∧ o + H.F ≤ 8 * sc := by rcases ho with rfl | rfl <;> omega - have eS := addr_sO hp (o := stO H) (by omega) - have eO := addr_sO hp (o := o) (by omega) - refine upd_frame hH ha fun s' ha' hpost => ?_ - have f := ha'.frame - rw [stk_eq hk, eS] at f - rw [eS, eO] at hpost - refine hQ s' (hk.call hp ha' ?_ ?_) f fun msg hr hc => hpost msg hr (by - rw [zero_append_ofNat (by omega)]; exact hc) - · simp only [List.mem_cons, List.not_mem_nil, or_false] - rw [eS] - rintro r (rfl | rfl) - · exact save_off hp (by simp only [stO]; omega) (by simp only [stO]; omega) - · exact ((cal_disj hH hp (b := 8 * H.W) (n := 16) (Nat.le_refl _) (by omega))).symm - · simp only [List.mem_cons, List.not_mem_nil, or_false] - rw [eS] - rintro r (rfl | rfl) - · exact st_sub hp - · exact cal_sub hH hp - -theorem finArgs_ok {m : Nat} {s : State} (hk : KR (H := H) sc s₀ m s) {o : Nat} (ho : o = uO H ∨ o = tmpO H) : - WP isa (.block (finBlock H o)) s fun t => - KR (H := H) sc s₀ m t ∧ - FinArgs hH t .ebx (sO s₀ (stO H)) (sO s₀ o) (scr s₀) (BitVec.ofNat 32 (H.B + H.D)) 0 ∧ t.mem = s.mem := by - obtain ⟨hb, hf, hnw, hW, hS0, hS, hD0, hDF, hF, hB0, hB⟩ := bounds hp - have hwb := hH.hWb - have eu : uO H = H.buf + H.S + H.F := rfl - have et : tmpO H = H.buf + H.S := rfl - have es : stO H = H.buf := rfl - have ho' : stO H + H.S ≤ o ∧ o + H.F ≤ 8 * sc := by rcases ho with rfl | rfl <;> omega - have sR : scR sc s₀ ∈ s₀.wr := (mem_wr hp).1 - have osub : Region.Sub ⟨SA s₀ o, H.F⟩ (scR sc s₀) := off_sub hp (by omega) - have eS := addr_sO hp (o := stO H) (by omega) - have eO := addr_sO hp (o := o) (by omega) - simp only [finBlock, atSt, Hash.count2, Impl.Hmac.Generic.X86.scr, List.cons_append, List.nil_append] - refine wp_mov fun s₁ u₁ => wp_addi fun s₂ u₂ => wp_movi fun s₃ u₃ => wp_movi fun s₄ u₄ => - wp_mov fun s₅ u₅ => wp_addi fun s₆ u₆ => WP.block_nil ?_ - have k₆ : KR (H := H) sc s₀ m s₆ := - (((((hk.upd (by decide) u₁).upd (by decide) u₂).upd (by decide) u₃).upd (by decide) u₄).upd - (by decide) u₅).upd (by decide) u₆ - refine ⟨k₆, ?_, by rw [u₆.mem, u₅.mem, u₄.mem, u₃.mem, u₂.mem, u₁.mem]⟩ - exact - { hst := by rw [u₆.other _ (by decide), u₅.other _ (by decide), u₄.other _ (by decide), - u₃.other _ (by decide), u₂.gpr, u₁.gpr, hk.ebp] - eax := by rw [u₆.other _ (by decide), u₅.other _ (by decide), u₄.other _ (by decide), u₃.gpr] - ecx := by rw [u₆.other _ (by decide), u₅.other _ (by decide), u₄.gpr] - edx := by rw [u₆.gpr, u₅.gpr, u₄.other _ (by decide), u₃.other _ (by decide), u₂.other _ (by decide), - u₁.other _ (by decide), hk.ebp] - ebp := k₆.ebp - hr := by decide - sp48 := by rw [k₆.esp]; exact hp.sp48 - cw := by - rw [k₆.wr, eS, eO] - exact Covers.of_sub fun r hr => by - simp only [List.mem_cons, List.not_mem_nil, or_false] at hr - rcases hr with rfl | rfl | rfl - · exact sub_of_off sR (by omega) - · exact sub_of_off sR (by omega) - · exact sub_of_self (r := scR sc s₀) sR (by show hH.Wb ≤ 8 * sc; omega) - st_o := by rw [eS, eO]; exact part_disj hp (by omega) (by omega) (by omega) - st_sc := by rw [eS]; exact (cal_disj hH hp (by omega) (by omega)).symm - o_sc := by rw [eO]; exact (cal_disj hH hp (by omega) (by omega)).symm - b_st := by rw [stk_eq k₆, eS]; exact hp.b_s.sub_right (st_sub hp) - b_o := by rw [stk_eq k₆, eO]; exact hp.b_s.sub_right osub - b_sc := by rw [stk_eq k₆]; exact hp.b_s.sub_right (cal_sub hH hp) - nst := by rw [toNat_sO hp (by omega)]; omega - no := by rw [toNat_sO hp (by omega)]; omega - nsc := by omega } - -theorem finCall_ok {m : Nat} {t : State} (hk : KR (H := H) sc s₀ m t) {o : Nat} (ho : o = uO H ∨ o = tmpO H) - (ha : FinArgs hH t .ebx (sO s₀ (stO H)) (sO s₀ o) (scr s₀) (BitVec.ofNat 32 (H.B + H.D)) 0) - {Q : State → Prop} - (hQ : ∀ s', KR (H := H) sc s₀ m s' → - Frame [⟨ST (H := H) s₀, H.S⟩, ⟨SA s₀ o, H.F⟩, calR hH s₀, stkR s₀] t.mem s'.mem → - (∀ msg, hH.SH.Repr t.mem (ST (H := H) s₀) msg → msg.length < 2 ^ 64 → - BitVec.ofNat 64 (H.B + H.D) = BitVec.ofNat 64 msg.length → - (bytesAt s'.mem (SA s₀ o) H.F).take H.D = hH.SH.H.hash msg) → Q s') : - WP isa (.frame (.push (fin5 .ebx)) (.call H.finN H.finC) (.pop .eax (fin5 .ebx).length)) t Q := by - obtain ⟨hb, hf, hnw, hW, hS0, hS, hD0, hDF, hF, hB0, hB⟩ := bounds hp - have hwb := hH.hWb - have eu : uO H = H.buf + H.S + H.F := rfl - have et : tmpO H = H.buf + H.S := rfl - have es : stO H = H.buf := rfl - have ho' : stO H + H.S ≤ o ∧ o + H.F ≤ 8 * sc := by rcases ho with rfl | rfl <;> omega - have eS := addr_sO hp (o := stO H) (by omega) - have eO := addr_sO hp (o := o) (by omega) - refine fin_frame hH ha fun s' ha' hpost => ?_ - have f := ha'.frame - rw [stk_eq hk, eS, eO] at f - rw [eS, eO] at hpost - refine hQ s' (hk.call hp ha' ?_ ?_) f fun msg hr hl hc => hpost msg hr hl (by - rw [zero_append_ofNat (by omega)]; exact hc) - · simp only [List.mem_cons, List.not_mem_nil, or_false] - rw [eS, eO] - rintro r (rfl | rfl | rfl) - · exact save_off hp (by omega) (by omega) - · exact save_off hp (by omega) (by omega) - · exact ((cal_disj hH hp (b := 8 * H.W) (n := 16) (Nat.le_refl _) (by omega))).symm - · simp only [List.mem_cons, List.not_mem_nil, or_false] - rw [eS, eO] - rintro r (rfl | rfl | rfl) - · exact st_sub hp - · exact off_sub hp (by omega) - · exact cal_sub hH hp - -/-! ## `T ← T ⊕ U` and the count -/ - -theorem xor'_ok {m : Nat} {s : State} (hk : KR (H := H) sc s₀ m s) (hsi : s.gpr .esi = tp s₀) : - WP isa (xorLoop H) s fun t => KR (H := H) sc s₀ m t ∧ - t.mem = writeBytes s.mem ((tp s₀).setWidth 64) (Spec.Pbkdf2.xorBytes - (bytesAt s.mem ((tp s₀).setWidth 64) H.D) (bytesAt s.mem (UA (H := H) s₀) H.D)) := by - obtain ⟨hb, hf, hnw, hW, hS0, hS, hD0, hDF, hF, hB0, hB⟩ := bounds hp - have eu : uO H = H.buf + H.S + H.F := rfl - obtain ⟨sR, tR'⟩ := mem_wr hp - have nt := hp.nt - have usub : Region.Sub ⟨UA (H := H) s₀, H.D⟩ (scR sc s₀) := off_sub hp (by omega) - refine WP.mono (xor_ok (uo := uO H) (n := H.D) hD0 (by omega) - (by rw [hk.ebp]; omega) (by rw [hsi]; omega) - (fun k hk' => by - rw [hk.ebp, hk.rd, hk.wr]; exact inRegions_of_sub (List.mem_append_right _ sR) usub (by omega) hk') - (fun k hk' => by rw [hsi, hk.wr]; exact inRegions_of_sub tR' (fun _ h => h) (by omega) hk') - (by rw [hk.ebp, hsi]; exact hp.t_s.symm.sub_left usub)) fun t x => ?_ - rw [hk.ebp, hsi] at x - refine ⟨hk.keep x.rd x.wr (fun r hr => x.other r (kregs_clob r hr)) - (x.mem ▸ Proof.Sha256.Stream.writeBytes_frame _ _ _ (R := tR (H := H) s₀) (by - rw [xorBytes_length' _ _ (by simp [bytesAt_length]), bytesAt_length]; exact Region.contains_self _ _)) - (fun r hr => by simp only [List.mem_singleton] at hr; subst hr; exact hp.t_s.symm.sub_left (save_sub hp)) - (fun r hr => by simp only [List.mem_singleton] at hr; subst hr; exact ⟨_, by simp, fun _ h => h⟩), x.mem⟩ - -omit hp in -theorem dec_ok {m : Nat} (hm : 1 ≤ m) (hn : m < 2 ^ 32) {s : State} (hk : KR (H := H) sc s₀ m s) : - WP isa (.block [.alu .sub .edi (.imm 1)]) s fun t => KR (H := H) sc s₀ (m - 1) t ∧ t.mem = s.mem ∧ - t.zf = some (decide (m - 1 = 0)) := - wp_subi fun t u z => WP.block_nil ⟨⟨by rw [u.rd, hk.rd], by rw [u.wr, hk.wr], - by rw [u.other _ (by decide), hk.esp], by rw [u.other _ (by decide), hk.ebp], - by rw [u.gpr, hk.edi, show (1 : BitVec 32) = BitVec.ofNat 32 1 from rfl, sub_ofNat hm], - u.mem ▸ hk.saved, u.mem ▸ hk.frame⟩, - u.mem, by rw [z, hk.edi, show (1 : BitVec 32) = BitVec.ofNat 32 1 from rfl, sub_ofNat hm, - ofNat_beq_zero (by omega)]⟩ - -end - -/-! ## One step -/ - -/-- The key's states represent `K₀ ⊕ ipad` and `K₀ ⊕ opad`. -/ -def KeyOK (s₀ : State) (k0 : List Byte) : Prop := - k0.length = H.B ∧ hH.SH.Repr s₀.mem ((key s₀).setWidth 64) (xorPad k0 ipad) ∧ - hH.SH.Repr s₀.mem ((key s₀).setWidth 64 + BitVec.ofNat 64 H.S) (xorPad k0 opad) - -/-- With `m` steps left, what is left to compute is the rest of the whole. -/ -structure Inv (s₀ : State) (m : Nat) (s : State) : Prop where - kr : KR (H := H) sc s₀ m s - it : ∀ k0, KeyOK hH s₀ k0 → - Spec.Pbkdf2.iterate (hmacBlockKey hH.SH.H k0) (nn s₀) (bytesAt s₀.mem ((up s₀).setWidth 64) H.D) - (bytesAt s₀.mem ((tp s₀).setWidth 64) H.D) = - Spec.Pbkdf2.iterate (hmacBlockKey hH.SH.H k0) m (bytesAt s.mem (UA (H := H) s₀) H.D) - (bytesAt s.mem ((tp s₀).setWidth 64) H.D) - -section -variable {sc : Nat} {s₀ : State} (hp : Pre (H := H) sc s₀) -include hp - -theorem body_ok {m : Nat} (hm : 1 ≤ m) (hn : m < 2 ^ 32) {s : State} (h : Inv hH sc s₀ m s) : - WP isa (body H) s fun t => Inv hH sc s₀ (m - 1) t ∧ t.zf = some (decide (m - 1 = 0)) := by - obtain ⟨hb, hf, hnw, hW, hS0, hS, hD0, hDF, hF, hB0, hB⟩ := bounds hp - have eu : uO H = H.buf + H.S + H.F := rfl - have et : tmpO H = H.buf + H.S := rfl - have es : stO H = H.buf := rfl - have hwb := hH.hWb - -- Where things are. - have ua : Region.Sub ⟨UA (H := H) s₀, H.D⟩ (scR sc s₀) := off_sub hp (by omega) - have dM₁ : Region.Disjoint ⟨TM (H := H) s₀, H.D⟩ ⟨ST (H := H) s₀, H.S⟩ := - part_disj hp (by omega) (by omega) (by omega) - have dU₁ : Region.Disjoint ⟨UA (H := H) s₀, H.D⟩ ⟨ST (H := H) s₀, H.S⟩ := - part_disj hp (by omega) (by omega) (by omega) - have dT : ∀ r : Region, Region.Sub r (scR sc s₀) → Region.Disjoint (tR (H := H) s₀) r := - fun r hr => hp.t_s.sub_right hr - have dT₄ : Region.Disjoint (tR (H := H) s₀) (stkR s₀) := hp.b_t.symm - have hDn : H.D ≤ 2 ^ 64 := by omega - -- The pieces. - refine WP.seq (WP.mono (ld_ok hp h.kr (.inl rfl)) fun l₁ ⟨kl₁, sl₁, ml₁⟩ => ?_) - refine WP.seq (WP.mono (copyKey_ok hH hp kl₁ sl₁ (.inl rfl)) fun c₁ ⟨kc₁, fc₁, rc₁⟩ => ?_) - refine WP.seq (WP.seq (WP.mono (updArgs_ok hH hp kc₁ (.inl rfl)) fun a₁ ⟨ka₁, aa₁, ma₁⟩ => - updCall_ok hH hp ka₁ (.inl rfl) aa₁ fun u₁ ku₁ fu₁ ru₁ => ?_)) - refine WP.seq (WP.seq (WP.mono (finArgs_ok hH hp ku₁ (.inr rfl)) fun b₁ ⟨kb₁, ab₁, mb₁⟩ => - finCall_ok hH hp kb₁ (.inr rfl) ab₁ fun f₁ kf₁ ff₁ rf₁ => ?_)) - refine WP.seq (WP.mono (ld_ok hp kf₁ (.inl rfl)) fun l₂ ⟨kl₂, sl₂, ml₂⟩ => ?_) - refine WP.seq (WP.mono (copyKey_ok hH hp kl₂ sl₂ (.inr rfl)) fun c₂ ⟨kc₂, fc₂, rc₂⟩ => ?_) - refine WP.seq (WP.seq (WP.mono (updArgs_ok hH hp kc₂ (.inr rfl)) fun a₂ ⟨ka₂, aa₂, ma₂⟩ => - updCall_ok hH hp ka₂ (.inr rfl) aa₂ fun u₂ ku₂ fu₂ ru₂ => ?_)) - refine WP.seq (WP.seq (WP.mono (finArgs_ok hH hp ku₂ (.inl rfl)) fun b₂ ⟨kb₂, ab₂, mb₂⟩ => - finCall_ok hH hp kb₂ (.inl rfl) ab₂ fun f₂ kf₂ ff₂ rf₂ => ?_)) - refine WP.seq (WP.mono (ld_ok hp kf₂ (.inr rfl)) fun l₃ ⟨kl₃, sl₃, ml₃⟩ => ?_) - refine WP.seq (WP.mono (xor'_ok hp kl₃ sl₃) fun x ⟨kx, mx⟩ => ?_) - refine WP.mono (dec_ok hm hn kx) fun t ⟨kt, mt, zt⟩ => ⟨⟨kt, fun k0 hk => ?_⟩, zt⟩ - -- The bytes of `U` and `T` at each point. - obtain ⟨hl0, hrI, hrO⟩ := hk - have U₁ : bytesAt c₁.mem (UA (H := H) s₀) H.D = bytesAt s.mem (UA (H := H) s₀) H.D := by - rw [← ml₁]; exact bytes_keep fc₁ (by simp only [List.mem_singleton]; rintro r rfl; exact dU₁) hDn - have T₁ : bytesAt c₁.mem ((tp s₀).setWidth 64) H.D = bytesAt s.mem ((tp s₀).setWidth 64) H.D := by - rw [← ml₁]; exact bytes_keep fc₁ (by simp only [List.mem_singleton]; rintro r rfl; exact dT _ (st_sub hp)) hDn - have T₂ : bytesAt u₁.mem ((tp s₀).setWidth 64) H.D = bytesAt c₁.mem ((tp s₀).setWidth 64) H.D := by - rw [← ma₁]; exact bytes_keep fu₁ (by - simp only [List.mem_cons, List.not_mem_nil, or_false] - rintro r (rfl | rfl | rfl) - · exact dT _ (st_sub hp) - · exact dT _ (cal_sub hH hp) - · exact dT₄) hDn - have T₃ : bytesAt f₁.mem ((tp s₀).setWidth 64) H.D = bytesAt u₁.mem ((tp s₀).setWidth 64) H.D := by - rw [← mb₁]; exact bytes_keep ff₁ (by - simp only [List.mem_cons, List.not_mem_nil, or_false] - rintro r (rfl | rfl | rfl | rfl) - · exact dT _ (st_sub hp) - · exact dT _ (tm_sub hp) - · exact dT _ (cal_sub hH hp) - · exact dT₄) hDn - have T₄ : bytesAt c₂.mem ((tp s₀).setWidth 64) H.D = bytesAt f₁.mem ((tp s₀).setWidth 64) H.D := by - rw [← ml₂]; exact bytes_keep fc₂ (by simp only [List.mem_singleton]; rintro r rfl; exact dT _ (st_sub hp)) hDn - have T₅ : bytesAt u₂.mem ((tp s₀).setWidth 64) H.D = bytesAt c₂.mem ((tp s₀).setWidth 64) H.D := by - rw [← ma₂]; exact bytes_keep fu₂ (by - simp only [List.mem_cons, List.not_mem_nil, or_false] - rintro r (rfl | rfl | rfl) - · exact dT _ (st_sub hp) - · exact dT _ (cal_sub hH hp) - · exact dT₄) hDn - have T₆ : bytesAt f₂.mem ((tp s₀).setWidth 64) H.D = bytesAt u₂.mem ((tp s₀).setWidth 64) H.D := by - rw [← mb₂]; exact bytes_keep ff₂ (by - simp only [List.mem_cons, List.not_mem_nil, or_false] - rintro r (rfl | rfl | rfl | rfl) - · exact dT _ (st_sub hp) - · exact dT _ (ua_sub hp) - · exact dT _ (cal_sub hH hp) - · exact dT₄) hDn - have M₄ : bytesAt c₂.mem (TM (H := H) s₀) H.D = bytesAt f₁.mem (TM (H := H) s₀) H.D := by - rw [← ml₂]; exact bytes_keep fc₂ (by simp only [List.mem_singleton]; rintro r rfl; exact dM₁) hDn - -- The inner hash. - have rI₁ := rc₁ _ (by rw [add_zero']; exact hrI) - have rU₁ := ru₁ _ (ma₁ ▸ rI₁) (by rw [xorPad_length, hl0]) - rw [ma₁, U₁] at rU₁ - have hl₁ : (xorPad k0 ipad ++ bytesAt s.mem (UA (H := H) s₀) H.D).length = H.B + H.D := by - rw [List.length_append, xorPad_length, hl0, bytesAt_length] - have dig₁ := rf₁ _ (mb₁ ▸ rU₁) (by rw [hl₁]; omega) (by rw [hl₁]) - -- The outer hash. - have rO₂ := rc₂ _ hrO - have rU₂ := ru₂ _ (ma₂ ▸ rO₂) (by rw [xorPad_length, hl0]) - rw [ma₂, M₄, bytesAt_take _ _ hDF, dig₁] at rU₂ - have hl₂ : (xorPad k0 opad ++ hH.SH.H.hash (xorPad k0 ipad ++ bytesAt s.mem (UA (H := H) s₀) H.D)).length = - H.B + H.D := by - rw [List.length_append, xorPad_length, hl0, ← dig₁, List.length_take, bytesAt_length, Nat.min_eq_left hDF] - have dig₂ := rf₂ _ (mb₂ ▸ rU₂) (by rw [hl₂]; omega) (by rw [hl₂]) - rw [← bytesAt_take _ _ hDF] at dig₂ - -- `T ← T ⊕ U`. - have hx : (Spec.Pbkdf2.xorBytes (bytesAt l₃.mem ((tp s₀).setWidth 64) H.D) - (bytesAt l₃.mem (UA (H := H) s₀) H.D)).length = H.D := by - rw [xorBytes_length' _ _ (by simp [bytesAt_length]), bytesAt_length] - have Ux : bytesAt t.mem (UA (H := H) s₀) H.D = bytesAt f₂.mem (UA (H := H) s₀) H.D := by - rw [mt, mx, ← ml₃] - exact bytes_keep (Proof.Sha256.Stream.writeBytes_frame _ _ _ (R := tR (H := H) s₀) (by - rw [hx]; exact Region.contains_self _ _)) (by - simp only [List.mem_singleton]; rintro r rfl; exact (dT _ ua).symm) hDn - have Tx : bytesAt t.mem ((tp s₀).setWidth 64) H.D = Spec.Pbkdf2.xorBytes - (bytesAt f₂.mem ((tp s₀).setWidth 64) H.D) (bytesAt f₂.mem (UA (H := H) s₀) H.D) := by - rw [mt, mx, bytesAt_writeBytes_self' hx (by omega), ml₃] - rw [h.it k0 ⟨hl0, hrI, hrO⟩, show m = (m - 1) + 1 by omega, Ux, Tx, dig₂, T₆, T₅, T₄, T₃, T₂, T₁, - Nat.add_sub_cancel] - rfl - -/-! ## The prologue and the loop -/ - -omit hp in -theorem nn_lt : nn s₀ < 2 ^ 32 := (arg s₀ 2).isLt - -theorem pro_ok : WP isa (.block (prologue H)) s₀ fun t => KR (H := H) sc s₀ (nn s₀) t ∧ t.gpr .esi = up s₀ ∧ - Frame [saveR H (scr s₀)] s₀.mem t.mem := by - have hW := hp.hW; have hf := hp.fits; have nw := hp.nw - simp only [Hash.buf] at hf - obtain ⟨sR, _⟩ := mem_wr hp - have dA : ∀ r ∈ [saveR H (scr s₀)], (argR s₀).Disjoint r := by - simp only [List.mem_singleton]; rintro r rfl; exact hp.a_s.sub_right (save_sub hp) - simp only [prologue, List.singleton_append] - refine wp_movm (a := argAddr s₀ 4) (argW rfl 4) (argIn hp rfl rfl (by decide)) fun s₁ u₁ => ?_ - refine save_ok H (scr := scr s₀) u₁.gpr hW (by rw [u₁.wr]; exact sR) (by omega) (by omega) - fun s₂ g₂ rd₂ wr₂ f₂ sv₂ => ?_ - have e₂ : ∀ r, r ≠ .eax → s₂.gpr r = s₀.gpr r := fun r hr => by rw [g₂, u₁.other r hr] - have f₂' : Frame [saveR H (scr s₀)] s₀.mem s₂.mem := by rw [← u₁.mem]; exact f₂ - have rA : ∀ i < 5, s₂.mem.readW (argAddr s₀ i) 32 = arg s₀ i := fun i hi => - f₂'.readW (r := ⟨argAddr s₀ i, 4⟩) (Region.contains_self _ _) (fun r hr => - (dA r hr).sub_left (arg_sub rfl (by omega) (by have := hp.spf; omega))) (by decide) - have i₂ : ∀ i < 5, InRegions (s₂.rd ++ s₂.wr) (argAddr s₀ i) 4 := fun i hi => by - rw [rd₂, wr₂, u₁.rd, u₁.wr]; exact argIn hp rfl rfl hi - refine wp_mov fun s₃ u₃ => ?_ - refine wp_movm (a := argAddr s₀ 2) (by rw [ea_at, u₃.other _ (by decide), e₂ _ (by decide)]; rfl) - (by rw [u₃.rd, u₃.wr]; exact i₂ 2 (by decide)) fun s₄ u₄ => ?_ - refine wp_movm (a := argAddr s₀ 1) (by - rw [ea_at, u₄.other _ (by decide), u₃.other _ (by decide), e₂ _ (by decide)]; rfl) - (by rw [u₄.rd, u₄.wr, u₃.rd, u₃.wr]; exact i₂ 1 (by decide)) fun s₅ u₅ => WP.block_nil ?_ - have hm : s₅.mem = s₂.mem := by rw [u₅.mem, u₄.mem, u₃.mem] - refine ⟨⟨by rw [u₅.rd, u₄.rd, u₃.rd, rd₂, u₁.rd], by rw [u₅.wr, u₄.wr, u₃.wr, wr₂, u₁.wr], - by rw [u₅.other _ (by decide), u₄.other _ (by decide), u₃.other _ (by decide), e₂ _ (by decide)], - by rw [u₅.other _ (by decide), u₄.other _ (by decide), u₃.gpr, g₂, u₁.gpr]; rfl, - by rw [u₅.other _ (by decide), u₄.gpr, u₃.mem, rA 2 (by decide), BitVec.ofNat_toNat, BitVec.setWidth_eq], - hm ▸ sv₂.of_eq H fun r hr => u₁.other r (by - simp only [savedRegs, List.mem_cons, List.not_mem_nil, or_false] at hr - rcases hr with rfl | rfl | rfl | rfl <;> decide), - (hm ▸ f₂').sub fun r hr => by - simp only [List.mem_singleton] at hr; subst hr; exact ⟨scR sc s₀, by simp, save_sub hp⟩⟩, - by rw [u₅.gpr, u₄.mem, u₃.mem, rA 1 (by decide)], hm ▸ f₂'⟩ - -/-- `U` into `scratch`. -/ -theorem copyU_ok {s : State} (hk : KR (H := H) sc s₀ (nn s₀) s) (hsi : s.gpr .esi = up s₀) - (hf : Frame [saveR H (scr s₀)] s₀.mem s.mem) : - WP isa (copy .esi 0 .ebp (uO H) H.D) s (Inv hH sc s₀ (nn s₀)) := by - obtain ⟨hb, hf', hnw, hW, hS0, hS, hD0, hDF, hF, hB0, hB⟩ := bounds hp - have eu : uO H = H.buf + H.S + H.F := rfl - obtain ⟨sR, tR'⟩ := mem_wr hp - have nu := hp.nu - have uR' : uR (H := H) s₀ ∈ s.rd ++ s.wr := by rw [hk.rd, hp.rd]; simp - have usub : Region.Sub ⟨UA (H := H) s₀, H.D⟩ (scR sc s₀) := off_sub hp (by omega) - refine WP.mono (copy_ok (so := 0) (d := uO H) (n := H.D) (by decide) (by decide) - hD0 (by omega) (by rw [hsi]; omega) (by rw [hk.ebp]; omega) - (fun k hk' => by rw [hsi, add_zero']; exact inRegions_of_sub uR' (fun _ h => h) (by omega) hk') - (fun k hk' => by rw [hk.ebp, hk.wr]; exact inRegions_of_sub sR usub (by omega) hk') - (by rw [hsi, hk.ebp, add_zero']; exact hp.u_s.sub_right usub)) fun t c => ?_ - rw [hsi, hk.ebp, add_zero'] at c - have fc : Frame [⟨UA (H := H) s₀, H.D⟩] s.mem t.mem := - c.mem ▸ Proof.Sha256.Stream.writeBytes_frame _ _ _ (by rw [bytesAt_length]; exact Region.contains_self _ _) - refine ⟨hk.keep c.rd c.wr (fun r hr => c.other r (not_cclob (kregs_clob r hr))) - fc (fun r hr => by - simp only [List.mem_singleton] at hr; subst hr - exact save_off hp (by omega) (by omega)) - (fun r hr => by simp only [List.mem_singleton] at hr; subst hr; exact ⟨_, by simp, usub⟩), fun k0 _ => ?_⟩ - congr 1 - · rw [c.mem, bytesAt_writeBytes_self' (bytesAt_length _ _ _) (by omega)] - exact (bytes_keep hf (by - simp only [List.mem_singleton]; rintro r rfl; exact hp.u_s.sub_right (save_sub hp)) (by omega)).symm - · exact ((bytes_keep fc (by simp only [List.mem_singleton]; rintro r rfl; exact hp.t_s.sub_right usub) - (by omega)).trans (bytes_keep hf (by - simp only [List.mem_singleton]; rintro r rfl; exact hp.t_s.sub_right (save_sub hp)) (by omega))).symm - -omit hp in -/-- `test edi, edi`: the flags of whether there are steps. -/ -theorem test_ok {s : State} (h : Inv hH sc s₀ (nn s₀) s) : - WP isa (.block [.alu .test .edi (.reg .edi)]) s fun t => Inv hH sc s₀ (nn s₀) t ∧ - t.zf = some (decide (nn s₀ = 0)) := by - refine wp_test fun s₁ f₁ z₁ => WP.block_nil ⟨⟨h.kr.keep f₁.rd f₁.wr - (fun r _ => by rw [f₁.gpr]) (rs := []) (by rw [f₁.mem]; exact Frame.refl _ _) (by simp) (by simp), - fun k0 hk => by rw [h.it k0 hk, f₁.mem]⟩, ?_⟩ - rw [z₁, h.kr.edi, test_z, Proof.Sha256.X86.Stream.toNat_ofNat_lt nn_lt] - -theorem loop_ok {s : State} (h : Inv hH sc s₀ (nn s₀) s) (hz : s.zf = some (decide (nn s₀ = 0))) : - WP isa (.ite .e (.block []) (.loop (body H) .ne)) s (Inv hH sc s₀ 0) := by - have hlt := nn_lt (s₀ := s₀) - refine WP.ite (decide (nn s₀ = 0)) (by show eval .e s = _; rw [eval_e, hz]) (fun h0 => WP.block_nil ?_) - fun h0 => ?_ - · have e : nn s₀ = 0 := by simpa using h0 - exact e ▸ h - · have hpos : 1 ≤ nn s₀ := by have := of_decide_eq_false h0; omega - refine WP.loop (M := isa) (fun k t => ∃ m, k = m ∧ 1 ≤ m ∧ m ≤ nn s₀ ∧ Inv hH sc s₀ m t) ?_ (nn s₀) s - ⟨nn s₀, rfl, hpos, (Nat.le_refl _), h⟩ - rintro k t ⟨m, hkm, h1, h2, ht⟩ - refine WP.mono (body_ok hH hp h1 (by omega) ht) fun t' ⟨ht', hz'⟩ => ?_ - have he : isa.eval .ne t' = some (!decide (m - 1 = 0)) := by - show eval .ne t' = _; rw [eval_ne, hz']; rfl - by_cases hl : m - 1 = 0 - · exact .inl ⟨by rw [he]; simp [hl], hl ▸ ht'⟩ - · exact .inr ⟨by rw [he]; simp [hl], m - 1, by omega, m - 1, rfl, by omega, by omega, ht'⟩ - -theorem correct : WP isa (iterate H) s₀ fun s' => abiPreserved s₀ s' ∧ (iterG hH.SH sc).post s₀ s' := by - obtain ⟨hb, hf', hnw, hW, hS0, hS, hD0, hDF, hF, hB0, hB⟩ := bounds hp - refine WP.seq (WP.mono (pro_ok hp) fun s₂ ⟨k₂, x₂, f₂⟩ => ?_) - refine WP.seq (WP.mono (copyU_ok hH hp k₂ x₂ f₂) fun s₃ h₃ => ?_) - refine WP.seq (WP.mono (test_ok hH h₃) fun s₄ ⟨h₄, z₄⟩ => ?_) - refine WP.seq (WP.mono (loop_ok hH hp h₄ z₄) fun s₅ h₅ => ?_) - have k₅ := h₅.kr - have hL : 8 * H.W + 16 ≤ 8 * sc := by omega - refine WP.mono (restore_ok H k₅.ebp k₅.saved (by rw [k₅.wr]; exact (mem_wr hp).1) hL hnw) - fun s' ⟨hm, _, _, hg, ho⟩ => ⟨⟨fun r hr => ?_, by rw [hm]; exact k₅.ret hp⟩, ?_⟩ - · by_cases he : r = .esp - · subst he; rw [ho _ (by decide) (by decide), k₅.esp] - · exact hg r (callee_saved r hr he) - intro k0 hl hrI hrO - have hS' := hH.hS; have hD' := hH.hD; have hB' := hH.hB - rw [hB'] at hl - rw [hS'] at hrO - show bytesAt s'.mem ((tp s₀).setWidth 64) hH.SH.digestBytes = _ - rw [hD', hm, h₅.it k0 ⟨hl, hrI, hrO⟩] - rfl - -end - -end VG.Proof.Pbkdf2.Generic.X86 diff --git a/lean/VerifiedGarbage/Proof/Pbkdf2/Generic/X86/IterateCT.lean b/lean/VerifiedGarbage/Proof/Pbkdf2/Generic/X86/IterateCT.lean deleted file mode 100644 index 264745c82..000000000 --- a/lean/VerifiedGarbage/Proof/Pbkdf2/Generic/X86/IterateCT.lean +++ /dev/null @@ -1,329 +0,0 @@ -import VerifiedGarbage.Proof.Pbkdf2.Generic.X86.Iterate - -/-! -# PBKDF2-HMAC over any streaming hash function on x86 (32-bit): `iterate`, constant time - -Untrusted: everything here is checked by Lean. As on 32-bit ARM -(`Proof/Pbkdf2/Generic/Arm/Instances.lean`): the pieces between the calls -are checked by the taint analysis, those that read the arguments on the -stack (the prologue, and the loads of `key` and `t`) with the arguments -public (`argTaint`); the calls are related by `upd_rel` and `fin_rel`. --/ - -namespace VG.Proof.Pbkdf2.Generic.X86 - -open VG.X86 -open VG.Impl.Hmac.Generic.X86 (Hash copy at_) -open VG.Impl.Pbkdf2.Generic.X86 (stO tmpO uO xorLoop atSt ldKey ldT body prologue iterate) -open VG.Proof.Sha256.X86.Stream (eval_e eval_ne) -open VG.Proof.Hmac.Generic.X86 - -/-- The registers `KR` fixes. -/ -abbrev pubRegs : List Reg := [.esp, .ebp, .edi] - -theorem skip_check : ∃ hc, (VG.Taint.check taint (τr []) (.block []) hc).isSome = true := - ⟨_, by taint_decide⟩ - -theorem test_check : ∃ hc, (VG.Taint.check taint (τr pubRegs) (.block [.alu .test .edi (.reg .edi)]) hc).isSome = true := - ⟨_, by taint_decide⟩ - -theorem dec_check : - ∃ hc, (VG.Taint.check taint (τr pubRegs) (.block [.alu .sub .edi (.imm 1)]) hc).isSome = true := - ⟨_, by taint_decide⟩ - -theorem ld_check {i : Nat} (hi : i = 0 ∨ i = 3) : ∃ hc, (VG.Taint.check taint (argTaint [.ebp, .edi] (4 + 4 * 5)) - (.block [.mov .esi (.mem (at_ .esp (4 + 4 * i)))]) hc).isSome = true := by - rcases hi with rfl | rfl <;> exact ⟨_, by taint_decide⟩ - -/-- The taint checks of the pieces of `iterate` between its calls. -/ -structure Checks (H : Hash) : Prop where - pro : ∃ hc, (VG.Taint.check taint (argTaint [] (4 + 4 * 5)) (.block (prologue H)) hc).isSome = true - copyU : ∃ hc, - (VG.Taint.check taint (τr (.esi :: pubRegs)) (copy .esi 0 .ebp (uO H) H.D) hc).isSome = true - copyK : ∀ o ∈ [0, H.S], ∃ hc, - (VG.Taint.check taint (τr (.esi :: pubRegs)) (copy .esi o .ebp (stO H) H.S) hc).isSome = true - upd : ∀ o ∈ [uO H, tmpO H], ∃ hc, - (VG.Taint.check taint (τr pubRegs) (.block (updBlock H o)) hc).isSome = true - fin : ∀ o ∈ [uO H, tmpO H], ∃ hc, - (VG.Taint.check taint (τr pubRegs) (.block (finBlock H o)) hc).isSome = true - xor : ∃ hc, (VG.Taint.check taint (τr (.esi :: pubRegs)) (xorLoop H) hc).isSome = true - restore : ∃ hc, (VG.Taint.check taint (τr pubRegs) (.block H.restore) hc).isSome = true - -/-- The public arguments are the same. -/ -structure PubEq (s₀ s₀' : State) : Prop where - esp : s₀.gpr .esp = s₀'.gpr .esp - args : ∀ i < 5, arg s₀ i = arg s₀' i - -variable {H : Hash} (hH : HashOK H) {sc : Nat} -variable {s₀ s₀' : State} (hp : Pre (H := H) sc s₀) (hp' : Pre (H := H) sc s₀') (hq : PubEq s₀ s₀') - -theorem PubEq.nn (hq : PubEq s₀ s₀') : Generic.X86.nn s₀ = Generic.X86.nn s₀' := by - show (arg s₀ 2).toNat = (arg s₀' 2).toNat; rw [hq.args 2 (by decide)] - -theorem kr_agree (hq : PubEq s₀ s₀') {m : Nat} {s s' : State} (h : KR (H := H) sc s₀ m s) - (h' : KR (H := H) sc s₀' m s') : ∀ r ∈ pubRegs, 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 - · rw [h.esp, h'.esp, E, E, hq.esp] - · rw [h.ebp, h'.ebp, scr, scr, hq.args 4 (by decide)] - · rw [h.edi, h'.edi] - -theorem esi_agree (hq : PubEq s₀ s₀') {m : Nat} {s s' : State} (h : KR (H := H) sc s₀ m s) - (h' : KR (H := H) sc s₀' m s') {i : Nat} (hi : i < 5) (e : s.gpr .esi = arg s₀ i) (e' : s'.gpr .esi = arg s₀' i) : - ∀ r ∈ .esi :: pubRegs, s.gpr r = s'.gpr r := by - intro r hr - rcases List.mem_cons.mp hr with rfl | hr - · rw [e, e', hq.args i hi] - · exact kr_agree hq h h' r hr - -theorem eqs (hq : PubEq s₀ s₀') : scr s₀' = scr s₀ ∧ ∀ o : Nat, sO s₀' o = sO s₀ o := - ⟨(hq.args 4 (by decide)).symm, fun o => by rw [sO, sO, scr, scr, hq.args 4 (by decide)]⟩ - -/-- The arguments lie outside the writable regions. -/ -theorem args_out {t : State} (h : Pre (H := H) sc t) {s : State} (hsp : s.gpr .esp = E t) (hwr : s.wr = t.wr) : - ArgsOut 5 s := by - have e : (⟨(s.gpr .esp).setWidth 64, 4 + 4 * 5⟩ : Region) = ⟨(E t).setWidth 64, 4 + 20⟩ := by rw [hsp] - refine ⟨by rw [hsp]; exact h.spf, ?_⟩ - rw [e, hwr, h.wr] - simp only [List.mem_cons, List.not_mem_nil, or_false] - rintro r (rfl | rfl) - · exact Taint.frame_disjoint (by have := h.spf; omega) h.r_t h.a_t - · exact Taint.frame_disjoint (by have := h.spf; omega) h.r_s h.a_s - -include hH hp hp' hq - -omit hH in -/-- A piece of code between calls that keeps `KR`. -/ -theorem kr_rel {m : Nat} {c : Prog isa} - (hck : ∃ hc, (VG.Taint.check taint (τr pubRegs) c hc).isSome = true) - (hw : ∀ {t₀ : State}, Pre (H := H) sc t₀ → ∀ s, KR (H := H) sc t₀ m s → WP isa c s (KR (H := H) sc t₀ m)) : - RelCT isa (fun s s' => KR (H := H) sc s₀ m s ∧ KR (H := H) sc s₀' m s') c - fun s s' => KR (H := H) sc s₀ m s ∧ KR (H := H) sc s₀' m s' := - rel_agree (τr pubRegs) (fun _ _ h h' => agree_regs (kr_agree hq h h')) hck (hw hp) (hw hp') - -omit hH in -/-- A load of `key` (`i = 0`) or `t` (`i = 3`) into `esi`. -/ -theorem ld_rel {m : Nat} {i : Nat} (hi : i = 0 ∨ i = 3) : - RelCT isa (fun s s' => KR (H := H) sc s₀ m s ∧ KR (H := H) sc s₀' m s') - (.block [.mov .esi (.mem (at_ .esp (4 + 4 * i)))]) - fun s s' => (KR (H := H) sc s₀ m s ∧ s.gpr .esi = arg s₀ i) ∧ - (KR (H := H) sc s₀' m s' ∧ s'.gpr .esi = arg s₀' i) := - rel_agree (argTaint [.ebp, .edi] (4 + 4 * 5)) (fun s s' k k' => - agree_argTaint (fun r hr => kr_agree hq k k' r (by - simp only [List.mem_cons, List.not_mem_nil, or_false] at hr ⊢; tauto)) - (kr_agree hq k k' .esp (by simp)) (args_out hp k.esp k.wr) (args_out hp' k'.esp k'.wr) - fun j hj => by rw [k.argEq hp hj, k'.argEq hp' hj, hq.args j hj]) (ld_check hi) - (fun _ k => WP.mono (ld_ok hp k hi) fun _ ⟨k₁, e, _⟩ => ⟨k₁, e⟩) - (fun _ k => WP.mono (ld_ok hp' k hi) fun _ ⟨k₁, e, _⟩ => ⟨k₁, e⟩) - -theorem upd_rel' {m : Nat} {o : Nat} (ho : o = uO H ∨ o = tmpO H) (hc : Checks H) : - RelCT isa (fun s s' => KR (H := H) sc s₀ m s ∧ KR (H := H) sc s₀' m s') - (H.callUpd (atSt H) .ebx .esi H.B o H.D) - fun s s' => KR (H := H) sc s₀ m s ∧ KR (H := H) sc s₀' m s' := by - obtain ⟨e2, e3⟩ := eqs hq - have ha := rel_agree (G := fun t => KR (H := H) sc s₀ m t ∧ - UpdArgs hH t .esi .ebx (sO s₀ (stO H)) (sO s₀ o) (scr s₀) (BitVec.ofNat 32 H.B) H.D) - (G' := fun t => KR (H := H) sc s₀' m t ∧ - UpdArgs hH t .esi .ebx (sO s₀ (stO H)) (sO s₀ o) (scr s₀) (BitVec.ofNat 32 H.B) H.D) - (τr pubRegs) (fun _ _ h h' => agree_regs (kr_agree hq h h')) (hc.upd o (by rcases ho with rfl | rfl <;> simp)) - (fun s h => WP.mono (updArgs_ok hH hp h ho) fun _ ⟨k, a, _⟩ => ⟨k, a⟩) - (fun s h => WP.mono (updArgs_ok hH hp' h ho) fun _ ⟨k, a, _⟩ => - ⟨k, e3 (stO H) ▸ e3 o ▸ e2 ▸ a⟩) - exact ha.seq (rel_wp (upd_rel hH (sp := E s₀) fun s s' ⟨⟨k, a⟩, ⟨k', a'⟩⟩ => - ⟨a, a', k.esp, by rw [k'.esp, E, E, hq.esp]⟩) - (fun _ ⟨k, a⟩ => updCall_ok hH hp k ho a fun _ k' _ _ => k') - (fun _ ⟨k, a⟩ => updCall_ok hH hp' k ho ((e3 (stO H)).symm ▸ (e3 o).symm ▸ e2.symm ▸ a) - fun _ k' _ _ => k')) - -theorem fin_rel' {m : Nat} {o : Nat} (ho : o = uO H ∨ o = tmpO H) (hc : Checks H) : - RelCT isa (fun s s' => KR (H := H) sc s₀ m s ∧ KR (H := H) sc s₀' m s') - (H.callFin (atSt H) H.count2 .ebx o) - fun s s' => KR (H := H) sc s₀ m s ∧ KR (H := H) sc s₀' m s' := by - obtain ⟨e2, e3⟩ := eqs hq - have ha := rel_agree (G := fun t => KR (H := H) sc s₀ m t ∧ - FinArgs hH t .ebx (sO s₀ (stO H)) (sO s₀ o) (scr s₀) (BitVec.ofNat 32 (H.B + H.D)) 0) - (G' := fun t => KR (H := H) sc s₀' m t ∧ - FinArgs hH t .ebx (sO s₀ (stO H)) (sO s₀ o) (scr s₀) (BitVec.ofNat 32 (H.B + H.D)) 0) - (τr pubRegs) (fun _ _ h h' => agree_regs (kr_agree hq h h')) (hc.fin o (by rcases ho with rfl | rfl <;> simp)) - (fun s h => WP.mono (finArgs_ok hH hp h ho) fun _ ⟨k, a, _⟩ => ⟨k, a⟩) - (fun s h => WP.mono (finArgs_ok hH hp' h ho) fun _ ⟨k, a, _⟩ => - ⟨k, e3 (stO H) ▸ e3 o ▸ e2 ▸ a⟩) - exact ha.seq (rel_wp (fin_rel hH (sp := E s₀) fun s s' ⟨⟨k, a⟩, ⟨k', a'⟩⟩ => - ⟨a, a', k.esp, by rw [k'.esp, E, E, hq.esp]⟩) - (fun _ ⟨k, a⟩ => finCall_ok hH hp k ho a fun _ k' _ _ => k') - (fun _ ⟨k, a⟩ => finCall_ok hH hp' k ho ((e3 (stO H)).symm ▸ (e3 o).symm ▸ e2.symm ▸ a) - fun _ k' _ _ => k')) - -theorem body_rel (hc : Checks H) {m : Nat} (hm : 1 ≤ m) (hn : m < 2 ^ 32) : - RelCT isa (fun s s' => KR (H := H) sc s₀ m s ∧ KR (H := H) sc s₀' m s') (body H) - fun s s' => KR (H := H) sc s₀ (m - 1) s ∧ KR (H := H) sc s₀' (m - 1) s' := by - have ck : ∀ {o : Nat}, (o = 0 ∨ o = H.S) → RelCT isa (fun s s' => (KR (H := H) sc s₀ m s ∧ s.gpr .esi = arg s₀ 0) ∧ - (KR (H := H) sc s₀' m s' ∧ s'.gpr .esi = arg s₀' 0)) - (copy .esi o .ebp (stO H) H.S) fun s s' => KR (H := H) sc s₀ m s ∧ KR (H := H) sc s₀' m s' := - fun ho => rel_agree (τr (.esi :: pubRegs)) (fun _ _ h h' => agree_regs - (esi_agree hq h.1 h'.1 (i := 0) (by decide) h.2 h'.2)) (hc.copyK _ (by rcases ho with rfl | rfl <;> simp)) - (fun s h => WP.mono (copyKey_ok hH hp h.1 h.2 ho) fun _ h => h.1) - (fun s h => WP.mono (copyKey_ok hH hp' h.1 h.2 ho) fun _ h => h.1) - have x : RelCT isa (fun s s' => (KR (H := H) sc s₀ m s ∧ s.gpr .esi = arg s₀ 3) ∧ - (KR (H := H) sc s₀' m s' ∧ s'.gpr .esi = arg s₀' 3)) - (xorLoop H) fun s s' => KR (H := H) sc s₀ m s ∧ KR (H := H) sc s₀' m s' := - rel_agree (τr (.esi :: pubRegs)) (fun _ _ h h' => agree_regs - (esi_agree hq h.1 h'.1 (i := 3) (by decide) h.2 h'.2)) hc.xor - (fun s h => WP.mono (xor'_ok hp h.1 h.2) fun _ h => h.1) - (fun s h => WP.mono (xor'_ok hp' h.1 h.2) fun _ h => h.1) - have d := rel_agree (G := KR (H := H) sc s₀ (m - 1)) (G' := KR (H := H) sc s₀' (m - 1)) (τr pubRegs) - (fun _ _ h h' => agree_regs (kr_agree hq h h')) dec_check - (fun s k => WP.mono (dec_ok hm hn k) fun _ h => h.1) (fun s k => WP.mono (dec_ok hm hn k) fun _ h => h.1) - exact (ld_rel hp hp' hq (.inl rfl)).seq ((ck (.inl rfl)).seq ((upd_rel' hH hp hp' hq (.inl rfl) hc).seq - ((fin_rel' hH hp hp' hq (.inr rfl) hc).seq ((ld_rel hp hp' hq (.inl rfl)).seq ((ck (.inr rfl)).seq - ((upd_rel' hH hp hp' hq (.inr rfl) hc).seq ((fin_rel' hH hp hp' hq (.inl rfl) hc).seq - ((ld_rel hp hp' hq (.inr rfl)).seq (x.seq d))))))))) - -/-- The loop's invariant in two runs, with `n` steps left. -/ -abbrev LoopInv (n : Nat) (s s' : State) : Prop := - 1 ≤ n ∧ n ≤ nn s₀ ∧ Inv hH sc s₀ n s ∧ Inv hH sc s₀' n s' - -theorem step_rel (hc : Checks H) (n : Nat) : - RelCT isa (LoopInv hH (sc := sc) (s₀ := s₀) (s₀' := s₀') n) (body H) fun s s' => - isa.eval .ne s = isa.eval .ne s' ∧ - (isa.eval .ne s = some false → Inv hH sc s₀ 0 s ∧ Inv hH sc s₀' 0 s') ∧ - (isa.eval .ne s = some true → ∃ m < n, LoopInv hH (sc := sc) (s₀ := s₀) (s₀' := s₀') m s s') := by - have hlt := nn_lt (s₀ := s₀) - by_cases hn : 1 ≤ n ∧ n ≤ nn s₀ - · have b := (body_rel hH hp hp' hq hc hn.1 (by omega)).mono (P' := LoopInv hH (sc := sc) (s₀ := s₀) (s₀' := s₀') n) - (fun _ _ (h : LoopInv hH (sc := sc) (s₀ := s₀) (s₀' := s₀') n _ _) => ⟨h.2.2.1.kr, h.2.2.2.kr⟩) - fun _ _ h => h - refine (b.wp (F₁ := fun (t : State) => Inv hH sc s₀ (n - 1) t ∧ t.zf = some (decide (n - 1 = 0))) - (F₂ := fun (t : State) => Inv hH sc s₀' (n - 1) t ∧ t.zf = some (decide (n - 1 = 0))) - fun s s' (h : LoopInv hH (sc := sc) (s₀ := s₀) (s₀' := s₀') n _ _) => - ⟨body_ok hH hp hn.1 (by omega) h.2.2.1, body_ok hH hp' hn.1 (by omega) h.2.2.2⟩).mono - (fun _ _ h => h) fun t t' h => ?_ - obtain ⟨_, ⟨i, z⟩, ⟨i', z'⟩⟩ := h - have e : isa.eval .ne t = some (!decide (n - 1 = 0)) := by show eval .ne t = _; rw [eval_ne, z]; rfl - have e' : isa.eval .ne t' = some (!decide (n - 1 = 0)) := by show eval .ne t' = _; rw [eval_ne, z']; rfl - rw [e, e'] - refine ⟨rfl, fun hf => ?_, fun ht => ?_⟩ - · have hl : n - 1 = 0 := by simpa using hf - exact ⟨hl ▸ i, hl ▸ i'⟩ - · have hl : n - 1 ≠ 0 := by simpa using ht - exact ⟨n - 1, by omega, by omega, by omega, i, i'⟩ - · intro _ _ _ _ _ _ h - exact absurd ⟨h.1, h.2.1⟩ hn - -theorem loop_rel (hc : Checks H) : - RelCT isa (fun s s' => (Inv hH sc s₀ (nn s₀) s ∧ s.zf = some (decide (nn s₀ = 0))) ∧ - (Inv hH sc s₀' (nn s₀') s' ∧ s'.zf = some (decide (nn s₀' = 0)))) - (.ite .e (.block []) (.loop (body H) .ne)) - fun s s' => Inv hH sc s₀ 0 s ∧ Inv hH sc s₀' 0 s' := by - have hN := hq.nn - have ev : ∀ {t : State} {k : Nat}, t.zf = some (decide (k = 0)) → isa.eval .e t = some (decide (k = 0)) := - fun h => by show eval .e _ = _; rw [eval_e, h] - refine RelCT.ite (fun s s' h => by rw [ev h.1.2, ev h.2.2, hN]) ?_ ?_ - · by_cases e : nn s₀ = 0 - · have e' : nn s₀' = 0 := hN ▸ e - exact (rel_agree (c := .block []) - (F := fun s => Inv hH sc s₀ (nn s₀) s ∧ s.zf = some (decide (nn s₀ = 0))) - (F' := fun s => Inv hH sc s₀' (nn s₀') s ∧ s.zf = some (decide (nn s₀' = 0))) - (G := Inv hH sc s₀ 0) (G' := Inv hH sc s₀' 0) (τr []) - (fun s s' h h' => agree_regs (by simp)) skip_check - (fun s h => WP.block_nil (e ▸ h.1)) (fun s h => WP.block_nil (e' ▸ h.1))).mono (fun _ _ h => h.1) - fun _ _ h => h - · intro _ _ _ _ _ _ h - have z := h.2 - rw [ev h.1.1.2] at z - exact absurd (by simpa using z) e - · refine (RelCT.loop (M := isa) (LoopInv hH (sc := sc) (s₀ := s₀) (s₀' := s₀')) (step_rel hH hp hp' hq hc) - (nn s₀)).mono (fun s s' h => ?_) fun _ _ h => h - have z := h.2 - rw [ev h.1.1.2] at z - have e : nn s₀ ≠ 0 := by simpa using z - exact ⟨by omega, (Nat.le_refl _), h.1.1.1, hN ▸ h.1.2.1⟩ - -theorem ct (hc : Checks H) : RelCT isa (fun s s' => s = s₀ ∧ s' = s₀') (iterate H) fun _ _ => True := by - have hN := hq.nn - have pro := rel_agree (F := fun s => s = s₀) (F' := fun s => s = s₀') - (G := fun s => KR (H := H) sc s₀ (nn s₀) s ∧ s.gpr .esi = up s₀ ∧ Frame [saveR H (scr s₀)] s₀.mem s.mem) - (G' := fun s => KR (H := H) sc s₀' (nn s₀') s ∧ s.gpr .esi = up s₀' ∧ Frame [saveR H (scr s₀')] s₀'.mem s.mem) - (argTaint [] (4 + 4 * 5)) (fun s s' e e' => by - rw [e, e'] - exact agree_argTaint (fun r hr => nomatch hr) hq.esp (args_out hp rfl rfl) (args_out hp' rfl rfl) - hq.args) hc.pro - (fun _ e => by rw [e]; exact pro_ok hp) (fun _ e => by rw [e]; exact pro_ok hp') - have cu := rel_agree - (F := fun s => KR (H := H) sc s₀ (nn s₀) s ∧ s.gpr .esi = up s₀ ∧ Frame [saveR H (scr s₀)] s₀.mem s.mem) - (F' := fun s => KR (H := H) sc s₀' (nn s₀') s ∧ s.gpr .esi = up s₀' ∧ Frame [saveR H (scr s₀')] s₀'.mem s.mem) - (G := Inv hH sc s₀ (nn s₀)) (G' := Inv hH sc s₀' (nn s₀')) (τr (.esi :: pubRegs)) - (fun s s' h h' => agree_regs (esi_agree hq h.1 (hN ▸ h'.1) (i := 1) (by decide) h.2.1 h'.2.1)) hc.copyU - (fun s h => copyU_ok hH hp h.1 h.2.1 h.2.2) (fun s h => copyU_ok hH hp' h.1 h.2.1 h.2.2) - have cm := rel_agree (F := Inv hH sc s₀ (nn s₀)) (F' := Inv hH sc s₀' (nn s₀')) - (G := fun s => Inv hH sc s₀ (nn s₀) s ∧ s.zf = some (decide (nn s₀ = 0))) - (G' := fun s => Inv hH sc s₀' (nn s₀') s ∧ s.zf = some (decide (nn s₀' = 0))) (τr pubRegs) - (fun s s' h h' => agree_regs (kr_agree hq h.kr (hN ▸ h'.kr))) test_check - (fun s h => test_ok hH h) (fun s h => test_ok hH h) - obtain ⟨_, hr⟩ := hc.restore - have restore : RelCT isa (fun s s' => Inv hH sc s₀ 0 s ∧ Inv hH sc s₀' 0 s') (.block H.restore) - fun _ _ => True := - RelCT.taint (A := taint) (τr pubRegs) (fun _ _ h => agree_regs (kr_agree hq h.1.kr h.2.kr)) hr - exact pro.seq (cu.seq (cm.seq ((loop_rel hH hp hp' hq hc).seq restore))) - -end VG.Proof.Pbkdf2.Generic.X86 - -namespace VG.Proof.Pbkdf2.Generic.X86 - -open VG.X86 -open VG.Impl.Hmac.Generic.X86 (Hash) -open VG.Proof.Hmac.Generic.X86 - -/-- `iterate` is verified against `iterG`, given the taint checks, which the -kernel evaluates for each hash function. -/ -theorem verified {H : Hash} (hH : HashOK H) {sc : Nat} (hc : Checks H) - (hfit : H.buf + H.S + 2 * H.F ≤ 8 * sc) (hsat : ∃ s, (iterG hH.SH sc).pre s) : - Verified X86.target (VG.Impl.Pbkdf2.Generic.X86.iterate H) (iterG hH.SH sc) := by - refine ⟨fun s hs => correct hH (pre_of hH sc hs hfit), fun s₁ s₂ t₁ t₂ s₁' s₂' h₁ h₂ hpub e₁ e₂ => ?_, hsat⟩ - obtain ⟨h1, h2⟩ := hpub - exact (ct hH (pre_of hH sc h₁ hfit) (pre_of hH sc h₂ hfit) ⟨h1, h2⟩ hc - _ _ _ _ _ _ ⟨rfl, rfl⟩ e₁ e₂).1 - -/-- The regions `iterate` reads and writes, of those `iterW` gives it. -/ -def narrowRd (S D : Nat) (s : State) : List Region := - [⟨(arg s 0).setWidth 64, 2 * S⟩, ⟨(arg s 1).setWidth 64, D⟩, ⟨argAddr s 0, 20⟩] -def narrowWr (D sc : Nat) (s : State) : List Region := - [⟨(arg s 3).setWidth 64, D⟩, ⟨(arg s 4).setWidth 64, 8 * sc⟩] - -/-- `iterate` is verified against `iterW`, which lets it write its arguments: -the code only reads them. -/ -theorem verifiedW {H : Hash} (hH : HashOK H) {sc : Nat} (hc : Checks H) - (hfit : H.buf + H.S + 2 * H.F ≤ 8 * sc) (hsat : ∃ s, (iterW hH.SH sc).pre s) : - Verified X86.target (VG.Impl.Pbkdf2.Generic.X86.iterate H) (iterW hH.SH sc) := by - have pre : ∀ s, (iterW hH.SH sc).pre s → (iterG hH.SH sc).pre - (s.withRegions (narrowRd hH.SH.stateBytes hH.SH.digestBytes s) (narrowWr hH.SH.digestBytes sc s)) := by - intro s h - obtain ⟨_, _, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11, h12, h13, h14, h15, h16, h17, h18, h19, h20⟩ := h - simp only [iterG, narrowRd, narrowWr, 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, h19, h20⟩ - refine Verified.narrowTo (verified hH hc hfit (hsat.elim fun s hs => ⟨_, pre s hs⟩)) - (narrowRd hH.SH.stateBytes hH.SH.digestBytes) (narrowWr hH.SH.digestBytes sc) pre (fun s h => ?_) - (fun s h => ?_) (fun _ _ _ h => h) (fun _ _ _ _ h => h) hsat - · obtain ⟨h1, h2, _⟩ := h - rw [h1, h2] - refine Covers.of_sub fun r hr => ?_ - simp only [narrowRd, narrowWr, List.cons_append, List.nil_append, List.mem_cons, List.not_mem_nil, - or_false] at hr - rcases hr with rfl | rfl | rfl | rfl | rfl - · exact ⟨_, List.mem_append_left _ List.mem_cons_self, 0, by simp, by simp⟩ - · exact ⟨_, List.mem_append_left _ (List.mem_cons_of_mem _ List.mem_cons_self), 0, by simp, by simp⟩ - · exact ⟨_, List.mem_append_right _ (List.mem_cons_of_mem _ (List.mem_cons_of_mem _ List.mem_cons_self)), - 0, by simp, by simp⟩ - · exact ⟨_, List.mem_append_right _ List.mem_cons_self, 0, by simp, by simp⟩ - · exact ⟨_, List.mem_append_right _ (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 [narrowWr, List.mem_cons, List.not_mem_nil, or_false] at hr - rcases hr with 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⟩ - -end VG.Proof.Pbkdf2.Generic.X86 diff --git a/lean/VerifiedGarbage/Proof/Pbkdf2/Md/X86/Block.lean b/lean/VerifiedGarbage/Proof/Pbkdf2/Md/X86/Block.lean new file mode 100644 index 000000000..682b2a5db --- /dev/null +++ b/lean/VerifiedGarbage/Proof/Pbkdf2/Md/X86/Block.lean @@ -0,0 +1,540 @@ +import VerifiedGarbage.Proof.Pbkdf2.MdHmac +import VerifiedGarbage.Proof.Pbkdf2.Memory +import VerifiedGarbage.Proof.Hmac.Generic.X86.Init +import VerifiedGarbage.Proof.Hmac.Generic.X86.Hash +import VerifiedGarbage.Impl.Pbkdf2.Md.X86 + +/-! +# HMAC and PBKDF2-HMAC over a Merkle–Damgård hash function on x86 (32-bit): the block + +Untrusted: everything here is checked by Lean. What HMAC's `finalize` and +PBKDF2's iteration (`Impl/Pbkdf2/Md/X86.lean`) share: a hash value at `ebx` +with a block right after it, which they pad (`pad_ok`), compress into the +hash value with any verified compression function (`cmp_ok`, against the +compression contract of the hash function's `Md`, `cmpK`; `cmp_rel` relates +two runs of the call) and write the digest into (`digest_ok`, from the hash +function's own `out`, `OutOk`); and the copies of words (`copyW_ok`) and +stores of constant words (`storeW_ok`) they are made of. +-/ + +namespace VG.Proof.Pbkdf2.Md.X86 + +open VG.X86 +open VG.Impl.Pbkdf2.Md.X86 (Hash cpW copyW wordOf storeW tail) +open VG.Impl.Hmac.Generic.X86 (at_) +open VG.Proof.MdStream (Md) +open VG.Proof.Sha256.X86.Stream (Upd Mupd wp_mov wp_movi wp_movm wp_store wp_addi sub_offset) +open VG.Proof.Hmac.Generic.X86 (ea_at stk After after_of stk_sub stk_sub' setWidth_add toNat_add_ofNat + rel_agree) +open VG.Proof.Hmac.Common (bytesAt_length bytesAt_add bytesAt_writeBytes_sep) +open VG.Proof.Sha256.Stream (writeBytes writeBytes_nil writeBytes_append writeBytes_frame) +open Spec.Sha256 (bytesAt) + +/-! ## Words -/ + +/-- Word `k` of `n` words at `[x + o]`, within the 32-bit address space. -/ +theorem addr_word {x : BitVec 32} {o n k : Nat} (h : x.toNat + o + 4 * n ≤ 2 ^ 32) (hk : k < n) : + addr x (o + 4 * k) = x.setWidth 64 + BitVec.ofNat 64 o + BitVec.ofNat 64 (4 * k) := by + rw [addr_eq (by omega), BitVec.add_assoc, ← BitVec.ofNat_add] + +/-- Copying `n` words from `[x + o₁]` to `[y + o₂]`. -/ +theorem copyW_ok {src dst : Reg} (hs : src ≠ .ecx) (hd : dst ≠ .ecx) {x y : BitVec 32} {o₁ o₂ : Nat} + (n : Nat) : ∀ (rest : List Instr) (s : State) (Q : State → Prop), + s.gpr src = x → s.gpr dst = y → x.toNat + o₁ + 4 * n ≤ 2 ^ 32 → y.toNat + o₂ + 4 * n ≤ 2 ^ 32 → + (∀ k < n, InRegions (s.rd ++ s.wr) (addr x (o₁ + 4 * k)) 4) → + (∀ k < n, InRegions s.wr (addr y (o₂ + 4 * k)) 4) → + Mem.Sep (x.setWidth 64 + BitVec.ofNat 64 o₁) (4 * n) (y.setWidth 64 + BitVec.ofNat 64 o₂) (4 * n) → + (∀ s', (∀ r, r ≠ .ecx → s'.gpr r = s.gpr r) → s'.rd = s.rd → s'.wr = s.wr → + s'.mem = writeBytes s.mem (y.setWidth 64 + BitVec.ofNat 64 o₂) + (bytesAt s.mem (x.setWidth 64 + BitVec.ofNat 64 o₁) (4 * n)) → + WP isa (.block rest) s' Q) → + WP isa (.block (copyW src o₁ dst o₂ n ++ rest)) s Q := by + induction n with + | zero => + intro rest s Q _ _ _ _ _ _ _ k + exact k s (fun _ _ => rfl) rfl rfl (by simp [bytesAt, writeBytes_nil]) + | succ n ih => + intro rest s Q hx hy fx fy hin hout hsep k + rw [copyW, List.range_succ, List.flatMap_append, List.flatMap_singleton, List.append_assoc] + refine ih _ s Q hx hy (by omega) (by omega) (fun j hj => hin j (by omega)) (fun j hj => hout j (by omega)) + (fun a ha hb => hsep a (by omega) (by omega)) fun s₁ g₁ rd₁ wr₁ m₁ => ?_ + simp only [cpW, List.cons_append, List.nil_append] + refine wp_movm (a := addr x (o₁ + 4 * n)) (by rw [ea_at, g₁ _ hs, hx]) + (by rw [rd₁, wr₁]; exact hin n (by omega)) fun s₂ u₂ => ?_ + refine wp_store (a := addr y (o₂ + 4 * n)) (by rw [ea_at, u₂.other _ hd, g₁ _ hd, hy]) + (by rw [u₂.wr, wr₁]; exact hout n (by omega)) fun s₃ u₃ => ?_ + refine k s₃ (fun r hr => by rw [u₃.gpr, u₂.other r hr, g₁ r hr]) + (by rw [u₃.rd, u₂.rd, rd₁]) (by rw [u₃.wr, u₂.wr, wr₁]) ?_ + rw [u₃.mem, u₂.gpr, u₂.mem, addr_word fx (by omega : n < n + 1), addr_word fy (by omega : n < n + 1), m₁] + have := VG.Proof.Hmac.Common.copy_mem s.mem (x.setWidth 64 + BitVec.ofNat 64 o₁) + (y.setWidth 64 + BitVec.ofNat 64 o₂) n 4 (by rw [show 4 * n + 4 = 4 * (n + 1) by omega]; exact hsep) + (by omega) + simp only [Nat.reduceMul] at this + rw [this, show 4 * (n + 1) = 4 * n + 4 by omega] + +/-- The bytes of a little-endian word made of four bytes. -/ +theorem word_bytes (a b c d : Byte) : + (List.range (32 / 8)).map (fun j => ((a ++ b ++ c ++ d : BitVec 32).setWidth (8 * (32 / 8))).extractLsb' (8 * j) 8) = + [d, c, b, a] := by + simp only [show 32 / 8 = 4 from rfl, BitVec.setWidth_eq, List.range_succ, + List.range_zero, List.nil_append, List.map_cons, List.map_nil, List.cons_append, List.cons.injEq, + and_true] + refine ⟨?_, ?_, ?_, ?_⟩ <;> + · ext i hi + simp only [BitVec.getElem_extractLsb', BitVec.getLsbD_append] + repeat' split + all_goals first | omega | (rw [← BitVec.getLsbD_eq_getElem]; congr 1; omega) + +/-- A word of `xs` is its four bytes. -/ +theorem wordOf_bytes {xs : List Byte} {k : Nat} (hk : 4 * k + 4 ≤ xs.length) : + (List.range (32 / 8)).map (fun j => ((wordOf xs k).setWidth (8 * (32 / 8))).extractLsb' (8 * j) 8) = + (xs.drop (4 * k)).take 4 := by + rw [wordOf, word_bytes] + apply List.ext_getElem (by simp; omega) + intro j h₁ h₂ + simp only [List.length_cons, List.length_nil] at h₁ + simp only [List.getElem_take, List.getElem_drop, List.getD_eq_getElem?_getD, + List.getElem?_eq_getElem (show 4 * k + 3 < xs.length by omega), List.getElem?_eq_getElem (show 4 * k + 2 < xs.length by omega), + List.getElem?_eq_getElem (show 4 * k + 1 < xs.length by omega), List.getElem?_eq_getElem (show 4 * k < xs.length by omega), + Option.getD_some] + rcases (by omega : j = 0 ∨ j = 1 ∨ j = 2 ∨ j = 3) with rfl | rfl | rfl | rfl <;> rfl + +/-- Storing the first `4 n` bytes of `xs` at `[y + o]`, a word at a time. -/ +theorem storeW_ok {dst : Reg} (hd : dst ≠ .ecx) {y : BitVec 32} {o : Nat} {xs : List Byte} (n : Nat) : + ∀ (rest : List Instr) (s : State) (Q : State → Prop), 4 * n ≤ xs.length → + s.gpr dst = y → y.toNat + o + 4 * n ≤ 2 ^ 32 → (∀ k < n, InRegions s.wr (addr y (o + 4 * k)) 4) → + (∀ s', (∀ r, r ≠ .ecx → s'.gpr r = s.gpr r) → s'.rd = s.rd → s'.wr = s.wr → + s'.mem = writeBytes s.mem (y.setWidth 64 + BitVec.ofNat 64 o) (xs.take (4 * n)) → + WP isa (.block rest) s' Q) → + WP isa (.block (storeW dst o xs n ++ rest)) s Q := by + induction n with + | zero => + intro rest s Q _ _ _ _ k + exact k s (fun _ _ => rfl) rfl rfl (by simp [writeBytes_nil]) + | succ n ih => + intro rest s Q hl hy fy hout k + rw [storeW, List.range_succ, List.flatMap_append, List.flatMap_singleton, List.append_assoc] + refine ih _ s Q (by omega) hy (by omega) (fun j hj => hout j (by omega)) fun s₁ g₁ rd₁ wr₁ m₁ => ?_ + simp only [List.cons_append, List.nil_append] + refine wp_movi fun s₂ u₂ => ?_ + refine wp_store (a := addr y (o + 4 * n)) (by rw [ea_at, u₂.other _ hd, g₁ _ hd, hy]) + (by rw [u₂.wr, wr₁]; exact hout n (by omega)) fun s₃ u₃ => ?_ + refine k s₃ (fun r hr => by rw [u₃.gpr, u₂.other r hr, g₁ r hr]) + (by rw [u₃.rd, u₂.rd, rd₁]) (by rw [u₃.wr, u₂.wr, wr₁]) ?_ + have ht : (xs.take (4 * n)).length = 4 * n := by simp; omega + rw [u₃.mem, u₂.gpr, u₂.mem, m₁, addr_word fy (by omega : n < n + 1), + Memory.writeW_bytes _ _ (wordOf xs n) ((xs.drop (4 * n)).take 4) (wordOf_bytes (by omega)), + Memory.writeBytes_append' _ _ _ (by rw [ht]) (by simp; omega), show 4 * (n + 1) = 4 * n + 4 by omega, + List.take_add] + +/-! ## The compression function -/ + +/-- The contract of a compression function `compress(state, blocks, n, scratch)` +of `H`, with `so` bytes of scratch space: updates the hash value at `state` +with the `n` blocks at `blocks` (as `Proof.Md5.compressX86` and the others). -/ +def cmpK {B N L : Nat} (H : Md B N L) (so : Nat) : Contract isa where + pre s := + let state : Region := ⟨(arg s 0).setWidth 64, N⟩ + let blocks : Region := ⟨(arg s 1).setWidth 64, B * (arg s 2).toNat⟩ + let scratch : Region := ⟨(arg s 3).setWidth 64, 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 + N ≤ 2 ^ 32 ∧ (arg s 1).toNat + B * (arg s 2).toNat ≤ 2 ^ 32 ∧ + (arg s 3).toNat + so ≤ 2 ^ 32 ∧ (s.gpr .esp).toNat + 20 ≤ 2 ^ 32 + post s s' := + H.stateAt s'.mem ((arg s 0).setWidth 64) = + H.compressBlocks (H.stateAt s.mem ((arg s 0).setWidth 64)) s.mem ((arg s 1).setWidth 64) (arg s 2).toNat + pub s₁ s₂ := + s₁.gpr .esp = s₂.gpr .esp ∧ + arg s₁ 0 = arg s₂ 0 ∧ arg s₁ 1 = arg s₂ 1 ∧ arg s₁ 2 = arg s₂ 2 ∧ arg s₁ 3 = arg s₂ 3 + +/-- A verified compression function, as the code calls it: correct and +constant time, never writing `esp`, and calling nothing that uses the +stack. -/ +structure CompOk {B N L : Nat} (H : Md B N L) (so : Nat) (code : Prog isa) : Prop where + verified : Verified X86.target code (cmpK H so) + nosp : NoSp code + stack : stackUse code = 0 + +/-- The four words a call of the compression function pushes, last to first. -/ +abbrev cmp4 : List Reg := [.ebp, .ecx, .eax, .ebx] + +theorem cmp4_nesp : Reg.esp ∉ cmp4 := by decide + +/-- A part of a region that `rs` covers. -/ +theorem covers_off {rs : List Region} {b : Addr} {L o n : Nat} (h : Covers [⟨b, L⟩] rs) (hl : o + n ≤ L) : + Covers [⟨b + BitVec.ofNat 64 o, n⟩] rs := fun a k hi => + h a k (Covers.of_sub (fun r hr => by + simp only [List.mem_singleton] at hr; subst hr + exact ⟨_, List.mem_singleton_self _, o, rfl, hl⟩) a k hi) + +theorem covers_cons {rs : List Region} {r : Region} {l : List Region} (h : Covers [r] rs) (h' : Covers l rs) : + Covers (r :: l) rs := fun a k ⟨q, hq, hc⟩ => by + rcases List.mem_cons.mp hq with rfl | hq + · exact h a k ⟨_, List.mem_singleton_self _, hc⟩ + · exact h' a k ⟨q, hq, hc⟩ + +/-- What the frame of a call of the compression function needs of the state +before its push: the hash value at `st` in `ebx` and the block after it in +`eax`, the scratch space at `sc` in `ebp`, `ecx = 1`, the regions the callee +may write, disjoint, and from the 48 bytes below `esp`, and none wrapping +around. -/ +structure CmpArgs (N B so : Nat) (s : State) (st sc : BitVec 32) : Prop where + ebx : s.gpr .ebx = st + eax : s.gpr .eax = st + BitVec.ofNat 32 N + ebp : s.gpr .ebp = sc + sp48 : 48 ≤ (s.gpr .esp).toNat + cst : Covers [⟨st.setWidth 64, N + B⟩] s.wr + csc : Covers [⟨sc.setWidth 64, so⟩] s.wr + st_sc : Region.Disjoint ⟨st.setWidth 64, N + B⟩ ⟨sc.setWidth 64, so⟩ + b_st : (stk s).Disjoint ⟨st.setWidth 64, N + B⟩ + b_sc : (stk s).Disjoint ⟨sc.setWidth 64, so⟩ + nst : st.toNat + (N + B) ≤ 2 ^ 32 + nsc : sc.toNat + so ≤ 2 ^ 32 + +/-- The regions the compression function is given: the block and its +arguments, the hash value and its scratch space. -/ +abbrev CmpArgs.rd (N B : Nat) (st sp : BitVec 32) : List Region := + [⟨(st + BitVec.ofNat 32 N).setWidth 64, B * 1⟩, below sp 16] +abbrev CmpArgs.wr (N so : Nat) (st sc : BitVec 32) : List Region := [⟨st.setWidth 64, N⟩, ⟨sc.setWidth 64, so⟩] + +namespace CmpArgs +variable {N B so : Nat} {s : State} {st sc : BitVec 32} (h : CmpArgs N B so s st sc) (hcx : s.gpr .ecx = 1) +include h + +theorem fit : 4 * cmp4.length + 4 ≤ (s.gpr .esp).toNat := by + have := h.sp48; simp only [List.length_cons, List.length_nil]; omega + + +theorem a0 : arg (pushed cmp4 s).callEntry 0 = st := by + rw [callEntry_arg h.fit cmp4_nesp (by simp)]; simpa using h.ebx +theorem a1 : arg (pushed cmp4 s).callEntry 1 = st + BitVec.ofNat 32 N := by + rw [callEntry_arg h.fit cmp4_nesp (by simp)]; simpa using h.eax +theorem a3 : arg (pushed cmp4 s).callEntry 3 = sc := by + rw [callEntry_arg h.fit cmp4_nesp (by simp)]; simpa using h.ebp + +include hcx in +theorem a2 : arg (pushed cmp4 s).callEntry 2 = 1 := by + rw [callEntry_arg h.fit cmp4_nesp (by simp)]; simpa using hcx + +theorem blk (hB : 0 < B) : (st + BitVec.ofNat 32 N).setWidth 64 = st.setWidth 64 + BitVec.ofNat 64 N := + setWidth_add (by have := h.nst; omega) + +include hcx in +theorem callPre {L : Nat} (H : Md B N L) (hB : 0 < B) : + CallPre (cmpK H so) cmp4 (CmpArgs.rd N B st (s.gpr .esp)) (CmpArgs.wr N so st sc) s := by + have e := h.sp48 + have fit := h.fit + have nst := h.nst + have a2' : (arg (pushed cmp4 s).callEntry 2).toNat = 1 := by rw [h.a2 hcx]; rfl + have hb : (st + BitVec.ofNat 32 N).toNat = st.toNat + N := toNat_add_ofNat (by omega) + have sS : Region.Sub ⟨st.setWidth 64, N⟩ ⟨st.setWidth 64, N + B⟩ := Region.sub_prefix (by omega) + have sB : Region.Sub ⟨(st + BitVec.ofNat 32 N).setWidth 64, B * 1⟩ ⟨st.setWidth 64, N + B⟩ := by + rw [h.blk hB]; exact sub_offset (by omega) (by omega) + have dBS : Region.Disjoint ⟨(st + BitVec.ofNat 32 N).setWidth 64, B * 1⟩ ⟨st.setWidth 64, N⟩ := by + rw [h.blk hB]; exact Offset.disjoint_base _ (by omega) (by omega) + refine ⟨?_, ?_, ?_⟩ + · simp only [cmpK, State.withRegions_rd, State.withRegions_wr, State.withRegions_gpr, arg_withRegions, + argAddr_withRegions, h.a0, h.a1, h.a3, a2', callEntry_argAddr0, callEntry_esp', cmp4, + List.length_cons, List.length_nil] + have sA : Region.Sub ⟨(s.gpr .esp - BitVec.ofNat 32 (4 * 4)).setWidth 64, 16⟩ (stk s) := + stk_sub e (by omega) (by omega) + have sR : Region.Sub ⟨(s.gpr .esp - BitVec.ofNat 32 (4 * 4 + 4)).setWidth 64, 4⟩ (stk s) := + stk_sub e (by omega) (by omega) + refine ⟨trivial, trivial, h.st_sc.sub_left sS, dBS, h.st_sc.sub_left sB, (h.b_st.sub_left sA).sub_right sS, + h.b_sc.sub_left sA, (h.b_st.sub_left sR).sub_right sS, h.b_sc.sub_left sR, by omega, by rw [hb]; omega, + h.nsc, ?_⟩ + rw [sub_toNat (by omega)]; have := (s.gpr .esp).isLt; omega + · have cB : Covers [⟨(st + BitVec.ofNat 32 N).setWidth 64, B * 1⟩] s.wr := by + rw [h.blk hB]; exact covers_off h.cst (by omega) + have cS : Covers [⟨st.setWidth 64, N⟩] s.wr := by + have := covers_off (o := 0) (n := N) h.cst (by omega); simpa using this + intro a n ⟨q, hq, hc⟩ + simp only [List.cons_append, List.nil_append, List.mem_cons, List.not_mem_nil, or_false] at hq + rcases hq with rfl | rfl | rfl | rfl + · obtain ⟨q', hq', hc'⟩ := cB a n ⟨_, List.mem_singleton_self _, hc⟩ + exact InRegions_append_cons.mpr (.inr ⟨q', List.mem_append_right _ hq', hc'⟩) + · refine InRegions_append_cons.mpr (.inl ?_) + simpa using hc + · obtain ⟨q', hq', hc'⟩ := cS a n ⟨_, List.mem_singleton_self _, hc⟩ + exact InRegions_append_cons.mpr (.inr ⟨q', List.mem_append_right _ hq', hc'⟩) + · obtain ⟨q', hq', hc'⟩ := h.csc a n ⟨_, List.mem_singleton_self _, hc⟩ + exact InRegions_append_cons.mpr (.inr ⟨q', List.mem_append_right _ hq', hc'⟩) + · have cS : Covers [⟨st.setWidth 64, N⟩] s.wr := by + have := covers_off (o := 0) (n := N) h.cst (by omega); simpa using this + intro a n hi + obtain ⟨q', hq', hc'⟩ := covers_cons cS h.csc a n hi + exact ⟨q', List.mem_cons_of_mem _ hq', hc'⟩ + +theorem entry_frame : Frame [stk s] s.mem (pushed cmp4 s).callEntry.mem := + (callEntry_frame h.fit cmp4_nesp).sub fun q hq => by + simp only [List.mem_singleton] at hq; subst hq + exact ⟨_, List.mem_singleton_self _, below_sub (by simp only [List.length_cons, List.length_nil]; omega) h.sp48⟩ + +end CmpArgs + +section +variable {B N L : Nat} {H : Md B N L} {so : Nat} {name : String} {code : Prog isa} (hc : CompOk H so code) +include hc + +/-- A call of the compression function on the block after the hash value at +`st`, in a frame of its arguments: it compresses the block into the hash +value, writing only the hash value, its scratch space and the stack below +`esp`. -/ +theorem cmp_frame (hB : 0 < B) {s : State} {st sc : BitVec 32} (h : CmpArgs N B so s st sc) (hcx : s.gpr .ecx = 1) + {Q : State → Prop} + (hQ : ∀ s', After s [⟨st.setWidth 64, N⟩, ⟨sc.setWidth 64, so⟩] s' → + H.stateAt s'.mem (st.setWidth 64) = + H.compress (H.stateAt s.mem (st.setWidth 64)) (H.blockAt s.mem (st.setWidth 64 + BitVec.ofNat 64 N)) → + Q s') : + WP isa (.frame (.push cmp4) (.call name code) (.pop .eax cmp4.length)) s Q := by + have e := h.sp48 + refine WP.callWith hc.verified.1 hc.nosp (by simp) cmp4_nesp + (by rw [hc.stack]; simp only [List.length_cons, List.length_nil]; omega) (h.callPre hcx H hB) + fun s' rd' wr' cs' f' ⟨s₂, m₂, post⟩ => ?_ + rw [hc.stack] at f' + refine hQ s' (after_of e (by simp only [List.length_cons, List.length_nil]; omega) rd' wr' cs' f') ?_ + simp only [cmpK, arg_withRegions, State.withRegions_mem, h.a0, h.a1, h.a2 hcx] at post + have fE := h.entry_frame + have dS : ∀ q ∈ [stk s], (⟨st.setWidth 64, N + B⟩ : Region).Disjoint q := by + simp only [List.mem_singleton]; rintro q rfl; exact h.b_st.symm + have e₁ : H.stateAt (pushed cmp4 s).callEntry.mem (st.setWidth 64) = H.stateAt s.mem (st.setWidth 64) := + H.stateAt_congr fun i hi => fE.bytes (R := ⟨st.setWidth 64, N + B⟩) dS (by + show N + B ≤ 2 ^ 64; have := h.nst; omega) (by show i < N + B; omega) + have e₂ : H.blockAt (pushed cmp4 s).callEntry.mem (st.setWidth 64 + BitVec.ofNat 64 N) = + H.blockAt s.mem (st.setWidth 64 + BitVec.ofNat 64 N) := by + simp only [Md.blockAt] + refine H.parse_congr fun k hk => ?_ + rw [Memory.add_ofNat] + exact fE.bytes (R := ⟨st.setWidth 64, N + B⟩) dS (by show N + B ≤ 2 ^ 64; have := h.nst; omega) + (by show N + k < N + B; omega) + rw [← m₂, post, show (1 : BitVec 32).toNat = 1 from rfl, Md.compressBlocks_one, e₁, h.blk hB, e₂] + +/-- The compression of the block after the hash value at `ebx`, with `eax` +at the block. -/ +theorem cmp_ok (hB : 0 < B) {s : State} {st sc : BitVec 32} (h : CmpArgs N B so s st sc) {Q : State → Prop} + (hQ : ∀ s', After s [⟨st.setWidth 64, N⟩, ⟨sc.setWidth 64, so⟩] s' → + H.stateAt s'.mem (st.setWidth 64) = + H.compress (H.stateAt s.mem (st.setWidth 64)) (H.blockAt s.mem (st.setWidth 64 + BitVec.ofNat 64 N)) → + Q s') : + WP isa (Impl.MdStream.X86.compressAt name code .ebx .ebp) s Q := by + refine WP.seq (wp_movi fun s₁ u₁ => WP.block_nil ?_) + have h₁ : CmpArgs N B so s₁ st sc := + { ebx := by rw [u₁.other _ (by decide), h.ebx], eax := by rw [u₁.other _ (by decide), h.eax], + ebp := by rw [u₁.other _ (by decide), h.ebp], sp48 := by rw [u₁.other _ (by decide)]; exact h.sp48, + cst := by rw [u₁.wr]; exact h.cst, csc := by rw [u₁.wr]; exact h.csc, st_sc := h.st_sc, b_st := by rw [stk, u₁.other _ (by decide)]; exact h.b_st, + b_sc := by rw [stk, u₁.other _ (by decide)]; exact h.b_sc, nst := h.nst, nsc := h.nsc } + refine cmp_frame hc hB h₁ u₁.gpr fun s' ha e => hQ s' ?_ (by rw [e, u₁.mem]) + exact ⟨ha.rd.trans u₁.rd, ha.wr.trans u₁.wr, fun r hr => (ha.cs r hr).trans (u₁.other r (by + simp only [calleeSaved, List.mem_cons, List.not_mem_nil, or_false] at hr + rcases hr with rfl | rfl | rfl | rfl | rfl <;> decide)), + by have f := ha.frame; rw [stk, u₁.other _ (by decide), u₁.mem] at f; rw [stk]; exact f⟩ + +omit hc in +theorem mov1_check : ∃ hc, (VG.Taint.check taint (τr []) (.block [.mov .ecx (.imm 1)]) hc).isSome = true := + ⟨_, by taint_decide⟩ + +/-- Two runs of the compression of the block, from the same hash value and +scratch space, and the same `esp`, leak the same: the call by the compression +function's contract. -/ +theorem cmp_rel (hB : 0 < B) {P : State → State → Prop} {sp st sc : BitVec 32} + (h : ∀ s s', P s s' → CmpArgs N B so s st sc ∧ CmpArgs N B so s' st sc ∧ s.gpr .esp = sp ∧ s'.gpr .esp = sp) : + RelCT isa P (Impl.MdStream.X86.compressAt name code .ebx .ebp) fun _ _ => True := by + have wp1 : ∀ s, CmpArgs N B so s st sc ∧ s.gpr .esp = sp → WP isa (.block [.mov .ecx (.imm 1)]) s + fun t => (CmpArgs N B so t st sc ∧ t.gpr .ecx = 1) ∧ t.gpr .esp = sp := fun s ⟨a, e⟩ => + wp_movi fun s₁ u₁ => WP.block_nil + ⟨⟨{ ebx := by rw [u₁.other _ (by decide), a.ebx], eax := by rw [u₁.other _ (by decide), a.eax], + ebp := by rw [u₁.other _ (by decide), a.ebp], sp48 := by rw [u₁.other _ (by decide)]; exact a.sp48, + cst := by rw [u₁.wr]; exact a.cst, csc := by rw [u₁.wr]; exact a.csc, st_sc := a.st_sc, + b_st := by rw [stk, u₁.other _ (by decide)]; exact a.b_st, + b_sc := by rw [stk, u₁.other _ (by decide)]; exact a.b_sc, nst := a.nst, nsc := a.nsc }, u₁.gpr⟩, + by rw [u₁.other _ (by decide), e]⟩ + have r1 := rel_agree (F := fun s => CmpArgs N B so s st sc ∧ s.gpr .esp = sp) + (F' := fun s => CmpArgs N B so s st sc ∧ s.gpr .esp = sp) (τr []) (fun _ _ _ _ => agree_regs (by simp)) + mov1_check (wp1) (wp1) + refine (r1.mono (fun s s' hp => by + obtain ⟨a, a', e, e'⟩ := h s s' hp; exact ⟨⟨a, e⟩, ⟨a', e'⟩⟩) fun _ _ h => h).seq ?_ + refine RelCT.callWith (rs := cmp4) hc.verified.1 hc.verified.2.1 (CmpArgs.rd N B st sp) + (CmpArgs.wr N so st sc) fun s s' ⟨⟨⟨a, x⟩, e⟩, ⟨⟨a', x'⟩, e'⟩⟩ => ?_ + have c := a.callPre x H hB + have c' := a'.callPre x' H hB + rw [e] at c; rw [e'] at c' + refine ⟨c, c', e.trans e'.symm, ?_, ?_, ?_, ?_, ?_⟩ + · simp only [State.withRegions_gpr, callEntry_esp', e, e'] + · simp only [arg_withRegions, a.a0, a'.a0] + · simp only [arg_withRegions, a.a1, a'.a1] + · simp only [arg_withRegions, a.a2 x, a'.a2 x'] + · simp only [arg_withRegions, a.a3, a'.a3] + +end + +/-! ## The digest -/ + +/-- `out` writes the digest of the `N`-byte hash value at `ebx` to `eax`, +writing only `ecx` and `edx`. -/ +def OutOk {B N L : Nat} (H : Md B N L) (out : List Instr) : Prop := + ∀ s : State, (s.gpr .ebx).toNat + N ≤ 2 ^ 32 → (s.gpr .eax).toNat + N ≤ 2 ^ 32 → + InRegions (s.rd ++ s.wr) ((s.gpr .ebx).setWidth 64) N → InRegions s.wr ((s.gpr .eax).setWidth 64) N → + Region.Disjoint ⟨(s.gpr .ebx).setWidth 64, N⟩ ⟨(s.gpr .eax).setWidth 64, N⟩ → + WP isa (.block out) s fun s' => + (∀ r, 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 .eax).setWidth 64) (H.digest (H.stateAt s.mem ((s.gpr .ebx).setWidth 64))) + +/-! ## The block after the hash value at `ebx` -/ + +/-- The sizes the proofs support, checked for each hash function by `decide`: +blocks of 64 or 128 bytes, a hash value of words, a digest of words of at +most the hash value, room in the block for the digest, the `0x80` word and +the length field, a streaming state of a hash value and a block, and the +compression function's scratch space within that of the streaming +functions. -/ +structure Sizes (H : Hash) : Prop where + B : H.B = 64 ∨ H.B = 128 + N : 0 < H.N ∧ H.N ≤ 64 ∧ H.N % 4 = 0 + D : 0 < H.D ∧ H.D ≤ H.N ∧ H.D % 4 = 0 + DL : H.D + H.L + 4 ≤ H.B + S : H.S = H.N + H.B + so : H.so ≤ 8 * H.st.W + W : H.st.W ≤ 64 + F : H.D ≤ H.st.F ∧ H.st.F ≤ 64 + +/-- A range within a region that `rs` covers. -/ +theorem inReg {rs : List Region} {b : Addr} {L o n : Nat} (h : Covers [⟨b, L⟩] rs) (hl : o + n ≤ L) + (hL : L < 2 ^ 64) : InRegions rs (b + BitVec.ofNat 64 o) n := + h _ _ ⟨_, List.mem_singleton_self _, Offset.contains_base _ hl (by omega)⟩ + +section +variable {H : Hash} (hz : Sizes H) +include hz + +theorem Sizes.B4 : H.B % 4 = 0 ∧ 64 ≤ H.B ∧ H.B ≤ 128 := by rcases hz.B with h | h <;> rw [h] <;> decide + +theorem Sizes.tail_length : H.tailB.length = H.B - H.D := by + have := hz.DL + simp only [Hash.tailB, tail, List.length_append, List.length_singleton, List.length_replicate, + List.length_map, List.length_range] + omega + +omit hz in +/-- `eax` at the block. -/ +theorem atBlk_ok {s : State} {rest : List Instr} {Q : State → Prop} + (k : ∀ s', s'.gpr .eax = s.gpr .ebx + BitVec.ofNat 32 H.N → (∀ r, r ≠ .eax → s'.gpr r = s.gpr r) → + s'.mem = s.mem → s'.rd = s.rd → s'.wr = s.wr → WP isa (.block rest) s' Q) : + WP isa (.block (H.atBlk ++ rest)) s Q := by + simp only [Hash.atBlk, List.cons_append, List.nil_append] + exact wp_mov fun s₁ u₁ => wp_addi fun s₂ u₂ => k s₂ (by rw [u₂.gpr, u₁.gpr]) + (fun r hr => by rw [u₂.other r hr, u₁.other r hr]) (by rw [u₂.mem, u₁.mem]) (by rw [u₂.rd, u₁.rd]) + (by rw [u₂.wr, u₁.wr]) + +/-- The padding after the block's first `D` bytes. -/ +theorem pad_ok {s : State} {x : BitVec 32} (hx : s.gpr .ebx = x) (hf : x.toNat + (H.N + H.B) ≤ 2 ^ 32) + (hw : Covers [⟨x.setWidth 64, H.N + H.B⟩] s.wr) {rest : List Instr} {Q : State → Prop} + (k : ∀ s', (∀ r, r ≠ .ecx → s'.gpr r = s.gpr r) → s'.rd = s.rd → s'.wr = s.wr → + s'.mem = writeBytes s.mem (x.setWidth 64 + BitVec.ofNat 64 (H.N + H.D)) H.tailB → + WP isa (.block rest) s' Q) : + WP isa (.block (H.pad ++ rest)) s Q := by + have := hz.D; have := hz.B4; have := hz.tail_length; have := hz.DL + have h4 : 4 * ((H.B - H.D) / 4) = H.B - H.D := by omega + refine storeW_ok (by decide) _ rest s Q (by omega) hx (by omega) (fun j hj => ?_) fun s' g rd wr m => + k s' g rd wr ?_ + · rw [addr_eq (by omega)]; exact inReg hw (by omega) (by omega) + · rw [m, h4, List.take_of_length_le (by omega)] + +end + +/-- The digest of the hash value into the block, from `OutOk`, the padding +after its first `D` bytes as it was. -/ +theorem digest_ok {H : Hash} (hz : Sizes H) {md : Md H.B H.N H.L} (hout : OutOk md H.out) {s : State} + {x : BitVec 32} (hx : s.gpr .ebx = x) (hf : x.toNat + (H.N + H.B) ≤ 2 ^ 32) + (hw : Covers [⟨x.setWidth 64, H.N + H.B⟩] s.wr) + (hpad : bytesAt s.mem (x.setWidth 64 + BitVec.ofNat 64 (H.N + H.D)) (H.B - H.D) = H.tailB) + {rest : List Instr} {Q : State → Prop} + (k : ∀ s', (∀ r, r ≠ .eax → r ≠ .ecx → r ≠ .edx → s'.gpr r = s.gpr r) → s'.rd = s.rd → s'.wr = s.wr → + Frame [⟨x.setWidth 64 + BitVec.ofNat 64 H.N, H.B⟩] s.mem s'.mem → + bytesAt s'.mem (x.setWidth 64 + BitVec.ofNat 64 H.N) H.D = (md.digest (md.stateAt s.mem (x.setWidth 64))).take H.D → + bytesAt s'.mem (x.setWidth 64 + BitVec.ofNat 64 (H.N + H.D)) (H.B - H.D) = H.tailB → + WP isa (.block rest) s' Q) : + WP isa (.block (H.digest ++ rest)) s Q := by + have := hz.D; have := hz.B4; have := hz.tail_length; have := hz.N; have := hz.DL + have h4 : 4 * ((H.N - H.D) / 4) = H.N - H.D := by omega + let X := x.setWidth 64 + have aN : (x + BitVec.ofNat 32 H.N).setWidth 64 = X + BitVec.ofNat 64 H.N := setWidth_add (by omega) + have tN : (x + BitVec.ofNat 32 H.N).toNat = x.toNat + H.N := toNat_add_ofNat (by omega) + unfold Hash.digest + simp only [List.append_assoc] + refine atBlk_ok fun s₁ e₁ g₁ m₁ rd₁ wr₁ => ?_ + rw [WP.block_append_iff] + have bx₁ : s₁.gpr .ebx = x := by rw [g₁ _ (by decide), hx] + refine WP.mono (hout s₁ (by rw [bx₁]; omega) (by rw [e₁, hx, tN]; omega) ?_ ?_ ?_) fun s₂ ⟨g₂, rd₂, wr₂, m₂⟩ => ?_ + · rw [bx₁, rd₁, wr₁] + have := inReg (o := 0) (n := H.N) hw (by omega) (by omega) + rw [BitVec.add_zero] at this + exact Proof.Hmac.Generic.Common.InRegions.right' this + · rw [e₁, hx, aN, wr₁]; exact inReg hw (by omega) (by omega) + · rw [bx₁, e₁, hx, aN]; exact Offset.base_disjoint _ (Nat.le_refl _) (by omega) + rw [e₁, hx, aN, bx₁, m₁] at m₂ + have hdl := md.digest_length (md.stateAt s.mem X) + have bx₂ : s₂.gpr .ebx = x := by rw [g₂ _ (by decide) (by decide), bx₁] + refine storeW_ok (by decide) _ rest s₂ Q (by omega) bx₂ (by omega) (fun j hj => ?_) + fun s₃ g₃ rd₃ wr₃ m₃ => k s₃ (fun r h1 h2 h3 => by rw [g₃ r h2, g₂ r h2 h3, g₁ r h1]) (by rw [rd₃, rd₂, rd₁]) + (by rw [wr₃, wr₂, wr₁]) ?_ ?_ ?_ + · rw [addr_eq (by omega), wr₂, wr₁]; exact inReg hw (by omega) (by omega) + · rw [m₃, m₂, h4] + refine (writeBytes_frame _ _ _ ?_).trans (writeBytes_frame _ _ _ ?_) + · rw [hdl]; have := Offset.contains_base (X + BitVec.ofNat 64 H.N) (d := 0) (n := H.N) (k := H.B) (by omega) + (by omega); rwa [BitVec.add_zero] at this + · rw [List.length_take, Nat.min_eq_left (by omega), ← Memory.add_ofNat] + exact Offset.contains_base _ (by omega) (by omega) + · rw [m₃, h4, bytesAt_writeBytes_sep _ _ ?_ (by omega), m₂, + Proof.Hmac.Generic.Common.bytesAt_take _ _ hz.D.2.1, + Proof.Hmac.Generic.Common.bytesAt_writeBytes_self' hdl (by omega)] + rw [List.length_take, Nat.min_eq_left (by omega), ← Memory.add_ofNat] + have := Offset.sep (X + BitVec.ofNat 64 H.N) (d := 0) (n := H.D) (e := H.D) (k := H.N - H.D) (.inl (by omega)) + (by omega) (by omega) + rwa [BitVec.add_zero] at this + · -- The padding: its first `N - D` bytes written back, the rest as it was. + have hsplit : ∀ m : Mem, bytesAt m (X + BitVec.ofNat 64 (H.N + H.D)) (H.B - H.D) = + bytesAt m (X + BitVec.ofNat 64 (H.N + H.D)) (H.N - H.D) ++ + bytesAt m (X + BitVec.ofNat 64 (H.N + H.N)) (H.B - H.N) := by + intro m + rw [show H.B - H.D = (H.N - H.D) + (H.B - H.N) by omega, bytesAt_add, Memory.add_ofNat, + show H.N + H.D + (H.N - H.D) = H.N + H.N by omega] + have hY : bytesAt s.mem (X + BitVec.ofNat 64 (H.N + H.N)) (H.B - H.N) = H.tailB.drop (H.N - H.D) := by + rw [← hpad, hsplit, List.drop_left' (bytesAt_length _ _ _)] + have r₂ : bytesAt s₂.mem (X + BitVec.ofNat 64 (H.N + H.N)) (H.B - H.N) = + bytesAt s.mem (X + BitVec.ofNat 64 (H.N + H.N)) (H.B - H.N) := by + rw [m₂, ← Memory.add_ofNat] + refine bytesAt_writeBytes_sep _ _ ?_ (by omega) + rw [hdl] + have := Offset.sep (X + BitVec.ofNat 64 H.N) (d := H.N) (n := H.B - H.N) (e := 0) (k := H.N) (.inr (by omega)) + (by omega) (by omega) + rwa [BitVec.add_zero] at this + have htl : (H.tailB.take (H.N - H.D)).length = H.N - H.D := by rw [List.length_take]; omega + rw [hsplit, m₃, h4, Proof.Hmac.Generic.Common.bytesAt_writeBytes_self' htl (by omega), + bytesAt_writeBytes_sep _ _ ?_ (by omega), r₂, hY, List.take_append_drop] + rw [htl, ← Memory.add_ofNat, ← Memory.add_ofNat] + exact Offset.sep _ (.inr (by omega)) (by omega) (by omega) + +/-! ## What the proofs know of a hash function -/ + +/-- A hash function's x86 functions, verified: its streaming functions, as +HMAC's `init` and `finalize` call them (`HashOK`), and its `Md`, from the +initial hash value `iv`, which is the hash function of the specification +(`link`), whose stored hash value depends only on its bytes (`reloc`), whose +padding of a `B + D`-byte message is the code's (`tail`), whose digest the +code's `out` writes, and whose compression function is verified (`comp`). -/ +structure MdOk (H : Hash) where + hH : VG.Proof.Hmac.Generic.X86.HashOK H.st + md : Md H.B H.N H.L + iv : md.HV + link : md.Link hH.SH iv H.D + reloc : md.Reloc + tail : md.tailPad H.D = H.tailB + out : OutOk md H.out + comp : CompOk md H.so H.compC + sizes : Sizes H + +end VG.Proof.Pbkdf2.Md.X86 diff --git a/lean/VerifiedGarbage/Proof/Pbkdf2/Md/X86/Hashes.lean b/lean/VerifiedGarbage/Proof/Pbkdf2/Md/X86/Hashes.lean new file mode 100644 index 000000000..800538c03 --- /dev/null +++ b/lean/VerifiedGarbage/Proof/Pbkdf2/Md/X86/Hashes.lean @@ -0,0 +1,247 @@ +import VerifiedGarbage.Proof.Pbkdf2.Md.X86.Block +import VerifiedGarbage.Proof.Hmac.Generic.X86.Hashes +import VerifiedGarbage.Proof.Sha512.Md +import VerifiedGarbage.Proof.Sha512.X86.Stream.Finalize + +/-! +# HMAC and PBKDF2-HMAC on x86 (32-bit): the Merkle–Damgård hash functions + +Untrusted: everything here is checked by Lean. MD5, SHA-1 and the SHA-512 +family as `Hash`es of `Impl/Pbkdf2/Md/X86.lean`: their streaming functions +(`Proof/Hmac/Generic/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`. +-/ + +namespace VG.Proof.Pbkdf2.Md.X86 + +open VG.X86 +open VG.Impl.Pbkdf2.Md.X86 (Hash) +open VG.Proof.MdStream (Md) +open VG.Proof.Hmac.Generic.X86 (md5H sha1H sha512H md5OK sha1OK sha384OK sha512OK sha512_224OK sha512_256OK) +open VG.Proof.Sha256.Stream (writeBytes writeBytes_nil writeBytes_append writeBytes_frame) + +/-! ## The hash functions -/ + +/-- MD5: a 16-byte hash value, a little-endian length field and digest. -/ +def md5M : Hash := + ⟨md5H, 16, 8, false, 64, "vg_md5_compress", Impl.Md5.X86.compress, Impl.Md5.X86.Stream.params.out⟩ + +/-- SHA-1: a 20-byte hash value, a big-endian length field and digest. -/ +def sha1M : Hash := + ⟨sha1H, 20, 8, true, 112, "vg_sha1_compress", Impl.Sha1.X86.compress, Impl.Sha1.X86.Stream.params.out⟩ + +/-- The member of the SHA-512 family with a `D`-byte digest and initial hash +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⟩ + +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) : + 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⟩ + +def md5Ok : MdOk md5M where + hH := md5OK + md := Proof.Md5.md + iv := Spec.Md5.H0 + link := ⟨rfl, rfl, rfl, fun _ _ _ h => h, fun m => by + show Spec.Md5.hash m = _ + rw [Proof.Md5.hash_eq] + exact (List.take_of_length_le (Nat.le_of_eq (Proof.Md5.md.digest_length _))).symm, by decide, by decide⟩ + reloc m m' p q h := by + apply Vector.ext + intro j hj + simp only [Proof.Md5.md, Spec.Md5.stateAt, Vector.getElem_ofFn] + exact Hmac.Generic.Common.readW_reloc (n := 16) h (by omega) + tail := by decide + out := outOk_of_shape Proof.Md5.X86.Stream.shape + comp := ⟨Proof.Md5.X86.compress_verified, NoSp.of_all (by lit_decide), by lit_decide⟩ + sizes := ⟨by decide, by decide, by decide, by decide, rfl, by decide, by decide, by decide⟩ + +def sha1Ok : MdOk sha1M where + hH := sha1OK + md := Proof.Sha1.md + iv := Spec.Sha1.H0 + link := ⟨rfl, rfl, rfl, fun _ _ _ h => h, fun m => by + show Spec.Sha1.hash m = _ + rw [Proof.Sha1.hash_eq] + exact (List.take_of_length_le (Nat.le_of_eq (Proof.Sha1.md.digest_length _))).symm, by decide, by decide⟩ + reloc m m' p q h := by + apply Vector.ext + intro j hj + simp only [Proof.Sha1.md, Spec.Sha1.stateAt, Vector.getElem_ofFn] + exact Hmac.Generic.Common.readW_reloc (n := 20) h (by omega) + tail := by decide + out := outOk_of_shape Proof.Sha1.X86.Stream.shape + comp := ⟨Proof.Sha1.X86.compress_verified, NoSp.of_all (by lit_decide), by lit_decide⟩ + sizes := ⟨by decide, by decide, by decide, by decide, rfl, by decide, by decide, by decide⟩ + +/-- `MdOk` for a member of the SHA-512 family, whose digest is the first `D` +bytes of the final hash value. -/ +def sha512Ok {D : Nat} {initN : String} {iv : Spec.Sha512.HashValue} + (hO : VG.Proof.Hmac.Generic.X86.HashOK (sha512H D initN iv)) (hR : hO.SH.Repr = Spec.Sha512.Repr iv) + (hh : ∀ m, hO.SH.H.hash m = (Spec.Sha512.finalHash iv m).take D) (hB : hO.SH.H.blockSize = 128) + (hS : hO.SH.stateBytes = 192) (hD : hO.SH.digestBytes = D) (hD64 : D ≤ 64) + (tail : Proof.Sha512.md.tailPad D = (sha512M D initN iv).tailB) (sizes : Sizes (sha512M D initN iv)) : + MdOk (sha512M D initN iv) where + hH := hO + md := Proof.Sha512.md + iv := iv + link := ⟨hB, hS, hD, fun _ _ _ h => by rw [hR] at h; exact h, hh, hD64, by have := sizes.DL; omega⟩ + reloc m m' p q h := by + apply Vector.ext + intro j hj + 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⟩ + 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⟩ +def sha512Ok' : MdOk sha512M' := sha512Ok sha512OK rfl + (fun m => (List.take_of_length_le (Nat.le_of_eq (Hmac.Generic.Common.finalHash_length _ m))).symm) + rfl rfl rfl (by decide) (by decide) ⟨by decide, by decide, by decide, by decide, rfl, by decide, by decide, by decide⟩ +def sha512_224Ok : MdOk sha512_224M := sha512Ok sha512_224OK 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⟩ +def sha512_256Ok : MdOk sha512_256M := sha512Ok sha512_256OK 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⟩ + +end VG.Proof.Pbkdf2.Md.X86 diff --git a/lean/VerifiedGarbage/Proof/Pbkdf2/Md/X86/HmacFin.lean b/lean/VerifiedGarbage/Proof/Pbkdf2/Md/X86/HmacFin.lean new file mode 100644 index 000000000..dce48d589 --- /dev/null +++ b/lean/VerifiedGarbage/Proof/Pbkdf2/Md/X86/HmacFin.lean @@ -0,0 +1,370 @@ +import VerifiedGarbage.Proof.Pbkdf2.Md.X86.Block +import VerifiedGarbage.Proof.Hmac.Generic.X86.Finalize + +/-! +# HMAC over a Merkle–Damgård hash function on x86 (32-bit): `finalize`, correct + +Untrusted: everything here is checked by Lean. HMAC's `finalize` +(`Impl/Pbkdf2/Md/X86.lean`) starts as in the streaming-level design: the +prologue and the call of the hash function's streaming `finalize` on the +inner state, which writes the inner digest to `scratch` +(`Proof/Hmac/Generic/X86/Finalize.lean`, whose `KR` the rest keeps). Then +the inner state gets the outer hash value and, in its buffer, the digest and +the padding (`mid_ok`); one compression (`cmpF_ok`) gives the outer hash +value, whose digest is the MAC (`out_ok`): `Md.Link.hmac_outer`. +-/ + +namespace VG.Proof.Pbkdf2.Md.X86.HmacFin + +open VG.X86 +open VG.Impl.Pbkdf2.Md.X86 (Hash copyW) +open VG.Proof.Pbkdf2.Md.X86 +open VG.Proof.MdStream (Md) +open VG.Proof.Hmac.Generic.X86 (HashOK finG SavedRegs saveR savedRegs restore_ok callee_saved ea_at stk After + setWidth_add toNat_add_ofNat) +open VG.Proof.Hmac.Generic.X86.Finalize (Pre KR E inn outer op scr inR outerR opR scR stkR T tR calR tO wr_mem + save_sub t_sub save_t wrs kregs kregs_callee stk_eq pro_ok fin1Args_ok finCall_ok) +open VG.Proof.Hmac.Generic.Common (InRegions.right' bytesAt_writeBytes_self' bytesAt_take covers_one) +open VG.Proof.Sha256.X86.Stream (Upd wp_mov sub_offset) +open VG.Proof.Hmac.Common (bytesAt_length bytesAt_add bytesAt_writeBytes_sep writeBytes_at bytesAt_getD' + xorPad_length) +open VG.Proof.Sha256.Stream (writeBytes writeBytes_nil writeBytes_append writeBytes_frame) +open Spec.Sha256 (bytesAt) +open Spec.Hmac (StreamingHash xorPad ipad opad hmacBlockKey) + +/-! ## Sizes and regions -/ + +section +variable {H : Hash} (hz : Sizes H) {sc : Nat} {s₀ : State} (hp : Pre (H := H.st) sc s₀) +include hz hp + +theorem bounds : H.st.buf = 8 * H.st.W + 16 ∧ H.st.buf + H.st.F ≤ 8 * sc ∧ (scr s₀).toNat + 8 * sc ≤ 2 ^ 32 ∧ + H.so ≤ 8 * H.st.W ∧ H.st.W ≤ 64 ∧ 0 < H.N ∧ H.N ≤ 64 ∧ 0 < H.D ∧ H.D ≤ H.N ∧ H.B ≤ 128 ∧ 64 ≤ H.B ∧ + H.S = H.N + H.B ∧ H.D ≤ H.st.F ∧ (inn s₀).toNat + (H.N + H.B) ≤ 2 ^ 32 ∧ + (outer s₀).toNat + (H.N + H.B) ≤ 2 ^ 32 ∧ (op s₀).toNat + H.D ≤ 2 ^ 32 := by + have := hp.ni; have := hp.no; have := hp.np + have hS := hz.S + exact ⟨rfl, hp.fits, hp.nw, hz.so, hz.W, hz.N.1, hz.N.2.1, hz.D.1, hz.D.2.1, hz.B4.2.2, hz.B4.2.1, hS, hz.F.1, + by rw [← hS]; exact hp.ni, by rw [← hS]; exact hp.no, hp.np⟩ + +/-- The compression function's scratch space. -/ +abbrev cmpR (H : Hash) (s₀ : State) : Region := ⟨(scr s₀).setWidth 64, H.so⟩ + +theorem cmp_sub : Region.Sub (cmpR H s₀) (scR sc s₀) := by + have := bounds hz hp; exact Region.sub_prefix (by omega) + +theorem save_cmp : (saveR H.st (scr s₀)).Disjoint (cmpR H s₀) := by + have := bounds hz hp + exact Offset.disjoint_base _ (by omega) (by omega) + +omit hp in +theorem inR_eq : inR (H := H.st) s₀ = ⟨(inn s₀).setWidth 64, H.N + H.B⟩ := by + rw [inR, show H.st.S = H.N + H.B from hz.S] + +/-- The inner state is writable. -/ +theorem cov_in {s : State} (hwr : s.wr = s₀.wr) : Covers [⟨(inn s₀).setWidth 64, H.N + H.B⟩] s.wr := by + rw [← inR_eq hz, hwr] + exact covers_one (wr_mem hp).2.1 + +omit hp in +/-- A part of the inner state. -/ +theorem in_sub {a n : Nat} (h : a + n ≤ H.N + H.B) : + Region.Sub ⟨(inn s₀).setWidth 64 + BitVec.ofNat 64 a, n⟩ (inR (H := H.st) s₀) := by + rw [inR_eq hz]; exact Offset.sub_base _ h + +theorem save_in {a n : Nat} (h : a + n ≤ H.N + H.B) : + (saveR H.st (scr s₀)).Disjoint ⟨(inn s₀).setWidth 64 + BitVec.ofNat 64 a, n⟩ := + (hp.i_s.symm.sub_left (save_sub hp)).sub_right (in_sub hz h) + +/-- `KR` after code that writes only a part of the inner state and `eax`, +`ecx` and `edx`. -/ +theorem kr_write {s s' : State} (h : KR (H := H.st) sc s₀ s) (hrd : s'.rd = s.rd) (hwr : s'.wr = s.wr) + (hg : ∀ r, r ≠ .eax → r ≠ .ecx → r ≠ .edx → s'.gpr r = s.gpr r) {a n : Nat} (hl : a + n ≤ H.N + H.B) + (hf : Frame [⟨(inn s₀).setWidth 64 + BitVec.ofNat 64 a, n⟩] s.mem s'.mem) : KR (H := H.st) sc s₀ s' := + h.keep hrd hwr (fun r hr => hg r (by revert hr; decide +revert) (by revert hr; decide +revert) + (by revert hr; decide +revert)) hf + (fun r hr => by simp only [List.mem_singleton] at hr; subst hr; exact save_in hz hp hl) + (fun r hr => by simp only [List.mem_singleton] at hr; subst hr; exact ⟨_, by simp, in_sub hz hl⟩) + +/-- The arguments of the compression of the inner buffer. -/ +theorem cmpArgs {s : State} (hk : KR (H := H.st) sc s₀ s) (hax : s.gpr .eax = inn s₀ + BitVec.ofNat 32 H.N) : + CmpArgs H.N H.B H.so s (inn s₀) (scr s₀) := by + have := bounds hz hp + exact + { ebx := hk.ebx, eax := hax, ebp := hk.ebp, sp48 := by rw [hk.esp]; exact hp.sp48 + cst := cov_in hz hp hk.wr + csc := by + rw [hk.wr] + exact Covers.of_sub fun r hr => by + simp only [List.mem_singleton] at hr; subst hr + exact ⟨scR sc s₀, (wr_mem hp).1, 0, by simp, by simp only; omega⟩ + st_sc := by rw [← inR_eq hz]; exact hp.i_s.sub_right (cmp_sub hz hp) + b_st := by rw [stk_eq hk, ← inR_eq hz]; exact hp.b_i + b_sc := by rw [stk_eq hk]; exact hp.b_s.sub_right (cmp_sub hz hp) + nst := by omega + nsc := by omega } + +end + +/-! ## The outer block -/ + +section +variable {H : Hash} (hO : MdOk H) {sc : Nat} {s₀ : State} (hp : Pre (H := H.st) sc s₀) +include hO hp + +/-- The outer hash value over the inner state's, the inner digest into its +buffer and the padding after it, and `eax` at the buffer. -/ +theorem mid_ok {s : State} (hk : KR (H := H.st) sc s₀ s) (hsi : s.gpr .esi = outer s₀) : + WP isa (.block H.finMid) s fun t => KR (H := H.st) sc s₀ t ∧ t.gpr .eax = inn s₀ + BitVec.ofNat 32 H.N ∧ + hO.md.stateAt t.mem ((inn s₀).setWidth 64) = hO.md.stateAt s.mem ((outer s₀).setWidth 64) ∧ + bytesAt t.mem ((inn s₀).setWidth 64 + BitVec.ofNat 64 H.N) H.D = bytesAt s.mem (T (H := H.st) s₀) H.D ∧ + bytesAt t.mem ((inn s₀).setWidth 64 + BitVec.ofNat 64 (H.N + H.D)) (H.B - H.D) = H.tailB ∧ + Frame [inR (H := H.st) s₀] s.mem t.mem := by + have hz := hO.sizes + obtain ⟨hb, hf, hw, hso, hW, hN0, hN, hD0, hDN, hB, hB64, hS, hDF, ni, no, np⟩ := bounds hz hp + have hN4 := hz.N.2.2; have hD4 := hz.D.2.2; have tl := hz.tail_length; have hDL := hz.DL + have hn4 : 4 * (H.N / 4) = H.N := by omega + have hd4 : 4 * (H.D / 4) = H.D := by omega + obtain ⟨sR, iR, _⟩ := wr_mem hp + have oc : Covers [⟨(outer s₀).setWidth 64, H.N + H.B⟩] (s.rd ++ s.wr) := + covers_one (by rw [hk.rd, hp.rd, ← hS]; simp) + have sc' : Covers [scR sc s₀] (s.rd ++ s.wr) := covers_one (by rw [hk.rd, hk.wr, hp.wr]; simp) + have ic := cov_in hz hp hk.wr + simp only [Hash.finMid, List.append_assoc] + -- The outer hash value. + refine copyW_ok (by decide) (by decide) (H.N / 4) _ s _ hsi hk.ebx (by omega) (by omega) + (fun j hj => by rw [addr_eq (by omega)]; exact inReg oc (by omega) (by omega)) + (fun j hj => by rw [addr_eq (by omega)]; exact inReg ic (by omega) (by omega)) ?_ fun s₁ g₁ rd₁ wr₁ m₁ => ?_ + · rw [hn4, BitVec.add_zero, BitVec.add_zero] + have c₁ : (outerR (H := H.st) s₀).Contains ((outer s₀).setWidth 64) H.N := + Memory.contains_base (show H.N ≤ H.st.S by rw [show H.st.S = H.N + H.B from hz.S]; omega) + have c₂ : (inR (H := H.st) s₀).Contains ((inn s₀).setWidth 64) H.N := + Memory.contains_base (show H.N ≤ H.st.S by rw [show H.st.S = H.N + H.B from hz.S]; omega) + exact hp.i_o.symm.sep c₁ c₂ + rw [hn4, BitVec.add_zero, BitVec.add_zero] at m₁ + have f₁ : Frame [⟨(inn s₀).setWidth 64, H.N⟩] s.mem s₁.mem := by + rw [m₁]; exact writeBytes_frame _ _ _ (by rw [bytesAt_length]; exact Region.contains_self _ _) + -- The digest. + refine copyW_ok (by decide) (by decide) (H.D / 4) _ s₁ _ (by rw [g₁ _ (by decide), hk.ebp]) + (by rw [g₁ _ (by decide), hk.ebx]) (by omega) (by omega) + (fun j hj => by rw [addr_eq (by omega), rd₁, wr₁]; exact inReg sc' (by omega) (by omega)) + (fun j hj => by rw [addr_eq (by omega), wr₁]; exact inReg ic (by omega) (by omega)) ?_ fun s₂ g₂ rd₂ wr₂ m₂ => ?_ + · rw [hd4] + exact hp.i_s.symm.sep (Offset.contains_base _ (by omega) (by omega)) + (by rw [inR_eq hz]; exact Offset.contains_base _ (by omega) (by omega)) + rw [hd4] at m₂ + have f₂ : Frame [⟨(inn s₀).setWidth 64 + BitVec.ofNat 64 H.N, H.D⟩] s₁.mem s₂.mem := by + rw [m₂]; exact writeBytes_frame _ _ _ (by rw [bytesAt_length]; exact Region.contains_self _ _) + -- The padding, and `eax` at the buffer. + refine pad_ok hz (x := inn s₀) (by rw [g₂ _ (by decide), g₁ _ (by decide), hk.ebx]) (by omega) + (by rw [wr₂, wr₁]; exact ic) fun s₃ g₃ rd₃ wr₃ m₃ => ?_ + rw [← List.append_nil H.atBlk] + refine atBlk_ok fun s₄ e₄ g₄ m₄ rd₄ wr₄ => WP.block_nil ?_ + have f₃ : Frame [⟨(inn s₀).setWidth 64 + BitVec.ofNat 64 (H.N + H.D), H.B - H.D⟩] s₂.mem s₄.mem := by + rw [m₄, m₃]; exact writeBytes_frame _ _ _ (by rw [tl]; exact Region.contains_self _ _) + have fI : Frame [inR (H := H.st) s₀] s.mem s₄.mem := + ((f₁.sub fun r hr => by + simp only [List.mem_singleton] at hr; subst hr + have := in_sub hz (s₀ := s₀) (a := 0) (n := H.N) (by omega); rw [BitVec.add_zero] at this + exact ⟨_, List.mem_singleton_self _, this⟩).trans + (f₂.sub fun r hr => by + simp only [List.mem_singleton] at hr; subst hr; exact ⟨_, List.mem_singleton_self _, in_sub hz (by omega)⟩)).trans + (f₃.sub fun r hr => by + simp only [List.mem_singleton] at hr; subst hr; exact ⟨_, List.mem_singleton_self _, in_sub hz (by omega)⟩) + have k₄ : KR (H := H.st) sc s₀ s₄ := hk.keep (by rw [rd₄, rd₃, rd₂, rd₁]) (by rw [wr₄, wr₃, wr₂, wr₁]) + (fun r hr => by + rw [g₄ r (by revert hr; decide +revert), g₃ r (by revert hr; decide +revert), + g₂ r (by revert hr; decide +revert), g₁ r (by revert hr; decide +revert)]) fI + (fun r hr => by simp only [List.mem_singleton] at hr; subst hr; exact hp.i_s.symm.sub_left (save_sub hp)) + (fun r hr => by simp only [List.mem_singleton] at hr; subst hr; exact ⟨_, by simp, fun _ h => h⟩) + -- The bytes before the padding are not written by it, and those before the digest not by it. + have d₃ : ∀ {a n : Nat}, a + n ≤ H.N + H.D → + ∀ r ∈ [(⟨(inn s₀).setWidth 64 + BitVec.ofNat 64 (H.N + H.D), H.B - H.D⟩ : Region)], + Region.Disjoint ⟨(inn s₀).setWidth 64 + BitVec.ofNat 64 a, n⟩ r := by + intro a n h r hr + simp only [List.mem_singleton] at hr; subst hr + exact Offset.disjoint _ (.inl h) (by omega) (by omega) + refine ⟨k₄, by rw [e₄, g₃ _ (by decide), g₂ _ (by decide), g₁ _ (by decide), hk.ebx], ?_, ?_, ?_, fI⟩ + · refine hO.reloc _ _ _ _ fun i hi => ?_ + have dN : ∀ {a n : Nat}, H.N ≤ a → a + n ≤ H.N + H.B → + ∀ r ∈ [(⟨(inn s₀).setWidth 64 + BitVec.ofNat 64 a, n⟩ : Region)], + Region.Disjoint ⟨(inn s₀).setWidth 64, H.N⟩ r := by + intro a n h₁ h₂ r hr + simp only [List.mem_singleton] at hr; subst hr + exact Offset.base_disjoint _ h₁ (by omega) + rw [f₃.bytes (R := ⟨(inn s₀).setWidth 64, H.N⟩) (dN (by omega) (by omega)) (by show H.N ≤ 2 ^ 64; omega) hi, + f₂.bytes (R := ⟨(inn s₀).setWidth 64, H.N⟩) (dN (by omega) (by omega)) (by show H.N ≤ 2 ^ 64; omega) hi, m₁, + writeBytes_at _ _ _ (by rw [bytesAt_length]; exact hi) (by rw [bytesAt_length]; omega), bytesAt_getD' _ _ hi] + · rw [Memory.frame_bytesAt f₃ (d₃ (by omega)) (by omega), m₂, bytesAt_writeBytes_self' (bytesAt_length _ _ _) (by omega)] + have dT : ∀ r ∈ [(⟨(inn s₀).setWidth 64, H.N⟩ : Region)], Region.Disjoint ⟨T (H := H.st) s₀, H.D⟩ r := by + simp only [List.mem_singleton]; rintro r rfl + refine (hp.i_s.symm.sub_left fun a ha => t_sub hp a (Region.sub_prefix hDF a ha)).sub_right ?_ + rw [inR_eq hz]; exact Region.sub_prefix (by omega) + exact Memory.frame_bytesAt f₁ dT (by omega) + · rw [m₄, m₃, ← tl, bytesAt_writeBytes_self' rfl (by omega)] + +/-- The compression of the inner buffer into the outer hash value. -/ +theorem cmpF_ok {s : State} (hk : KR (H := H.st) sc s₀ s) (hax : s.gpr .eax = inn s₀ + BitVec.ofNat 32 H.N) + {Q : State → Prop} + (k : ∀ s', KR (H := H.st) sc s₀ s' → + Frame [⟨(inn s₀).setWidth 64, H.N⟩, cmpR H s₀, stkR s₀] s.mem s'.mem → + hO.md.stateAt s'.mem ((inn s₀).setWidth 64) = hO.md.compress (hO.md.stateAt s.mem ((inn s₀).setWidth 64)) + (hO.md.blockAt s.mem ((inn s₀).setWidth 64 + BitVec.ofNat 64 H.N)) → Q s') : + WP isa H.cmp s Q := by + have hz := hO.sizes + obtain ⟨hb, hf, hw, hso, hW, hN0, hN, -⟩ := bounds hz hp + have hB := hz.B4 + refine cmp_ok hO.comp (by omega) (cmpArgs hz hp hk hax) fun s₃ ha e₃ => ?_ + have f := ha.frame + rw [stk_eq hk] at f + have sI : Region.Sub ⟨(inn s₀).setWidth 64, H.N⟩ (inR (H := H.st) s₀) := by + have := in_sub hz (s₀ := s₀) (a := 0) (n := H.N) (by omega); rwa [BitVec.add_zero] at this + refine k s₃ (hk.keep ha.rd ha.wr (fun r hr => ha.cs r (kregs_callee r hr)) f ?_ ?_) (f.mono (by simp)) e₃ + · simp only [List.cons_append, List.nil_append, List.mem_cons, List.not_mem_nil, or_false] + rintro r (rfl | rfl | rfl) + · exact (hp.i_s.symm.sub_left (save_sub hp)).sub_right sI + · exact save_cmp hz hp + · exact hp.b_s.symm.sub_left (save_sub hp) + · simp only [List.cons_append, List.nil_append, List.mem_cons, List.not_mem_nil, or_false] + rintro r (rfl | rfl | rfl) + · exact ⟨_, by simp, sI⟩ + · exact ⟨scR sc s₀, by simp, cmp_sub hz hp⟩ + · exact ⟨stkR s₀, by simp, fun _ h => h⟩ + +/-- The MAC to `out`, and our caller's registers back. -/ +theorem out_ok {s : State} (hk : KR (H := H.st) sc s₀ s) : + WP isa (.block H.finOut) s fun s' => abiPreserved s₀ s' ∧ + bytesAt s'.mem ((op s₀).setWidth 64) H.D = (hO.md.digest (hO.md.stateAt s.mem ((inn s₀).setWidth 64))).take H.D := by + have hz := hO.sizes + obtain ⟨hb, hf, hw, hso, hW, hN0, hN, hD0, hDN, hB, hB64, hS, hDF, ni, no, np⟩ := bounds hz hp + have hD4 := hz.D.2.2 + have hd4 : 4 * (H.D / 4) = H.D := by omega + have eD : H.st.D = H.D := rfl + obtain ⟨sR, iR, pR⟩ := wr_mem hp + have ic := cov_in hz hp hk.wr + have hdl := hO.md.digest_length (hO.md.stateAt s.mem ((inn s₀).setWidth 64)) + have sI : Region.Sub ⟨(inn s₀).setWidth 64, H.N⟩ (inR (H := H.st) s₀) := by + have := in_sub hz (s₀ := s₀) (a := 0) (n := H.N) (by omega); rwa [BitVec.add_zero] at this + have hL : 8 * H.st.W + 16 ≤ 8 * sc := by omega + -- The epilogue, from the state the MAC is written in. + have epi : ∀ t, KR (H := H.st) sc s₀ t → bytesAt t.mem ((op s₀).setWidth 64) H.D = + (hO.md.digest (hO.md.stateAt s.mem ((inn s₀).setWidth 64))).take H.D → + WP isa (.block H.st.restore) t fun s' => abiPreserved s₀ s' ∧ + bytesAt s'.mem ((op s₀).setWidth 64) H.D = + (hO.md.digest (hO.md.stateAt s.mem ((inn s₀).setWidth 64))).take H.D := fun t kt ht => + WP.mono (restore_ok H.st kt.ebp kt.saved (by rw [kt.wr]; exact sR) hL hw) + fun s' ⟨hm, _, _, hg, ho⟩ => ⟨⟨fun r hr => by + by_cases he : r = .esp + · subst he; rw [ho _ (by decide) (by decide), kt.esp] + · exact hg r (callee_saved r hr he), by rw [hm]; exact kt.ret hp⟩, by rw [hm]; exact ht⟩ + by_cases hDN' : H.D < H.N + · simp only [Hash.finOut, hDN', ite_true, List.append_assoc] + refine atBlk_ok fun s₁ e₁ g₁ m₁ rd₁ wr₁ => ?_ + have k₁ : KR (H := H.st) sc s₀ s₁ := kr_write hz hp hk rd₁ wr₁ (fun r h1 _ _ => g₁ r h1) (a := 0) (n := 0) + (by omega) (by rw [m₁]; exact Frame.refl _ _) + have aN : (inn s₀ + BitVec.ofNat 32 H.N).setWidth 64 = (inn s₀).setWidth 64 + BitVec.ofNat 64 H.N := + setWidth_add (by omega) + have tN : (inn s₀ + BitVec.ofNat 32 H.N).toNat = (inn s₀).toNat + H.N := toNat_add_ofNat (by omega) + rw [WP.block_append_iff] + refine WP.mono (hO.out s₁ (by rw [k₁.ebx]; omega) (by rw [e₁, hk.ebx, tN]; omega) ?_ ?_ ?_) + fun s₂ ⟨g₂, rd₂, wr₂, m₂⟩ => ?_ + · rw [k₁.ebx, k₁.rd, k₁.wr] + have := inReg (o := 0) (n := H.N) (cov_in hz hp (s := s₀) rfl) (by omega) (by omega) + rw [BitVec.add_zero] at this + exact InRegions.right' this + · rw [e₁, hk.ebx, aN, k₁.wr]; exact inReg (cov_in hz hp (s := s₀) rfl) (by omega) (by omega) + · rw [k₁.ebx, e₁, hk.ebx, aN]; exact Offset.base_disjoint _ (Nat.le_refl _) (by omega) + rw [e₁, hk.ebx, aN, k₁.ebx, m₁] at m₂ + have f₂ : Frame [⟨(inn s₀).setWidth 64 + BitVec.ofNat 64 H.N, H.N⟩] s₁.mem s₂.mem := by + rw [m₂, m₁]; exact writeBytes_frame _ _ _ (by rw [hdl]; exact Region.contains_self _ _) + have k₂ : KR (H := H.st) sc s₀ s₂ := kr_write hz hp k₁ rd₂ wr₂ (fun r _ h2 h3 => g₂ r h2 h3) (by omega) f₂ + refine copyW_ok (by decide) (by decide) (H.D / 4) _ s₂ _ k₂.ebx k₂.edi (by omega) (by omega) + (fun j hj => by + rw [addr_eq (by omega)]; exact InRegions.right' (inReg (cov_in hz hp k₂.wr) (by omega) (by omega))) + (fun j hj => by + rw [addr_eq (by omega), k₂.wr]; exact ⟨_, pR, Offset.contains_base _ (by omega) (by omega)⟩) ?_ + fun s₃ g₃ rd₃ wr₃ m₃ => ?_ + · rw [hd4, BitVec.add_zero] + exact hp.i_p.sep (by rw [inR_eq hz]; exact Offset.contains_base _ (by omega) (by omega)) + (Region.contains_self _ _) + rw [hd4, BitVec.add_zero] at m₃ + have f₃ : Frame [opR (H := H.st) s₀] s₂.mem s₃.mem := by + rw [m₃]; exact writeBytes_frame _ _ _ (by rw [bytesAt_length]; exact Region.contains_self _ _) + have k₃ : KR (H := H.st) sc s₀ s₃ := k₂.keep rd₃ wr₃ (fun r hr => g₃ r (by revert hr; decide +revert)) f₃ + (fun r hr => by simp only [List.mem_singleton] at hr; subst hr; exact hp.p_s.symm.sub_left (save_sub hp)) + (fun r hr => by simp only [List.mem_singleton] at hr; subst hr; exact ⟨_, by simp, fun _ h => h⟩) + refine epi s₃ k₃ ?_ + rw [m₃, bytesAt_writeBytes_self' (bytesAt_length _ _ _) (by omega), m₂, + bytesAt_take _ _ (Nat.le_of_lt hDN'), bytesAt_writeBytes_self' hdl (by omega)] + · have e : H.D = H.N := by omega + simp only [Hash.finOut, hDN', ite_false, List.cons_append] + refine wp_mov fun s₁ u₁ => ?_ + have k₁ : KR (H := H.st) sc s₀ s₁ := kr_write hz hp hk u₁.rd u₁.wr (fun r h1 _ _ => u₁.other r h1) (a := 0) (n := 0) + (by omega) (by rw [u₁.mem]; exact Frame.refl _ _) + rw [WP.block_append_iff] + refine WP.mono (hO.out s₁ (by rw [k₁.ebx]; omega) (by rw [u₁.gpr, hk.edi]; omega) ?_ ?_ ?_) + fun s₂ ⟨g₂, rd₂, wr₂, m₂⟩ => ?_ + · rw [k₁.ebx, k₁.rd, k₁.wr] + have := inReg (o := 0) (n := H.N) (cov_in hz hp (s := s₀) rfl) (by omega) (by omega) + rw [BitVec.add_zero] at this + exact InRegions.right' this + · rw [u₁.gpr, hk.edi, k₁.wr]; exact ⟨_, pR, Memory.contains_base (by omega)⟩ + · rw [k₁.ebx, u₁.gpr, hk.edi]; exact hp.i_p.sub_left sI |>.sub_right (Region.sub_prefix (by omega)) + rw [u₁.gpr, hk.edi, k₁.ebx, u₁.mem] at m₂ + have f₂ : Frame [opR (H := H.st) s₀] s₁.mem s₂.mem := by + rw [m₂, u₁.mem]; exact writeBytes_frame _ _ _ (by rw [hdl]; exact Memory.contains_base (by omega)) + have k₂ : KR (H := H.st) sc s₀ s₂ := k₁.keep rd₂ wr₂ + (fun r hr => g₂ r (by revert hr; decide +revert) (by revert hr; decide +revert)) f₂ + (fun r hr => by simp only [List.mem_singleton] at hr; subst hr; exact hp.p_s.symm.sub_left (save_sub hp)) + (fun r hr => by simp only [List.mem_singleton] at hr; subst hr; exact ⟨_, by simp, fun _ h => h⟩) + refine epi s₂ k₂ ?_ + rw [m₂, List.take_of_length_le (by omega), bytesAt_take _ _ (Nat.le_of_eq e) (F := H.N), + bytesAt_writeBytes_self' hdl (by omega), List.take_of_length_le (by omega)] + +theorem correct : WP isa H.hmacFin s₀ fun s' => abiPreserved s₀ s' ∧ (finG hO.hH.SH sc).post s₀ s' := by + have hz := hO.sizes + obtain ⟨hb, hf, hw, hso, hW, hN0, hN, hD0, hDN, hB, hB64, hS, hDF, ni, no, np⟩ := bounds hz hp + have hl := hO.link + have tl := hz.tail_length; have hDL := hz.DL + refine WP.seq (WP.mono (pro_ok hp) fun s₁ ⟨k₁, si₁, f₁⟩ => ?_) + refine WP.seq (WP.seq (WP.mono (fin1Args_ok hO.hH hp k₁) fun t₁ ⟨kt₁, a₁, st₁, m₁⟩ => + finCall_ok hO.hH hp kt₁ a₁ fun s₂ k₂ si₂ f₂ d₂ => ?_)) + refine WP.seq (WP.mono (mid_ok hO hp k₂ (by rw [si₂, st₁, si₁])) fun s₃ ⟨k₃, ax₃, e₃, b₃, p₃, f₃⟩ => ?_) + refine WP.seq (cmpF_ok hO hp k₃ ax₃ fun s₄ k₄ f₄ e₄ => ?_) + refine WP.mono (out_ok hO hp k₄) fun s' ⟨habi, hmac⟩ => ⟨habi, ?_⟩ + -- The functional part. + intro k0 text hk0 hlen hrI hcnt hrO + rw [hO.hH.hB] at hk0 hcnt + have hl0 : (xorPad k0 ipad ++ text).length = H.B + text.length := by + rw [List.length_append, xorPad_length, hk0] + -- The outer state is untouched until it is copied. + have oI : ∀ r ∈ [saveR H.st (scr s₀)], Region.Disjoint (outerR (H := H.st) s₀) r := by + simp only [List.mem_singleton]; rintro r rfl; exact hp.o_s.sub_right (save_sub hp) + have o₂ : ∀ r ∈ [inR (H := H.st) s₀, tR (H := H.st) s₀, calR hO.hH s₀, stkR s₀], + Region.Disjoint (outerR (H := H.st) s₀) r := by + simp only [List.mem_cons, List.not_mem_nil, or_false] + rintro r (rfl | rfl | rfl | rfl) + · exact hp.i_o.symm + · exact hp.o_s.sub_right (t_sub hp) + · exact hp.o_s.sub_right (VG.Proof.Hmac.Generic.X86.Finalize.cal_sub hO.hH hp) + · exact hp.b_o.symm + have rO₂ := Hmac.Generic.X86.Init.repr_keep hO.hH f₂ o₂ (m₁ ▸ Hmac.Generic.X86.Init.repr_keep hO.hH f₁ oI hrO) + -- The inner digest. + have dig := d₂ _ (m₁ ▸ Hmac.Generic.X86.Init.repr_keep hO.hH f₁ (by + simp only [List.mem_singleton]; rintro r rfl; exact hp.i_s.sub_right (save_sub hp)) hrI) + (by rw [hl0]; rw [hk0] at hlen; exact hlen) + (by rw [show arg s₀ 3 ++ arg s₀ 2 = Hmac.Generic.X86.countF s₀ from rfl, hcnt, hl0]) + rw [← bytesAt_take _ _ hDF] at dig + -- The outer hash value. + have lo : (xorPad k0 opad).length = H.B := by simp [xorPad, hk0] + have so₂ : hO.md.stateAt s₂.mem ((outer s₀).setWidth 64) = hO.md.compressList hO.iv (xorPad k0 opad) 1 := + Md.stateAt_of_repr (by omega) lo (hl.repr _ _ _ rO₂) + have pad₃ : bytesAt s₃.mem ((inn s₀).setWidth 64 + BitVec.ofNat 64 H.N + BitVec.ofNat 64 H.D) (H.B - H.D) = + hO.md.tailPad H.D := by rw [Memory.add_ofNat, p₃, hO.tail] + rw [e₄, e₃, so₂, Md.blockAt_tailPad (by omega) pad₃, b₃, dig] at hmac + show bytesAt s'.mem ((op s₀).setWidth 64) hO.hH.SH.digestBytes = hmacBlockKey hO.hH.SH.H k0 text + rw [hO.hH.hD, hmac, hl.hmac_outer (by rw [hk0]) text] + +end + +end VG.Proof.Pbkdf2.Md.X86.HmacFin diff --git a/lean/VerifiedGarbage/Proof/Pbkdf2/Md/X86/HmacFinCT.lean b/lean/VerifiedGarbage/Proof/Pbkdf2/Md/X86/HmacFinCT.lean new file mode 100644 index 000000000..7b29f173c --- /dev/null +++ b/lean/VerifiedGarbage/Proof/Pbkdf2/Md/X86/HmacFinCT.lean @@ -0,0 +1,213 @@ +import VerifiedGarbage.Proof.Pbkdf2.Md.X86.HmacFin + +/-! +# HMAC over a Merkle–Damgård hash function on x86 (32-bit): `finalize`, constant time + +Untrusted: everything here is checked by Lean. As for the streaming-level +functions (`Proof/Hmac/Generic/X86/`): the pieces between the calls are +checked by the taint analysis, the prologue and the arguments of the first +call, which read the arguments on the stack, with them public (`argTaint`); +the call of the streaming `finalize` is related by `fin_rel`, that of the +compression function by `cmp_rel`. Then `finalize` is verified against the +contract with the arguments read only (`finG`), and with them writable +(`finW`). +-/ + +namespace VG.Proof.Pbkdf2.Md.X86.HmacFin + +open VG.X86 +open VG.Impl.Pbkdf2.Md.X86 (Hash) +open VG.Proof.Pbkdf2.Md.X86 +open VG.Proof.Hmac.Generic.X86 (HashOK finG finW argTaint ArgsOut agree_argTaint rel_agree rel_wp stk fin_rel + FinArgs fin5) +open VG.Proof.Hmac.Generic.X86.Finalize (Pre KR E inn outer op scr tO pre_of pro_ok fin1Args_ok finCall_ok + stk_eq) + +/-- The taint checks of the pieces of `finalize` between its calls. -/ +structure Checks (H : Hash) : Prop where + pro : ∃ hc, (VG.Taint.check taint (argTaint [] (4 + 4 * 6)) (.block H.st.finPrologue) hc).isSome = true + fin1 : ∃ hc, (VG.Taint.check taint (argTaint [.ebp, .ebx, .edi] (4 + 4 * 6)) + (.block ([] ++ Impl.Hmac.Generic.X86.Hash.count1 ++ Impl.Hmac.Generic.X86.scr .edx H.st.buf)) hc).isSome = true + mid : ∃ hc, (VG.Taint.check taint (τr [.esp, .ebp, .ebx, .edi, .esi]) (.block H.finMid) hc).isSome = true + out : ∃ hc, (VG.Taint.check taint (τr [.esp, .ebp, .ebx, .edi]) (.block H.finOut) hc).isSome = true + +/-- The public arguments are the same. -/ +structure PubEq (s₀ s₀' : State) : Prop where + esp : s₀.gpr .esp = s₀'.gpr .esp + args : ∀ i < 6, arg s₀ i = arg s₀' i + +variable {H : Hash} (hO : MdOk H) {sc : Nat} (hc : Checks H) +variable {s₀ s₀' : State} (hp : Pre (H := H.st) sc s₀) (hp' : Pre (H := H.st) sc s₀') (hq : PubEq s₀ s₀') + +/-- The arguments lie outside the writable regions. -/ +theorem args_out {t : State} (h : Pre (H := H.st) sc t) {s : State} (hsp : s.gpr .esp = E t) (hwr : s.wr = t.wr) : + ArgsOut 6 s := by + have e : (⟨(s.gpr .esp).setWidth 64, 4 + 4 * 6⟩ : Region) = ⟨(E t).setWidth 64, 4 + 24⟩ := by rw [hsp] + refine ⟨by rw [hsp]; exact h.spf, ?_⟩ + rw [e, hwr, h.wr] + simp only [List.mem_cons, List.not_mem_nil, or_false] + rintro r (rfl | rfl | rfl) + · exact Taint.frame_disjoint (by have := h.spf; omega) h.r_i h.a_i + · exact Taint.frame_disjoint (by have := h.spf; omega) h.r_p h.a_p + · exact Taint.frame_disjoint (by have := h.spf; omega) h.r_s h.a_s + +include hq in +theorem kr_agree {s s' : State} (h : KR (H := H.st) sc s₀ s) (h' : KR (H := H.st) sc s₀' s') : + ∀ r ∈ [Reg.esp, .ebp, .ebx, .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 + · rw [h.esp, h'.esp, E, E, hq.esp] + · rw [h.ebp, h'.ebp, scr, scr, hq.args 5 (by decide)] + · rw [h.ebx, h'.ebx, inn, inn, hq.args 0 (by decide)] + · rw [h.edi, h'.edi, op, op, hq.args 4 (by decide)] + +theorem sub_regs {l l' : List Reg} (h : ∀ r ∈ l, r ∈ l') {s s' : State} (hs : ∀ r ∈ l', s.gpr r = s'.gpr r) : + ∀ r ∈ l, s.gpr r = s'.gpr r := fun r hr => hs r (h r hr) + +include hO hc hp hp' hq + +theorem ct : RelCT isa (fun s s' => s = s₀ ∧ s' = s₀') H.hmacFin fun _ _ => True := by + have hH := hO.hH + have e5 : scr s₀' = scr s₀ := (hq.args 5 (by decide)).symm + have e0 : inn s₀' = inn s₀ := (hq.args 0 (by decide)).symm + have eT : tO (H := H.st) s₀' = tO (H := H.st) s₀ := by rw [tO, tO, e5] + have e2 : arg s₀' 2 = arg s₀ 2 := (hq.args 2 (by decide)).symm + have e3 : arg s₀' 3 = arg s₀ 3 := (hq.args 3 (by decide)).symm + -- The prologue. + have pro : RelCT isa (fun s s' => s = s₀ ∧ s' = s₀') (.block H.st.finPrologue) + fun s s' => (KR (H := H.st) sc s₀ s ∧ s.gpr .esi = outer s₀) ∧ + (KR (H := H.st) sc s₀' s' ∧ s'.gpr .esi = outer s₀') := + rel_agree (argTaint [] (4 + 4 * 6)) (fun s s' e e' => by + subst e e' + exact agree_argTaint (fun r hr => nomatch hr) hq.esp (args_out hp rfl rfl) (args_out hp' rfl rfl) + hq.args) hc.pro + (fun _ e => by subst e; exact WP.mono (pro_ok hp) fun _ h => ⟨h.1, h.2.1⟩) + (fun _ e => by subst e; exact WP.mono (pro_ok hp') fun _ h => ⟨h.1, h.2.1⟩) + -- The call of the streaming `finalize`. + have a1 : RelCT isa (fun s s' => (KR (H := H.st) sc s₀ s ∧ s.gpr .esi = outer s₀) ∧ + (KR (H := H.st) sc s₀' s' ∧ s'.gpr .esi = outer s₀')) + (.block ([] ++ Impl.Hmac.Generic.X86.Hash.count1 ++ Impl.Hmac.Generic.X86.scr .edx H.st.buf)) + fun s s' => (KR (H := H.st) sc s₀ s ∧ + FinArgs hH s .ebx (inn s₀) (tO (H := H.st) s₀) (scr s₀) (arg s₀ 2) (arg s₀ 3) ∧ s.gpr .esi = outer s₀) ∧ + (KR (H := H.st) sc s₀' s' ∧ + FinArgs hH s' .ebx (inn s₀) (tO (H := H.st) s₀) (scr s₀) (arg s₀ 2) (arg s₀ 3) ∧ s'.gpr .esi = outer s₀') := + rel_agree (argTaint [.ebp, .ebx, .edi] (4 + 4 * 6)) (fun s s' ⟨k, _⟩ ⟨k', _⟩ => + agree_argTaint (sub_regs (by decide) (kr_agree hq k k')) (by rw [k.esp, k'.esp, E, E, hq.esp]) + (args_out hp k.esp k.wr) (args_out hp' k'.esp k'.wr) + fun i hi => by rw [k.argEq hp hi, k'.argEq hp' hi, hq.args i hi]) hc.fin1 + (fun _ ⟨k, si⟩ => WP.mono (fin1Args_ok hH hp k) fun _ ⟨k₁, a, s₁, _⟩ => ⟨k₁, a, s₁.trans si⟩) + (fun _ ⟨k, si⟩ => WP.mono (fin1Args_ok hH hp' k) fun _ ⟨k₁, a, s₁, _⟩ => + ⟨k₁, by rw [← e0, ← eT, ← e5, ← e2, ← e3]; exact a, s₁.trans si⟩) + have c1 : RelCT isa (fun s s' => (KR (H := H.st) sc s₀ s ∧ + FinArgs hH s .ebx (inn s₀) (tO (H := H.st) s₀) (scr s₀) (arg s₀ 2) (arg s₀ 3) ∧ s.gpr .esi = outer s₀) ∧ + (KR (H := H.st) sc s₀' s' ∧ + FinArgs hH s' .ebx (inn s₀) (tO (H := H.st) s₀) (scr s₀) (arg s₀ 2) (arg s₀ 3) ∧ s'.gpr .esi = outer s₀')) + (.frame (.push (fin5 .ebx)) (.call H.st.finN H.st.finC) (.pop .eax (fin5 .ebx).length)) + fun s s' => (KR (H := H.st) sc s₀ s ∧ s.gpr .esi = outer s₀) ∧ + (KR (H := H.st) sc s₀' s' ∧ s'.gpr .esi = outer s₀') := + rel_wp (fin_rel hH (sp := E s₀) fun s s' ⟨⟨k, a, _⟩, ⟨k', a', _⟩⟩ => + ⟨a, a', k.esp, by rw [k'.esp, E, E, hq.esp]⟩) + (fun _ ⟨k, a, si⟩ => finCall_ok hH hp k a fun _ k' si' _ _ => ⟨k', si'.trans si⟩) + (fun _ ⟨k, a, si⟩ => finCall_ok hH hp' k (by rw [e0, eT, e5]; exact a) + fun _ k' si' _ _ => ⟨k', si'.trans si⟩) + -- The outer block. + have mid : RelCT isa (fun s s' => (KR (H := H.st) sc s₀ s ∧ s.gpr .esi = outer s₀) ∧ + (KR (H := H.st) sc s₀' s' ∧ s'.gpr .esi = outer s₀')) (.block H.finMid) + fun s s' => (KR (H := H.st) sc s₀ s ∧ s.gpr .eax = inn s₀ + BitVec.ofNat 32 H.N) ∧ + (KR (H := H.st) sc s₀' s' ∧ s'.gpr .eax = inn s₀' + BitVec.ofNat 32 H.N) := + rel_agree (τr [.esp, .ebp, .ebx, .edi, .esi]) (fun s s' ⟨k, si⟩ ⟨k', si'⟩ => agree_regs fun r hr => by + simp only [List.mem_cons, List.not_mem_nil, or_false] at hr + rcases hr with rfl | rfl | rfl | rfl | rfl + · exact kr_agree hq k k' _ (by simp) + · exact kr_agree hq k k' _ (by simp) + · exact kr_agree hq k k' _ (by simp) + · exact kr_agree hq k k' _ (by simp) + · rw [si, si', outer, outer, hq.args 1 (by decide)]) hc.mid + (fun _ ⟨k, si⟩ => WP.mono (mid_ok hO hp k si) fun _ h => ⟨h.1, h.2.1⟩) + (fun _ ⟨k, si⟩ => WP.mono (mid_ok hO hp' k si) fun _ h => ⟨h.1, h.2.1⟩) + -- The compression. + have hB : 0 < H.B := by have := hO.sizes.B4; omega + have cm : RelCT isa (fun s s' => (KR (H := H.st) sc s₀ s ∧ s.gpr .eax = inn s₀ + BitVec.ofNat 32 H.N) ∧ + (KR (H := H.st) sc s₀' s' ∧ s'.gpr .eax = inn s₀' + BitVec.ofNat 32 H.N)) H.cmp + fun s s' => KR (H := H.st) sc s₀ s ∧ KR (H := H.st) sc s₀' s' := + rel_wp (cmp_rel hO.comp hB (sp := E s₀) fun s s' ⟨⟨k, a⟩, ⟨k', a'⟩⟩ => + ⟨cmpArgs hO.sizes hp k a, by have := cmpArgs hO.sizes hp' k' a'; rwa [e0, e5] at this, k.esp, + by rw [k'.esp, E, E, hq.esp]⟩) + (fun _ ⟨k, a⟩ => cmpF_ok hO hp k a fun _ k' _ _ => k') + (fun _ ⟨k, a⟩ => cmpF_ok hO hp' k a fun _ k' _ _ => k') + -- The MAC, and the end. + obtain ⟨_, ho⟩ := hc.out + have out : RelCT isa (fun s s' => KR (H := H.st) sc s₀ s ∧ KR (H := H.st) sc s₀' s') (.block H.finOut) + fun _ _ => True := + RelCT.taint (A := taint) (τr [.esp, .ebp, .ebx, .edi]) (fun _ _ h => agree_regs (kr_agree hq h.1 h.2)) ho + exact pro.seq ((a1.seq c1).seq (mid.seq (cm.seq out))) + +end VG.Proof.Pbkdf2.Md.X86.HmacFin + +namespace VG.Proof.Pbkdf2.Md.X86.HmacFin + +open VG.X86 +open VG.Impl.Pbkdf2.Md.X86 (Hash) +open VG.Proof.Pbkdf2.Md.X86 +open VG.Proof.Hmac.Generic.X86 (finG finW) +open VG.Proof.Hmac.Generic.X86.Finalize (pre_of) + +/-- `finalize` is verified against `finG`, given the taint checks, which the +kernel evaluates for each hash function. -/ +theorem verified {H : Hash} (hO : MdOk H) {sc : Nat} (hc : Checks H) + (hfit : H.st.buf + H.st.F ≤ 8 * sc) (hsat : ∃ s, (finG hO.hH.SH sc).pre s) : + Verified X86.target H.hmacFin (finG hO.hH.SH sc) := by + refine ⟨fun s hs => ?_, fun s₁ s₂ t₁ t₂ s₁' s₂' h₁ h₂ hpub e₁ e₂ => ?_, hsat⟩ + · obtain ⟨t, s', he, hg, hpost⟩ := correct hO (pre_of hO.hH sc hs hfit) + exact ⟨t, s', he, hg, hpost⟩ + · obtain ⟨h1, h2⟩ := hpub + exact (ct hO hc (pre_of hO.hH sc h₁ hfit) (pre_of hO.hH sc h₂ hfit) ⟨h1, h2⟩ + _ _ _ _ _ _ ⟨rfl, rfl⟩ e₁ e₂).1 + +/-- The regions `finalize` reads and writes, of those `finW` gives it. -/ +def narrowRd (S : Nat) (s : State) : List Region := [⟨(arg s 1).setWidth 64, S⟩, ⟨argAddr s 0, 24⟩] +def narrowWr (S D sc : Nat) (s : State) : List Region := + [⟨(arg s 0).setWidth 64, S⟩, ⟨(arg s 4).setWidth 64, D⟩, ⟨(arg s 5).setWidth 64, 8 * sc⟩] + +/-- `finalize` is verified against `finW`, which lets it write its arguments: +the code only reads them. -/ +theorem verifiedW {H : Hash} (hO : MdOk H) {sc : Nat} (hc : Checks H) + (hfit : H.st.buf + H.st.F ≤ 8 * sc) (hsat : ∃ s, (finW hO.hH.SH sc).pre s) : + Verified X86.target H.hmacFin (finW hO.hH.SH sc) := by + have pre : ∀ s, (finW hO.hH.SH sc).pre s → (finG hO.hH.SH sc).pre + (s.withRegions (narrowRd hO.hH.SH.stateBytes s) + (narrowWr hO.hH.SH.stateBytes hO.hH.SH.digestBytes sc s)) := by + intro s h + obtain ⟨_, _, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11, h12, h13, h14, h15, h16, h17, h18, h19, h20, h21, + h22, h23⟩ := h + simp only [finG, narrowRd, narrowWr, 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, h19, h20, + h21, h22, h23⟩ + refine Verified.narrowTo (verified hO hc hfit (hsat.elim fun s hs => ⟨_, pre s hs⟩)) + (narrowRd hO.hH.SH.stateBytes) (narrowWr hO.hH.SH.stateBytes hO.hH.SH.digestBytes sc) pre (fun s h => ?_) + (fun s h => ?_) (fun _ _ _ h => h) (fun _ _ _ _ h => h) hsat + · obtain ⟨h1, h2, _⟩ := h + rw [h1, h2] + refine Covers.of_sub fun r hr => ?_ + simp only [narrowRd, narrowWr, List.cons_append, List.nil_append, List.mem_cons, List.not_mem_nil, + or_false] at hr + rcases hr with rfl | rfl | rfl | rfl | rfl + · exact ⟨_, List.mem_append_left _ List.mem_cons_self, 0, by simp, by simp⟩ + · exact ⟨_, List.mem_append_right _ (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_append_right _ List.mem_cons_self, 0, by simp, by simp⟩ + · exact ⟨_, List.mem_append_right _ (List.mem_cons_of_mem _ List.mem_cons_self), 0, by simp, by simp⟩ + · exact ⟨_, List.mem_append_right _ (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 [narrowWr, 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 VG.Proof.Pbkdf2.Md.X86.HmacFin diff --git a/lean/VerifiedGarbage/Proof/Pbkdf2/Md/X86/Instances.lean b/lean/VerifiedGarbage/Proof/Pbkdf2/Md/X86/Instances.lean new file mode 100644 index 000000000..9d6994fc1 --- /dev/null +++ b/lean/VerifiedGarbage/Proof/Pbkdf2/Md/X86/Instances.lean @@ -0,0 +1,291 @@ +import VerifiedGarbage.Proof.Framework.Contract +import VerifiedGarbage.Proof.Pbkdf2.Md.X86.Lit +import VerifiedGarbage.Proof.Pbkdf2.Md.X86.IterateCT +import VerifiedGarbage.Proof.Pbkdf2.Md.X86.HmacFinCT + +/-! +# HMAC's `finalize` and PBKDF2's `iterate` on x86 (32-bit): the instances + +Untrusted: everything here is checked by Lean. The generic proofs +(`IterateCT.lean`, `HmacFinCT.lean`) at each hash function of `Hashes.lean`, +with the taint checks of their blocks, which the kernel evaluates for each +hash function, moved to the shared contracts of `Spec/Hmac/Generic.lean` and +`Spec/Pbkdf2/Generic.lean` (`sig_implies`), which the artifacts are emitted +with. +-/ + +namespace VG.Proof.Pbkdf2.Md.X86.Instances + +open VG.X86 +open VG.Proof.Pbkdf2.Md.X86 +open VG.Proof.Hmac.Generic.X86 (finW finG iterW iterG countF) + +/-- Memory holding the arguments `0x1000, 0x1400, 0, 0x1800, 0x2000` of +`iterate` at `0x6004`. -/ +def iterMem : Mem := fun a => + if a = 0x6005 then 0x10 else if a = 0x6009 then 0x14 else if a = 0x6011 then 0x18 else + if a = 0x6015 then 0x20 else 0 + +/-- A state satisfying `iterate`'s precondition, with states of `S` bytes, a +digest of `D` bytes and `8 sc` bytes of scratch space, with the arguments +writable. -/ +def iterSat (S D sc : Nat) : State where + gpr r := match r with + | .esp => 0x6000 | _ => 0 + cf := none + zf := none + sf := none + of := none + mem := iterMem + rd := [⟨0x1000, 2 * S⟩, ⟨0x1400, D⟩] + wr := [⟨0x1800, D⟩, ⟨0x2000, 8 * sc⟩, ⟨0x6004, 20⟩] + +theorem iterSat_args (S D sc : Nat) : + arg (iterSat S D sc) 0 = 0x1000 ∧ arg (iterSat S D sc) 1 = 0x1400 ∧ arg (iterSat S D sc) 2 = 0 ∧ + arg (iterSat S D sc) 3 = 0x1800 ∧ arg (iterSat S D sc) 4 = 0x2000 ∧ argAddr (iterSat S D sc) 0 = 0x6004 ∧ + (iterSat S D sc).gpr .esp = 0x6000 := by + have e : ∀ i, arg (iterSat S D sc) i = arg (iterSat 0 0 0) i := fun _ => rfl + have e' : argAddr (iterSat S D sc) 0 = argAddr (iterSat 0 0 0) 0 := rfl + rw [e, e, e, e, e, e'] + refine ⟨?_, ?_, ?_, ?_, ?_, ?_, rfl⟩ <;> decide + +/-- Memory holding the arguments `0x1000, 0x1400, 0, 0, 0x1800, 0x2000` of +`finalize` at `0x6004`. -/ +def finMem : Mem := fun a => + if a = 0x6005 then 0x10 else if a = 0x6009 then 0x14 else if a = 0x6015 then 0x18 else + if a = 0x6019 then 0x20 else 0 + +/-- A state satisfying `finalize`'s precondition, with states of `S` bytes, +a digest of `D` bytes and `8 sc` bytes of scratch space, with the arguments +writable. -/ +def finSat (S D sc : Nat) : State where + gpr r := match r with + | .esp => 0x6000 | _ => 0 + cf := none + zf := none + sf := none + of := none + mem := finMem + rd := [⟨0x1400, S⟩] + wr := [⟨0x1000, S⟩, ⟨0x1800, D⟩, ⟨0x2000, 8 * sc⟩, ⟨0x6004, 24⟩] + +theorem finSat_args (S D sc : Nat) : + arg (finSat S D sc) 0 = 0x1000 ∧ arg (finSat S D sc) 1 = 0x1400 ∧ arg (finSat S D sc) 2 = 0 ∧ + arg (finSat S D sc) 3 = 0 ∧ arg (finSat S D sc) 4 = 0x1800 ∧ arg (finSat S D sc) 5 = 0x2000 ∧ + argAddr (finSat S D sc) 0 = 0x6004 ∧ (finSat S D sc).gpr .esp = 0x6000 := by + have e : ∀ i, arg (finSat S D sc) i = arg (finSat 0 0 0) i := fun _ => rfl + have e' : argAddr (finSat S D sc) 0 = argAddr (finSat 0 0 0) 0 := rfl + rw [e, e, e, e, e, e, e'] + refine ⟨?_, ?_, ?_, ?_, ?_, ?_, ?_, rfl⟩ <;> decide + +/-! ## MD5 -/ + +theorem md5_iterChecks : Iterate.Checks md5M where + pro := ⟨_, by taint_decide⟩ + load := ⟨_, by taint_decide⟩ + mid := ⟨_, by taint_decide⟩ + tail := ⟨_, by taint_decide⟩ + restore := ⟨_, by taint_decide⟩ + +theorem md5_finChecks : HmacFin.Checks md5M where + pro := ⟨_, by taint_decide⟩ + fin1 := ⟨_, by taint_decide⟩ + mid := ⟨_, by taint_decide⟩ + out := ⟨_, by taint_decide⟩ + +theorem md5_iterImp : (iterW Spec.Hmac.md5S 48).Implies (Spec.Hmac.md5I.iterateContract X86.abi 48) := by + obtain ⟨a0, a1, a2, a3, a4, e, esp⟩ := iterSat_args 80 16 48 + sig_implies [Spec.Hmac.Instance.iterateContract, Spec.Pbkdf2.iterateContract, Spec.Pbkdf2.iterateSig, + Spec.Hmac.md5I, Spec.Hmac.md5S, Spec.Hmac.md5, iterW, iterG, X86.abi, X86.argSlots, X86.argVal, + X86.argBytes] + [a0, a1, a2, a3, a4, e, esp, iterSat] using iterSat 80 16 48 + +theorem md5_finImp : (finW Spec.Hmac.md5S 48).Implies (Spec.Hmac.md5I.finalizeContract X86.abi 48) := by + obtain ⟨a0, a1, a2, a3, a4, a5, e, esp⟩ := finSat_args 80 16 48 + sig_implies [Spec.Hmac.Instance.finalizeContract, Spec.Hmac.finalizeContract, Spec.Hmac.finalizeSig, + Spec.Hmac.md5I, Spec.Hmac.md5S, Spec.Hmac.md5, finW, finG, countF, X86.abi, X86.argSlots, + X86.argVal, X86.argBytes] + [a0, a1, a2, a3, a4, a5, e, esp, finSat] using finSat 80 16 48 + +theorem md5_iterate : Verified X86.target md5M.iterate (Spec.Hmac.md5I.iterateContract X86.abi 48) := + (Iterate.verifiedW md5Ok md5_iterChecks (by decide) md5_iterImp.sat_left).of_implies md5_iterImp + +theorem md5_finalize : Verified X86.target md5M.hmacFin (Spec.Hmac.md5I.finalizeContract X86.abi 48) := + (HmacFin.verifiedW md5Ok md5_finChecks (by decide) md5_finImp.sat_left).of_implies md5_finImp + +/-! ## SHA-1 -/ + +theorem sha1_iterChecks : Iterate.Checks sha1M where + pro := ⟨_, by taint_decide⟩ + load := ⟨_, by taint_decide⟩ + mid := ⟨_, by taint_decide⟩ + tail := ⟨_, by taint_decide⟩ + restore := ⟨_, by taint_decide⟩ + +theorem sha1_finChecks : HmacFin.Checks sha1M where + pro := ⟨_, by taint_decide⟩ + fin1 := ⟨_, by taint_decide⟩ + mid := ⟨_, by taint_decide⟩ + out := ⟨_, by taint_decide⟩ + +theorem sha1_iterImp : (iterW Spec.Hmac.sha1S 56).Implies (Spec.Hmac.sha1I.iterateContract X86.abi 48) := by + obtain ⟨a0, a1, a2, a3, a4, e, esp⟩ := iterSat_args 84 20 56 + sig_implies [Spec.Hmac.Instance.iterateContract, Spec.Pbkdf2.iterateContract, Spec.Pbkdf2.iterateSig, + Spec.Hmac.sha1I, Spec.Hmac.sha1S, Spec.Hmac.sha1, iterW, iterG, X86.abi, X86.argSlots, X86.argVal, + X86.argBytes] + [a0, a1, a2, a3, a4, e, esp, iterSat] using iterSat 84 20 56 + +theorem sha1_finImp : (finW Spec.Hmac.sha1S 56).Implies (Spec.Hmac.sha1I.finalizeContract X86.abi 48) := by + obtain ⟨a0, a1, a2, a3, a4, a5, e, esp⟩ := finSat_args 84 20 56 + sig_implies [Spec.Hmac.Instance.finalizeContract, Spec.Hmac.finalizeContract, Spec.Hmac.finalizeSig, + Spec.Hmac.sha1I, Spec.Hmac.sha1S, Spec.Hmac.sha1, finW, finG, countF, X86.abi, X86.argSlots, + X86.argVal, X86.argBytes] + [a0, a1, a2, a3, a4, a5, e, esp, finSat] using finSat 84 20 56 + +theorem sha1_iterate : Verified X86.target sha1M.iterate (Spec.Hmac.sha1I.iterateContract X86.abi 48) := + (Iterate.verifiedW sha1Ok sha1_iterChecks (by decide) sha1_iterImp.sat_left).of_implies sha1_iterImp + +theorem sha1_finalize : Verified X86.target sha1M.hmacFin (Spec.Hmac.sha1I.finalizeContract X86.abi 48) := + (HmacFin.verifiedW sha1Ok sha1_finChecks (by decide) sha1_finImp.sat_left).of_implies sha1_finImp + +/-! ## SHA-384 -/ + +theorem sha384_iterChecks : Iterate.Checks sha384M where + pro := ⟨_, by taint_decide⟩ + load := ⟨_, by taint_decide⟩ + mid := ⟨_, by taint_decide⟩ + tail := ⟨_, by taint_decide⟩ + restore := ⟨_, by taint_decide⟩ + +theorem sha384_finChecks : HmacFin.Checks sha384M where + pro := ⟨_, by taint_decide⟩ + fin1 := ⟨_, by taint_decide⟩ + mid := ⟨_, by taint_decide⟩ + out := ⟨_, by taint_decide⟩ + +theorem sha384_iterImp : (iterW Spec.Hmac.sha384S 234).Implies (Spec.Hmac.sha384I.iterateContract X86.abi 48) := by + obtain ⟨a0, a1, a2, a3, a4, e, esp⟩ := iterSat_args 192 48 234 + sig_implies [Spec.Hmac.Instance.iterateContract, Spec.Pbkdf2.iterateContract, Spec.Pbkdf2.iterateSig, + Spec.Hmac.sha384I, Spec.Hmac.sha384S, Spec.Hmac.sha384, iterW, iterG, X86.abi, X86.argSlots, X86.argVal, + X86.argBytes] + [a0, a1, a2, a3, a4, e, esp, iterSat] using iterSat 192 48 234 + +theorem sha384_finImp : (finW Spec.Hmac.sha384S 234).Implies (Spec.Hmac.sha384I.finalizeContract X86.abi 48) := by + obtain ⟨a0, a1, a2, a3, a4, a5, e, esp⟩ := finSat_args 192 48 234 + sig_implies [Spec.Hmac.Instance.finalizeContract, Spec.Hmac.finalizeContract, Spec.Hmac.finalizeSig, + Spec.Hmac.sha384I, Spec.Hmac.sha384S, Spec.Hmac.sha384, finW, finG, countF, X86.abi, X86.argSlots, + X86.argVal, X86.argBytes] + [a0, a1, a2, a3, a4, a5, e, esp, finSat] using finSat 192 48 234 + +theorem sha384_iterate : Verified X86.target sha384M.iterate (Spec.Hmac.sha384I.iterateContract X86.abi 48) := + (Iterate.verifiedW sha384Ok sha384_iterChecks (by decide) sha384_iterImp.sat_left).of_implies sha384_iterImp + +theorem sha384_finalize : Verified X86.target sha384M.hmacFin (Spec.Hmac.sha384I.finalizeContract X86.abi 48) := + (HmacFin.verifiedW sha384Ok sha384_finChecks (by decide) sha384_finImp.sat_left).of_implies sha384_finImp + +/-! ## SHA-512 -/ + +theorem sha512_iterChecks : Iterate.Checks sha512M' where + pro := ⟨_, by taint_decide⟩ + load := ⟨_, by taint_decide⟩ + mid := ⟨_, by taint_decide⟩ + tail := ⟨_, by taint_decide⟩ + restore := ⟨_, by taint_decide⟩ + +theorem sha512_finChecks : HmacFin.Checks sha512M' where + pro := ⟨_, by taint_decide⟩ + fin1 := ⟨_, by taint_decide⟩ + mid := ⟨_, by taint_decide⟩ + out := ⟨_, by taint_decide⟩ + +theorem sha512_iterImp : (iterW Spec.Hmac.sha512S 234).Implies (Spec.Hmac.sha512I.iterateContract X86.abi 48) := by + obtain ⟨a0, a1, a2, a3, a4, e, esp⟩ := iterSat_args 192 64 234 + sig_implies [Spec.Hmac.Instance.iterateContract, Spec.Pbkdf2.iterateContract, Spec.Pbkdf2.iterateSig, + Spec.Hmac.sha512I, Spec.Hmac.sha512S, Spec.Hmac.sha512, iterW, iterG, X86.abi, X86.argSlots, X86.argVal, + X86.argBytes] + [a0, a1, a2, a3, a4, e, esp, iterSat] using iterSat 192 64 234 + +theorem sha512_finImp : (finW Spec.Hmac.sha512S 234).Implies (Spec.Hmac.sha512I.finalizeContract X86.abi 48) := by + obtain ⟨a0, a1, a2, a3, a4, a5, e, esp⟩ := finSat_args 192 64 234 + sig_implies [Spec.Hmac.Instance.finalizeContract, Spec.Hmac.finalizeContract, Spec.Hmac.finalizeSig, + Spec.Hmac.sha512I, Spec.Hmac.sha512S, Spec.Hmac.sha512, finW, finG, countF, X86.abi, X86.argSlots, + X86.argVal, X86.argBytes] + [a0, a1, a2, a3, a4, a5, e, esp, finSat] using finSat 192 64 234 + +theorem sha512_iterate : Verified X86.target sha512M'.iterate (Spec.Hmac.sha512I.iterateContract X86.abi 48) := + (Iterate.verifiedW sha512Ok' sha512_iterChecks (by decide) sha512_iterImp.sat_left).of_implies sha512_iterImp + +theorem sha512_finalize : Verified X86.target sha512M'.hmacFin (Spec.Hmac.sha512I.finalizeContract X86.abi 48) := + (HmacFin.verifiedW sha512Ok' sha512_finChecks (by decide) sha512_finImp.sat_left).of_implies sha512_finImp + +/-! ## SHA-512/224 -/ + +theorem sha512_224_iterChecks : Iterate.Checks sha512_224M where + pro := ⟨_, by taint_decide⟩ + load := ⟨_, by taint_decide⟩ + mid := ⟨_, by taint_decide⟩ + tail := ⟨_, by taint_decide⟩ + restore := ⟨_, by taint_decide⟩ + +theorem sha512_224_finChecks : HmacFin.Checks sha512_224M where + pro := ⟨_, by taint_decide⟩ + fin1 := ⟨_, by taint_decide⟩ + mid := ⟨_, by taint_decide⟩ + out := ⟨_, by taint_decide⟩ + +theorem sha512_224_iterImp : (iterW Spec.Hmac.sha512_224S 234).Implies (Spec.Hmac.sha512_224I.iterateContract X86.abi 48) := by + obtain ⟨a0, a1, a2, a3, a4, e, esp⟩ := iterSat_args 192 28 234 + sig_implies [Spec.Hmac.Instance.iterateContract, Spec.Pbkdf2.iterateContract, Spec.Pbkdf2.iterateSig, + Spec.Hmac.sha512_224I, Spec.Hmac.sha512_224S, Spec.Hmac.sha512_224, iterW, iterG, X86.abi, X86.argSlots, X86.argVal, + X86.argBytes] + [a0, a1, a2, a3, a4, e, esp, iterSat] using iterSat 192 28 234 + +theorem sha512_224_finImp : (finW Spec.Hmac.sha512_224S 234).Implies (Spec.Hmac.sha512_224I.finalizeContract X86.abi 48) := by + obtain ⟨a0, a1, a2, a3, a4, a5, e, esp⟩ := finSat_args 192 28 234 + sig_implies [Spec.Hmac.Instance.finalizeContract, Spec.Hmac.finalizeContract, Spec.Hmac.finalizeSig, + Spec.Hmac.sha512_224I, Spec.Hmac.sha512_224S, Spec.Hmac.sha512_224, finW, finG, countF, X86.abi, X86.argSlots, + X86.argVal, X86.argBytes] + [a0, a1, a2, a3, a4, a5, e, esp, finSat] using finSat 192 28 234 + +theorem sha512_224_iterate : Verified X86.target sha512_224M.iterate (Spec.Hmac.sha512_224I.iterateContract X86.abi 48) := + (Iterate.verifiedW sha512_224Ok sha512_224_iterChecks (by decide) sha512_224_iterImp.sat_left).of_implies sha512_224_iterImp + +theorem sha512_224_finalize : Verified X86.target sha512_224M.hmacFin (Spec.Hmac.sha512_224I.finalizeContract X86.abi 48) := + (HmacFin.verifiedW sha512_224Ok sha512_224_finChecks (by decide) sha512_224_finImp.sat_left).of_implies sha512_224_finImp + +/-! ## SHA-512/256 -/ + +theorem sha512_256_iterChecks : Iterate.Checks sha512_256M where + pro := ⟨_, by taint_decide⟩ + load := ⟨_, by taint_decide⟩ + mid := ⟨_, by taint_decide⟩ + tail := ⟨_, by taint_decide⟩ + restore := ⟨_, by taint_decide⟩ + +theorem sha512_256_finChecks : HmacFin.Checks sha512_256M where + pro := ⟨_, by taint_decide⟩ + fin1 := ⟨_, by taint_decide⟩ + mid := ⟨_, by taint_decide⟩ + out := ⟨_, by taint_decide⟩ + +theorem sha512_256_iterImp : (iterW Spec.Hmac.sha512_256S 234).Implies (Spec.Hmac.sha512_256I.iterateContract X86.abi 48) := by + obtain ⟨a0, a1, a2, a3, a4, e, esp⟩ := iterSat_args 192 32 234 + sig_implies [Spec.Hmac.Instance.iterateContract, Spec.Pbkdf2.iterateContract, Spec.Pbkdf2.iterateSig, + Spec.Hmac.sha512_256I, Spec.Hmac.sha512_256S, Spec.Hmac.sha512_256, iterW, iterG, X86.abi, X86.argSlots, X86.argVal, + X86.argBytes] + [a0, a1, a2, a3, a4, e, esp, iterSat] using iterSat 192 32 234 + +theorem sha512_256_finImp : (finW Spec.Hmac.sha512_256S 234).Implies (Spec.Hmac.sha512_256I.finalizeContract X86.abi 48) := by + obtain ⟨a0, a1, a2, a3, a4, a5, e, esp⟩ := finSat_args 192 32 234 + sig_implies [Spec.Hmac.Instance.finalizeContract, Spec.Hmac.finalizeContract, Spec.Hmac.finalizeSig, + Spec.Hmac.sha512_256I, Spec.Hmac.sha512_256S, Spec.Hmac.sha512_256, finW, finG, countF, X86.abi, X86.argSlots, + X86.argVal, X86.argBytes] + [a0, a1, a2, a3, a4, a5, e, esp, finSat] using finSat 192 32 234 + +theorem sha512_256_iterate : Verified X86.target sha512_256M.iterate (Spec.Hmac.sha512_256I.iterateContract X86.abi 48) := + (Iterate.verifiedW sha512_256Ok sha512_256_iterChecks (by decide) sha512_256_iterImp.sat_left).of_implies sha512_256_iterImp + +theorem sha512_256_finalize : Verified X86.target sha512_256M.hmacFin (Spec.Hmac.sha512_256I.finalizeContract X86.abi 48) := + (HmacFin.verifiedW sha512_256Ok sha512_256_finChecks (by decide) sha512_256_finImp.sat_left).of_implies sha512_256_finImp + +end VG.Proof.Pbkdf2.Md.X86.Instances diff --git a/lean/VerifiedGarbage/Proof/Pbkdf2/Md/X86/Iterate.lean b/lean/VerifiedGarbage/Proof/Pbkdf2/Md/X86/Iterate.lean new file mode 100644 index 000000000..13f44e85b --- /dev/null +++ b/lean/VerifiedGarbage/Proof/Pbkdf2/Md/X86/Iterate.lean @@ -0,0 +1,819 @@ +import VerifiedGarbage.Proof.Pbkdf2.Md.X86.Block + +/-! +# PBKDF2-HMAC's iteration over a Merkle–Damgård hash function on x86 (32-bit): correct + +Untrusted: everything here is checked by Lean. The iteration +(`Impl/Pbkdf2/Md/X86.lean`) is correct for any hash function whose code the +proofs know (`MdOk`): `Md.hmac_step` says that its two compressions per step +compute HMAC. The arguments are on the stack: `scratch`, `key`, `n` and `u` +are loaded first (after our caller's registers are saved in `scratch`), and +`t` in each step. The loop counts the steps left in `edi` down with `sub`, +and branches on its result. +-/ + +namespace VG.Proof.Pbkdf2.Md.X86.Iterate + +open VG.X86 +open VG.Impl.Pbkdf2.Md.X86 (Hash copyW) +open VG.Impl.Hmac.Generic.X86 (at_) +open VG.Proof.Pbkdf2.Md.X86 +open VG.Proof.MdStream (Md) +open VG.Proof.Hmac.Generic.X86 (HashOK iterG SavedRegs saveR savedRegs save_ok restore_ok callee_saved ea_at stk + After setWidth_add toNat_add_ofNat stk_ret stk_args arg_contains arg_keep argAddr_eq saved_mem test_z) +open VG.Proof.Hmac.Generic.Common (InRegions.right' bytesAt_writeBytes_self' bytesAt_take covers_one) +open VG.Proof.Sha256.X86.Stream (Upd Mupd Fupd wp_mov wp_movi wp_movm wp_store wp_addi wp_subi wp_test + sub_offset ofNat_beq_zero sub_ofNat eval_e eval_ne) +open VG.Proof.Hmac.Common (bytesAt_length bytesAt_add bytesAt_writeBytes_sep writeBytes_at bytesAt_getD') +open VG.Proof.Sha256.Stream (writeBytes writeBytes_nil writeBytes_append writeBytes_frame) +open Spec.Sha256 (bytesAt) +open Spec.Hmac (StreamingHash xorPad ipad opad hmacBlockKey) + +section +variable (H : Hash) (sc : Nat) (s₀ : State) + +abbrev E : BitVec 32 := s₀.gpr .esp +abbrev key : BitVec 32 := arg s₀ 0 +abbrev up : BitVec 32 := arg s₀ 1 +abbrev tp : BitVec 32 := arg s₀ 3 +abbrev scr : BitVec 32 := arg s₀ 4 +/-- The number of steps. -/ +abbrev nn : Nat := (arg s₀ 2).toNat +abbrev keyR : Region := ⟨(key s₀).setWidth 64, 2 * H.S⟩ +abbrev uR : Region := ⟨(up s₀).setWidth 64, H.D⟩ +abbrev tR : Region := ⟨(tp s₀).setWidth 64, H.D⟩ +abbrev scR : Region := ⟨(scr s₀).setWidth 64, 8 * sc⟩ +abbrev argR : Region := ⟨addr (E s₀) 4, 20⟩ +abbrev retR : Region := ⟨(E s₀).setWidth 64, 4⟩ +abbrev stkR : Region := below (E s₀) 48 +/-- Byte `o` of `scratch`. -/ +abbrev SA (o : Nat) : Addr := (scr s₀).setWidth 64 + BitVec.ofNat 64 o +/-- The hash value being compressed, as `ebx` holds it, and its address; +the block is right after it. -/ +abbrev hv : BitVec 32 := scr s₀ + BitVec.ofNat 32 H.st.buf +/-- The compression function's scratch space. -/ +abbrev cmpR : Region := ⟨(scr s₀).setWidth 64, H.so⟩ + +end + +/-- The precondition, with the sizes of `H`. -/ +structure Pre (H : Hash) (sc : Nat) (s₀ : State) : Prop where + rd : s₀.rd = [keyR H s₀, uR H s₀, argR s₀] + wr : s₀.wr = [tR H s₀, scR sc s₀] + k_t : (keyR H s₀).Disjoint (tR H s₀) + k_s : (keyR H s₀).Disjoint (scR sc s₀) + u_t : (uR H s₀).Disjoint (tR H s₀) + u_s : (uR H s₀).Disjoint (scR sc s₀) + t_s : (tR H s₀).Disjoint (scR sc s₀) + a_t : (argR s₀).Disjoint (tR H s₀) + a_s : (argR s₀).Disjoint (scR sc s₀) + r_t : (retR s₀).Disjoint (tR H s₀) + r_s : (retR s₀).Disjoint (scR sc s₀) + b_k : (stkR s₀).Disjoint (keyR H s₀) + b_u : (stkR s₀).Disjoint (uR H s₀) + b_t : (stkR s₀).Disjoint (tR H s₀) + b_s : (stkR s₀).Disjoint (scR sc s₀) + nk : (key s₀).toNat + 2 * H.S ≤ 2 ^ 32 + nu : (up s₀).toNat + H.D ≤ 2 ^ 32 + nt : (tp s₀).toNat + H.D ≤ 2 ^ 32 + nw : (scr s₀).toNat + 8 * sc ≤ 2 ^ 32 + sp48 : 48 ≤ (E s₀).toNat + spf : (E s₀).toNat + 24 ≤ 2 ^ 32 + fits : H.st.buf + H.N + H.B ≤ 8 * sc + hz : Sizes H + +theorem pre_of {H : Hash} (hH : HashOK H.st) {sc : Nat} {s₀ : State} (h : (iterG hH.SH sc).pre s₀) (hz : Sizes H) + (hfit : H.st.buf + H.N + H.B ≤ 8 * sc) : Pre H sc s₀ := by + obtain ⟨h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11, h12, h13, h14, h15, h16, h17, h18, h19, h20⟩ := h + have hS := hH.hS + have hD := hH.hD + have e : (⟨(s₀.gpr .esp).setWidth 64 - 48, 48⟩ : Region) = stkR s₀ := by + simp only [stkR, below]; rw [Taint.sub_setWidth h19]; rfl + simp only [hS, hD, e] at * + exact ⟨h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11, h12, h13, h14, h15, h16, h17, h18, h19, h20, hfit, hz⟩ + +/-! ## The parts of `scratch` -/ + +section +variable {H : Hash} {sc : Nat} {s₀ : State} (hp : Pre H sc s₀) +include hp + +theorem bounds : H.st.buf = 8 * H.st.W + 16 ∧ H.st.buf + H.N + H.B ≤ 8 * sc ∧ (scr s₀).toNat + 8 * sc ≤ 2 ^ 32 ∧ + H.so ≤ 8 * H.st.W ∧ H.st.W ≤ 64 ∧ 0 < H.N ∧ H.N ≤ 64 ∧ 0 < H.D ∧ H.D ≤ H.N ∧ H.B ≤ 128 ∧ 64 ≤ H.B ∧ + H.S = H.N + H.B := + ⟨rfl, hp.fits, hp.nw, hp.hz.so, hp.hz.W, hp.hz.N.1, hp.hz.N.2.1, hp.hz.D.1, hp.hz.D.2.1, hp.hz.B4.2.2, + hp.hz.B4.2.1, hp.hz.S⟩ + +theorem off_sub {o n : Nat} (h : o + n ≤ 8 * sc) : Region.Sub ⟨SA s₀ o, n⟩ (scR sc s₀) := + sub_offset h (by have := hp.nw; omega) + +theorem hv_eq : (hv H s₀).setWidth 64 = SA s₀ H.st.buf := + setWidth_add (by have := bounds hp; omega) + +theorem hv_toNat : (hv H s₀).toNat = (scr s₀).toNat + H.st.buf := + toNat_add_ofNat (by have := bounds hp; omega) + +/-- The hash value and the block. -/ +theorem hvR_sub : Region.Sub ⟨(hv H s₀).setWidth 64, H.N + H.B⟩ (scR sc s₀) := by + rw [hv_eq hp]; obtain ⟨-, hf, -⟩ := bounds hp; exact off_sub hp (by omega) + +theorem cmp_sub : Region.Sub (cmpR H s₀) (scR sc s₀) := by + obtain ⟨hb, hf, -, hso, -⟩ := bounds hp; exact Region.sub_prefix (by omega) + +theorem save_sub : Region.Sub (saveR H.st (scr s₀)) (scR sc s₀) := by + obtain ⟨hb, hf, -⟩ := bounds hp; exact off_sub hp (by omega) + +/-- The parts of `scratch` do not overlap. -/ +theorem part_disj {a m b n : Nat} (h : a + m ≤ b ∨ b + n ≤ a) (ha : a + m ≤ 8 * sc) (hb : b + n ≤ 8 * sc) : + Region.Disjoint ⟨SA s₀ a, m⟩ ⟨SA s₀ b, n⟩ := + VG.Proof.Hmac.Generic.Common.off_disj _ h (by have := hp.nw; omega) (by have := hp.nw; omega) + +theorem hv_cmp : Region.Disjoint ⟨(hv H s₀).setWidth 64, H.N + H.B⟩ (cmpR H s₀) := by + obtain ⟨hb, hf, hw, hso, -⟩ := bounds hp + rw [hv_eq hp]; exact Offset.disjoint_base _ (by omega) (by omega) + +theorem save_hv {n : Nat} (h : n ≤ H.N + H.B) : (saveR H.st (scr s₀)).Disjoint ⟨(hv H s₀).setWidth 64, n⟩ := by + obtain ⟨hb, hf, -⟩ := bounds hp + rw [hv_eq hp]; exact part_disj hp (by omega) (by omega) (by omega) + +theorem save_cmp : (saveR H.st (scr s₀)).Disjoint (cmpR H s₀) := by + obtain ⟨hb, hf, hw, hso, -⟩ := bounds hp + exact Offset.disjoint_base _ (by omega) (by omega) + +theorem stk_arg : (stkR s₀).Disjoint (argR s₀) := stk_args hp.sp48 (by have := hp.spf; omega) + +theorem stk_ret' : (stkR s₀).Disjoint (retR s₀) := stk_ret hp.sp48 (by have := hp.spf; omega) + +theorem t_hv {n : Nat} (h : n ≤ H.N + H.B) : Region.Disjoint (tR H s₀) ⟨(hv H s₀).setWidth 64, n⟩ := + hp.t_s.sub_right fun a ha => hvR_sub hp a (Region.sub_prefix h a ha) + +theorem t_blk : Region.Disjoint (tR H s₀) ⟨(hv H s₀).setWidth 64 + BitVec.ofNat 64 H.N, H.B⟩ := by + obtain ⟨hb, hf, hw, -⟩ := bounds hp + refine hp.t_s.sub_right fun a ha => hvR_sub hp a (Offset.sub_base _ (by omega) a ha) + +end + +/-! ## What the pieces keep -/ + +/-- The regions everything writes: `T`, `scratch` and the stack below `esp`. -/ +abbrev wrs (H : Hash) (sc : Nat) (s₀ : State) : List Region := [tR H s₀, scR sc s₀, stkR s₀] + +/-- The registers and memory kept from the prologue on, with `m` steps left. -/ +structure KR (H : Hash) (sc : Nat) (s₀ : State) (m : Nat) (s : State) : Prop where + rd : s.rd = s₀.rd + wr : s.wr = s₀.wr + esp : s.gpr .esp = E s₀ + ebp : s.gpr .ebp = scr s₀ + ebx : s.gpr .ebx = hv H s₀ + esi : s.gpr .esi = key s₀ + edi : s.gpr .edi = BitVec.ofNat 32 m + saved : SavedRegs H.st (scr s₀) s₀ s.mem + frame : Frame (wrs H sc s₀) s₀.mem s.mem + +/-- The registers `KR` fixes. -/ +abbrev kregs : List Reg := [.esp, .ebp, .ebx, .esi, .edi] + +theorem kregs_callee : ∀ r ∈ kregs, r ∈ calleeSaved := by decide + +section +variable {H : Hash} {sc : Nat} {s₀ : State} + +theorem KR.keep {m : Nat} {s s' : State} (h : KR H sc s₀ m s) (hrd : s'.rd = s.rd) + (hwr : s'.wr = s.wr) (hg : ∀ r ∈ kregs, s'.gpr r = s.gpr r) {rs : List Region} + (hf : Frame rs s.mem s'.mem) (hs : ∀ r ∈ rs, (saveR H.st (scr s₀)).Disjoint r) + (hsub : ∀ r ∈ rs, ∃ r' ∈ wrs H sc s₀, Region.Sub r r') : KR H sc s₀ m s' := + ⟨hrd.trans h.rd, hwr.trans h.wr, (hg _ (by simp)).trans h.esp, (hg _ (by simp)).trans h.ebp, + (hg _ (by simp)).trans h.ebx, (hg _ (by simp)).trans h.esi, (hg _ (by simp)).trans h.edi, + h.saved.frame H.st hf hs, h.frame.trans (hf.sub hsub)⟩ + +/-- `KR` after code that writes only `eax`, `ecx` and `edx` and a part of +`scratch` other than where our caller's registers are. -/ +theorem KR.write {m : Nat} {s s' : State} (h : KR H sc s₀ m s) (hrd : s'.rd = s.rd) (hwr : s'.wr = s.wr) + (hg : ∀ r, r ≠ .eax → r ≠ .ecx → r ≠ .edx → s'.gpr r = s.gpr r) {R : Region} (hf : Frame [R] s.mem s'.mem) + (hs : (saveR H.st (scr s₀)).Disjoint R) (hsub : ∃ r' ∈ wrs H sc s₀, Region.Sub R r') : KR H sc s₀ m s' := + h.keep hrd hwr (fun r hr => hg r (by revert hr; decide +revert) (by revert hr; decide +revert) + (by revert hr; decide +revert)) hf (fun r hr => by simp only [List.mem_singleton] at hr; subst hr; exact hs) + (fun r hr => by simp only [List.mem_singleton] at hr; subst hr; exact hsub) + +theorem stk_eq {m : Nat} {s : State} (hk : KR H sc s₀ m s) : stk s = stkR s₀ := by rw [stk, hk.esp] + +end + +section +variable {H : Hash} {sc : Nat} {s₀ : State} (hp : Pre H sc s₀) +include hp + +theorem mem_wr : scR sc s₀ ∈ s₀.wr ∧ tR H s₀ ∈ s₀.wr := by rw [hp.wr]; simp + +theorem argR_in : argR s₀ ∈ s₀.rd ++ s₀.wr := by rw [hp.rd]; simp + +theorem argIn {s : State} (hrd : s.rd = s₀.rd) (hwr : s.wr = s₀.wr) {i : Nat} (hi : i < 5) : + InRegions (s.rd ++ s.wr) (argAddr s₀ i) 4 := by + rw [hrd, hwr] + exact ⟨argR s₀, argR_in hp, arg_contains rfl (by omega) (by have := hp.spf; omega)⟩ + +theorem KR.argEq {m : Nat} {s : State} (hk : KR H sc s₀ m s) {i : Nat} (hi : i < 5) : + VG.X86.arg s i = VG.X86.arg s₀ i := + arg_keep rfl hk.esp (n := 20) (by have := hp.spf; omega) hk.frame (by + simp only [List.mem_cons, List.not_mem_nil, or_false] + rintro r (rfl | rfl | rfl) + · exact hp.a_t + · exact hp.a_s + · exact (stk_arg hp).symm) (by omega) + +theorem KR.readArg {m : Nat} {s : State} (hk : KR H sc s₀ m s) {i : Nat} (hi : i < 5) : + s.mem.readW (argAddr s₀ i) 32 = VG.X86.arg s₀ i := by + have := hk.argEq hp hi + simp only [VG.X86.arg] at this ⊢ + rwa [show argAddr s i = argAddr s₀ i by rw [argAddr_eq, argAddr_eq, hk.esp]] at this + +theorem KR.ret {m : Nat} {s : State} (hk : KR H sc s₀ m s) : + s.mem.readW ((E s₀).setWidth 64) 32 = s₀.mem.readW ((E s₀).setWidth 64) 32 := + hk.frame.readW (r := retR s₀) (Region.contains_self _ _) (by + simp only [List.mem_cons, List.not_mem_nil, or_false] + rintro r (rfl | rfl | rfl) + · exact hp.r_t + · exact hp.r_s + · exact (stk_ret' hp).symm) (by decide) + +/-- `KR` after a call that writes parts of `scratch`. -/ +theorem KR.call {m : Nat} {s s' : State} (h : KR H sc s₀ m s) {ws : List Region} (ha : After s ws s') + (hs : ∀ r ∈ ws, (saveR H.st (scr s₀)).Disjoint r) (hsub : ∀ r ∈ ws, Region.Sub r (scR sc s₀)) : + KR H sc s₀ m s' := by + have f := ha.frame + rw [stk_eq h] at f + refine h.keep ha.rd ha.wr (fun r hr => ha.cs r (kregs_callee r hr)) f (fun r hr => ?_) (fun r hr => ?_) + · rcases List.mem_append.mp hr with hr | hr + · exact hs r hr + · simp only [List.mem_singleton] at hr; subst hr; exact hp.b_s.symm.sub_left (save_sub hp) + · rcases List.mem_append.mp hr with hr | hr + · exact ⟨scR sc s₀, by simp, hsub r hr⟩ + · simp only [List.mem_singleton] at hr; subst hr; exact ⟨stkR s₀, by simp, fun _ h => h⟩ + +/-- The hash value and block are writable. -/ +theorem cov_hv {s : State} (hwr : s.wr = s₀.wr) : Covers [⟨(hv H s₀).setWidth 64, H.N + H.B⟩] s.wr := by + obtain ⟨hb, hf, -⟩ := bounds hp + rw [hv_eq hp, hwr] + exact Covers.of_sub fun r hr => by + simp only [List.mem_singleton] at hr; subst hr + exact ⟨scR sc s₀, (mem_wr hp).1, H.st.buf, rfl, by simp only; omega⟩ + +/-- The arguments of the compression of the block. -/ +theorem cmpArgs {m : Nat} {s : State} (hk : KR H sc s₀ m s) (hax : s.gpr .eax = hv H s₀ + BitVec.ofNat 32 H.N) : + CmpArgs H.N H.B H.so s (hv H s₀) (scr s₀) := by + obtain ⟨hb, hf, hw, hso, -⟩ := bounds hp + have := hv_toNat hp + exact + { ebx := hk.ebx, eax := hax, ebp := hk.ebp, sp48 := by rw [hk.esp]; exact hp.sp48 + cst := cov_hv hp hk.wr + csc := by + rw [hk.wr] + exact Covers.of_sub fun r hr => by + simp only [List.mem_singleton] at hr; subst hr + exact ⟨scR sc s₀, (mem_wr hp).1, 0, by simp, by simp only; omega⟩ + st_sc := hv_cmp hp + b_st := by rw [stk_eq hk]; exact hp.b_s.sub_right (hvR_sub hp) + b_sc := by rw [stk_eq hk]; exact hp.b_s.sub_right (cmp_sub hp) + nst := by omega + nsc := by omega } + +/-- The key's bytes are as on entry. -/ +theorem key_bytes {m : Nat} {s : State} (hk : KR H sc s₀ m s) {i : Nat} (hi : i < 2 * H.S) : + s.mem ((key s₀).setWidth 64 + BitVec.ofNat 64 i) = s₀.mem ((key s₀).setWidth 64 + BitVec.ofNat 64 i) := + hk.frame.bytes (R := keyR H s₀) (by + simp only [List.mem_cons, List.not_mem_nil, or_false] + rintro r (rfl | rfl | rfl) + · exact hp.k_t + · exact hp.k_s + · exact hp.b_k.symm) (by show 2 * H.S ≤ 2 ^ 64; have := hp.nk; omega) hi + +end + +/-! ## The loop invariant -/ + +section +variable {H : Hash} (hO : MdOk H) (s₀ : State) + +/-- A step, as the code computes it, from the key's inner and outer hash values. -/ +abbrev stepM : List Byte → List Byte := + hO.md.step H.D (hO.md.stateAt s₀.mem ((key s₀).setWidth 64)) + (hO.md.stateAt s₀.mem ((key s₀).setWidth 64 + BitVec.ofNat 64 H.S)) + +end + +/-- The loop invariant, with `m` steps left. -/ +structure Inv {H : Hash} (hO : MdOk H) (sc : Nat) (s₀ : State) (m : Nat) (s : State) : Prop + extends KR H sc s₀ m s where + pad : bytesAt s.mem ((hv H s₀).setWidth 64 + BitVec.ofNat 64 (H.N + H.D)) (H.B - H.D) = H.tailB + le : m ≤ nn s₀ + val : Spec.Pbkdf2.iterate (stepM hO s₀) (nn s₀) (bytesAt s₀.mem ((up s₀).setWidth 64) H.D) + (bytesAt s₀.mem ((tp s₀).setWidth 64) H.D) = + Spec.Pbkdf2.iterate (stepM hO s₀) m (bytesAt s.mem ((hv H s₀).setWidth 64 + BitVec.ofNat 64 H.N) H.D) + (bytesAt s.mem ((tp s₀).setWidth 64) H.D) + +/-! ## Loading a hash value of the key and compressing the block into it -/ + +section +variable {H : Hash} (hO : MdOk H) {sc : Nat} {s₀ : State} (hp : Pre H sc s₀) +include hp + +/-- The block, after the hash value, is outside what the load and the +compression write. -/ +theorem blk_disj {a n : Nat} (h₁ : H.N ≤ a) (h₂ : a + n ≤ H.N + H.B) : + ∀ r ∈ [(⟨(hv H s₀).setWidth 64, H.N⟩ : Region), cmpR H s₀, stkR s₀], + Region.Disjoint ⟨(hv H s₀).setWidth 64 + BitVec.ofNat 64 a, n⟩ r := by + obtain ⟨hb, hf, hw, -⟩ := bounds hp + have := hv_toNat hp + intro r hr + simp only [List.mem_cons, List.not_mem_nil, or_false] at hr + rcases hr with rfl | rfl | rfl + · exact Offset.disjoint_base _ h₁ (by omega) + · exact (hv_cmp hp).sub_left (Offset.sub_base _ (by omega)) + · exact (hp.b_s.sub_right fun a' ha' => hvR_sub hp a' (Offset.sub_base _ (by omega) a' ha')).symm + +/-- Loading the key's hash value at `key + o` into the hash value being +compressed, and `eax` at the block. -/ +theorem load_ok {o : Nat} (ho : o + H.N ≤ 2 * H.S) {m : Nat} {s : State} (h : KR H sc s₀ m s) + {rest : List Instr} {Q : State → Prop} + (k : ∀ s', KR H sc s₀ m s' → s'.gpr .eax = hv H s₀ + BitVec.ofNat 32 H.N → + Frame [⟨(hv H s₀).setWidth 64, H.N⟩] s.mem s'.mem → + hO.md.stateAt s'.mem ((hv H s₀).setWidth 64) = hO.md.stateAt s₀.mem ((key s₀).setWidth 64 + BitVec.ofNat 64 o) → + WP isa (.block rest) s' Q) : + WP isa (.block (H.loadKey o ++ H.atBlk ++ rest)) s Q := by + obtain ⟨hb, hf, hw, hso, hW, hN0, hN, hD0, hDN, hB, hB64, hS⟩ := bounds hp + have hN4 := hp.hz.N.2.2 + have hn4 : 4 * (H.N / 4) = H.N := by omega + have hvt := hv_toNat hp + have nk := hp.nk + have kc : Covers [keyR H s₀] (s.rd ++ s.wr) := covers_one (by rw [h.rd, hp.rd]; simp) + rw [List.append_assoc] + refine copyW_ok (by decide) (by decide) (H.N / 4) _ s _ h.esi h.ebx (by omega) (by omega) + (fun j hj => by rw [addr_eq (by omega)]; exact inReg kc (by omega) (by omega)) + (fun j hj => by rw [addr_eq (by omega)]; exact inReg (cov_hv hp h.wr) (by omega) (by omega)) ?_ + fun s₁ g₁ rd₁ wr₁ m₁ => ?_ + · rw [hn4] + exact hp.k_s.sep (Offset.contains_base _ (by omega) (by omega)) + (by rw [BitVec.add_zero, hv_eq hp]; exact Offset.contains_base _ (by omega) (by omega)) + rw [hn4, BitVec.add_zero] at m₁ + have f₁ : Frame [⟨(hv H s₀).setWidth 64, H.N⟩] s.mem s₁.mem := by + rw [m₁]; exact writeBytes_frame _ _ _ (by rw [bytesAt_length]; exact Region.contains_self _ _) + refine atBlk_ok fun s₂ e₂ g₂ m₂ rd₂ wr₂ => ?_ + have k₂ : KR H sc s₀ m s₂ := h.write (by rw [rd₂, rd₁]) (by rw [wr₂, wr₁]) + (fun r h1 h2 _ => by rw [g₂ r h1, g₁ r h2]) (m₂ ▸ f₁) (save_hv hp (by omega)) + ⟨scR sc s₀, by simp, fun a ha => hvR_sub hp a (Region.sub_prefix (by omega) a ha)⟩ + refine k s₂ k₂ (by rw [e₂, g₁ _ (by decide), h.ebx]) (m₂ ▸ f₁) ?_ + refine hO.reloc _ _ _ _ fun i hi => ?_ + rw [m₂, m₁, writeBytes_at _ _ _ (by rw [bytesAt_length]; exact hi) (by rw [bytesAt_length]; omega), + bytesAt_getD' _ _ hi, Memory.add_ofNat] + exact key_bytes hp h (by omega) + +/-- The compression of the block into the hash value. -/ +theorem cmpS_ok {m : Nat} {s : State} (h : KR H sc s₀ m s) (hax : s.gpr .eax = hv H s₀ + BitVec.ofNat 32 H.N) + {Q : State → Prop} + (k : ∀ s', KR H sc s₀ m s' → Frame [⟨(hv H s₀).setWidth 64, H.N⟩, cmpR H s₀, stkR s₀] s.mem s'.mem → + hO.md.stateAt s'.mem ((hv H s₀).setWidth 64) = hO.md.compress (hO.md.stateAt s.mem ((hv H s₀).setWidth 64)) + (hO.md.blockAt s.mem ((hv H s₀).setWidth 64 + BitVec.ofNat 64 H.N)) → Q s') : + WP isa H.cmp s Q := by + obtain ⟨hb, hf, hw, hso, hW, hN0, hN, hD0, hDN, hB, hB64, hS⟩ := bounds hp + refine cmp_ok hO.comp (by omega) (cmpArgs hp h hax) fun s₃ ha e₃ => ?_ + have k₃ : KR H sc s₀ m s₃ := h.call hp ha (by + simp only [List.mem_cons, List.not_mem_nil, or_false] + rintro r (rfl | rfl) + · exact save_hv hp (by omega) + · exact save_cmp hp) (by + simp only [List.mem_cons, List.not_mem_nil, or_false] + rintro r (rfl | rfl) + · exact fun a ha => hvR_sub hp a (Region.sub_prefix (by omega) a ha) + · exact cmp_sub hp) + have f := ha.frame + rw [stk_eq h] at f + exact k s₃ k₃ (f.mono (by simp)) e₃ + +theorem lc_ok {o : Nat} (ho : o + H.N ≤ 2 * H.S) {m : Nat} {s : State} (h : KR H sc s₀ m s) + (hpad : bytesAt s.mem ((hv H s₀).setWidth 64 + BitVec.ofNat 64 (H.N + H.D)) (H.B - H.D) = H.tailB) {c : Prog isa} + {Q : State → Prop} + (k : ∀ s', KR H sc s₀ m s' → Frame [⟨(hv H s₀).setWidth 64, H.N⟩, cmpR H s₀, stkR s₀] s.mem s'.mem → + hO.md.stateAt s'.mem ((hv H s₀).setWidth 64) = hO.md.compress + (hO.md.stateAt s₀.mem ((key s₀).setWidth 64 + BitVec.ofNat 64 o)) + (hO.md.tailBlock H.D (bytesAt s.mem ((hv H s₀).setWidth 64 + BitVec.ofNat 64 H.N) H.D)) → + bytesAt s'.mem ((hv H s₀).setWidth 64 + BitVec.ofNat 64 (H.N + H.D)) (H.B - H.D) = H.tailB → + bytesAt s'.mem ((hv H s₀).setWidth 64 + BitVec.ofNat 64 H.N) H.D = + bytesAt s.mem ((hv H s₀).setWidth 64 + BitVec.ofNat 64 H.N) H.D → WP isa c s' Q) : + WP isa (.block (H.loadKey o ++ H.atBlk)) s fun s' => WP isa (.seq H.cmp c) s' Q := by + obtain ⟨hb, hf, hw, hso, hW, hN0, hN, hD0, hDN, hB, hB64, hS⟩ := bounds hp + rw [← List.append_nil (H.loadKey o ++ H.atBlk)] + refine load_ok hO hp ho h fun s₂ k₂ ax₂ f₁ st₂ => WP.block_nil (WP.seq (cmpS_ok hO hp k₂ ax₂ fun s₃ k₃ f₂ e₃ => ?_)) + have dB : ∀ {a n : Nat}, H.N ≤ a → a + n ≤ H.N + H.B → + ∀ r ∈ [(⟨(hv H s₀).setWidth 64, H.N⟩ : Region)], Region.Disjoint ⟨(hv H s₀).setWidth 64 + BitVec.ofNat 64 a, n⟩ r := + fun h₁ h₂ r hr => blk_disj hp h₁ h₂ r (by simp only [List.mem_singleton] at hr; simp [hr]) + have pad₂ : bytesAt s₂.mem ((hv H s₀).setWidth 64 + BitVec.ofNat 64 H.N + BitVec.ofNat 64 H.D) (H.B - H.D) = + hO.md.tailPad H.D := by + rw [Memory.add_ofNat, Memory.frame_bytesAt f₁ (dB (by omega) (by omega)) (by omega), hpad, hO.tail] + have u₂ : bytesAt s₂.mem ((hv H s₀).setWidth 64 + BitVec.ofNat 64 H.N) H.D = + bytesAt s.mem ((hv H s₀).setWidth 64 + BitVec.ofNat 64 H.N) H.D := + Memory.frame_bytesAt f₁ (dB (by omega) (by omega)) (by omega) + have f₃ : Frame [⟨(hv H s₀).setWidth 64, H.N⟩, cmpR H s₀, stkR s₀] s.mem s₃.mem := + (f₁.mono (by simp)).trans f₂ + refine k s₃ k₃ f₃ ?_ ?_ ?_ + · rw [e₃, st₂, Md.blockAt_tailPad (by omega) pad₂, u₂] + · rw [Memory.frame_bytesAt f₃ (blk_disj hp (by omega) (by omega)) (by omega), hpad] + · exact Memory.frame_bytesAt f₃ (blk_disj hp (by omega) (by omega)) (by omega) + +/-! ## The end of a step: the digest, `T ← T ⊕ U` and the count -/ + +omit hp in +theorem writeW_xor32 (m m' : Mem) (d a b : Addr) : + m.writeW d (m'.readW a 32 ^^^ m'.readW b 32) = + writeBytes m d (Spec.Pbkdf2.xorBytes (bytesAt m' b 4) (bytesAt m' a 4)) := by + simp only [Mem.writeW, Mem.readW] + rw [show (32 : Nat) / 8 = 4 from rfl, BitVec.setWidth_eq, BitVec.setWidth_eq, BitVec.setWidth_eq, + VG.WriteBytes.write_eq_writeBytes] + refine congrArg (writeBytes m d) ?_ + apply List.ext_getElem (by simp [Spec.Pbkdf2.xorBytes, bytesAt]) + intro j h₁ h₂ + simp only [List.length_map, List.length_range] at h₁ + simp only [Spec.Pbkdf2.xorBytes, bytesAt, List.getElem_map, List.getElem_range, List.getElem_zipWith] + rw [BitVec.extractLsb'_xor, Mem.extractLsb'_read _ _ h₁, Mem.extractLsb'_read _ _ h₁, BitVec.xor_comm] + +omit hp in +theorem wp_xorm {is : List Instr} {s : State} {Q : State → Prop} {d : Reg} {m : MemOp} {a : Addr} + (ha : s.ea m = a) (hin : InRegions (s.rd ++ s.wr) a 4) + (k : ∀ s', Upd s s' d (s.gpr d ^^^ s.mem.readW a 32) → WP isa (.block is) s' Q) : + WP isa (.block (.alu .xor d (.mem m) :: is)) s Q := by + refine VG.Proof.Sha256.X86.Stream.WP.cons + (s' := (arithFlags s (s.gpr d ^^^ s.mem.readW a 32) false false).setReg d (s.gpr d ^^^ s.mem.readW a 32)) + ?_ (k _ (Upd.flags _ _ _ _ _ _)) + simp [exec, execAlu, readSrc, State.load32, ha, hin] + +omit hp in +/-- `T ← T ⊕ U` for the first `n` words of `T` at `t` (in `edx`) and `U` at +`x + N` (`x` in `ebx`). -/ +theorem xor_ok {x t : BitVec 32} (hd : Region.Disjoint ⟨t.setWidth 64, H.D⟩ ⟨x.setWidth 64 + BitVec.ofNat 64 H.N, H.D⟩) + (fx : x.toNat + H.N + H.D ≤ 2 ^ 32) (ft : t.toNat + H.D ≤ 2 ^ 32) : + ∀ n, 4 * n ≤ H.D → ∀ (rest : List Instr) (s : State) (Q : State → Prop), s.gpr .ebx = x → s.gpr .edx = t → + (∀ k < n, InRegions (s.rd ++ s.wr) (addr x (H.N + 4 * k)) 4) → + (∀ k < n, InRegions s.wr (addr t (4 * k)) 4) → + (∀ s', (∀ r, r ≠ .ecx → s'.gpr r = s.gpr r) → s'.rd = s.rd → s'.wr = s.wr → + s'.mem = writeBytes s.mem (t.setWidth 64) + (Spec.Pbkdf2.xorBytes (bytesAt s.mem (t.setWidth 64) (4 * n)) + (bytesAt s.mem (x.setWidth 64 + BitVec.ofNat 64 H.N) (4 * n))) → + WP isa (.block rest) s' Q) → + WP isa (.block ((List.range n).flatMap H.xorW ++ rest)) s Q := by + intro n + induction n with + | zero => + intro _ rest s Q _ _ _ _ k + exact k s (fun _ _ => rfl) rfl rfl (by simp [bytesAt, Spec.Pbkdf2.xorBytes, writeBytes_nil]) + | succ n ih => + intro hn rest s Q hbx hdx hin hout k + rw [List.range_succ, List.flatMap_append, List.flatMap_singleton, List.append_assoc] + refine ih (by omega) _ s Q hbx hdx (fun j hj => hin j (by omega)) (fun j hj => hout j (by omega)) + fun s₁ g₁ rd₁ wr₁ m₁ => ?_ + simp only [Hash.xorW, List.cons_append, List.nil_append] + have eU : addr x (H.N + 4 * n) = x.setWidth 64 + BitVec.ofNat 64 H.N + BitVec.ofNat 64 (4 * n) := by + rw [addr_eq (by omega), Memory.add_ofNat] + have eT : addr t (4 * n) = t.setWidth 64 + BitVec.ofNat 64 (4 * n) := addr_eq (by omega) + refine wp_movm (a := addr x (H.N + 4 * n)) (by rw [ea_at, g₁ _ (by decide), hbx]) + (by rw [rd₁, wr₁]; exact hin n (by omega)) fun s₂ u₂ => ?_ + have hw := hout n (by omega) + refine wp_xorm (a := addr t (4 * n)) (by rw [ea_at, u₂.other _ (by decide), g₁ _ (by decide), hdx]) + (by rw [u₂.rd, u₂.wr, rd₁, wr₁]; exact InRegions.right' hw) fun s₃ u₃ => ?_ + refine wp_store (a := addr t (4 * n)) + (by rw [ea_at, u₃.other _ (by decide), u₂.other _ (by decide), g₁ _ (by decide), hdx]) + (by rw [u₃.wr, u₂.wr, wr₁]; exact hw) fun s₄ u₄ => k s₄ (fun r hr => by + rw [u₄.gpr, u₃.other r hr, u₂.other r hr, g₁ r hr]) (by rw [u₄.rd, u₃.rd, u₂.rd, rd₁]) + (by rw [u₄.wr, u₃.wr, u₂.wr, wr₁]) ?_ + have hl : (Spec.Pbkdf2.xorBytes (bytesAt s.mem (t.setWidth 64) (4 * n)) + (bytesAt s.mem (x.setWidth 64 + BitVec.ofNat 64 H.N) (4 * n))).length = 4 * n := by + rw [Memory.xorBytes_length _ _ (by simp [bytesAt]), bytesAt_length] + rw [u₄.mem, u₃.gpr, u₃.mem, u₂.gpr, u₂.mem, writeW_xor32, m₁, eU, eT, + bytesAt_writeBytes_sep (p := t.setWidth 64 + BitVec.ofNat 64 (4 * n)), + bytesAt_writeBytes_sep (p := x.setWidth 64 + BitVec.ofNat 64 H.N + BitVec.ofNat 64 (4 * n))] + · have e := writeBytes_append s.mem (t.setWidth 64) _ (Spec.Pbkdf2.xorBytes + (bytesAt s.mem (t.setWidth 64 + BitVec.ofNat 64 (4 * n)) 4) + (bytesAt s.mem (x.setWidth 64 + BitVec.ofNat 64 H.N + BitVec.ofNat 64 (4 * n)) 4)) + (by rw [hl, Memory.xorBytes_length _ _ (by simp [bytesAt]), bytesAt_length]; omega) + rw [hl] at e + rw [e, Nat.mul_succ, bytesAt_add, bytesAt_add, Spec.Pbkdf2.xorBytes, Spec.Pbkdf2.xorBytes, + Spec.Pbkdf2.xorBytes, List.zipWith_append (by simp [bytesAt])] + · intro y h₁ h₂ + rw [hl] at h₂ + exact hd y (by simp only [Region.Contains]; omega) (Memory.off_contains h₁ (by omega) (by omega)) + · omega + · intro y h₁ h₂ + rw [hl] at h₂ + exact Memory.sep_after h₁ h₂ (by omega) + · omega + +theorem tail_ok {m : Nat} (hm : 1 ≤ m) (hn : m < 2 ^ 32) {s : State} (h : KR H sc s₀ m s) + (hpad : bytesAt s.mem ((hv H s₀).setWidth 64 + BitVec.ofNat 64 (H.N + H.D)) (H.B - H.D) = H.tailB) + {Q : State → Prop} + (k : ∀ s', KR H sc s₀ (m - 1) s' → s'.zf = some (decide (m - 1 = 0)) → + Frame [⟨(hv H s₀).setWidth 64 + BitVec.ofNat 64 H.N, H.B⟩, tR H s₀] s.mem s'.mem → + bytesAt s'.mem ((hv H s₀).setWidth 64 + BitVec.ofNat 64 (H.N + H.D)) (H.B - H.D) = H.tailB → + bytesAt s'.mem ((hv H s₀).setWidth 64 + BitVec.ofNat 64 H.N) H.D = + (hO.md.digest (hO.md.stateAt s.mem ((hv H s₀).setWidth 64))).take H.D → + bytesAt s'.mem ((tp s₀).setWidth 64) H.D = Spec.Pbkdf2.xorBytes (bytesAt s.mem ((tp s₀).setWidth 64) H.D) + ((hO.md.digest (hO.md.stateAt s.mem ((hv H s₀).setWidth 64))).take H.D) → Q s') : + WP isa (.block (H.digest ++ H.tStep)) s Q := by + obtain ⟨hb, hf, hw, hso, hW, hN0, hN, hD0, hDN, hB, hB64, hS⟩ := bounds hp + have hD4 := hp.hz.D.2.2 + have hvt := hv_toNat hp + have nt := hp.nt + have hD4' : 4 * (H.D / 4) = H.D := by omega + have sbB : Region.Sub ⟨(hv H s₀).setWidth 64 + BitVec.ofNat 64 H.N, H.B⟩ (scR sc s₀) := + fun a ha => hvR_sub hp a (Offset.sub_base _ (by omega) a ha) + refine digest_ok hp.hz hO.out h.ebx (by omega) (cov_hv hp h.wr) hpad fun s₁ g₁ rd₁ wr₁ f₁ b₁ p₁ => ?_ + have k₁ : KR H sc s₀ m s₁ := h.write rd₁ wr₁ g₁ f₁ + ((save_hv hp (Nat.le_refl _)).sub_right (Offset.sub_base _ (by omega))) ⟨scR sc s₀, by simp, sbB⟩ + simp only [Hash.tStep, List.cons_append, List.nil_append] + refine wp_movm (a := argAddr s₀ 3) (by rw [ea_at, k₁.esp]; rfl) (argIn hp k₁.rd k₁.wr (by decide)) + fun s₂ u₂ => ?_ + have dx₂ : s₂.gpr .edx = tp s₀ := by rw [u₂.gpr, k₁.readArg hp (by decide)] + have k₂ : KR H sc s₀ m s₂ := k₁.write u₂.rd u₂.wr (fun r _ _ h3 => u₂.other r h3) (R := ⟨0, 0⟩) + (by rw [u₂.mem]; exact Frame.refl _ _) (fun _ _ h => by simp [Region.Contains] at h) + ⟨scR sc s₀, by simp, fun _ h => by simp [Region.Contains] at h⟩ + have hd : Region.Disjoint ⟨(tp s₀).setWidth 64, H.D⟩ ⟨(hv H s₀).setWidth 64 + BitVec.ofNat 64 H.N, H.D⟩ := + (t_blk hp).sub_right (Region.sub_prefix (by omega)) + refine xor_ok hd (by omega) nt (H.D / 4) (by omega) _ s₂ _ k₂.ebx dx₂ + (fun j hj => by + rw [addr_eq (by omega)] + exact InRegions.right' (inReg (cov_hv hp k₂.wr) (by omega) (by omega))) + (fun j hj => by + rw [addr_eq (by omega), k₂.wr] + exact ⟨tR H s₀, (mem_wr hp).2, Offset.contains_base _ (by omega) (by omega)⟩) + fun s₃ g₃ rd₃ wr₃ m₃ => ?_ + rw [hD4'] at m₃ + have hxl : (Spec.Pbkdf2.xorBytes (bytesAt s₂.mem ((tp s₀).setWidth 64) H.D) + (bytesAt s₂.mem ((hv H s₀).setWidth 64 + BitVec.ofNat 64 H.N) H.D)).length = H.D := by + rw [Memory.xorBytes_length _ _ (by simp [bytesAt]), bytesAt_length] + have f₃ : Frame [tR H s₀] s₂.mem s₃.mem := by + rw [m₃]; exact writeBytes_frame _ _ _ (by rw [hxl]; exact Region.contains_self _ _) + have k₃ : KR H sc s₀ m s₃ := k₂.write rd₃ wr₃ (fun r _ h2 _ => g₃ r h2) f₃ + (hp.t_s.sub_right (save_sub hp)).symm ⟨tR H s₀, by simp, fun _ h => h⟩ + refine wp_subi fun s₄ u₄ z₄ => WP.block_nil ?_ + have e₄ : s₃.gpr .edi - 1 = BitVec.ofNat 32 (m - 1) := by + rw [k₃.edi, show (1 : BitVec 32) = BitVec.ofNat 32 1 from rfl, sub_ofNat hm] + have k₄ : KR H sc s₀ (m - 1) s₄ := + ⟨by rw [u₄.rd, k₃.rd], by rw [u₄.wr, k₃.wr], by rw [u₄.other _ (by decide), k₃.esp], + by rw [u₄.other _ (by decide), k₃.ebp], by rw [u₄.other _ (by decide), k₃.ebx], + by rw [u₄.other _ (by decide), k₃.esi], by rw [u₄.gpr, e₄], u₄.mem ▸ k₃.saved, u₄.mem ▸ k₃.frame⟩ + have m₂ : s₂.mem = s₁.mem := u₂.mem + have tB : ∀ r ∈ [tR H s₀], Region.Disjoint ⟨(hv H s₀).setWidth 64 + BitVec.ofNat 64 H.N, H.B⟩ r := by + simp only [List.mem_singleton]; rintro r rfl; exact (t_blk hp).symm + have tB' : ∀ {a n : Nat}, H.N ≤ a → a + n ≤ H.N + H.B → + ∀ r ∈ [tR H s₀], Region.Disjoint ⟨(hv H s₀).setWidth 64 + BitVec.ofNat 64 a, n⟩ r := by + intro a n h₁ h₂ r hr + simp only [List.mem_singleton] at hr; subst hr + exact ((t_blk hp).sub_right (Offset.sub _ (by omega) (by omega))).symm + refine k s₄ k₄ (by rw [z₄, e₄, ofNat_beq_zero (by omega)]) ?_ ?_ ?_ ?_ + · rw [u₄.mem]; exact (f₁.mono (by simp)).trans (m₂ ▸ f₃.mono (by simp)) + · rw [u₄.mem, Memory.frame_bytesAt f₃ (tB' (by omega) (by omega)) (by omega), m₂, p₁] + · rw [u₄.mem, Memory.frame_bytesAt f₃ (tB' (Nat.le_refl _) (by omega)) (by omega), m₂, b₁] + · have hT₁ : bytesAt s₁.mem ((tp s₀).setWidth 64) H.D = bytesAt s.mem ((tp s₀).setWidth 64) H.D := + Memory.frame_bytesAt f₁ (fun r hr => by + simp only [List.mem_singleton] at hr; subst hr; exact t_blk hp) (by omega) + rw [u₄.mem, m₃, bytesAt_writeBytes_self' hxl (by omega), m₂, hT₁, b₁] + +end + +/-! ## A step -/ + +section +variable {H : Hash} (hO : MdOk H) {sc : Nat} {s₀ : State} (hp : Pre H sc s₀) +include hp + +omit hp in +theorem iterate_succ (f : List Byte → List Byte) (n : Nat) (u t : List Byte) : + Spec.Pbkdf2.iterate f (n + 1) u t = Spec.Pbkdf2.iterate f n (f u) (Spec.Pbkdf2.xorBytes t (f u)) := rfl + +theorem body_ok {r : Nat} {s : State} (h : Inv hO sc s₀ (r + 1) s) : + WP isa H.body s fun s' => eval .ne s' = some (r != 0) ∧ Inv hO sc s₀ r s' := by + obtain ⟨hb, hf, hw, hso, hW, hN0, hN, hD0, hDN, hB, hB64, hS⟩ := bounds hp + have hvt := hv_toNat hp + have hlt : r + 1 < 2 ^ 32 := by have := h.le; have := (arg s₀ 2).isLt; simp only [nn] at *; omega + have sbB : Region.Sub ⟨(hv H s₀).setWidth 64 + BitVec.ofNat 64 H.N, H.B⟩ (scR sc s₀) := + fun a ha => hvR_sub hp a (Offset.sub_base _ (by omega) a ha) + unfold Hash.body + refine WP.seq (lc_ok hO hp (o := 0) (by omega) h.toKR h.pad fun s₂ k₂ f₂ e₂ p₂ u₂ => ?_) + refine WP.seq ?_ + rw [List.append_assoc] + refine digest_ok hp.hz hO.out k₂.ebx (by omega) (cov_hv hp k₂.wr) p₂ fun s₃ g₃ rd₃ wr₃ f₃ b₃ p₃ => ?_ + have k₃ : KR H sc s₀ (r + 1) s₃ := k₂.write rd₃ wr₃ g₃ f₃ + ((save_hv hp (Nat.le_refl _)).sub_right (Offset.sub_base _ (by omega))) ⟨scR sc s₀, by simp, sbB⟩ + refine lc_ok hO hp (o := H.S) (by omega) k₃ p₃ fun s₅ k₅ f₅ e₅ p₅ u₅ => ?_ + refine tail_ok hO hp (m := r + 1) (by omega) hlt k₅ p₅ fun s₈ k₈ z₈ f₈ p₈ b₈ t₈ => ?_ + rw [Nat.add_sub_cancel] at k₈ z₈ + -- `T` is untouched until the end. + have dT : ∀ {rs : List Region}, (∀ q ∈ rs, Region.Sub q (scR sc s₀) ∨ q = stkR s₀) → + ∀ q ∈ rs, Region.Disjoint ⟨(tp s₀).setWidth 64, H.D⟩ q := by + intro rs hrs q hq + rcases hrs q hq with hq | rfl + · exact hp.t_s.sub_right hq + · exact hp.b_t.symm + have sub₁ : ∀ q ∈ [(⟨(hv H s₀).setWidth 64, H.N⟩ : Region), cmpR H s₀, stkR s₀], + Region.Sub q (scR sc s₀) ∨ q = stkR s₀ := by + simp only [List.mem_cons, List.not_mem_nil, or_false] + rintro q (rfl | rfl | rfl) + · exact .inl fun a ha => hvR_sub hp a (Region.sub_prefix (by omega) a ha) + · exact .inl (cmp_sub hp) + · exact .inr rfl + have hT₅ : bytesAt s₅.mem ((tp s₀).setWidth 64) H.D = bytesAt s.mem ((tp s₀).setWidth 64) H.D := by + rw [Memory.frame_bytesAt f₅ (dT sub₁) (by omega), + Memory.frame_bytesAt f₃ (dT (by simp only [List.mem_singleton]; rintro q rfl; exact .inl sbB)) (by omega), + Memory.frame_bytesAt f₂ (dT sub₁) (by omega)] + rw [hT₅, e₅, b₃, e₂, show (key s₀).setWidth 64 + BitVec.ofNat 64 0 = (key s₀).setWidth 64 by simp] at t₈ + rw [e₅, b₃, e₂, show (key s₀).setWidth 64 + BitVec.ofNat 64 0 = (key s₀).setWidth 64 by simp] at b₈ + refine ⟨?_, { k₈ with pad := p₈, le := by have := h.le; omega, val := ?_ }⟩ + · rw [eval_ne, z₈, Option.map_some] + cases r <;> rfl + · rw [h.val, iterate_succ, b₈, t₈]; rfl + +theorem loop_ok {n : Nat} {s : State} (h : Inv hO sc s₀ n s) (hz' : s.zf = some (decide (n = 0))) : + WP isa (.ite .e (.block []) (.loop H.body .ne)) s (Inv hO sc s₀ 0) := by + refine WP.ite (decide (n = 0)) (by show s.zf = _; exact hz') (fun hb => ?_) (fun hb => ?_) + · obtain rfl : n = 0 := by simpa using hb + exact WP.block_nil h + · obtain ⟨m, rfl⟩ : ∃ m, n = m + 1 := ⟨n - 1, by simp at hb; omega⟩ + refine WP.loop (fun m s => Inv hO sc s₀ (m + 1) s) + (fun m s hs' => WP.mono (body_ok hO hp hs') fun s' ⟨he, hi⟩ => ?_) m s h + cases m with + | zero => exact .inl ⟨he, hi⟩ + | succ m => exact .inr ⟨he, m, by omega, hi⟩ + +end + +/-! ## The prologue and the epilogue -/ + +section +variable {H : Hash} (hO : MdOk H) {sc : Nat} {s₀ : State} (hp : Pre H sc s₀) +include hp + +theorem pro_ok : WP isa (.block H.prologue) s₀ fun s => Inv hO sc s₀ (nn s₀) s ∧ s.zf = some (decide (nn s₀ = 0)) := by + obtain ⟨hb, hf, hw, hso, hW, hN0, hN, hD0, hDN, hB, hB64, hS⟩ := bounds hp + obtain ⟨sR, tR'⟩ := mem_wr hp + have hvt := hv_toNat hp + have hD4 := hp.hz.D.2.2 + have hD4' : 4 * (H.D / 4) = H.D := by omega + have tl := hp.hz.tail_length + have nu := hp.nu; have nt := hp.nt + have dA : ∀ r ∈ [saveR H.st (scr s₀)], (argR s₀).Disjoint r := by + simp only [List.mem_singleton]; rintro r rfl; exact hp.a_s.sub_right (save_sub hp) + simp only [Hash.prologue, List.append_assoc, List.singleton_append] + refine wp_movm (a := argAddr s₀ 4) (by rw [ea_at]; rfl) (argIn hp rfl rfl (by decide)) fun s₁ u₁ => ?_ + refine save_ok H.st (scr := scr s₀) u₁.gpr hW (by rw [u₁.wr]; exact sR) (by omega) (by omega) + fun s₂ g₂ rd₂ wr₂ f₂ sv₂ => ?_ + have e₂ : ∀ r, r ≠ .eax → s₂.gpr r = s₀.gpr r := fun r hr => by rw [g₂, u₁.other r hr] + have f₂' : Frame [saveR H.st (scr s₀)] s₀.mem s₂.mem := by rw [← u₁.mem]; exact f₂ + have rA : ∀ i < 5, s₂.mem.readW (argAddr s₀ i) 32 = arg s₀ i := fun i hi => + f₂'.readW (r := ⟨argAddr s₀ i, 4⟩) (Region.contains_self _ _) (fun r hr => + (dA r hr).sub_left (VG.Proof.Hmac.Generic.X86.arg_sub rfl (by omega) (by have := hp.spf; omega))) (by decide) + have i₂ : ∀ i < 5, InRegions (s₂.rd ++ s₂.wr) (argAddr s₀ i) 4 := fun i hi => by + rw [rd₂, wr₂, u₁.rd, u₁.wr]; exact argIn hp rfl rfl hi + refine wp_mov fun s₃ u₃ => ?_ + refine wp_movm (a := argAddr s₀ 0) (by rw [ea_at, u₃.other _ (by decide), e₂ _ (by decide)]; rfl) + (by rw [u₃.rd, u₃.wr]; exact i₂ 0 (by decide)) fun s₄ u₄ => ?_ + refine wp_movm (a := argAddr s₀ 2) (by + rw [ea_at, u₄.other _ (by decide), u₃.other _ (by decide), e₂ _ (by decide)]; rfl) + (by rw [u₄.rd, u₄.wr, u₃.rd, u₃.wr]; exact i₂ 2 (by decide)) fun s₅ u₅ => ?_ + refine wp_mov fun s₆ u₆ => wp_addi fun s₇ u₇ => ?_ + refine wp_movm (a := argAddr s₀ 1) (by + rw [ea_at, u₇.other _ (by decide), u₆.other _ (by decide), u₅.other _ (by decide), u₄.other _ (by decide), + u₃.other _ (by decide), e₂ _ (by decide)]; rfl) + (by rw [u₇.rd, u₇.wr, u₆.rd, u₆.wr, u₅.rd, u₅.wr, u₄.rd, u₄.wr, u₃.rd, u₃.wr]; exact i₂ 1 (by decide)) + fun s₈ u₈ => ?_ + have m₈ : s₈.mem = s₂.mem := by rw [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, rd₂, u₁.rd] + have wr₈ : s₈.wr = s₀.wr := by rw [u₈.wr, u₇.wr, u₆.wr, u₅.wr, u₄.wr, u₃.wr, wr₂, u₁.wr] + have bp₈ : s₈.gpr .ebp = scr s₀ := by + rw [u₈.other _ (by decide), u₇.other _ (by decide), u₆.other _ (by decide), u₅.other _ (by decide), + u₄.other _ (by decide), u₃.gpr, g₂, u₁.gpr]; rfl + have bx₈ : s₈.gpr .ebx = hv H s₀ := by + rw [u₈.other _ (by decide), u₇.gpr, u₆.gpr, u₅.other _ (by decide), u₄.other _ (by decide), u₃.gpr, g₂, u₁.gpr] + rfl + have si₈ : s₈.gpr .esi = key s₀ := by + rw [u₈.other _ (by decide), u₇.other _ (by decide), u₆.other _ (by decide), u₅.other _ (by decide), u₄.gpr, + u₃.mem, rA 0 (by decide)] + have di₈ : s₈.gpr .edi = arg s₀ 2 := by + rw [u₈.other _ (by decide), u₇.other _ (by decide), u₆.other _ (by decide), u₅.gpr, u₄.mem, u₃.mem, + rA 2 (by decide)] + have dx₈ : s₈.gpr .edx = up s₀ := by + rw [u₈.gpr, u₇.mem, u₆.mem, u₅.mem, u₄.mem, u₃.mem, rA 1 (by decide)] + have sp₈ : s₈.gpr .esp = E s₀ := by + 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), e₂ _ (by decide)] + have ucov : Covers [uR H s₀] (s₈.rd ++ s₈.wr) := covers_one (by rw [rd₈, hp.rd]; simp) + -- `U` into the block. + refine copyW_ok (by decide) (by decide) (H.D / 4) _ s₈ _ dx₈ bx₈ (by omega) (by omega) + (fun j hj => by + rw [addr_eq (by omega)]; have := inReg (o := 4 * j) (n := 4) ucov (by omega) (by omega) + rwa [show 0 + 4 * j = 4 * j by omega]) + (fun j hj => by rw [addr_eq (by omega)]; exact inReg (cov_hv hp wr₈) (by omega) (by omega)) ?_ + fun s₉ g₉ rd₉ wr₉ m₉ => ?_ + · rw [hD4', BitVec.add_zero] + exact hp.u_s.sep (Region.contains_self _ _) + (by rw [hv_eq hp, Memory.add_ofNat]; exact Offset.contains_base _ (by omega) (by omega)) + rw [hD4', BitVec.add_zero] at m₉ + -- The padding. + refine pad_ok hp.hz (s := s₉) (x := hv H s₀) (by rw [g₉ _ (by decide), bx₈]) (by omega) (cov_hv hp (wr₉.trans wr₈)) + fun s₁₀ g₁₀ rd₁₀ wr₁₀ m₁₀ => ?_ + refine wp_test fun s₁₁ u₁₁ z₁₁ => WP.block_nil ?_ + have m₁₁ : s₁₁.mem = writeBytes (writeBytes s₂.mem ((hv H s₀).setWidth 64 + BitVec.ofNat 64 H.N) + (bytesAt s₂.mem ((up s₀).setWidth 64) H.D)) ((hv H s₀).setWidth 64 + BitVec.ofNat 64 (H.N + H.D)) H.tailB := by + rw [u₁₁.mem, m₁₀, m₉, m₈] + have gr : ∀ r, r ≠ .eax → r ≠ .ecx → r ≠ .edx → s₁₁.gpr r = s₈.gpr r := fun r _ h2 _ => by + rw [u₁₁.gpr, g₁₀ r h2, g₉ r h2] + have fB : Frame [⟨(hv H s₀).setWidth 64 + BitVec.ofNat 64 H.N, H.B⟩] s₂.mem s₁₁.mem := by + rw [m₁₁] + refine (writeBytes_frame _ _ _ ?_).trans (writeBytes_frame _ _ _ ?_) + · rw [bytesAt_length] + have := Offset.contains_base ((hv H s₀).setWidth 64 + BitVec.ofNat 64 H.N) (d := 0) (n := H.D) (k := H.B) + (by omega) (by omega) + rwa [BitVec.add_zero] at this + · rw [tl, ← Memory.add_ofNat]; exact Offset.contains_base _ (by omega) (by omega) + have sbB : Region.Sub ⟨(hv H s₀).setWidth 64 + BitVec.ofNat 64 H.N, H.B⟩ (scR sc s₀) := + fun a ha => hvR_sub hp a (Offset.sub_base _ (by omega) a ha) + have dsB : (saveR H.st (scr s₀)).Disjoint ⟨(hv H s₀).setWidth 64 + BitVec.ofNat 64 H.N, H.B⟩ := + (save_hv hp (Nat.le_refl _)).sub_right (Offset.sub_base _ (by omega)) + have sv : SavedRegs H.st (scr s₀) s₀ s₁₁.mem := + (sv₂.of_eq H.st fun r hr => u₁.other r (by + simp only [savedRegs, List.mem_cons, List.not_mem_nil, or_false] at hr + rcases hr with rfl | rfl | rfl | rfl <;> decide)).frame H.st fB (fun r hr => by + simp only [List.mem_singleton] at hr; subst hr; exact dsB) + have fr : Frame (wrs H sc s₀) s₀.mem s₁₁.mem := + (f₂'.sub fun r hr => by + simp only [List.mem_singleton] at hr; subst hr; exact ⟨scR sc s₀, by simp, save_sub hp⟩).trans + (fB.sub fun r hr => by simp only [List.mem_singleton] at hr; subst hr; exact ⟨scR sc s₀, by simp, sbB⟩) + have edi : s₁₁.gpr .edi = BitVec.ofNat 32 (nn s₀) := by + rw [gr _ (by decide) (by decide) (by decide), di₈, nn, BitVec.ofNat_toNat, BitVec.setWidth_eq] + have dU : Mem.Sep ((hv H s₀).setWidth 64 + BitVec.ofNat 64 H.N) H.D + ((hv H s₀).setWidth 64 + BitVec.ofNat 64 (H.N + H.D)) H.tailB.length := by + rw [tl, ← Memory.add_ofNat] + have := Offset.sep ((hv H s₀).setWidth 64 + BitVec.ofNat 64 H.N) (d := 0) (n := H.D) (e := H.D) + (k := H.B - H.D) (.inl (by omega)) (by omega) (by omega) + rwa [BitVec.add_zero] at this + refine ⟨⟨⟨by rw [u₁₁.rd, rd₁₀, rd₉, rd₈], by rw [u₁₁.wr, wr₁₀, wr₉, wr₈], + by rw [gr _ (by decide) (by decide) (by decide), sp₈], by rw [gr _ (by decide) (by decide) (by decide), bp₈], + by rw [gr _ (by decide) (by decide) (by decide), bx₈], by rw [gr _ (by decide) (by decide) (by decide), si₈], + edi, sv, fr⟩, ?_, Nat.le_refl _, ?_⟩, ?_⟩ + · rw [m₁₁, ← tl, bytesAt_writeBytes_self' rfl (by omega)] + · -- `U` and `T`. + have hU₂ : bytesAt s₂.mem ((up s₀).setWidth 64) H.D = bytesAt s₀.mem ((up s₀).setWidth 64) H.D := + Memory.frame_bytesAt f₂' (fun r hr => by + simp only [List.mem_singleton] at hr; subst hr; exact hp.u_s.sub_right (save_sub hp)) (by omega) + have hU : bytesAt s₁₁.mem ((hv H s₀).setWidth 64 + BitVec.ofNat 64 H.N) H.D = + bytesAt s₀.mem ((up s₀).setWidth 64) H.D := by + rw [m₁₁, bytesAt_writeBytes_sep _ _ dU (by omega), bytesAt_writeBytes_self' (bytesAt_length _ _ _) (by omega), + hU₂] + have hT : bytesAt s₁₁.mem ((tp s₀).setWidth 64) H.D = bytesAt s₀.mem ((tp s₀).setWidth 64) H.D := + Memory.frame_bytesAt ((f₂'.mono (rs' := [saveR H.st (scr s₀), ⟨(hv H s₀).setWidth 64 + BitVec.ofNat 64 H.N, H.B⟩]) + (by simp)).trans (fB.mono (by simp))) (fun r hr => by + simp only [List.mem_cons, List.not_mem_nil, or_false] at hr + rcases hr with rfl | rfl + · exact hp.t_s.sub_right (save_sub hp) + · exact t_blk hp) (by omega) + rw [hU, hT] + · rw [z₁₁, g₁₀ _ (by decide), g₉ _ (by decide), di₈, test_z] + +omit hp in +/-- The final `T` is PBKDF2's, for a key as the contract requires. -/ +theorem post_eq {m : Mem} + (hT : bytesAt m ((tp s₀).setWidth 64) H.D = Spec.Pbkdf2.iterate (stepM hO s₀) (nn s₀) + (bytesAt s₀.mem ((up s₀).setWidth 64) H.D) (bytesAt s₀.mem ((tp s₀).setWidth 64) H.D)) + {k0 : List Byte} (hk : k0.length = hO.hH.SH.H.blockSize) + (hi : hO.hH.SH.Repr s₀.mem ((key s₀).setWidth 64) (xorPad k0 ipad)) + (ho : hO.hH.SH.Repr s₀.mem ((key s₀).setWidth 64 + BitVec.ofNat 64 hO.hH.SH.stateBytes) (xorPad k0 opad)) : + bytesAt m ((tp s₀).setWidth 64) hO.hH.SH.digestBytes = + Spec.Pbkdf2.iterate (hmacBlockKey hO.hH.SH.H k0) (nn s₀) (bytesAt s₀.mem ((up s₀).setWidth 64) hO.hH.SH.digestBytes) + (bytesAt s₀.mem ((tp s₀).setWidth 64) hO.hH.SH.digestBytes) := by + have hl := hO.link + have hB : 0 < H.B := by have := hl.DL; omega + rw [hl.hB] at hk + rw [hl.hS, ← hO.sizes.S] at ho + have li : (xorPad k0 ipad).length = H.B := by simp [xorPad, hk] + have lo : (xorPad k0 opad).length = H.B := by simp [xorPad, hk] + have ei := Md.stateAt_of_repr hB li (hl.repr _ _ _ hi) + have eo := Md.stateAt_of_repr hB lo (hl.repr _ _ _ ho) + rw [hl.hD] + refine hT.trans (Md.iterate_congr (fun u hu => ?_) (fun u => Md.step_length _ hl.DN _ _ u) _ _ _ + (bytesAt_length _ _ _)).symm + rw [Md.hmac_step hl hk hu, ei, eo] + +theorem epilogue_ok {s : State} (h : Inv hO sc s₀ 0 s) : + WP isa (.block H.st.restore) s fun s' => abiPreserved s₀ s' ∧ (iterG hO.hH.SH sc).post s₀ s' := by + obtain ⟨hb, hf, hw, -⟩ := bounds hp + refine WP.mono (restore_ok H.st h.ebp h.saved (by rw [h.wr]; exact (mem_wr hp).1) (by omega) hp.nw) + fun s' ⟨hm, _, _, hg, ho⟩ => ⟨⟨fun r hr => ?_, by rw [hm]; exact h.toKR.ret hp⟩, fun k0 hk hi ho' => ?_⟩ + · by_cases he : r = .esp + · subst he; rw [ho _ (by decide) (by decide), h.esp] + · exact hg r (callee_saved r hr he) + · rw [hm]; exact post_eq hO h.val.symm hk hi ho' + +theorem correct : WP isa H.iterate s₀ fun s' => abiPreserved s₀ s' ∧ (iterG hO.hH.SH sc).post s₀ s' := by + unfold Hash.iterate + refine WP.seq (WP.mono (pro_ok hO hp) fun s₁ ⟨h, hz'⟩ => ?_) + exact WP.seq (WP.mono (loop_ok hO hp h hz') fun s₂ h₂ => epilogue_ok hO hp h₂) + +end + +end VG.Proof.Pbkdf2.Md.X86.Iterate diff --git a/lean/VerifiedGarbage/Proof/Pbkdf2/Md/X86/IterateCT.lean b/lean/VerifiedGarbage/Proof/Pbkdf2/Md/X86/IterateCT.lean new file mode 100644 index 000000000..611e1cf6a --- /dev/null +++ b/lean/VerifiedGarbage/Proof/Pbkdf2/Md/X86/IterateCT.lean @@ -0,0 +1,289 @@ +import VerifiedGarbage.Proof.Pbkdf2.Md.X86.Iterate + +/-! +# PBKDF2-HMAC's iteration over a Merkle–Damgård hash function on x86 (32-bit): constant time + +Untrusted: everything here is checked by Lean. As for the streaming-level +functions (`Proof/Hmac/Generic/X86/`): the pieces between the calls are +checked by the taint analysis, those that read the arguments on the stack +(the prologue, and the end of a step, which loads `t`) with the arguments +public (`argTaint`); the calls of the compression function are related by +`cmp_rel`, from its contract. Then `iterate` is verified against the +contract with the arguments read only (`iterG`), and with them writable +(`iterW`). +-/ + +namespace VG.Proof.Pbkdf2.Md.X86.Iterate + +open VG.X86 +open VG.Impl.Pbkdf2.Md.X86 (Hash) +open VG.Proof.Pbkdf2.Md.X86 +open VG.Proof.Hmac.Generic.X86 (HashOK iterG iterW argTaint ArgsOut agree_argTaint rel_agree rel_wp stk) +open VG.Proof.Sha256.X86.Stream (eval_e eval_ne) +open Spec.Sha256 (bytesAt) + +/-- The registers `KR` fixes. -/ +abbrev pubRegs : List Reg := [.esp, .ebp, .ebx, .esi, .edi] + +/-- The taint checks of the pieces of `iterate` between its calls. -/ +structure Checks (H : Hash) : Prop where + pro : ∃ hc, (VG.Taint.check taint (argTaint [] (4 + 4 * 5)) (.block H.prologue) hc).isSome = true + load : ∃ hc, (VG.Taint.check taint (τr pubRegs) (.block (H.loadKey 0 ++ H.atBlk)) hc).isSome = true + mid : ∃ hc, (VG.Taint.check taint (τr pubRegs) (.block (H.digest ++ H.loadKey H.S ++ H.atBlk)) hc).isSome = true + tail : ∃ hc, (VG.Taint.check taint (argTaint [.ebp, .ebx, .esi, .edi] (4 + 4 * 5)) + (.block (H.digest ++ H.tStep)) hc).isSome = true + restore : ∃ hc, (VG.Taint.check taint (τr [.ebp]) (.block H.st.restore) hc).isSome = true + +theorem skip_check : ∃ hc, (VG.Taint.check taint (τr []) (.block []) hc).isSome = true := + ⟨_, by taint_decide⟩ + +/-- The public arguments are the same. -/ +structure PubEq (s₀ s₀' : State) : Prop where + esp : s₀.gpr .esp = s₀'.gpr .esp + args : ∀ i < 5, arg s₀ i = arg s₀' i + +/-- What the pieces keep, and the padding. -/ +structure KP (H : Hash) (sc : Nat) (s₀ : State) (m : Nat) (s : State) : Prop extends KR H sc s₀ m s where + pad : bytesAt s.mem ((hv H s₀).setWidth 64 + BitVec.ofNat 64 (H.N + H.D)) (H.B - H.D) = H.tailB + +/-! ## Each piece, in one run -/ + +section +variable {H : Hash} (hO : MdOk H) {sc : Nat} {s₀ : State} (hp : Pre H sc s₀) +include hO hp + +theorem b1_ok {m : Nat} {s : State} (h : KP H sc s₀ m s) : + WP isa (.block (H.loadKey 0 ++ H.atBlk)) s fun t => + KP H sc s₀ m t ∧ t.gpr .eax = hv H s₀ + BitVec.ofNat 32 H.N := by + rw [← List.append_nil (H.loadKey 0 ++ H.atBlk)] + have := bounds hp + refine load_ok hO hp (by have := hp.hz.S; omega) h.toKR fun s₂ k₂ ax₂ f₁ _ => WP.block_nil ⟨⟨k₂, ?_⟩, ax₂⟩ + rw [Memory.frame_bytesAt f₁ (fun r hr => blk_disj hp (by omega) (by omega) r (by + simp only [List.mem_singleton] at hr; simp [hr])) (by omega), h.pad] + +theorem c_ok {m : Nat} {s : State} (h : KP H sc s₀ m s) (hax : s.gpr .eax = hv H s₀ + BitVec.ofNat 32 H.N) : + WP isa H.cmp s (KP H sc s₀ m) := by + have := bounds hp + refine cmpS_ok hO hp h.toKR hax fun s₃ k₃ f₃ _ => ⟨k₃, ?_⟩ + rw [Memory.frame_bytesAt f₃ (blk_disj hp (by omega) (by omega)) (by omega), h.pad] + +theorem b2_ok {m : Nat} {s : State} (h : KP H sc s₀ m s) : + WP isa (.block (H.digest ++ H.loadKey H.S ++ H.atBlk)) s fun t => + KP H sc s₀ m t ∧ t.gpr .eax = hv H s₀ + BitVec.ofNat 32 H.N := by + obtain ⟨hb, hf, hw, hso, hW, hN0, hN, hD0, hDN, hB, hB64, hS⟩ := bounds hp + have := hv_toNat hp; have := hp.hz.DL + have sbB : Region.Sub ⟨(hv H s₀).setWidth 64 + BitVec.ofNat 64 H.N, H.B⟩ (scR sc s₀) := + fun a ha => hvR_sub hp a (Offset.sub_base _ (by omega) a ha) + rw [List.append_assoc] + refine digest_ok hp.hz hO.out h.ebx (by omega) (cov_hv hp h.wr) h.pad fun s₃ g₃ rd₃ wr₃ f₃ _ p₃ => ?_ + have k₃ : KR H sc s₀ m s₃ := h.toKR.write rd₃ wr₃ g₃ f₃ + ((save_hv hp (Nat.le_refl _)).sub_right (Offset.sub_base _ (by omega))) ⟨scR sc s₀, by simp, sbB⟩ + rw [← List.append_nil (H.loadKey H.S ++ H.atBlk)] + refine load_ok hO hp (by omega) k₃ fun s₂ k₂ ax₂ f₁ _ => WP.block_nil ⟨⟨k₂, ?_⟩, ax₂⟩ + rw [Memory.frame_bytesAt f₁ (fun r hr => blk_disj hp (by omega) (by omega) r (by + simp only [List.mem_singleton] at hr; simp [hr])) (by omega), p₃] + +theorem b3_ok {m : Nat} (hm : 1 ≤ m) (hn : m < 2 ^ 32) {s : State} (h : KP H sc s₀ m s) : + WP isa (.block (H.digest ++ H.tStep)) s fun t => KP H sc s₀ (m - 1) t ∧ t.zf = some (decide (m - 1 = 0)) := + tail_ok hO hp hm hn h.toKR h.pad fun _ k z _ p _ _ => ⟨⟨k, p⟩, z⟩ + +end + +/-! ## Two runs -/ + +variable {H : Hash} (hO : MdOk H) {sc : Nat} +variable {s₀ s₀' : State} (hp : Pre H sc s₀) (hp' : Pre H sc s₀') (hq : PubEq s₀ s₀') + +theorem PubEq.nn (hq : PubEq s₀ s₀') : nn s₀ = nn s₀' := by + show (arg s₀ 2).toNat = (arg s₀' 2).toNat; rw [hq.args 2 (by decide)] + +theorem eqs (hq : PubEq s₀ s₀') : scr s₀' = scr s₀ ∧ hv H s₀' = hv H s₀ := + ⟨(hq.args 4 (by decide)).symm, by rw [hv, hv, scr, scr, hq.args 4 (by decide)]⟩ + +theorem kr_agree (hq : PubEq s₀ s₀') {m : Nat} {s s' : State} (h : KR H sc s₀ m s) + (h' : KR H sc s₀' m s') : ∀ r ∈ pubRegs, 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, E, E, hq.esp] + · rw [h.ebp, h'.ebp, (eqs (H := H) hq).1] + · rw [h.ebx, h'.ebx, (eqs (H := H) hq).2] + · rw [h.esi, h'.esi, key, key, hq.args 0 (by decide)] + · rw [h.edi, h'.edi] + +/-- The arguments lie outside the writable regions. -/ +theorem args_out {t : State} (h : Pre H sc t) {s : State} (hsp : s.gpr .esp = E t) (hwr : s.wr = t.wr) : + ArgsOut 5 s := by + have e : (⟨(s.gpr .esp).setWidth 64, 4 + 4 * 5⟩ : Region) = ⟨(E t).setWidth 64, 4 + 20⟩ := by rw [hsp] + refine ⟨by rw [hsp]; exact h.spf, ?_⟩ + rw [e, hwr, h.wr] + simp only [List.mem_cons, List.not_mem_nil, or_false] + rintro r (rfl | rfl) + · exact Taint.frame_disjoint (by have := h.spf; omega) h.r_t h.a_t + · exact Taint.frame_disjoint (by have := h.spf; omega) h.r_s h.a_s + +include hO hp hp' hq + +/-- A call of the compression function, in both runs. -/ +theorem cmp_rel' {m : Nat} : + RelCT isa (fun s s' => (KP H sc s₀ m s ∧ s.gpr .eax = hv H s₀ + BitVec.ofNat 32 H.N) ∧ + (KP H sc s₀' m s' ∧ s'.gpr .eax = hv H s₀' + BitVec.ofNat 32 H.N)) H.cmp + fun s s' => KP H sc s₀ m s ∧ KP H sc s₀' m s' := by + obtain ⟨e4, ehv⟩ := eqs (H := H) hq + have hB : 0 < H.B := by have := hp.hz.B4; omega + exact rel_wp (cmp_rel hO.comp hB (sp := E s₀) fun s s' ⟨⟨k, a⟩, ⟨k', a'⟩⟩ => + ⟨cmpArgs hp k.toKR a, by have := cmpArgs hp' k'.toKR a'; rwa [e4, ehv] at this, k.esp, + by rw [k'.esp, E, E, hq.esp]⟩) + (fun _ ⟨k, a⟩ => c_ok hO hp k a) (fun _ ⟨k, a⟩ => c_ok hO hp' k a) + +theorem body_rel (hc : Checks H) {m : Nat} (hm : 1 ≤ m) (hn : m < 2 ^ 32) : + RelCT isa (fun s s' => KP H sc s₀ m s ∧ KP H sc s₀' m s') H.body + fun s s' => (KP H sc s₀ (m - 1) s ∧ s.zf = some (decide (m - 1 = 0))) ∧ + (KP H sc s₀' (m - 1) s' ∧ s'.zf = some (decide (m - 1 = 0))) := by + have b1 := rel_agree (F := KP H sc s₀ m) (F' := KP H sc s₀' m) (τr pubRegs) (fun _ _ h h' => agree_regs (kr_agree hq h.toKR h'.toKR)) hc.load + (fun _ h => b1_ok hO hp h) (fun _ h => b1_ok hO hp' h) + have b2 := rel_agree (F := KP H sc s₀ m) (F' := KP H sc s₀' m) (τr pubRegs) (fun _ _ h h' => agree_regs (kr_agree hq h.toKR h'.toKR)) hc.mid + (fun _ h => b2_ok hO hp h) (fun _ h => b2_ok hO hp' h) + have b3 := rel_agree (F := KP H sc s₀ m) (F' := KP H sc s₀' m) (argTaint [.ebp, .ebx, .esi, .edi] (4 + 4 * 5)) (fun s s' k k' => + agree_argTaint (fun r hr => kr_agree hq k.toKR k'.toKR r (by + simp only [List.mem_cons, List.not_mem_nil, or_false] at hr ⊢; tauto)) + (kr_agree hq k.toKR k'.toKR .esp (by simp)) (args_out hp k.esp k.wr) (args_out hp' k'.esp k'.wr) + fun j hj => by rw [k.toKR.argEq hp hj, k'.toKR.argEq hp' hj, hq.args j hj]) hc.tail + (fun _ h => b3_ok hO hp hm hn h) (fun _ h => b3_ok hO hp' hm hn h) + exact b1.seq ((cmp_rel' hO hp hp' hq).seq (b2.seq ((cmp_rel' hO hp hp' hq).seq b3))) + +/-- The loop's invariant in two runs, with `n` steps left. -/ +abbrev LoopInv (n : Nat) (s s' : State) : Prop := + 1 ≤ n ∧ n ≤ nn s₀ ∧ KP H sc s₀ n s ∧ KP H sc s₀' n s' + +theorem step_rel (hc : Checks H) (n : Nat) : + RelCT isa (LoopInv (H := H) (sc := sc) (s₀ := s₀) (s₀' := s₀') n) H.body fun s s' => + isa.eval .ne s = isa.eval .ne s' ∧ + (isa.eval .ne s = some false → KP H sc s₀ 0 s ∧ KP H sc s₀' 0 s') ∧ + (isa.eval .ne s = some true → ∃ m < n, LoopInv (H := H) (sc := sc) (s₀ := s₀) (s₀' := s₀') m s s') := by + have hlt : nn s₀ < 2 ^ 32 := (arg s₀ 2).isLt + by_cases hn : 1 ≤ n ∧ n ≤ nn s₀ + · refine ((body_rel hO hp hp' hq hc hn.1 (by omega)).mono + (P' := LoopInv (H := H) (sc := sc) (s₀ := s₀) (s₀' := s₀') n) (fun _ _ h => ⟨h.2.2.1, h.2.2.2⟩) + fun _ _ h => h).mono (fun _ _ h => h) fun t t' h => ?_ + obtain ⟨⟨i, z⟩, ⟨i', z'⟩⟩ := h + have e : isa.eval .ne t = some (!decide (n - 1 = 0)) := by show eval .ne t = _; rw [eval_ne, z]; rfl + have e' : isa.eval .ne t' = some (!decide (n - 1 = 0)) := by show eval .ne t' = _; rw [eval_ne, z']; rfl + rw [e, e'] + refine ⟨rfl, fun hf => ?_, fun ht => ?_⟩ + · have hl : n - 1 = 0 := by simpa using hf + exact ⟨hl ▸ i, hl ▸ i'⟩ + · have hl : n - 1 ≠ 0 := by simpa using ht + exact ⟨n - 1, by omega, by omega, by omega, i, i'⟩ + · intro _ _ _ _ _ _ h + exact absurd ⟨h.1, h.2.1⟩ hn + +theorem loop_rel (hc : Checks H) : + RelCT isa (fun s s' => (KP H sc s₀ (nn s₀) s ∧ s.zf = some (decide (nn s₀ = 0))) ∧ + (KP H sc s₀' (nn s₀') s' ∧ s'.zf = some (decide (nn s₀' = 0)))) + (.ite .e (.block []) (.loop H.body .ne)) + fun s s' => KP H sc s₀ 0 s ∧ KP H sc s₀' 0 s' := by + have hN := hq.nn + have ev : ∀ {t : State} {k : Nat}, t.zf = some (decide (k = 0)) → isa.eval .e t = some (decide (k = 0)) := + fun h => by show eval .e _ = _; rw [eval_e, h] + refine RelCT.ite (fun s s' h => by rw [ev h.1.2, ev h.2.2, hN]) ?_ ?_ + · by_cases e : nn s₀ = 0 + · have e' : nn s₀' = 0 := hN ▸ e + exact (rel_agree (c := .block []) + (F := fun s => KP H sc s₀ (nn s₀) s ∧ s.zf = some (decide (nn s₀ = 0))) + (F' := fun s => KP H sc s₀' (nn s₀') s ∧ s.zf = some (decide (nn s₀' = 0))) + (G := KP H sc s₀ 0) (G' := KP H sc s₀' 0) (τr []) + (fun s s' h h' => agree_regs (by simp)) skip_check + (fun s h => WP.block_nil (e ▸ h.1)) (fun s h => WP.block_nil (e' ▸ h.1))).mono (fun _ _ h => h.1) + fun _ _ h => h + · intro _ _ _ _ _ _ h + have z := h.2 + rw [ev h.1.1.2] at z + exact absurd (by simpa using z) e + · refine (RelCT.loop (M := isa) (LoopInv (H := H) (sc := sc) (s₀ := s₀) (s₀' := s₀')) + (step_rel hO hp hp' hq hc) (nn s₀)).mono (fun s s' h => ?_) fun _ _ h => h + have z := h.2 + rw [ev h.1.1.2] at z + have e : nn s₀ ≠ 0 := by simpa using z + exact ⟨by omega, Nat.le_refl _, h.1.1.1, hN ▸ h.1.2.1⟩ + +theorem ct (hc : Checks H) : RelCT isa (fun s s' => s = s₀ ∧ s' = s₀') H.iterate fun _ _ => True := by + have hN := hq.nn + have pro := rel_agree (F := fun s => s = s₀) (F' := fun s => s = s₀') + (G := fun s => KP H sc s₀ (nn s₀) s ∧ s.zf = some (decide (nn s₀ = 0))) + (G' := fun s => KP H sc s₀' (nn s₀') s ∧ s.zf = some (decide (nn s₀' = 0))) + (argTaint [] (4 + 4 * 5)) (fun s s' e e' => by + rw [e, e'] + exact agree_argTaint (fun r hr => nomatch hr) hq.esp (args_out hp rfl rfl) (args_out hp' rfl rfl) + hq.args) hc.pro + (fun _ e => by rw [e]; exact WP.mono (pro_ok hO hp) fun _ ⟨h, z⟩ => ⟨⟨h.toKR, h.pad⟩, z⟩) + (fun _ e => by rw [e]; exact WP.mono (pro_ok hO hp') fun _ ⟨h, z⟩ => ⟨⟨h.toKR, h.pad⟩, z⟩) + obtain ⟨_, hr⟩ := hc.restore + have restore : RelCT isa (fun s s' => KP H sc s₀ 0 s ∧ KP H sc s₀' 0 s') (.block H.st.restore) + fun _ _ => True := + RelCT.taint (A := taint) (τr [.ebp]) (fun _ _ h => agree_regs fun r hr => by + simp only [List.mem_singleton] at hr; subst hr + exact kr_agree hq h.1.toKR h.2.toKR .ebp (by simp)) hr + exact pro.seq ((loop_rel hO hp hp' hq hc).seq restore) + +end VG.Proof.Pbkdf2.Md.X86.Iterate + +namespace VG.Proof.Pbkdf2.Md.X86.Iterate + +open VG.X86 +open VG.Impl.Pbkdf2.Md.X86 (Hash) +open VG.Proof.Pbkdf2.Md.X86 +open VG.Proof.Hmac.Generic.X86 (iterG iterW) + +/-- `iterate` is verified against `iterG`, given the taint checks, which the +kernel evaluates for each hash function. -/ +theorem verified {H : Hash} (hO : MdOk H) {sc : Nat} (hc : Checks H) + (hfit : H.st.buf + H.N + H.B ≤ 8 * sc) (hsat : ∃ s, (iterG hO.hH.SH sc).pre s) : + Verified X86.target H.iterate (iterG hO.hH.SH sc) := by + refine ⟨fun s hs => correct hO (pre_of hO.hH hs hO.sizes hfit), fun s₁ s₂ t₁ t₂ s₁' s₂' h₁ h₂ hpub e₁ e₂ => ?_, hsat⟩ + obtain ⟨h1, h2⟩ := hpub + exact (ct hO (pre_of hO.hH h₁ hO.sizes hfit) (pre_of hO.hH h₂ hO.sizes hfit) ⟨h1, h2⟩ hc + _ _ _ _ _ _ ⟨rfl, rfl⟩ e₁ e₂).1 + +/-- The regions `iterate` reads and writes, of those `iterW` gives it. -/ +def narrowRd (S D : Nat) (s : State) : List Region := + [⟨(arg s 0).setWidth 64, 2 * S⟩, ⟨(arg s 1).setWidth 64, D⟩, ⟨argAddr s 0, 20⟩] +def narrowWr (D sc : Nat) (s : State) : List Region := + [⟨(arg s 3).setWidth 64, D⟩, ⟨(arg s 4).setWidth 64, 8 * sc⟩] + +/-- `iterate` is verified against `iterW`, which lets it write its arguments: +the code only reads them. -/ +theorem verifiedW {H : Hash} (hO : MdOk H) {sc : Nat} (hc : Checks H) + (hfit : H.st.buf + H.N + H.B ≤ 8 * sc) (hsat : ∃ s, (iterW hO.hH.SH sc).pre s) : + Verified X86.target H.iterate (iterW hO.hH.SH sc) := by + have pre : ∀ s, (iterW hO.hH.SH sc).pre s → (iterG hO.hH.SH sc).pre + (s.withRegions (narrowRd hO.hH.SH.stateBytes hO.hH.SH.digestBytes s) (narrowWr hO.hH.SH.digestBytes sc s)) := by + intro s h + obtain ⟨_, _, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11, h12, h13, h14, h15, h16, h17, h18, h19, h20⟩ := h + simp only [iterG, narrowRd, narrowWr, 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, h19, h20⟩ + refine Verified.narrowTo (verified hO hc hfit (hsat.elim fun s hs => ⟨_, pre s hs⟩)) + (narrowRd hO.hH.SH.stateBytes hO.hH.SH.digestBytes) (narrowWr hO.hH.SH.digestBytes sc) pre (fun s h => ?_) + (fun s h => ?_) (fun _ _ _ h => h) (fun _ _ _ _ h => h) hsat + · obtain ⟨h1, h2, _⟩ := h + rw [h1, h2] + refine Covers.of_sub fun r hr => ?_ + simp only [narrowRd, narrowWr, List.cons_append, List.nil_append, List.mem_cons, List.not_mem_nil, + or_false] at hr + rcases hr with rfl | rfl | rfl | rfl | rfl + · exact ⟨_, List.mem_append_left _ List.mem_cons_self, 0, by simp, by simp⟩ + · exact ⟨_, List.mem_append_left _ (List.mem_cons_of_mem _ List.mem_cons_self), 0, by simp, by simp⟩ + · exact ⟨_, List.mem_append_right _ (List.mem_cons_of_mem _ (List.mem_cons_of_mem _ List.mem_cons_self)), + 0, by simp, by simp⟩ + · exact ⟨_, List.mem_append_right _ List.mem_cons_self, 0, by simp, by simp⟩ + · exact ⟨_, List.mem_append_right _ (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 [narrowWr, List.mem_cons, List.not_mem_nil, or_false] at hr + rcases hr with 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⟩ + +end VG.Proof.Pbkdf2.Md.X86.Iterate diff --git a/lean/VerifiedGarbage/Proof/Pbkdf2/Md/X86/Lit.lean b/lean/VerifiedGarbage/Proof/Pbkdf2/Md/X86/Lit.lean new file mode 100644 index 000000000..be10998a8 --- /dev/null +++ b/lean/VerifiedGarbage/Proof/Pbkdf2/Md/X86/Lit.lean @@ -0,0 +1,30 @@ +import VerifiedGarbage.Proof.Framework.X86.Lit +import VerifiedGarbage.Proof.Pbkdf2.Md.X86.Hashes + +/-! +# HMAC's `finalize` and PBKDF2's `iterate` on x86 (32-bit): the code as literals + +Untrusted: everything here is checked by Lean. `Hash.hmacFin` and +`Hash.iterate` (`Impl/Pbkdf2/Md/X86.lean`) at each hash function of +`Hashes.lean`, as literals (`materialize_code`, `Proof/Framework/Lit.lean`) +that refer to the literals of the functions they call (the compression +functions, and the streaming `finalize`): the registration files' `spSafe` +checks evaluate them. +-/ + +namespace VG.Proof.Pbkdf2.Md.X86 + +materialize_code md5MFinalize := md5M.hmacFin +materialize_code md5MIterate := md5M.iterate +materialize_code sha1MFinalize := sha1M.hmacFin +materialize_code sha1MIterate := sha1M.iterate +materialize_code sha384MFinalize := sha384M.hmacFin +materialize_code sha384MIterate := sha384M.iterate +materialize_code sha512MFinalize := sha512M'.hmacFin +materialize_code sha512MIterate := sha512M'.iterate +materialize_code sha512_224MFinalize := sha512_224M.hmacFin +materialize_code sha512_224MIterate := sha512_224M.iterate +materialize_code sha512_256MFinalize := sha512_256M.hmacFin +materialize_code sha512_256MIterate := sha512_256M.iterate + +end VG.Proof.Pbkdf2.Md.X86 diff --git a/lean/VerifiedGarbage/Proof/Pbkdf2/MdHmac.lean b/lean/VerifiedGarbage/Proof/Pbkdf2/MdHmac.lean new file mode 100644 index 000000000..5a093a852 --- /dev/null +++ b/lean/VerifiedGarbage/Proof/Pbkdf2/MdHmac.lean @@ -0,0 +1,54 @@ +import VerifiedGarbage.Proof.Pbkdf2.MdStep +import VerifiedGarbage.Proof.Hmac.Common + +/-! +# HMAC over a Merkle–Damgård hash function: the outer hash as one compression + +Untrusted: everything here is checked by Lean. HMAC's outer hash, of a key's +outer block (`K₀ ⊕ opad`, one block) and an inner digest of `D` bytes, is one +compression, of the hash value of the outer block with the block of the +digest and the padding of a `B + D`-byte message (`Link.hmac_outer`), for any +hash function the streaming proofs describe (`Md`), whatever the target. A +block in memory made of `D` bytes followed by that padding is the padded +block of those bytes (`blockAt_tailPad`). +-/ + +namespace VG.Proof.MdStream.Md + +open VG.Spec.Hmac (StreamingHash xorPad ipad opad hmacBlockKey) +open VG.Spec.Sha256 (bytesAt) + +variable {B N L : Nat} {H : Md B N L} + +/-- The block in memory at `p`, of `D` bytes of message and the padding after +them. -/ +theorem blockAt_tailPad {D : Nat} {m : Mem} {p : Addr} (hD : D ≤ B) + (h : bytesAt m (p + BitVec.ofNat 64 D) (B - D) = H.tailPad D) : + H.blockAt m p = H.tailBlock D (bytesAt m p D) := by + simp only [blockAt, tailBlock] + refine H.parse_congr fun k hk => ?_ + have e := Hmac.Common.bytesAt_add m p D (B - D) + rw [h, show D + (B - D) = B by omega] at e + rw [← e, Hmac.Common.bytesAt_getD' _ _ hk] + +/-- The hash of a block `p` and `D` bytes `x` is one compression, of the hash +value of `p` with the block of `x` and the padding. -/ +theorem Link.hash_outer {S : StreamingHash} {iv : H.HV} {D : Nat} (hl : H.Link S iv D) {p x : List Byte} + (hp : p.length = B) (hx : x.length = D) : + S.H.hash (p ++ x) = (H.digest (H.compress (H.compressList iv p 1) (H.tailBlock D x))).take D := by + rw [hl.hash, Md.hash_block H iv hp hx hl.DL] + +/-- A digest has `D` bytes. -/ +theorem Link.hash_length {S : StreamingHash} {iv : H.HV} {D : Nat} (hl : H.Link S iv D) (x : List Byte) : + (S.H.hash x).length = D := by + rw [hl.hash, List.length_take, Md.hash, H.digest_length]; exact Nat.min_eq_left hl.DN + +/-- HMAC's outer hash, for a key of one block, is one compression of the hash +value of its outer block, with the inner digest padded. -/ +theorem Link.hmac_outer {S : StreamingHash} {iv : H.HV} {D : Nat} (hl : H.Link S iv D) {k0 : List Byte} + (hk : k0.length = B) (text : List Byte) : + hmacBlockKey S.H k0 text = (H.digest (H.compress (H.compressList iv (xorPad k0 opad) 1) + (H.tailBlock D (S.H.hash (xorPad k0 ipad ++ text))))).take D := + hl.hash_outer (by simp [xorPad, hk]) (hl.hash_length _) + +end VG.Proof.MdStream.Md diff --git a/lean/VerifiedGarbage/Proof/Pbkdf2/Whole/X86/CT.lean b/lean/VerifiedGarbage/Proof/Pbkdf2/Whole/X86/CT.lean index f8032eaeb..a17263663 100644 --- a/lean/VerifiedGarbage/Proof/Pbkdf2/Whole/X86/CT.lean +++ b/lean/VerifiedGarbage/Proof/Pbkdf2/Whole/X86/CT.lean @@ -4,7 +4,7 @@ import VerifiedGarbage.Proof.Pbkdf2.Whole.X86.Loop # PBKDF2-HMAC on x86 (32-bit), the whole derivation: constant time Untrusted: everything here is checked by Lean. As for `iterate` -(`Proof/Pbkdf2/Generic/X86/IterateCT.lean`): the pieces of code between the +(`Proof/Pbkdf2/Md/X86/IterateCT.lean`): the pieces of code between the calls are checked by the taint analysis (`Checks`, which the kernel evaluates for each hash function), with the arguments, `esp`, `ebp` and, in the loop over the blocks, `ebx` public (`piece`); the calls are related by diff --git a/lean/VerifiedGarbage/Proof/Pbkdf2/Whole/X86/Instances.lean b/lean/VerifiedGarbage/Proof/Pbkdf2/Whole/X86/Instances.lean index f4859c90b..abbfa7975 100644 --- a/lean/VerifiedGarbage/Proof/Pbkdf2/Whole/X86/Instances.lean +++ b/lean/VerifiedGarbage/Proof/Pbkdf2/Whole/X86/Instances.lean @@ -2,13 +2,13 @@ import VerifiedGarbage.Proof.Framework.Contract import VerifiedGarbage.Proof.Pbkdf2.Whole.X86.Lit import VerifiedGarbage.Proof.Pbkdf2.Whole.X86.CT import VerifiedGarbage.Proof.Hmac.Generic.X86.Instances -import VerifiedGarbage.Proof.Pbkdf2.Generic.X86.Instances +import VerifiedGarbage.Proof.Pbkdf2.Md.X86.Instances /-! # PBKDF2-HMAC on x86 (32-bit), the whole derivation: the instances Untrusted: everything here is checked by Lean. The generic proof -(`CT.lean`) at each hash function of `Proof/Hmac/Generic/X86/Hashes.lean`: +(`CT.lean`) at each hash function of `Proof/Pbkdf2/Md/X86/Hashes.lean`: the functions it calls are verified by their own registration files, the taint checks are evaluated by the kernel, and a state satisfies the shared contract (`pbkSat`). @@ -48,8 +48,8 @@ def sha1OKF : FnsOK sha1F where Wf := 56 Wt := 56 hi := .of_verified Proof.Hmac.Generic.X86.Instances.sha1_init - hf := .of_verified Proof.Hmac.Generic.X86.Instances.sha1_finalize - it := .of_verified Proof.Pbkdf2.Generic.X86.Instances.sha1 + hf := .of_verified Proof.Pbkdf2.Md.X86.Instances.sha1_finalize + it := .of_verified Proof.Pbkdf2.Md.X86.Instances.sha1_iterate hiSp := nosp_of (by lit_decide) hfSp := nosp_of (by lit_decide) itSp := nosp_of (by lit_decide) @@ -101,8 +101,8 @@ def md5OKF : FnsOK md5F where Wf := 48 Wt := 48 hi := .of_verified Proof.Hmac.Generic.X86.Instances.md5_init - hf := .of_verified Proof.Hmac.Generic.X86.Instances.md5_finalize - it := .of_verified Proof.Pbkdf2.Generic.X86.Instances.md5 + hf := .of_verified Proof.Pbkdf2.Md.X86.Instances.md5_finalize + it := .of_verified Proof.Pbkdf2.Md.X86.Instances.md5_iterate hiSp := nosp_of (by lit_decide) hfSp := nosp_of (by lit_decide) itSp := nosp_of (by lit_decide) @@ -154,8 +154,8 @@ def sha384OKF : FnsOK sha384F where Wf := 234 Wt := 234 hi := .of_verified Proof.Hmac.Generic.X86.Instances.sha384_init - hf := .of_verified Proof.Hmac.Generic.X86.Instances.sha384_finalize - it := .of_verified Proof.Pbkdf2.Generic.X86.Instances.sha384 + hf := .of_verified Proof.Pbkdf2.Md.X86.Instances.sha384_finalize + it := .of_verified Proof.Pbkdf2.Md.X86.Instances.sha384_iterate hiSp := nosp_of (by lit_decide) hfSp := nosp_of (by lit_decide) itSp := nosp_of (by lit_decide) @@ -207,8 +207,8 @@ def sha512OKF : FnsOK sha512F where Wf := 234 Wt := 234 hi := .of_verified Proof.Hmac.Generic.X86.Instances.sha512_init - hf := .of_verified Proof.Hmac.Generic.X86.Instances.sha512_finalize - it := .of_verified Proof.Pbkdf2.Generic.X86.Instances.sha512 + hf := .of_verified Proof.Pbkdf2.Md.X86.Instances.sha512_finalize + it := .of_verified Proof.Pbkdf2.Md.X86.Instances.sha512_iterate hiSp := nosp_of (by lit_decide) hfSp := nosp_of (by lit_decide) itSp := nosp_of (by lit_decide) @@ -260,8 +260,8 @@ def sha512_224OKF : FnsOK sha512_224F where Wf := 234 Wt := 234 hi := .of_verified Proof.Hmac.Generic.X86.Instances.sha512_224_init - hf := .of_verified Proof.Hmac.Generic.X86.Instances.sha512_224_finalize - it := .of_verified Proof.Pbkdf2.Generic.X86.Instances.sha512_224 + hf := .of_verified Proof.Pbkdf2.Md.X86.Instances.sha512_224_finalize + it := .of_verified Proof.Pbkdf2.Md.X86.Instances.sha512_224_iterate hiSp := nosp_of (by lit_decide) hfSp := nosp_of (by lit_decide) itSp := nosp_of (by lit_decide) @@ -313,8 +313,8 @@ def sha512_256OKF : FnsOK sha512_256F where Wf := 234 Wt := 234 hi := .of_verified Proof.Hmac.Generic.X86.Instances.sha512_256_init - hf := .of_verified Proof.Hmac.Generic.X86.Instances.sha512_256_finalize - it := .of_verified Proof.Pbkdf2.Generic.X86.Instances.sha512_256 + hf := .of_verified Proof.Pbkdf2.Md.X86.Instances.sha512_256_finalize + it := .of_verified Proof.Pbkdf2.Md.X86.Instances.sha512_256_iterate hiSp := nosp_of (by lit_decide) hfSp := nosp_of (by lit_decide) itSp := nosp_of (by lit_decide) diff --git a/lean/VerifiedGarbage/Proof/Pbkdf2/Whole/X86/Lit.lean b/lean/VerifiedGarbage/Proof/Pbkdf2/Whole/X86/Lit.lean index ce38c6fd8..87738bdc3 100644 --- a/lean/VerifiedGarbage/Proof/Pbkdf2/Whole/X86/Lit.lean +++ b/lean/VerifiedGarbage/Proof/Pbkdf2/Whole/X86/Lit.lean @@ -1,13 +1,15 @@ import VerifiedGarbage.Proof.Hmac.Generic.X86.Lit +import VerifiedGarbage.Proof.Pbkdf2.Md.X86.Lit import VerifiedGarbage.Impl.Pbkdf2.Whole.X86 /-! # PBKDF2-HMAC on x86 (32-bit), the whole derivation: the functions it calls, and its code as literals Untrusted: everything here is checked by Lean. For each hash function of -`Proof/Hmac/Generic/X86/Hashes.lean`, the functions `pbkdf2` calls (`Fns`): -its streaming functions, HMAC's `init` and `finalize` and PBKDF2's -`iterate` for it, by the names they are registered with; and `pbkdf2` as a +`Proof/Pbkdf2/Md/X86/Hashes.lean`, the functions `pbkdf2` calls (`Fns`): +its streaming functions, HMAC's `init` (`Impl/Hmac/Generic/X86.lean`) and +`finalize` and PBKDF2's `iterate` (`Impl/Pbkdf2/Md/X86.lean`) for it, by the +names they are registered with; and `pbkdf2` as a literal (`materialize_code`, `Proof/Framework/Lit.lean`), which the registration files' `spSafe` checks evaluate. -/ @@ -15,26 +17,26 @@ registration files' `spSafe` checks evaluate. namespace VG.Proof.Pbkdf2.Whole.X86 open VG.Impl.Pbkdf2.Whole.X86 (Fns) -open VG.Proof.Hmac.Generic.X86 +open VG.Proof.Pbkdf2.Md.X86 -/-- The functions `pbkdf2` calls for the hash function `H` of the instance +/-- The functions `pbkdf2` calls for the hash function `M` of the instance `I`, with the working space of `I`'s functions. -/ -def fnsOf (I : Spec.Hmac.Instance) (H : Impl.Hmac.Generic.X86.Hash) : Fns where - H := H +def fnsOf (I : Spec.Hmac.Instance) (M : Impl.Pbkdf2.Md.X86.Hash) : Fns where + H := M.st W := I.scratch hiN := I.initApi.name - hiC := H.init + hiC := M.st.init hfN := I.finalizeApi.name - hfC := H.finalize + hfC := M.hmacFin itN := I.iterateApi.name - itC := Impl.Pbkdf2.Generic.X86.iterate H - -def sha1F : Fns := fnsOf Spec.Hmac.sha1I sha1H -def md5F : Fns := fnsOf Spec.Hmac.md5I md5H -def sha384F : Fns := fnsOf Spec.Hmac.sha384I sha384H -def sha512F : Fns := fnsOf Spec.Hmac.sha512I sha512H' -def sha512_224F : Fns := fnsOf Spec.Hmac.sha512_224I sha512_224H -def sha512_256F : Fns := fnsOf Spec.Hmac.sha512_256I sha512_256H + itC := M.iterate + +def sha1F : Fns := fnsOf Spec.Hmac.sha1I sha1M +def md5F : Fns := fnsOf Spec.Hmac.md5I md5M +def sha384F : Fns := fnsOf Spec.Hmac.sha384I sha384M +def sha512F : Fns := fnsOf Spec.Hmac.sha512I sha512M' +def sha512_224F : Fns := fnsOf Spec.Hmac.sha512_224I sha512_224M +def sha512_256F : Fns := fnsOf Spec.Hmac.sha512_256I sha512_256M materialize_code sha1Pbkdf2 := sha1F.pbkdf2 materialize_code md5Pbkdf2 := md5F.pbkdf2 diff --git a/src/asm/x86/hmac_md5.rs b/src/asm/x86/hmac_md5.rs index 84c8bc86a..5d0599b61 100644 --- a/src/asm/x86/hmac_md5.rs +++ b/src/asm/x86/hmac_md5.rs @@ -162,61 +162,67 @@ pub(crate) unsafe extern "C" fn vg_hmac_md5_finalize(inner: *mut [u8; 80], outer "pop eax", "pop eax", "pop eax", + "mov ecx, DWORD PTR [esi]", + "mov DWORD PTR [ebx], ecx", + "mov ecx, DWORD PTR [esi+4]", + "mov DWORD PTR [ebx+4], ecx", + "mov ecx, DWORD PTR [esi+8]", + "mov DWORD PTR [ebx+8], ecx", + "mov ecx, DWORD PTR [esi+12]", + "mov DWORD PTR [ebx+12], ecx", + "mov ecx, DWORD PTR [ebp+128]", + "mov DWORD PTR [ebx+16], ecx", + "mov ecx, DWORD PTR [ebp+132]", + "mov DWORD PTR [ebx+20], ecx", + "mov ecx, DWORD PTR [ebp+136]", + "mov DWORD PTR [ebx+24], ecx", + "mov ecx, DWORD PTR [ebp+140]", + "mov DWORD PTR [ebx+28], ecx", + "mov ecx, 128", + "mov DWORD PTR [ebx+32], ecx", "mov ecx, 0", - "20:", - "mov eax, esi", - "add eax, ecx", - "movzx edx, BYTE PTR [eax]", - "mov eax, ebx", - "add eax, ecx", - "mov BYTE PTR [eax], dl", - "add ecx, 1", - "cmp ecx, 80", - "jne 20b", - "mov eax, 0", - "mov esi, 64", - "mov ecx, 16", - "mov edx, ebp", - "add edx, 128", - "push ebp", - "push ecx", - "push edx", - "push eax", - "push esi", - "push ebx", - "call {vg_md5_update}", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "mov eax, 80", + "mov DWORD PTR [ebx+36], ecx", "mov ecx, 0", - "mov edx, ebp", - "add edx, 128", + "mov DWORD PTR [ebx+40], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+44], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+48], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+52], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+56], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+60], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+64], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+68], ecx", + "mov ecx, 640", + "mov DWORD PTR [ebx+72], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+76], ecx", + "mov eax, ebx", + "add eax, 16", + "mov ecx, 1", "push ebp", - "push edx", "push ecx", "push eax", "push ebx", - "call {vg_md5_finalize}", - "pop eax", + "call {vg_md5_compress}", "pop eax", "pop eax", "pop eax", "pop eax", - "mov ecx, 0", - "21:", - "mov eax, ebp", - "add eax, ecx", - "movzx edx, BYTE PTR [eax+128]", "mov eax, edi", - "add eax, ecx", - "mov BYTE PTR [eax], dl", - "add ecx, 1", - "cmp ecx, 16", - "jne 21b", + "mov ecx, DWORD PTR [ebx]", + "mov DWORD PTR [eax], ecx", + "mov ecx, DWORD PTR [ebx+4]", + "mov DWORD PTR [eax+4], ecx", + "mov ecx, DWORD PTR [ebx+8]", + "mov DWORD PTR [eax+8], ecx", + "mov ecx, DWORD PTR [ebx+12]", + "mov DWORD PTR [eax+12], ecx", "mov eax, ebp", "mov ebx, DWORD PTR [eax+112]", "mov esi, DWORD PTR [eax+116]", @@ -224,6 +230,6 @@ pub(crate) unsafe extern "C" fn vg_hmac_md5_finalize(inner: *mut [u8; 80], outer "mov ebp, DWORD PTR [eax+124]", "ret", vg_md5_finalize = sym super::md5::vg_md5_finalize, - vg_md5_update = sym super::md5::vg_md5_update, + vg_md5_compress = sym super::md5::vg_md5_compress, ) } diff --git a/src/asm/x86/hmac_sha1.rs b/src/asm/x86/hmac_sha1.rs index 32d92cd49..8ee30d56b 100644 --- a/src/asm/x86/hmac_sha1.rs +++ b/src/asm/x86/hmac_sha1.rs @@ -162,61 +162,76 @@ pub(crate) unsafe extern "C" fn vg_hmac_sha1_finalize(inner: *mut [u8; 84], oute "pop eax", "pop eax", "pop eax", + "mov ecx, DWORD PTR [esi]", + "mov DWORD PTR [ebx], ecx", + "mov ecx, DWORD PTR [esi+4]", + "mov DWORD PTR [ebx+4], ecx", + "mov ecx, DWORD PTR [esi+8]", + "mov DWORD PTR [ebx+8], ecx", + "mov ecx, DWORD PTR [esi+12]", + "mov DWORD PTR [ebx+12], ecx", + "mov ecx, DWORD PTR [esi+16]", + "mov DWORD PTR [ebx+16], ecx", + "mov ecx, DWORD PTR [ebp+176]", + "mov DWORD PTR [ebx+20], ecx", + "mov ecx, DWORD PTR [ebp+180]", + "mov DWORD PTR [ebx+24], ecx", + "mov ecx, DWORD PTR [ebp+184]", + "mov DWORD PTR [ebx+28], ecx", + "mov ecx, DWORD PTR [ebp+188]", + "mov DWORD PTR [ebx+32], ecx", + "mov ecx, DWORD PTR [ebp+192]", + "mov DWORD PTR [ebx+36], ecx", + "mov ecx, 128", + "mov DWORD PTR [ebx+40], ecx", "mov ecx, 0", - "20:", - "mov eax, esi", - "add eax, ecx", - "movzx edx, BYTE PTR [eax]", - "mov eax, ebx", - "add eax, ecx", - "mov BYTE PTR [eax], dl", - "add ecx, 1", - "cmp ecx, 84", - "jne 20b", - "mov eax, 0", - "mov esi, 64", - "mov ecx, 20", - "mov edx, ebp", - "add edx, 176", - "push ebp", - "push ecx", - "push edx", - "push eax", - "push esi", - "push ebx", - "call {vg_sha1_update}", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "mov eax, 84", + "mov DWORD PTR [ebx+44], ecx", "mov ecx, 0", - "mov edx, ebp", - "add edx, 176", + "mov DWORD PTR [ebx+48], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+52], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+56], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+60], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+64], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+68], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+72], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+76], ecx", + "mov ecx, -1610481664", + "mov DWORD PTR [ebx+80], ecx", + "mov eax, ebx", + "add eax, 20", + "mov ecx, 1", "push ebp", - "push edx", "push ecx", "push eax", "push ebx", - "call {vg_sha1_finalize}", - "pop eax", + "call {vg_sha1_compress}", "pop eax", "pop eax", "pop eax", "pop eax", - "mov ecx, 0", - "21:", - "mov eax, ebp", - "add eax, ecx", - "movzx edx, BYTE PTR [eax+176]", "mov eax, edi", - "add eax, ecx", - "mov BYTE PTR [eax], dl", - "add ecx, 1", - "cmp ecx, 20", - "jne 21b", + "mov ecx, DWORD PTR [ebx]", + "bswap ecx", + "mov DWORD PTR [eax], ecx", + "mov ecx, DWORD PTR [ebx+4]", + "bswap ecx", + "mov DWORD PTR [eax+4], ecx", + "mov ecx, DWORD PTR [ebx+8]", + "bswap ecx", + "mov DWORD PTR [eax+8], ecx", + "mov ecx, DWORD PTR [ebx+12]", + "bswap ecx", + "mov DWORD PTR [eax+12], ecx", + "mov ecx, DWORD PTR [ebx+16]", + "bswap ecx", + "mov DWORD PTR [eax+16], ecx", "mov eax, ebp", "mov ebx, DWORD PTR [eax+160]", "mov esi, DWORD PTR [eax+164]", @@ -224,6 +239,6 @@ pub(crate) unsafe extern "C" fn vg_hmac_sha1_finalize(inner: *mut [u8; 84], oute "mov ebp, DWORD PTR [eax+172]", "ret", vg_sha1_finalize = sym super::sha1::vg_sha1_finalize, - vg_sha1_update = sym super::sha1::vg_sha1_update, + vg_sha1_compress = sym super::sha1::vg_sha1_compress, ) } diff --git a/src/asm/x86/hmac_sha384.rs b/src/asm/x86/hmac_sha384.rs index ab0e8bf63..515398136 100644 --- a/src/asm/x86/hmac_sha384.rs +++ b/src/asm/x86/hmac_sha384.rs @@ -162,61 +162,188 @@ pub(crate) unsafe extern "C" fn vg_hmac_sha384_finalize(inner: *mut [u8; 192], o "pop eax", "pop eax", "pop eax", + "mov ecx, DWORD PTR [esi]", + "mov DWORD PTR [ebx], ecx", + "mov ecx, DWORD PTR [esi+4]", + "mov DWORD PTR [ebx+4], ecx", + "mov ecx, DWORD PTR [esi+8]", + "mov DWORD PTR [ebx+8], ecx", + "mov ecx, DWORD PTR [esi+12]", + "mov DWORD PTR [ebx+12], ecx", + "mov ecx, DWORD PTR [esi+16]", + "mov DWORD PTR [ebx+16], ecx", + "mov ecx, DWORD PTR [esi+20]", + "mov DWORD PTR [ebx+20], ecx", + "mov ecx, DWORD PTR [esi+24]", + "mov DWORD PTR [ebx+24], ecx", + "mov ecx, DWORD PTR [esi+28]", + "mov DWORD PTR [ebx+28], ecx", + "mov ecx, DWORD PTR [esi+32]", + "mov DWORD PTR [ebx+32], ecx", + "mov ecx, DWORD PTR [esi+36]", + "mov DWORD PTR [ebx+36], ecx", + "mov ecx, DWORD PTR [esi+40]", + "mov DWORD PTR [ebx+40], ecx", + "mov ecx, DWORD PTR [esi+44]", + "mov DWORD PTR [ebx+44], ecx", + "mov ecx, DWORD PTR [esi+48]", + "mov DWORD PTR [ebx+48], ecx", + "mov ecx, DWORD PTR [esi+52]", + "mov DWORD PTR [ebx+52], ecx", + "mov ecx, DWORD PTR [esi+56]", + "mov DWORD PTR [ebx+56], ecx", + "mov ecx, DWORD PTR [esi+60]", + "mov DWORD PTR [ebx+60], ecx", + "mov ecx, DWORD PTR [ebp+288]", + "mov DWORD PTR [ebx+64], ecx", + "mov ecx, DWORD PTR [ebp+292]", + "mov DWORD PTR [ebx+68], ecx", + "mov ecx, DWORD PTR [ebp+296]", + "mov DWORD PTR [ebx+72], ecx", + "mov ecx, DWORD PTR [ebp+300]", + "mov DWORD PTR [ebx+76], ecx", + "mov ecx, DWORD PTR [ebp+304]", + "mov DWORD PTR [ebx+80], ecx", + "mov ecx, DWORD PTR [ebp+308]", + "mov DWORD PTR [ebx+84], ecx", + "mov ecx, DWORD PTR [ebp+312]", + "mov DWORD PTR [ebx+88], ecx", + "mov ecx, DWORD PTR [ebp+316]", + "mov DWORD PTR [ebx+92], ecx", + "mov ecx, DWORD PTR [ebp+320]", + "mov DWORD PTR [ebx+96], ecx", + "mov ecx, DWORD PTR [ebp+324]", + "mov DWORD PTR [ebx+100], ecx", + "mov ecx, DWORD PTR [ebp+328]", + "mov DWORD PTR [ebx+104], ecx", + "mov ecx, DWORD PTR [ebp+332]", + "mov DWORD PTR [ebx+108], ecx", + "mov ecx, 128", + "mov DWORD PTR [ebx+112], ecx", "mov ecx, 0", - "20:", - "mov eax, esi", - "add eax, ecx", - "movzx edx, BYTE PTR [eax]", - "mov eax, ebx", - "add eax, ecx", - "mov BYTE PTR [eax], dl", - "add ecx, 1", - "cmp ecx, 192", - "jne 20b", - "mov eax, 0", - "mov esi, 128", - "mov ecx, 48", - "mov edx, ebp", - "add edx, 288", - "push ebp", - "push ecx", - "push edx", - "push eax", - "push esi", - "push ebx", - "call {vg_sha512_update}", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "mov eax, 176", + "mov DWORD PTR [ebx+116], ecx", "mov ecx, 0", - "mov edx, ebp", - "add edx, 288", + "mov DWORD PTR [ebx+120], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+124], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+128], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+132], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+136], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+140], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+144], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+148], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+152], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+156], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+160], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+164], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+168], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+172], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+176], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+180], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+184], ecx", + "mov ecx, -2147155968", + "mov DWORD PTR [ebx+188], ecx", + "mov eax, ebx", + "add eax, 64", + "mov ecx, 1", "push ebp", - "push edx", "push ecx", "push eax", "push ebx", - "call {vg_sha512_finalize}", - "pop eax", + "call {vg_sha512_compress}", "pop eax", "pop eax", "pop eax", "pop eax", - "mov ecx, 0", - "21:", - "mov eax, ebp", - "add eax, ecx", - "movzx edx, BYTE PTR [eax+288]", - "mov eax, edi", - "add eax, ecx", - "mov BYTE PTR [eax], dl", - "add ecx, 1", - "cmp ecx, 48", - "jne 21b", + "mov eax, ebx", + "add eax, 64", + "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+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+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+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+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+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+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+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", + "mov ecx, DWORD PTR [ebx+68]", + "mov DWORD PTR [edi+4], ecx", + "mov ecx, DWORD PTR [ebx+72]", + "mov DWORD PTR [edi+8], ecx", + "mov ecx, DWORD PTR [ebx+76]", + "mov DWORD PTR [edi+12], ecx", + "mov ecx, DWORD PTR [ebx+80]", + "mov DWORD PTR [edi+16], ecx", + "mov ecx, DWORD PTR [ebx+84]", + "mov DWORD PTR [edi+20], ecx", + "mov ecx, DWORD PTR [ebx+88]", + "mov DWORD PTR [edi+24], ecx", + "mov ecx, DWORD PTR [ebx+92]", + "mov DWORD PTR [edi+28], ecx", + "mov ecx, DWORD PTR [ebx+96]", + "mov DWORD PTR [edi+32], ecx", + "mov ecx, DWORD PTR [ebx+100]", + "mov DWORD PTR [edi+36], ecx", + "mov ecx, DWORD PTR [ebx+104]", + "mov DWORD PTR [edi+40], ecx", + "mov ecx, DWORD PTR [ebx+108]", + "mov DWORD PTR [edi+44], ecx", "mov eax, ebp", "mov ebx, DWORD PTR [eax+272]", "mov esi, DWORD PTR [eax+276]", @@ -224,6 +351,6 @@ pub(crate) unsafe extern "C" fn vg_hmac_sha384_finalize(inner: *mut [u8; 192], o "mov ebp, DWORD PTR [eax+284]", "ret", vg_sha512_finalize = sym super::sha512::vg_sha512_finalize, - vg_sha512_update = sym super::sha512::vg_sha512_update, + vg_sha512_compress = sym super::sha512::vg_sha512_compress, ) } diff --git a/src/asm/x86/hmac_sha512.rs b/src/asm/x86/hmac_sha512.rs index c71c23a0e..e361a7459 100644 --- a/src/asm/x86/hmac_sha512.rs +++ b/src/asm/x86/hmac_sha512.rs @@ -162,61 +162,163 @@ pub(crate) unsafe extern "C" fn vg_hmac_sha512_finalize(inner: *mut [u8; 192], o "pop eax", "pop eax", "pop eax", + "mov ecx, DWORD PTR [esi]", + "mov DWORD PTR [ebx], ecx", + "mov ecx, DWORD PTR [esi+4]", + "mov DWORD PTR [ebx+4], ecx", + "mov ecx, DWORD PTR [esi+8]", + "mov DWORD PTR [ebx+8], ecx", + "mov ecx, DWORD PTR [esi+12]", + "mov DWORD PTR [ebx+12], ecx", + "mov ecx, DWORD PTR [esi+16]", + "mov DWORD PTR [ebx+16], ecx", + "mov ecx, DWORD PTR [esi+20]", + "mov DWORD PTR [ebx+20], ecx", + "mov ecx, DWORD PTR [esi+24]", + "mov DWORD PTR [ebx+24], ecx", + "mov ecx, DWORD PTR [esi+28]", + "mov DWORD PTR [ebx+28], ecx", + "mov ecx, DWORD PTR [esi+32]", + "mov DWORD PTR [ebx+32], ecx", + "mov ecx, DWORD PTR [esi+36]", + "mov DWORD PTR [ebx+36], ecx", + "mov ecx, DWORD PTR [esi+40]", + "mov DWORD PTR [ebx+40], ecx", + "mov ecx, DWORD PTR [esi+44]", + "mov DWORD PTR [ebx+44], ecx", + "mov ecx, DWORD PTR [esi+48]", + "mov DWORD PTR [ebx+48], ecx", + "mov ecx, DWORD PTR [esi+52]", + "mov DWORD PTR [ebx+52], ecx", + "mov ecx, DWORD PTR [esi+56]", + "mov DWORD PTR [ebx+56], ecx", + "mov ecx, DWORD PTR [esi+60]", + "mov DWORD PTR [ebx+60], ecx", + "mov ecx, DWORD PTR [ebp+288]", + "mov DWORD PTR [ebx+64], ecx", + "mov ecx, DWORD PTR [ebp+292]", + "mov DWORD PTR [ebx+68], ecx", + "mov ecx, DWORD PTR [ebp+296]", + "mov DWORD PTR [ebx+72], ecx", + "mov ecx, DWORD PTR [ebp+300]", + "mov DWORD PTR [ebx+76], ecx", + "mov ecx, DWORD PTR [ebp+304]", + "mov DWORD PTR [ebx+80], ecx", + "mov ecx, DWORD PTR [ebp+308]", + "mov DWORD PTR [ebx+84], ecx", + "mov ecx, DWORD PTR [ebp+312]", + "mov DWORD PTR [ebx+88], ecx", + "mov ecx, DWORD PTR [ebp+316]", + "mov DWORD PTR [ebx+92], ecx", + "mov ecx, DWORD PTR [ebp+320]", + "mov DWORD PTR [ebx+96], ecx", + "mov ecx, DWORD PTR [ebp+324]", + "mov DWORD PTR [ebx+100], ecx", + "mov ecx, DWORD PTR [ebp+328]", + "mov DWORD PTR [ebx+104], ecx", + "mov ecx, DWORD PTR [ebp+332]", + "mov DWORD PTR [ebx+108], ecx", + "mov ecx, DWORD PTR [ebp+336]", + "mov DWORD PTR [ebx+112], ecx", + "mov ecx, DWORD PTR [ebp+340]", + "mov DWORD PTR [ebx+116], ecx", + "mov ecx, DWORD PTR [ebp+344]", + "mov DWORD PTR [ebx+120], ecx", + "mov ecx, DWORD PTR [ebp+348]", + "mov DWORD PTR [ebx+124], ecx", + "mov ecx, 128", + "mov DWORD PTR [ebx+128], ecx", "mov ecx, 0", - "20:", - "mov eax, esi", - "add eax, ecx", - "movzx edx, BYTE PTR [eax]", - "mov eax, ebx", - "add eax, ecx", - "mov BYTE PTR [eax], dl", - "add ecx, 1", - "cmp ecx, 192", - "jne 20b", - "mov eax, 0", - "mov esi, 128", - "mov ecx, 64", - "mov edx, ebp", - "add edx, 288", - "push ebp", - "push ecx", - "push edx", - "push eax", - "push esi", - "push ebx", - "call {vg_sha512_update}", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "mov eax, 192", + "mov DWORD PTR [ebx+132], ecx", "mov ecx, 0", - "mov edx, ebp", - "add edx, 288", + "mov DWORD PTR [ebx+136], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+140], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+144], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+148], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+152], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+156], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+160], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+164], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+168], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+172], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+176], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+180], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+184], ecx", + "mov ecx, 393216", + "mov DWORD PTR [ebx+188], ecx", + "mov eax, ebx", + "add eax, 64", + "mov ecx, 1", "push ebp", - "push edx", "push ecx", "push eax", "push ebx", - "call {vg_sha512_finalize}", + "call {vg_sha512_compress}", "pop eax", "pop eax", "pop eax", "pop eax", - "pop eax", - "mov ecx, 0", - "21:", - "mov eax, ebp", - "add eax, ecx", - "movzx edx, BYTE PTR [eax+288]", "mov eax, edi", - "add eax, ecx", - "mov BYTE PTR [eax], dl", - "add ecx, 1", - "cmp ecx, 64", - "jne 21b", + "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+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+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+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+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+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+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+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]", "mov esi, DWORD PTR [eax+276]", @@ -224,6 +326,6 @@ pub(crate) unsafe extern "C" fn vg_hmac_sha512_finalize(inner: *mut [u8; 192], o "mov ebp, DWORD PTR [eax+284]", "ret", vg_sha512_finalize = sym super::sha512::vg_sha512_finalize, - vg_sha512_update = sym super::sha512::vg_sha512_update, + vg_sha512_compress = sym super::sha512::vg_sha512_compress, ) } diff --git a/src/asm/x86/hmac_sha512_224.rs b/src/asm/x86/hmac_sha512_224.rs index 3aa7b158d..66443ae16 100644 --- a/src/asm/x86/hmac_sha512_224.rs +++ b/src/asm/x86/hmac_sha512_224.rs @@ -162,61 +162,178 @@ pub(crate) unsafe extern "C" fn vg_hmac_sha512_224_finalize(inner: *mut [u8; 192 "pop eax", "pop eax", "pop eax", + "mov ecx, DWORD PTR [esi]", + "mov DWORD PTR [ebx], ecx", + "mov ecx, DWORD PTR [esi+4]", + "mov DWORD PTR [ebx+4], ecx", + "mov ecx, DWORD PTR [esi+8]", + "mov DWORD PTR [ebx+8], ecx", + "mov ecx, DWORD PTR [esi+12]", + "mov DWORD PTR [ebx+12], ecx", + "mov ecx, DWORD PTR [esi+16]", + "mov DWORD PTR [ebx+16], ecx", + "mov ecx, DWORD PTR [esi+20]", + "mov DWORD PTR [ebx+20], ecx", + "mov ecx, DWORD PTR [esi+24]", + "mov DWORD PTR [ebx+24], ecx", + "mov ecx, DWORD PTR [esi+28]", + "mov DWORD PTR [ebx+28], ecx", + "mov ecx, DWORD PTR [esi+32]", + "mov DWORD PTR [ebx+32], ecx", + "mov ecx, DWORD PTR [esi+36]", + "mov DWORD PTR [ebx+36], ecx", + "mov ecx, DWORD PTR [esi+40]", + "mov DWORD PTR [ebx+40], ecx", + "mov ecx, DWORD PTR [esi+44]", + "mov DWORD PTR [ebx+44], ecx", + "mov ecx, DWORD PTR [esi+48]", + "mov DWORD PTR [ebx+48], ecx", + "mov ecx, DWORD PTR [esi+52]", + "mov DWORD PTR [ebx+52], ecx", + "mov ecx, DWORD PTR [esi+56]", + "mov DWORD PTR [ebx+56], ecx", + "mov ecx, DWORD PTR [esi+60]", + "mov DWORD PTR [ebx+60], ecx", + "mov ecx, DWORD PTR [ebp+288]", + "mov DWORD PTR [ebx+64], ecx", + "mov ecx, DWORD PTR [ebp+292]", + "mov DWORD PTR [ebx+68], ecx", + "mov ecx, DWORD PTR [ebp+296]", + "mov DWORD PTR [ebx+72], ecx", + "mov ecx, DWORD PTR [ebp+300]", + "mov DWORD PTR [ebx+76], ecx", + "mov ecx, DWORD PTR [ebp+304]", + "mov DWORD PTR [ebx+80], ecx", + "mov ecx, DWORD PTR [ebp+308]", + "mov DWORD PTR [ebx+84], ecx", + "mov ecx, DWORD PTR [ebp+312]", + "mov DWORD PTR [ebx+88], ecx", + "mov ecx, 128", + "mov DWORD PTR [ebx+92], ecx", "mov ecx, 0", - "20:", - "mov eax, esi", - "add eax, ecx", - "movzx edx, BYTE PTR [eax]", - "mov eax, ebx", - "add eax, ecx", - "mov BYTE PTR [eax], dl", - "add ecx, 1", - "cmp ecx, 192", - "jne 20b", - "mov eax, 0", - "mov esi, 128", - "mov ecx, 28", - "mov edx, ebp", - "add edx, 288", - "push ebp", - "push ecx", - "push edx", - "push eax", - "push esi", - "push ebx", - "call {vg_sha512_update}", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "mov eax, 156", + "mov DWORD PTR [ebx+96], ecx", "mov ecx, 0", - "mov edx, ebp", - "add edx, 288", + "mov DWORD PTR [ebx+100], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+104], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+108], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+112], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+116], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+120], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+124], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+128], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+132], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+136], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+140], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+144], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+148], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+152], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+156], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+160], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+164], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+168], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+172], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+176], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+180], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+184], ecx", + "mov ecx, -536608768", + "mov DWORD PTR [ebx+188], ecx", + "mov eax, ebx", + "add eax, 64", + "mov ecx, 1", "push ebp", - "push edx", "push ecx", "push eax", "push ebx", - "call {vg_sha512_finalize}", + "call {vg_sha512_compress}", "pop eax", "pop eax", "pop eax", "pop eax", - "pop eax", - "mov ecx, 0", - "21:", - "mov eax, ebp", - "add eax, ecx", - "movzx edx, BYTE PTR [eax+288]", - "mov eax, edi", - "add eax, ecx", - "mov BYTE PTR [eax], dl", - "add ecx, 1", - "cmp ecx, 28", - "jne 21b", + "mov eax, ebx", + "add eax, 64", + "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+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+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+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+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+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+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+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", + "mov ecx, DWORD PTR [ebx+68]", + "mov DWORD PTR [edi+4], ecx", + "mov ecx, DWORD PTR [ebx+72]", + "mov DWORD PTR [edi+8], ecx", + "mov ecx, DWORD PTR [ebx+76]", + "mov DWORD PTR [edi+12], ecx", + "mov ecx, DWORD PTR [ebx+80]", + "mov DWORD PTR [edi+16], ecx", + "mov ecx, DWORD PTR [ebx+84]", + "mov DWORD PTR [edi+20], ecx", + "mov ecx, DWORD PTR [ebx+88]", + "mov DWORD PTR [edi+24], ecx", "mov eax, ebp", "mov ebx, DWORD PTR [eax+272]", "mov esi, DWORD PTR [eax+276]", @@ -224,6 +341,6 @@ pub(crate) unsafe extern "C" fn vg_hmac_sha512_224_finalize(inner: *mut [u8; 192 "mov ebp, DWORD PTR [eax+284]", "ret", vg_sha512_finalize = sym super::sha512::vg_sha512_finalize, - vg_sha512_update = sym super::sha512::vg_sha512_update, + vg_sha512_compress = sym super::sha512::vg_sha512_compress, ) } diff --git a/src/asm/x86/hmac_sha512_256.rs b/src/asm/x86/hmac_sha512_256.rs index 609728395..a47854424 100644 --- a/src/asm/x86/hmac_sha512_256.rs +++ b/src/asm/x86/hmac_sha512_256.rs @@ -162,61 +162,180 @@ pub(crate) unsafe extern "C" fn vg_hmac_sha512_256_finalize(inner: *mut [u8; 192 "pop eax", "pop eax", "pop eax", + "mov ecx, DWORD PTR [esi]", + "mov DWORD PTR [ebx], ecx", + "mov ecx, DWORD PTR [esi+4]", + "mov DWORD PTR [ebx+4], ecx", + "mov ecx, DWORD PTR [esi+8]", + "mov DWORD PTR [ebx+8], ecx", + "mov ecx, DWORD PTR [esi+12]", + "mov DWORD PTR [ebx+12], ecx", + "mov ecx, DWORD PTR [esi+16]", + "mov DWORD PTR [ebx+16], ecx", + "mov ecx, DWORD PTR [esi+20]", + "mov DWORD PTR [ebx+20], ecx", + "mov ecx, DWORD PTR [esi+24]", + "mov DWORD PTR [ebx+24], ecx", + "mov ecx, DWORD PTR [esi+28]", + "mov DWORD PTR [ebx+28], ecx", + "mov ecx, DWORD PTR [esi+32]", + "mov DWORD PTR [ebx+32], ecx", + "mov ecx, DWORD PTR [esi+36]", + "mov DWORD PTR [ebx+36], ecx", + "mov ecx, DWORD PTR [esi+40]", + "mov DWORD PTR [ebx+40], ecx", + "mov ecx, DWORD PTR [esi+44]", + "mov DWORD PTR [ebx+44], ecx", + "mov ecx, DWORD PTR [esi+48]", + "mov DWORD PTR [ebx+48], ecx", + "mov ecx, DWORD PTR [esi+52]", + "mov DWORD PTR [ebx+52], ecx", + "mov ecx, DWORD PTR [esi+56]", + "mov DWORD PTR [ebx+56], ecx", + "mov ecx, DWORD PTR [esi+60]", + "mov DWORD PTR [ebx+60], ecx", + "mov ecx, DWORD PTR [ebp+288]", + "mov DWORD PTR [ebx+64], ecx", + "mov ecx, DWORD PTR [ebp+292]", + "mov DWORD PTR [ebx+68], ecx", + "mov ecx, DWORD PTR [ebp+296]", + "mov DWORD PTR [ebx+72], ecx", + "mov ecx, DWORD PTR [ebp+300]", + "mov DWORD PTR [ebx+76], ecx", + "mov ecx, DWORD PTR [ebp+304]", + "mov DWORD PTR [ebx+80], ecx", + "mov ecx, DWORD PTR [ebp+308]", + "mov DWORD PTR [ebx+84], ecx", + "mov ecx, DWORD PTR [ebp+312]", + "mov DWORD PTR [ebx+88], ecx", + "mov ecx, DWORD PTR [ebp+316]", + "mov DWORD PTR [ebx+92], ecx", + "mov ecx, 128", + "mov DWORD PTR [ebx+96], ecx", "mov ecx, 0", - "20:", - "mov eax, esi", - "add eax, ecx", - "movzx edx, BYTE PTR [eax]", - "mov eax, ebx", - "add eax, ecx", - "mov BYTE PTR [eax], dl", - "add ecx, 1", - "cmp ecx, 192", - "jne 20b", - "mov eax, 0", - "mov esi, 128", - "mov ecx, 32", - "mov edx, ebp", - "add edx, 288", - "push ebp", - "push ecx", - "push edx", - "push eax", - "push esi", - "push ebx", - "call {vg_sha512_update}", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "mov eax, 160", + "mov DWORD PTR [ebx+100], ecx", "mov ecx, 0", - "mov edx, ebp", - "add edx, 288", + "mov DWORD PTR [ebx+104], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+108], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+112], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+116], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+120], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+124], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+128], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+132], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+136], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+140], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+144], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+148], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+152], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+156], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+160], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+164], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+168], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+172], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+176], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+180], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+184], ecx", + "mov ecx, 327680", + "mov DWORD PTR [ebx+188], ecx", + "mov eax, ebx", + "add eax, 64", + "mov ecx, 1", "push ebp", - "push edx", "push ecx", "push eax", "push ebx", - "call {vg_sha512_finalize}", + "call {vg_sha512_compress}", "pop eax", "pop eax", "pop eax", "pop eax", - "pop eax", - "mov ecx, 0", - "21:", - "mov eax, ebp", - "add eax, ecx", - "movzx edx, BYTE PTR [eax+288]", - "mov eax, edi", - "add eax, ecx", - "mov BYTE PTR [eax], dl", - "add ecx, 1", - "cmp ecx, 32", - "jne 21b", + "mov eax, ebx", + "add eax, 64", + "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+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+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+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+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+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+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+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", + "mov ecx, DWORD PTR [ebx+68]", + "mov DWORD PTR [edi+4], ecx", + "mov ecx, DWORD PTR [ebx+72]", + "mov DWORD PTR [edi+8], ecx", + "mov ecx, DWORD PTR [ebx+76]", + "mov DWORD PTR [edi+12], ecx", + "mov ecx, DWORD PTR [ebx+80]", + "mov DWORD PTR [edi+16], ecx", + "mov ecx, DWORD PTR [ebx+84]", + "mov DWORD PTR [edi+20], ecx", + "mov ecx, DWORD PTR [ebx+88]", + "mov DWORD PTR [edi+24], ecx", + "mov ecx, DWORD PTR [ebx+92]", + "mov DWORD PTR [edi+28], ecx", "mov eax, ebp", "mov ebx, DWORD PTR [eax+272]", "mov esi, DWORD PTR [eax+276]", @@ -224,6 +343,6 @@ pub(crate) unsafe extern "C" fn vg_hmac_sha512_256_finalize(inner: *mut [u8; 192 "mov ebp, DWORD PTR [eax+284]", "ret", vg_sha512_finalize = sym super::sha512::vg_sha512_finalize, - vg_sha512_update = sym super::sha512::vg_sha512_update, + vg_sha512_compress = sym super::sha512::vg_sha512_compress, ) } diff --git a/src/asm/x86/pbkdf2_md5.rs b/src/asm/x86/pbkdf2_md5.rs index c6954ceac..89469f659 100644 --- a/src/asm/x86/pbkdf2_md5.rs +++ b/src/asm/x86/pbkdf2_md5.rs @@ -26,147 +26,131 @@ pub(crate) unsafe extern "C" fn vg_pbkdf2_hmac_md5_iterate(key: *const [u8; 160] "mov DWORD PTR [eax+120], edi", "mov DWORD PTR [eax+124], ebp", "mov ebp, eax", - "mov edi, DWORD PTR [esp+12]", - "mov esi, DWORD PTR [esp+8]", - "mov ecx, 0", - "20:", - "mov eax, esi", - "add eax, ecx", - "movzx edx, BYTE PTR [eax]", - "mov eax, ebp", - "add eax, ecx", - "mov BYTE PTR [eax+224], dl", - "add ecx, 1", - "cmp ecx, 16", - "jne 20b", - "test edi, edi", - "je 21f", - "23:", "mov esi, DWORD PTR [esp+4]", - "mov ecx, 0", - "24:", - "mov eax, esi", - "add eax, ecx", - "movzx edx, BYTE PTR [eax]", - "mov eax, ebp", - "add eax, ecx", - "mov BYTE PTR [eax+128], dl", - "add ecx, 1", - "cmp ecx, 80", - "jne 24b", - "mov ebx, ebp", - "add ebx, 128", - "mov eax, 0", - "mov esi, 64", - "mov ecx, 16", - "mov edx, ebp", - "add edx, 224", - "push ebp", - "push ecx", - "push edx", - "push eax", - "push esi", - "push ebx", - "call {vg_md5_update}", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "pop eax", + "mov edi, DWORD PTR [esp+12]", "mov ebx, ebp", "add ebx, 128", - "mov eax, 80", + "mov edx, DWORD PTR [esp+8]", + "mov ecx, DWORD PTR [edx]", + "mov DWORD PTR [ebx+16], ecx", + "mov ecx, DWORD PTR [edx+4]", + "mov DWORD PTR [ebx+20], ecx", + "mov ecx, DWORD PTR [edx+8]", + "mov DWORD PTR [ebx+24], ecx", + "mov ecx, DWORD PTR [edx+12]", + "mov DWORD PTR [ebx+28], ecx", + "mov ecx, 128", + "mov DWORD PTR [ebx+32], ecx", "mov ecx, 0", - "mov edx, ebp", - "add edx, 208", - "push ebp", - "push edx", - "push ecx", - "push eax", - "push ebx", - "call {vg_md5_finalize}", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "mov esi, DWORD PTR [esp+4]", + "mov DWORD PTR [ebx+36], ecx", "mov ecx, 0", - "25:", - "mov eax, esi", - "add eax, ecx", - "movzx edx, BYTE PTR [eax+80]", - "mov eax, ebp", - "add eax, ecx", - "mov BYTE PTR [eax+128], dl", - "add ecx, 1", - "cmp ecx, 80", - "jne 25b", - "mov ebx, ebp", - "add ebx, 128", - "mov eax, 0", - "mov esi, 64", - "mov ecx, 16", - "mov edx, ebp", - "add edx, 208", + "mov DWORD PTR [ebx+40], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+44], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+48], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+52], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+56], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+60], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+64], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+68], ecx", + "mov ecx, 640", + "mov DWORD PTR [ebx+72], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+76], ecx", + "test edi, edi", + "je 20f", + "22:", + "mov ecx, DWORD PTR [esi]", + "mov DWORD PTR [ebx], ecx", + "mov ecx, DWORD PTR [esi+4]", + "mov DWORD PTR [ebx+4], ecx", + "mov ecx, DWORD PTR [esi+8]", + "mov DWORD PTR [ebx+8], ecx", + "mov ecx, DWORD PTR [esi+12]", + "mov DWORD PTR [ebx+12], ecx", + "mov eax, ebx", + "add eax, 16", + "mov ecx, 1", "push ebp", "push ecx", - "push edx", "push eax", - "push esi", "push ebx", - "call {vg_md5_update}", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "mov ebx, ebp", - "add ebx, 128", - "mov eax, 80", - "mov ecx, 0", - "mov edx, ebp", - "add edx, 224", + "call {vg_md5_compress}", + "pop eax", + "pop eax", + "pop eax", + "pop eax", + "mov eax, ebx", + "add eax, 16", + "mov ecx, DWORD PTR [ebx]", + "mov DWORD PTR [eax], ecx", + "mov ecx, DWORD PTR [ebx+4]", + "mov DWORD PTR [eax+4], ecx", + "mov ecx, DWORD PTR [ebx+8]", + "mov DWORD PTR [eax+8], ecx", + "mov ecx, DWORD PTR [ebx+12]", + "mov DWORD PTR [eax+12], ecx", + "mov ecx, DWORD PTR [esi+80]", + "mov DWORD PTR [ebx], ecx", + "mov ecx, DWORD PTR [esi+84]", + "mov DWORD PTR [ebx+4], ecx", + "mov ecx, DWORD PTR [esi+88]", + "mov DWORD PTR [ebx+8], ecx", + "mov ecx, DWORD PTR [esi+92]", + "mov DWORD PTR [ebx+12], ecx", + "mov eax, ebx", + "add eax, 16", + "mov ecx, 1", "push ebp", - "push edx", "push ecx", "push eax", "push ebx", - "call {vg_md5_finalize}", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "mov esi, DWORD PTR [esp+16]", - "mov ecx, 0", - "26:", - "mov eax, ebp", - "add eax, ecx", - "movzx edx, BYTE PTR [eax+224]", - "mov eax, esi", - "add eax, ecx", - "movzx ebx, BYTE PTR [eax]", - "xor edx, ebx", - "mov BYTE PTR [eax], dl", - "add ecx, 1", - "cmp ecx, 16", - "jne 26b", + "call {vg_md5_compress}", + "pop eax", + "pop eax", + "pop eax", + "pop eax", + "mov eax, ebx", + "add eax, 16", + "mov ecx, DWORD PTR [ebx]", + "mov DWORD PTR [eax], ecx", + "mov ecx, DWORD PTR [ebx+4]", + "mov DWORD PTR [eax+4], ecx", + "mov ecx, DWORD PTR [ebx+8]", + "mov DWORD PTR [eax+8], ecx", + "mov ecx, DWORD PTR [ebx+12]", + "mov DWORD PTR [eax+12], ecx", + "mov edx, DWORD PTR [esp+16]", + "mov ecx, DWORD PTR [ebx+16]", + "xor ecx, DWORD PTR [edx]", + "mov DWORD PTR [edx], ecx", + "mov ecx, DWORD PTR [ebx+20]", + "xor ecx, DWORD PTR [edx+4]", + "mov DWORD PTR [edx+4], ecx", + "mov ecx, DWORD PTR [ebx+24]", + "xor ecx, DWORD PTR [edx+8]", + "mov DWORD PTR [edx+8], ecx", + "mov ecx, DWORD PTR [ebx+28]", + "xor ecx, DWORD PTR [edx+12]", + "mov DWORD PTR [edx+12], ecx", "sub edi, 1", - "jne 23b", - "jmp 22f", + "jne 22b", + "jmp 21f", + "20:", "21:", - "22:", "mov eax, ebp", "mov ebx, DWORD PTR [eax+112]", "mov esi, DWORD PTR [eax+116]", "mov edi, DWORD PTR [eax+120]", "mov ebp, DWORD PTR [eax+124]", "ret", - vg_md5_update = sym super::md5::vg_md5_update, - vg_md5_finalize = sym super::md5::vg_md5_finalize, + vg_md5_compress = sym super::md5::vg_md5_compress, ) } diff --git a/src/asm/x86/pbkdf2_sha1.rs b/src/asm/x86/pbkdf2_sha1.rs index 869579cbc..060be630b 100644 --- a/src/asm/x86/pbkdf2_sha1.rs +++ b/src/asm/x86/pbkdf2_sha1.rs @@ -26,147 +26,152 @@ pub(crate) unsafe extern "C" fn vg_pbkdf2_hmac_sha1_iterate(key: *const [u8; 168 "mov DWORD PTR [eax+168], edi", "mov DWORD PTR [eax+172], ebp", "mov ebp, eax", - "mov edi, DWORD PTR [esp+12]", - "mov esi, DWORD PTR [esp+8]", - "mov ecx, 0", - "20:", - "mov eax, esi", - "add eax, ecx", - "movzx edx, BYTE PTR [eax]", - "mov eax, ebp", - "add eax, ecx", - "mov BYTE PTR [eax+280], dl", - "add ecx, 1", - "cmp ecx, 20", - "jne 20b", - "test edi, edi", - "je 21f", - "23:", "mov esi, DWORD PTR [esp+4]", - "mov ecx, 0", - "24:", - "mov eax, esi", - "add eax, ecx", - "movzx edx, BYTE PTR [eax]", - "mov eax, ebp", - "add eax, ecx", - "mov BYTE PTR [eax+176], dl", - "add ecx, 1", - "cmp ecx, 84", - "jne 24b", - "mov ebx, ebp", - "add ebx, 176", - "mov eax, 0", - "mov esi, 64", - "mov ecx, 20", - "mov edx, ebp", - "add edx, 280", - "push ebp", - "push ecx", - "push edx", - "push eax", - "push esi", - "push ebx", - "call {vg_sha1_update}", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "pop eax", + "mov edi, DWORD PTR [esp+12]", "mov ebx, ebp", "add ebx, 176", - "mov eax, 84", + "mov edx, DWORD PTR [esp+8]", + "mov ecx, DWORD PTR [edx]", + "mov DWORD PTR [ebx+20], ecx", + "mov ecx, DWORD PTR [edx+4]", + "mov DWORD PTR [ebx+24], ecx", + "mov ecx, DWORD PTR [edx+8]", + "mov DWORD PTR [ebx+28], ecx", + "mov ecx, DWORD PTR [edx+12]", + "mov DWORD PTR [ebx+32], ecx", + "mov ecx, DWORD PTR [edx+16]", + "mov DWORD PTR [ebx+36], ecx", + "mov ecx, 128", + "mov DWORD PTR [ebx+40], ecx", "mov ecx, 0", - "mov edx, ebp", - "add edx, 260", - "push ebp", - "push edx", - "push ecx", - "push eax", - "push ebx", - "call {vg_sha1_finalize}", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "mov esi, DWORD PTR [esp+4]", + "mov DWORD PTR [ebx+44], ecx", "mov ecx, 0", - "25:", - "mov eax, esi", - "add eax, ecx", - "movzx edx, BYTE PTR [eax+84]", - "mov eax, ebp", - "add eax, ecx", - "mov BYTE PTR [eax+176], dl", - "add ecx, 1", - "cmp ecx, 84", - "jne 25b", - "mov ebx, ebp", - "add ebx, 176", - "mov eax, 0", - "mov esi, 64", - "mov ecx, 20", - "mov edx, ebp", - "add edx, 260", + "mov DWORD PTR [ebx+48], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+52], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+56], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+60], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+64], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+68], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+72], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+76], ecx", + "mov ecx, -1610481664", + "mov DWORD PTR [ebx+80], ecx", + "test edi, edi", + "je 20f", + "22:", + "mov ecx, DWORD PTR [esi]", + "mov DWORD PTR [ebx], ecx", + "mov ecx, DWORD PTR [esi+4]", + "mov DWORD PTR [ebx+4], ecx", + "mov ecx, DWORD PTR [esi+8]", + "mov DWORD PTR [ebx+8], ecx", + "mov ecx, DWORD PTR [esi+12]", + "mov DWORD PTR [ebx+12], ecx", + "mov ecx, DWORD PTR [esi+16]", + "mov DWORD PTR [ebx+16], ecx", + "mov eax, ebx", + "add eax, 20", + "mov ecx, 1", "push ebp", "push ecx", - "push edx", "push eax", - "push esi", "push ebx", - "call {vg_sha1_update}", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "mov ebx, ebp", - "add ebx, 176", - "mov eax, 84", - "mov ecx, 0", - "mov edx, ebp", - "add edx, 280", + "call {vg_sha1_compress}", + "pop eax", + "pop eax", + "pop eax", + "pop eax", + "mov eax, ebx", + "add eax, 20", + "mov ecx, DWORD PTR [ebx]", + "bswap ecx", + "mov DWORD PTR [eax], ecx", + "mov ecx, DWORD PTR [ebx+4]", + "bswap ecx", + "mov DWORD PTR [eax+4], ecx", + "mov ecx, DWORD PTR [ebx+8]", + "bswap ecx", + "mov DWORD PTR [eax+8], ecx", + "mov ecx, DWORD PTR [ebx+12]", + "bswap ecx", + "mov DWORD PTR [eax+12], ecx", + "mov ecx, DWORD PTR [ebx+16]", + "bswap ecx", + "mov DWORD PTR [eax+16], ecx", + "mov ecx, DWORD PTR [esi+84]", + "mov DWORD PTR [ebx], ecx", + "mov ecx, DWORD PTR [esi+88]", + "mov DWORD PTR [ebx+4], ecx", + "mov ecx, DWORD PTR [esi+92]", + "mov DWORD PTR [ebx+8], ecx", + "mov ecx, DWORD PTR [esi+96]", + "mov DWORD PTR [ebx+12], ecx", + "mov ecx, DWORD PTR [esi+100]", + "mov DWORD PTR [ebx+16], ecx", + "mov eax, ebx", + "add eax, 20", + "mov ecx, 1", "push ebp", - "push edx", "push ecx", "push eax", "push ebx", - "call {vg_sha1_finalize}", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "mov esi, DWORD PTR [esp+16]", - "mov ecx, 0", - "26:", - "mov eax, ebp", - "add eax, ecx", - "movzx edx, BYTE PTR [eax+280]", - "mov eax, esi", - "add eax, ecx", - "movzx ebx, BYTE PTR [eax]", - "xor edx, ebx", - "mov BYTE PTR [eax], dl", - "add ecx, 1", - "cmp ecx, 20", - "jne 26b", + "call {vg_sha1_compress}", + "pop eax", + "pop eax", + "pop eax", + "pop eax", + "mov eax, ebx", + "add eax, 20", + "mov ecx, DWORD PTR [ebx]", + "bswap ecx", + "mov DWORD PTR [eax], ecx", + "mov ecx, DWORD PTR [ebx+4]", + "bswap ecx", + "mov DWORD PTR [eax+4], ecx", + "mov ecx, DWORD PTR [ebx+8]", + "bswap ecx", + "mov DWORD PTR [eax+8], ecx", + "mov ecx, DWORD PTR [ebx+12]", + "bswap ecx", + "mov DWORD PTR [eax+12], ecx", + "mov ecx, DWORD PTR [ebx+16]", + "bswap ecx", + "mov DWORD PTR [eax+16], ecx", + "mov edx, DWORD PTR [esp+16]", + "mov ecx, DWORD PTR [ebx+20]", + "xor ecx, DWORD PTR [edx]", + "mov DWORD PTR [edx], ecx", + "mov ecx, DWORD PTR [ebx+24]", + "xor ecx, DWORD PTR [edx+4]", + "mov DWORD PTR [edx+4], ecx", + "mov ecx, DWORD PTR [ebx+28]", + "xor ecx, DWORD PTR [edx+8]", + "mov DWORD PTR [edx+8], ecx", + "mov ecx, DWORD PTR [ebx+32]", + "xor ecx, DWORD PTR [edx+12]", + "mov DWORD PTR [edx+12], ecx", + "mov ecx, DWORD PTR [ebx+36]", + "xor ecx, DWORD PTR [edx+16]", + "mov DWORD PTR [edx+16], ecx", "sub edi, 1", - "jne 23b", - "jmp 22f", + "jne 22b", + "jmp 21f", + "20:", "21:", - "22:", "mov eax, ebp", "mov ebx, DWORD PTR [eax+160]", "mov esi, DWORD PTR [eax+164]", "mov edi, DWORD PTR [eax+168]", "mov ebp, DWORD PTR [eax+172]", "ret", - vg_sha1_update = sym super::sha1::vg_sha1_update, - vg_sha1_finalize = sym super::sha1::vg_sha1_finalize, + vg_sha1_compress = sym super::sha1::vg_sha1_compress, ) } diff --git a/src/asm/x86/pbkdf2_sha384.rs b/src/asm/x86/pbkdf2_sha384.rs index 99154f383..b93aab365 100644 --- a/src/asm/x86/pbkdf2_sha384.rs +++ b/src/asm/x86/pbkdf2_sha384.rs @@ -26,147 +26,331 @@ pub(crate) unsafe extern "C" fn vg_pbkdf2_hmac_sha384_iterate(key: *const [u8; 3 "mov DWORD PTR [eax+280], edi", "mov DWORD PTR [eax+284], ebp", "mov ebp, eax", - "mov edi, DWORD PTR [esp+12]", - "mov esi, DWORD PTR [esp+8]", - "mov ecx, 0", - "20:", - "mov eax, esi", - "add eax, ecx", - "movzx edx, BYTE PTR [eax]", - "mov eax, ebp", - "add eax, ecx", - "mov BYTE PTR [eax+544], dl", - "add ecx, 1", - "cmp ecx, 48", - "jne 20b", - "test edi, edi", - "je 21f", - "23:", "mov esi, DWORD PTR [esp+4]", - "mov ecx, 0", - "24:", - "mov eax, esi", - "add eax, ecx", - "movzx edx, BYTE PTR [eax]", - "mov eax, ebp", - "add eax, ecx", - "mov BYTE PTR [eax+288], dl", - "add ecx, 1", - "cmp ecx, 192", - "jne 24b", - "mov ebx, ebp", - "add ebx, 288", - "mov eax, 0", - "mov esi, 128", - "mov ecx, 48", - "mov edx, ebp", - "add edx, 544", - "push ebp", - "push ecx", - "push edx", - "push eax", - "push esi", - "push ebx", - "call {vg_sha512_update}", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "pop eax", + "mov edi, DWORD PTR [esp+12]", "mov ebx, ebp", "add ebx, 288", - "mov eax, 176", + "mov edx, DWORD PTR [esp+8]", + "mov ecx, DWORD PTR [edx]", + "mov DWORD PTR [ebx+64], ecx", + "mov ecx, DWORD PTR [edx+4]", + "mov DWORD PTR [ebx+68], ecx", + "mov ecx, DWORD PTR [edx+8]", + "mov DWORD PTR [ebx+72], ecx", + "mov ecx, DWORD PTR [edx+12]", + "mov DWORD PTR [ebx+76], ecx", + "mov ecx, DWORD PTR [edx+16]", + "mov DWORD PTR [ebx+80], ecx", + "mov ecx, DWORD PTR [edx+20]", + "mov DWORD PTR [ebx+84], ecx", + "mov ecx, DWORD PTR [edx+24]", + "mov DWORD PTR [ebx+88], ecx", + "mov ecx, DWORD PTR [edx+28]", + "mov DWORD PTR [ebx+92], ecx", + "mov ecx, DWORD PTR [edx+32]", + "mov DWORD PTR [ebx+96], ecx", + "mov ecx, DWORD PTR [edx+36]", + "mov DWORD PTR [ebx+100], ecx", + "mov ecx, DWORD PTR [edx+40]", + "mov DWORD PTR [ebx+104], ecx", + "mov ecx, DWORD PTR [edx+44]", + "mov DWORD PTR [ebx+108], ecx", + "mov ecx, 128", + "mov DWORD PTR [ebx+112], ecx", "mov ecx, 0", - "mov edx, ebp", - "add edx, 480", - "push ebp", - "push edx", - "push ecx", - "push eax", - "push ebx", - "call {vg_sha512_finalize}", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "mov esi, DWORD PTR [esp+4]", + "mov DWORD PTR [ebx+116], ecx", "mov ecx, 0", - "25:", - "mov eax, esi", - "add eax, ecx", - "movzx edx, BYTE PTR [eax+192]", - "mov eax, ebp", - "add eax, ecx", - "mov BYTE PTR [eax+288], dl", - "add ecx, 1", - "cmp ecx, 192", - "jne 25b", - "mov ebx, ebp", - "add ebx, 288", - "mov eax, 0", - "mov esi, 128", - "mov ecx, 48", - "mov edx, ebp", - "add edx, 480", + "mov DWORD PTR [ebx+120], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+124], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+128], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+132], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+136], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+140], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+144], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+148], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+152], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+156], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+160], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+164], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+168], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+172], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+176], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+180], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+184], ecx", + "mov ecx, -2147155968", + "mov DWORD PTR [ebx+188], ecx", + "test edi, edi", + "je 20f", + "22:", + "mov ecx, DWORD PTR [esi]", + "mov DWORD PTR [ebx], ecx", + "mov ecx, DWORD PTR [esi+4]", + "mov DWORD PTR [ebx+4], ecx", + "mov ecx, DWORD PTR [esi+8]", + "mov DWORD PTR [ebx+8], ecx", + "mov ecx, DWORD PTR [esi+12]", + "mov DWORD PTR [ebx+12], ecx", + "mov ecx, DWORD PTR [esi+16]", + "mov DWORD PTR [ebx+16], ecx", + "mov ecx, DWORD PTR [esi+20]", + "mov DWORD PTR [ebx+20], ecx", + "mov ecx, DWORD PTR [esi+24]", + "mov DWORD PTR [ebx+24], ecx", + "mov ecx, DWORD PTR [esi+28]", + "mov DWORD PTR [ebx+28], ecx", + "mov ecx, DWORD PTR [esi+32]", + "mov DWORD PTR [ebx+32], ecx", + "mov ecx, DWORD PTR [esi+36]", + "mov DWORD PTR [ebx+36], ecx", + "mov ecx, DWORD PTR [esi+40]", + "mov DWORD PTR [ebx+40], ecx", + "mov ecx, DWORD PTR [esi+44]", + "mov DWORD PTR [ebx+44], ecx", + "mov ecx, DWORD PTR [esi+48]", + "mov DWORD PTR [ebx+48], ecx", + "mov ecx, DWORD PTR [esi+52]", + "mov DWORD PTR [ebx+52], ecx", + "mov ecx, DWORD PTR [esi+56]", + "mov DWORD PTR [ebx+56], ecx", + "mov ecx, DWORD PTR [esi+60]", + "mov DWORD PTR [ebx+60], ecx", + "mov eax, ebx", + "add eax, 64", + "mov ecx, 1", "push ebp", "push ecx", - "push edx", "push eax", - "push esi", "push ebx", - "call {vg_sha512_update}", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "mov ebx, ebp", - "add ebx, 288", - "mov eax, 176", + "call {vg_sha512_compress}", + "pop eax", + "pop eax", + "pop eax", + "pop eax", + "mov eax, ebx", + "add eax, 64", + "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+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+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+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+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+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+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+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", "mov ecx, 0", - "mov edx, ebp", - "add edx, 544", + "mov DWORD PTR [ebx+116], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+120], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+124], ecx", + "mov ecx, DWORD PTR [esi+192]", + "mov DWORD PTR [ebx], ecx", + "mov ecx, DWORD PTR [esi+196]", + "mov DWORD PTR [ebx+4], ecx", + "mov ecx, DWORD PTR [esi+200]", + "mov DWORD PTR [ebx+8], ecx", + "mov ecx, DWORD PTR [esi+204]", + "mov DWORD PTR [ebx+12], ecx", + "mov ecx, DWORD PTR [esi+208]", + "mov DWORD PTR [ebx+16], ecx", + "mov ecx, DWORD PTR [esi+212]", + "mov DWORD PTR [ebx+20], ecx", + "mov ecx, DWORD PTR [esi+216]", + "mov DWORD PTR [ebx+24], ecx", + "mov ecx, DWORD PTR [esi+220]", + "mov DWORD PTR [ebx+28], ecx", + "mov ecx, DWORD PTR [esi+224]", + "mov DWORD PTR [ebx+32], ecx", + "mov ecx, DWORD PTR [esi+228]", + "mov DWORD PTR [ebx+36], ecx", + "mov ecx, DWORD PTR [esi+232]", + "mov DWORD PTR [ebx+40], ecx", + "mov ecx, DWORD PTR [esi+236]", + "mov DWORD PTR [ebx+44], ecx", + "mov ecx, DWORD PTR [esi+240]", + "mov DWORD PTR [ebx+48], ecx", + "mov ecx, DWORD PTR [esi+244]", + "mov DWORD PTR [ebx+52], ecx", + "mov ecx, DWORD PTR [esi+248]", + "mov DWORD PTR [ebx+56], ecx", + "mov ecx, DWORD PTR [esi+252]", + "mov DWORD PTR [ebx+60], ecx", + "mov eax, ebx", + "add eax, 64", + "mov ecx, 1", "push ebp", - "push edx", "push ecx", "push eax", "push ebx", - "call {vg_sha512_finalize}", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "mov esi, DWORD PTR [esp+16]", + "call {vg_sha512_compress}", + "pop eax", + "pop eax", + "pop eax", + "pop eax", + "mov eax, ebx", + "add eax, 64", + "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+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+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+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+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+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+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+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", "mov ecx, 0", - "26:", - "mov eax, ebp", - "add eax, ecx", - "movzx edx, BYTE PTR [eax+544]", - "mov eax, esi", - "add eax, ecx", - "movzx ebx, BYTE PTR [eax]", - "xor edx, ebx", - "mov BYTE PTR [eax], dl", - "add ecx, 1", - "cmp ecx, 48", - "jne 26b", + "mov DWORD PTR [ebx+116], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+120], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+124], ecx", + "mov edx, DWORD PTR [esp+16]", + "mov ecx, DWORD PTR [ebx+64]", + "xor ecx, DWORD PTR [edx]", + "mov DWORD PTR [edx], ecx", + "mov ecx, DWORD PTR [ebx+68]", + "xor ecx, DWORD PTR [edx+4]", + "mov DWORD PTR [edx+4], ecx", + "mov ecx, DWORD PTR [ebx+72]", + "xor ecx, DWORD PTR [edx+8]", + "mov DWORD PTR [edx+8], ecx", + "mov ecx, DWORD PTR [ebx+76]", + "xor ecx, DWORD PTR [edx+12]", + "mov DWORD PTR [edx+12], ecx", + "mov ecx, DWORD PTR [ebx+80]", + "xor ecx, DWORD PTR [edx+16]", + "mov DWORD PTR [edx+16], ecx", + "mov ecx, DWORD PTR [ebx+84]", + "xor ecx, DWORD PTR [edx+20]", + "mov DWORD PTR [edx+20], ecx", + "mov ecx, DWORD PTR [ebx+88]", + "xor ecx, DWORD PTR [edx+24]", + "mov DWORD PTR [edx+24], ecx", + "mov ecx, DWORD PTR [ebx+92]", + "xor ecx, DWORD PTR [edx+28]", + "mov DWORD PTR [edx+28], ecx", + "mov ecx, DWORD PTR [ebx+96]", + "xor ecx, DWORD PTR [edx+32]", + "mov DWORD PTR [edx+32], ecx", + "mov ecx, DWORD PTR [ebx+100]", + "xor ecx, DWORD PTR [edx+36]", + "mov DWORD PTR [edx+36], ecx", + "mov ecx, DWORD PTR [ebx+104]", + "xor ecx, DWORD PTR [edx+40]", + "mov DWORD PTR [edx+40], ecx", + "mov ecx, DWORD PTR [ebx+108]", + "xor ecx, DWORD PTR [edx+44]", + "mov DWORD PTR [edx+44], ecx", "sub edi, 1", - "jne 23b", - "jmp 22f", + "jne 22b", + "jmp 21f", + "20:", "21:", - "22:", "mov eax, ebp", "mov ebx, DWORD PTR [eax+272]", "mov esi, DWORD PTR [eax+276]", "mov edi, DWORD PTR [eax+280]", "mov ebp, DWORD PTR [eax+284]", "ret", - vg_sha512_update = sym super::sha512::vg_sha512_update, - vg_sha512_finalize = sym super::sha512::vg_sha512_finalize, + vg_sha512_compress = sym super::sha512::vg_sha512_compress, ) } diff --git a/src/asm/x86/pbkdf2_sha512.rs b/src/asm/x86/pbkdf2_sha512.rs index c29a75a0f..801075774 100644 --- a/src/asm/x86/pbkdf2_sha512.rs +++ b/src/asm/x86/pbkdf2_sha512.rs @@ -26,147 +26,327 @@ pub(crate) unsafe extern "C" fn vg_pbkdf2_hmac_sha512_iterate(key: *const [u8; 3 "mov DWORD PTR [eax+280], edi", "mov DWORD PTR [eax+284], ebp", "mov ebp, eax", - "mov edi, DWORD PTR [esp+12]", - "mov esi, DWORD PTR [esp+8]", - "mov ecx, 0", - "20:", - "mov eax, esi", - "add eax, ecx", - "movzx edx, BYTE PTR [eax]", - "mov eax, ebp", - "add eax, ecx", - "mov BYTE PTR [eax+544], dl", - "add ecx, 1", - "cmp ecx, 64", - "jne 20b", - "test edi, edi", - "je 21f", - "23:", "mov esi, DWORD PTR [esp+4]", - "mov ecx, 0", - "24:", - "mov eax, esi", - "add eax, ecx", - "movzx edx, BYTE PTR [eax]", - "mov eax, ebp", - "add eax, ecx", - "mov BYTE PTR [eax+288], dl", - "add ecx, 1", - "cmp ecx, 192", - "jne 24b", - "mov ebx, ebp", - "add ebx, 288", - "mov eax, 0", - "mov esi, 128", - "mov ecx, 64", - "mov edx, ebp", - "add edx, 544", - "push ebp", - "push ecx", - "push edx", - "push eax", - "push esi", - "push ebx", - "call {vg_sha512_update}", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "pop eax", + "mov edi, DWORD PTR [esp+12]", "mov ebx, ebp", "add ebx, 288", - "mov eax, 192", + "mov edx, DWORD PTR [esp+8]", + "mov ecx, DWORD PTR [edx]", + "mov DWORD PTR [ebx+64], ecx", + "mov ecx, DWORD PTR [edx+4]", + "mov DWORD PTR [ebx+68], ecx", + "mov ecx, DWORD PTR [edx+8]", + "mov DWORD PTR [ebx+72], ecx", + "mov ecx, DWORD PTR [edx+12]", + "mov DWORD PTR [ebx+76], ecx", + "mov ecx, DWORD PTR [edx+16]", + "mov DWORD PTR [ebx+80], ecx", + "mov ecx, DWORD PTR [edx+20]", + "mov DWORD PTR [ebx+84], ecx", + "mov ecx, DWORD PTR [edx+24]", + "mov DWORD PTR [ebx+88], ecx", + "mov ecx, DWORD PTR [edx+28]", + "mov DWORD PTR [ebx+92], ecx", + "mov ecx, DWORD PTR [edx+32]", + "mov DWORD PTR [ebx+96], ecx", + "mov ecx, DWORD PTR [edx+36]", + "mov DWORD PTR [ebx+100], ecx", + "mov ecx, DWORD PTR [edx+40]", + "mov DWORD PTR [ebx+104], ecx", + "mov ecx, DWORD PTR [edx+44]", + "mov DWORD PTR [ebx+108], ecx", + "mov ecx, DWORD PTR [edx+48]", + "mov DWORD PTR [ebx+112], ecx", + "mov ecx, DWORD PTR [edx+52]", + "mov DWORD PTR [ebx+116], ecx", + "mov ecx, DWORD PTR [edx+56]", + "mov DWORD PTR [ebx+120], ecx", + "mov ecx, DWORD PTR [edx+60]", + "mov DWORD PTR [ebx+124], ecx", + "mov ecx, 128", + "mov DWORD PTR [ebx+128], ecx", "mov ecx, 0", - "mov edx, ebp", - "add edx, 480", - "push ebp", - "push edx", - "push ecx", - "push eax", - "push ebx", - "call {vg_sha512_finalize}", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "mov esi, DWORD PTR [esp+4]", + "mov DWORD PTR [ebx+132], ecx", "mov ecx, 0", - "25:", - "mov eax, esi", - "add eax, ecx", - "movzx edx, BYTE PTR [eax+192]", - "mov eax, ebp", - "add eax, ecx", - "mov BYTE PTR [eax+288], dl", - "add ecx, 1", - "cmp ecx, 192", - "jne 25b", - "mov ebx, ebp", - "add ebx, 288", - "mov eax, 0", - "mov esi, 128", - "mov ecx, 64", - "mov edx, ebp", - "add edx, 480", + "mov DWORD PTR [ebx+136], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+140], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+144], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+148], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+152], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+156], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+160], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+164], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+168], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+172], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+176], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+180], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+184], ecx", + "mov ecx, 393216", + "mov DWORD PTR [ebx+188], ecx", + "test edi, edi", + "je 20f", + "22:", + "mov ecx, DWORD PTR [esi]", + "mov DWORD PTR [ebx], ecx", + "mov ecx, DWORD PTR [esi+4]", + "mov DWORD PTR [ebx+4], ecx", + "mov ecx, DWORD PTR [esi+8]", + "mov DWORD PTR [ebx+8], ecx", + "mov ecx, DWORD PTR [esi+12]", + "mov DWORD PTR [ebx+12], ecx", + "mov ecx, DWORD PTR [esi+16]", + "mov DWORD PTR [ebx+16], ecx", + "mov ecx, DWORD PTR [esi+20]", + "mov DWORD PTR [ebx+20], ecx", + "mov ecx, DWORD PTR [esi+24]", + "mov DWORD PTR [ebx+24], ecx", + "mov ecx, DWORD PTR [esi+28]", + "mov DWORD PTR [ebx+28], ecx", + "mov ecx, DWORD PTR [esi+32]", + "mov DWORD PTR [ebx+32], ecx", + "mov ecx, DWORD PTR [esi+36]", + "mov DWORD PTR [ebx+36], ecx", + "mov ecx, DWORD PTR [esi+40]", + "mov DWORD PTR [ebx+40], ecx", + "mov ecx, DWORD PTR [esi+44]", + "mov DWORD PTR [ebx+44], ecx", + "mov ecx, DWORD PTR [esi+48]", + "mov DWORD PTR [ebx+48], ecx", + "mov ecx, DWORD PTR [esi+52]", + "mov DWORD PTR [ebx+52], ecx", + "mov ecx, DWORD PTR [esi+56]", + "mov DWORD PTR [ebx+56], ecx", + "mov ecx, DWORD PTR [esi+60]", + "mov DWORD PTR [ebx+60], ecx", + "mov eax, ebx", + "add eax, 64", + "mov ecx, 1", "push ebp", "push ecx", - "push edx", "push eax", - "push esi", "push ebx", - "call {vg_sha512_update}", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "mov ebx, ebp", - "add ebx, 288", - "mov eax, 192", - "mov ecx, 0", - "mov edx, ebp", - "add edx, 544", + "call {vg_sha512_compress}", + "pop eax", + "pop eax", + "pop eax", + "pop eax", + "mov eax, ebx", + "add eax, 64", + "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+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+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+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+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+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+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+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", + "mov ecx, DWORD PTR [esi+196]", + "mov DWORD PTR [ebx+4], ecx", + "mov ecx, DWORD PTR [esi+200]", + "mov DWORD PTR [ebx+8], ecx", + "mov ecx, DWORD PTR [esi+204]", + "mov DWORD PTR [ebx+12], ecx", + "mov ecx, DWORD PTR [esi+208]", + "mov DWORD PTR [ebx+16], ecx", + "mov ecx, DWORD PTR [esi+212]", + "mov DWORD PTR [ebx+20], ecx", + "mov ecx, DWORD PTR [esi+216]", + "mov DWORD PTR [ebx+24], ecx", + "mov ecx, DWORD PTR [esi+220]", + "mov DWORD PTR [ebx+28], ecx", + "mov ecx, DWORD PTR [esi+224]", + "mov DWORD PTR [ebx+32], ecx", + "mov ecx, DWORD PTR [esi+228]", + "mov DWORD PTR [ebx+36], ecx", + "mov ecx, DWORD PTR [esi+232]", + "mov DWORD PTR [ebx+40], ecx", + "mov ecx, DWORD PTR [esi+236]", + "mov DWORD PTR [ebx+44], ecx", + "mov ecx, DWORD PTR [esi+240]", + "mov DWORD PTR [ebx+48], ecx", + "mov ecx, DWORD PTR [esi+244]", + "mov DWORD PTR [ebx+52], ecx", + "mov ecx, DWORD PTR [esi+248]", + "mov DWORD PTR [ebx+56], ecx", + "mov ecx, DWORD PTR [esi+252]", + "mov DWORD PTR [ebx+60], ecx", + "mov eax, ebx", + "add eax, 64", + "mov ecx, 1", "push ebp", - "push edx", "push ecx", "push eax", "push ebx", - "call {vg_sha512_finalize}", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "mov esi, DWORD PTR [esp+16]", - "mov ecx, 0", - "26:", - "mov eax, ebp", - "add eax, ecx", - "movzx edx, BYTE PTR [eax+544]", - "mov eax, esi", - "add eax, ecx", - "movzx ebx, BYTE PTR [eax]", - "xor edx, ebx", - "mov BYTE PTR [eax], dl", - "add ecx, 1", - "cmp ecx, 64", - "jne 26b", + "call {vg_sha512_compress}", + "pop eax", + "pop eax", + "pop eax", + "pop eax", + "mov eax, ebx", + "add eax, 64", + "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+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+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+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+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+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+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+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]", + "xor ecx, DWORD PTR [edx]", + "mov DWORD PTR [edx], ecx", + "mov ecx, DWORD PTR [ebx+68]", + "xor ecx, DWORD PTR [edx+4]", + "mov DWORD PTR [edx+4], ecx", + "mov ecx, DWORD PTR [ebx+72]", + "xor ecx, DWORD PTR [edx+8]", + "mov DWORD PTR [edx+8], ecx", + "mov ecx, DWORD PTR [ebx+76]", + "xor ecx, DWORD PTR [edx+12]", + "mov DWORD PTR [edx+12], ecx", + "mov ecx, DWORD PTR [ebx+80]", + "xor ecx, DWORD PTR [edx+16]", + "mov DWORD PTR [edx+16], ecx", + "mov ecx, DWORD PTR [ebx+84]", + "xor ecx, DWORD PTR [edx+20]", + "mov DWORD PTR [edx+20], ecx", + "mov ecx, DWORD PTR [ebx+88]", + "xor ecx, DWORD PTR [edx+24]", + "mov DWORD PTR [edx+24], ecx", + "mov ecx, DWORD PTR [ebx+92]", + "xor ecx, DWORD PTR [edx+28]", + "mov DWORD PTR [edx+28], ecx", + "mov ecx, DWORD PTR [ebx+96]", + "xor ecx, DWORD PTR [edx+32]", + "mov DWORD PTR [edx+32], ecx", + "mov ecx, DWORD PTR [ebx+100]", + "xor ecx, DWORD PTR [edx+36]", + "mov DWORD PTR [edx+36], ecx", + "mov ecx, DWORD PTR [ebx+104]", + "xor ecx, DWORD PTR [edx+40]", + "mov DWORD PTR [edx+40], ecx", + "mov ecx, DWORD PTR [ebx+108]", + "xor ecx, DWORD PTR [edx+44]", + "mov DWORD PTR [edx+44], ecx", + "mov ecx, DWORD PTR [ebx+112]", + "xor ecx, DWORD PTR [edx+48]", + "mov DWORD PTR [edx+48], ecx", + "mov ecx, DWORD PTR [ebx+116]", + "xor ecx, DWORD PTR [edx+52]", + "mov DWORD PTR [edx+52], ecx", + "mov ecx, DWORD PTR [ebx+120]", + "xor ecx, DWORD PTR [edx+56]", + "mov DWORD PTR [edx+56], ecx", + "mov ecx, DWORD PTR [ebx+124]", + "xor ecx, DWORD PTR [edx+60]", + "mov DWORD PTR [edx+60], ecx", "sub edi, 1", - "jne 23b", - "jmp 22f", + "jne 22b", + "jmp 21f", + "20:", "21:", - "22:", "mov eax, ebp", "mov ebx, DWORD PTR [eax+272]", "mov esi, DWORD PTR [eax+276]", "mov edi, DWORD PTR [eax+280]", "mov ebp, DWORD PTR [eax+284]", "ret", - vg_sha512_update = sym super::sha512::vg_sha512_update, - vg_sha512_finalize = sym super::sha512::vg_sha512_finalize, + vg_sha512_compress = sym super::sha512::vg_sha512_compress, ) } diff --git a/src/asm/x86/pbkdf2_sha512_224.rs b/src/asm/x86/pbkdf2_sha512_224.rs index 75e521917..2c18d7d16 100644 --- a/src/asm/x86/pbkdf2_sha512_224.rs +++ b/src/asm/x86/pbkdf2_sha512_224.rs @@ -26,147 +26,336 @@ pub(crate) unsafe extern "C" fn vg_pbkdf2_hmac_sha512_224_iterate(key: *const [u "mov DWORD PTR [eax+280], edi", "mov DWORD PTR [eax+284], ebp", "mov ebp, eax", - "mov edi, DWORD PTR [esp+12]", - "mov esi, DWORD PTR [esp+8]", - "mov ecx, 0", - "20:", - "mov eax, esi", - "add eax, ecx", - "movzx edx, BYTE PTR [eax]", - "mov eax, ebp", - "add eax, ecx", - "mov BYTE PTR [eax+544], dl", - "add ecx, 1", - "cmp ecx, 28", - "jne 20b", - "test edi, edi", - "je 21f", - "23:", "mov esi, DWORD PTR [esp+4]", - "mov ecx, 0", - "24:", - "mov eax, esi", - "add eax, ecx", - "movzx edx, BYTE PTR [eax]", - "mov eax, ebp", - "add eax, ecx", - "mov BYTE PTR [eax+288], dl", - "add ecx, 1", - "cmp ecx, 192", - "jne 24b", - "mov ebx, ebp", - "add ebx, 288", - "mov eax, 0", - "mov esi, 128", - "mov ecx, 28", - "mov edx, ebp", - "add edx, 544", - "push ebp", - "push ecx", - "push edx", - "push eax", - "push esi", - "push ebx", - "call {vg_sha512_update}", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "pop eax", + "mov edi, DWORD PTR [esp+12]", "mov ebx, ebp", "add ebx, 288", - "mov eax, 156", + "mov edx, DWORD PTR [esp+8]", + "mov ecx, DWORD PTR [edx]", + "mov DWORD PTR [ebx+64], ecx", + "mov ecx, DWORD PTR [edx+4]", + "mov DWORD PTR [ebx+68], ecx", + "mov ecx, DWORD PTR [edx+8]", + "mov DWORD PTR [ebx+72], ecx", + "mov ecx, DWORD PTR [edx+12]", + "mov DWORD PTR [ebx+76], ecx", + "mov ecx, DWORD PTR [edx+16]", + "mov DWORD PTR [ebx+80], ecx", + "mov ecx, DWORD PTR [edx+20]", + "mov DWORD PTR [ebx+84], ecx", + "mov ecx, DWORD PTR [edx+24]", + "mov DWORD PTR [ebx+88], ecx", + "mov ecx, 128", + "mov DWORD PTR [ebx+92], ecx", "mov ecx, 0", - "mov edx, ebp", - "add edx, 480", - "push ebp", - "push edx", - "push ecx", - "push eax", - "push ebx", - "call {vg_sha512_finalize}", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "mov esi, DWORD PTR [esp+4]", + "mov DWORD PTR [ebx+96], ecx", "mov ecx, 0", - "25:", - "mov eax, esi", - "add eax, ecx", - "movzx edx, BYTE PTR [eax+192]", - "mov eax, ebp", - "add eax, ecx", - "mov BYTE PTR [eax+288], dl", - "add ecx, 1", - "cmp ecx, 192", - "jne 25b", - "mov ebx, ebp", - "add ebx, 288", - "mov eax, 0", - "mov esi, 128", - "mov ecx, 28", - "mov edx, ebp", - "add edx, 480", + "mov DWORD PTR [ebx+100], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+104], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+108], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+112], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+116], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+120], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+124], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+128], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+132], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+136], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+140], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+144], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+148], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+152], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+156], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+160], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+164], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+168], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+172], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+176], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+180], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+184], ecx", + "mov ecx, -536608768", + "mov DWORD PTR [ebx+188], ecx", + "test edi, edi", + "je 20f", + "22:", + "mov ecx, DWORD PTR [esi]", + "mov DWORD PTR [ebx], ecx", + "mov ecx, DWORD PTR [esi+4]", + "mov DWORD PTR [ebx+4], ecx", + "mov ecx, DWORD PTR [esi+8]", + "mov DWORD PTR [ebx+8], ecx", + "mov ecx, DWORD PTR [esi+12]", + "mov DWORD PTR [ebx+12], ecx", + "mov ecx, DWORD PTR [esi+16]", + "mov DWORD PTR [ebx+16], ecx", + "mov ecx, DWORD PTR [esi+20]", + "mov DWORD PTR [ebx+20], ecx", + "mov ecx, DWORD PTR [esi+24]", + "mov DWORD PTR [ebx+24], ecx", + "mov ecx, DWORD PTR [esi+28]", + "mov DWORD PTR [ebx+28], ecx", + "mov ecx, DWORD PTR [esi+32]", + "mov DWORD PTR [ebx+32], ecx", + "mov ecx, DWORD PTR [esi+36]", + "mov DWORD PTR [ebx+36], ecx", + "mov ecx, DWORD PTR [esi+40]", + "mov DWORD PTR [ebx+40], ecx", + "mov ecx, DWORD PTR [esi+44]", + "mov DWORD PTR [ebx+44], ecx", + "mov ecx, DWORD PTR [esi+48]", + "mov DWORD PTR [ebx+48], ecx", + "mov ecx, DWORD PTR [esi+52]", + "mov DWORD PTR [ebx+52], ecx", + "mov ecx, DWORD PTR [esi+56]", + "mov DWORD PTR [ebx+56], ecx", + "mov ecx, DWORD PTR [esi+60]", + "mov DWORD PTR [ebx+60], ecx", + "mov eax, ebx", + "add eax, 64", + "mov ecx, 1", "push ebp", "push ecx", - "push edx", "push eax", - "push esi", "push ebx", - "call {vg_sha512_update}", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "mov ebx, ebp", - "add ebx, 288", - "mov eax, 156", + "call {vg_sha512_compress}", + "pop eax", + "pop eax", + "pop eax", + "pop eax", + "mov eax, ebx", + "add eax, 64", + "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+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+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+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+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+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+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+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", "mov ecx, 0", - "mov edx, ebp", - "add edx, 544", + "mov DWORD PTR [ebx+96], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+100], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+104], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+108], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+112], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+116], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+120], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+124], ecx", + "mov ecx, DWORD PTR [esi+192]", + "mov DWORD PTR [ebx], ecx", + "mov ecx, DWORD PTR [esi+196]", + "mov DWORD PTR [ebx+4], ecx", + "mov ecx, DWORD PTR [esi+200]", + "mov DWORD PTR [ebx+8], ecx", + "mov ecx, DWORD PTR [esi+204]", + "mov DWORD PTR [ebx+12], ecx", + "mov ecx, DWORD PTR [esi+208]", + "mov DWORD PTR [ebx+16], ecx", + "mov ecx, DWORD PTR [esi+212]", + "mov DWORD PTR [ebx+20], ecx", + "mov ecx, DWORD PTR [esi+216]", + "mov DWORD PTR [ebx+24], ecx", + "mov ecx, DWORD PTR [esi+220]", + "mov DWORD PTR [ebx+28], ecx", + "mov ecx, DWORD PTR [esi+224]", + "mov DWORD PTR [ebx+32], ecx", + "mov ecx, DWORD PTR [esi+228]", + "mov DWORD PTR [ebx+36], ecx", + "mov ecx, DWORD PTR [esi+232]", + "mov DWORD PTR [ebx+40], ecx", + "mov ecx, DWORD PTR [esi+236]", + "mov DWORD PTR [ebx+44], ecx", + "mov ecx, DWORD PTR [esi+240]", + "mov DWORD PTR [ebx+48], ecx", + "mov ecx, DWORD PTR [esi+244]", + "mov DWORD PTR [ebx+52], ecx", + "mov ecx, DWORD PTR [esi+248]", + "mov DWORD PTR [ebx+56], ecx", + "mov ecx, DWORD PTR [esi+252]", + "mov DWORD PTR [ebx+60], ecx", + "mov eax, ebx", + "add eax, 64", + "mov ecx, 1", "push ebp", - "push edx", "push ecx", "push eax", "push ebx", - "call {vg_sha512_finalize}", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "mov esi, DWORD PTR [esp+16]", + "call {vg_sha512_compress}", + "pop eax", + "pop eax", + "pop eax", + "pop eax", + "mov eax, ebx", + "add eax, 64", + "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+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+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+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+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+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+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+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", "mov ecx, 0", - "26:", - "mov eax, ebp", - "add eax, ecx", - "movzx edx, BYTE PTR [eax+544]", - "mov eax, esi", - "add eax, ecx", - "movzx ebx, BYTE PTR [eax]", - "xor edx, ebx", - "mov BYTE PTR [eax], dl", - "add ecx, 1", - "cmp ecx, 28", - "jne 26b", + "mov DWORD PTR [ebx+96], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+100], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+104], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+108], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+112], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+116], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+120], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+124], ecx", + "mov edx, DWORD PTR [esp+16]", + "mov ecx, DWORD PTR [ebx+64]", + "xor ecx, DWORD PTR [edx]", + "mov DWORD PTR [edx], ecx", + "mov ecx, DWORD PTR [ebx+68]", + "xor ecx, DWORD PTR [edx+4]", + "mov DWORD PTR [edx+4], ecx", + "mov ecx, DWORD PTR [ebx+72]", + "xor ecx, DWORD PTR [edx+8]", + "mov DWORD PTR [edx+8], ecx", + "mov ecx, DWORD PTR [ebx+76]", + "xor ecx, DWORD PTR [edx+12]", + "mov DWORD PTR [edx+12], ecx", + "mov ecx, DWORD PTR [ebx+80]", + "xor ecx, DWORD PTR [edx+16]", + "mov DWORD PTR [edx+16], ecx", + "mov ecx, DWORD PTR [ebx+84]", + "xor ecx, DWORD PTR [edx+20]", + "mov DWORD PTR [edx+20], ecx", + "mov ecx, DWORD PTR [ebx+88]", + "xor ecx, DWORD PTR [edx+24]", + "mov DWORD PTR [edx+24], ecx", "sub edi, 1", - "jne 23b", - "jmp 22f", + "jne 22b", + "jmp 21f", + "20:", "21:", - "22:", "mov eax, ebp", "mov ebx, DWORD PTR [eax+272]", "mov esi, DWORD PTR [eax+276]", "mov edi, DWORD PTR [eax+280]", "mov ebp, DWORD PTR [eax+284]", "ret", - vg_sha512_update = sym super::sha512::vg_sha512_update, - vg_sha512_finalize = sym super::sha512::vg_sha512_finalize, + vg_sha512_compress = sym super::sha512::vg_sha512_compress, ) } diff --git a/src/asm/x86/pbkdf2_sha512_256.rs b/src/asm/x86/pbkdf2_sha512_256.rs index 8d16eafd7..ff4cf20a8 100644 --- a/src/asm/x86/pbkdf2_sha512_256.rs +++ b/src/asm/x86/pbkdf2_sha512_256.rs @@ -26,147 +26,335 @@ pub(crate) unsafe extern "C" fn vg_pbkdf2_hmac_sha512_256_iterate(key: *const [u "mov DWORD PTR [eax+280], edi", "mov DWORD PTR [eax+284], ebp", "mov ebp, eax", - "mov edi, DWORD PTR [esp+12]", - "mov esi, DWORD PTR [esp+8]", - "mov ecx, 0", - "20:", - "mov eax, esi", - "add eax, ecx", - "movzx edx, BYTE PTR [eax]", - "mov eax, ebp", - "add eax, ecx", - "mov BYTE PTR [eax+544], dl", - "add ecx, 1", - "cmp ecx, 32", - "jne 20b", - "test edi, edi", - "je 21f", - "23:", "mov esi, DWORD PTR [esp+4]", - "mov ecx, 0", - "24:", - "mov eax, esi", - "add eax, ecx", - "movzx edx, BYTE PTR [eax]", - "mov eax, ebp", - "add eax, ecx", - "mov BYTE PTR [eax+288], dl", - "add ecx, 1", - "cmp ecx, 192", - "jne 24b", - "mov ebx, ebp", - "add ebx, 288", - "mov eax, 0", - "mov esi, 128", - "mov ecx, 32", - "mov edx, ebp", - "add edx, 544", - "push ebp", - "push ecx", - "push edx", - "push eax", - "push esi", - "push ebx", - "call {vg_sha512_update}", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "pop eax", + "mov edi, DWORD PTR [esp+12]", "mov ebx, ebp", "add ebx, 288", - "mov eax, 160", + "mov edx, DWORD PTR [esp+8]", + "mov ecx, DWORD PTR [edx]", + "mov DWORD PTR [ebx+64], ecx", + "mov ecx, DWORD PTR [edx+4]", + "mov DWORD PTR [ebx+68], ecx", + "mov ecx, DWORD PTR [edx+8]", + "mov DWORD PTR [ebx+72], ecx", + "mov ecx, DWORD PTR [edx+12]", + "mov DWORD PTR [ebx+76], ecx", + "mov ecx, DWORD PTR [edx+16]", + "mov DWORD PTR [ebx+80], ecx", + "mov ecx, DWORD PTR [edx+20]", + "mov DWORD PTR [ebx+84], ecx", + "mov ecx, DWORD PTR [edx+24]", + "mov DWORD PTR [ebx+88], ecx", + "mov ecx, DWORD PTR [edx+28]", + "mov DWORD PTR [ebx+92], ecx", + "mov ecx, 128", + "mov DWORD PTR [ebx+96], ecx", "mov ecx, 0", - "mov edx, ebp", - "add edx, 480", - "push ebp", - "push edx", - "push ecx", - "push eax", - "push ebx", - "call {vg_sha512_finalize}", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "mov esi, DWORD PTR [esp+4]", + "mov DWORD PTR [ebx+100], ecx", "mov ecx, 0", - "25:", - "mov eax, esi", - "add eax, ecx", - "movzx edx, BYTE PTR [eax+192]", - "mov eax, ebp", - "add eax, ecx", - "mov BYTE PTR [eax+288], dl", - "add ecx, 1", - "cmp ecx, 192", - "jne 25b", - "mov ebx, ebp", - "add ebx, 288", - "mov eax, 0", - "mov esi, 128", - "mov ecx, 32", - "mov edx, ebp", - "add edx, 480", + "mov DWORD PTR [ebx+104], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+108], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+112], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+116], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+120], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+124], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+128], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+132], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+136], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+140], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+144], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+148], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+152], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+156], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+160], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+164], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+168], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+172], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+176], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+180], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+184], ecx", + "mov ecx, 327680", + "mov DWORD PTR [ebx+188], ecx", + "test edi, edi", + "je 20f", + "22:", + "mov ecx, DWORD PTR [esi]", + "mov DWORD PTR [ebx], ecx", + "mov ecx, DWORD PTR [esi+4]", + "mov DWORD PTR [ebx+4], ecx", + "mov ecx, DWORD PTR [esi+8]", + "mov DWORD PTR [ebx+8], ecx", + "mov ecx, DWORD PTR [esi+12]", + "mov DWORD PTR [ebx+12], ecx", + "mov ecx, DWORD PTR [esi+16]", + "mov DWORD PTR [ebx+16], ecx", + "mov ecx, DWORD PTR [esi+20]", + "mov DWORD PTR [ebx+20], ecx", + "mov ecx, DWORD PTR [esi+24]", + "mov DWORD PTR [ebx+24], ecx", + "mov ecx, DWORD PTR [esi+28]", + "mov DWORD PTR [ebx+28], ecx", + "mov ecx, DWORD PTR [esi+32]", + "mov DWORD PTR [ebx+32], ecx", + "mov ecx, DWORD PTR [esi+36]", + "mov DWORD PTR [ebx+36], ecx", + "mov ecx, DWORD PTR [esi+40]", + "mov DWORD PTR [ebx+40], ecx", + "mov ecx, DWORD PTR [esi+44]", + "mov DWORD PTR [ebx+44], ecx", + "mov ecx, DWORD PTR [esi+48]", + "mov DWORD PTR [ebx+48], ecx", + "mov ecx, DWORD PTR [esi+52]", + "mov DWORD PTR [ebx+52], ecx", + "mov ecx, DWORD PTR [esi+56]", + "mov DWORD PTR [ebx+56], ecx", + "mov ecx, DWORD PTR [esi+60]", + "mov DWORD PTR [ebx+60], ecx", + "mov eax, ebx", + "add eax, 64", + "mov ecx, 1", "push ebp", "push ecx", - "push edx", "push eax", - "push esi", "push ebx", - "call {vg_sha512_update}", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "mov ebx, ebp", - "add ebx, 288", - "mov eax, 160", + "call {vg_sha512_compress}", + "pop eax", + "pop eax", + "pop eax", + "pop eax", + "mov eax, ebx", + "add eax, 64", + "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+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+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+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+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+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+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+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", "mov ecx, 0", - "mov edx, ebp", - "add edx, 544", + "mov DWORD PTR [ebx+100], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+104], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+108], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+112], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+116], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+120], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+124], ecx", + "mov ecx, DWORD PTR [esi+192]", + "mov DWORD PTR [ebx], ecx", + "mov ecx, DWORD PTR [esi+196]", + "mov DWORD PTR [ebx+4], ecx", + "mov ecx, DWORD PTR [esi+200]", + "mov DWORD PTR [ebx+8], ecx", + "mov ecx, DWORD PTR [esi+204]", + "mov DWORD PTR [ebx+12], ecx", + "mov ecx, DWORD PTR [esi+208]", + "mov DWORD PTR [ebx+16], ecx", + "mov ecx, DWORD PTR [esi+212]", + "mov DWORD PTR [ebx+20], ecx", + "mov ecx, DWORD PTR [esi+216]", + "mov DWORD PTR [ebx+24], ecx", + "mov ecx, DWORD PTR [esi+220]", + "mov DWORD PTR [ebx+28], ecx", + "mov ecx, DWORD PTR [esi+224]", + "mov DWORD PTR [ebx+32], ecx", + "mov ecx, DWORD PTR [esi+228]", + "mov DWORD PTR [ebx+36], ecx", + "mov ecx, DWORD PTR [esi+232]", + "mov DWORD PTR [ebx+40], ecx", + "mov ecx, DWORD PTR [esi+236]", + "mov DWORD PTR [ebx+44], ecx", + "mov ecx, DWORD PTR [esi+240]", + "mov DWORD PTR [ebx+48], ecx", + "mov ecx, DWORD PTR [esi+244]", + "mov DWORD PTR [ebx+52], ecx", + "mov ecx, DWORD PTR [esi+248]", + "mov DWORD PTR [ebx+56], ecx", + "mov ecx, DWORD PTR [esi+252]", + "mov DWORD PTR [ebx+60], ecx", + "mov eax, ebx", + "add eax, 64", + "mov ecx, 1", "push ebp", - "push edx", "push ecx", "push eax", "push ebx", - "call {vg_sha512_finalize}", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "pop eax", - "mov esi, DWORD PTR [esp+16]", + "call {vg_sha512_compress}", + "pop eax", + "pop eax", + "pop eax", + "pop eax", + "mov eax, ebx", + "add eax, 64", + "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+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+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+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+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+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+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+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", "mov ecx, 0", - "26:", - "mov eax, ebp", - "add eax, ecx", - "movzx edx, BYTE PTR [eax+544]", - "mov eax, esi", - "add eax, ecx", - "movzx ebx, BYTE PTR [eax]", - "xor edx, ebx", - "mov BYTE PTR [eax], dl", - "add ecx, 1", - "cmp ecx, 32", - "jne 26b", + "mov DWORD PTR [ebx+100], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+104], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+108], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+112], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+116], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+120], ecx", + "mov ecx, 0", + "mov DWORD PTR [ebx+124], ecx", + "mov edx, DWORD PTR [esp+16]", + "mov ecx, DWORD PTR [ebx+64]", + "xor ecx, DWORD PTR [edx]", + "mov DWORD PTR [edx], ecx", + "mov ecx, DWORD PTR [ebx+68]", + "xor ecx, DWORD PTR [edx+4]", + "mov DWORD PTR [edx+4], ecx", + "mov ecx, DWORD PTR [ebx+72]", + "xor ecx, DWORD PTR [edx+8]", + "mov DWORD PTR [edx+8], ecx", + "mov ecx, DWORD PTR [ebx+76]", + "xor ecx, DWORD PTR [edx+12]", + "mov DWORD PTR [edx+12], ecx", + "mov ecx, DWORD PTR [ebx+80]", + "xor ecx, DWORD PTR [edx+16]", + "mov DWORD PTR [edx+16], ecx", + "mov ecx, DWORD PTR [ebx+84]", + "xor ecx, DWORD PTR [edx+20]", + "mov DWORD PTR [edx+20], ecx", + "mov ecx, DWORD PTR [ebx+88]", + "xor ecx, DWORD PTR [edx+24]", + "mov DWORD PTR [edx+24], ecx", + "mov ecx, DWORD PTR [ebx+92]", + "xor ecx, DWORD PTR [edx+28]", + "mov DWORD PTR [edx+28], ecx", "sub edi, 1", - "jne 23b", - "jmp 22f", + "jne 22b", + "jmp 21f", + "20:", "21:", - "22:", "mov eax, ebp", "mov ebx, DWORD PTR [eax+272]", "mov esi, DWORD PTR [eax+276]", "mov edi, DWORD PTR [eax+280]", "mov ebp, DWORD PTR [eax+284]", "ret", - vg_sha512_update = sym super::sha512::vg_sha512_update, - vg_sha512_finalize = sym super::sha512::vg_sha512_finalize, + vg_sha512_compress = sym super::sha512::vg_sha512_compress, ) }