From d279c15eaf453f1e88675b57b09348e34cd7e031 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 28 Sep 2026 12:02:46 +0000 Subject: [PATCH] SHA-256 on PPC64LE: verified compress/init/update/finalize vg_sha256_compress keeps the working variables in the low words of r7-r12, r14 and r15 (saving the nonvolatile r14-r19 in its scratch space), loads the message big-endian with lwbrx, and builds the round constants with lis/ori. init/update/finalize follow the AArch64 implementation: their variables live in r26-r31 (saved in scratch), they call vg_sha256_compress, and the link register is moved to r0 and saved in an ELFv2 frame around the whole function. The digest and the message length are stored big-endian with stwbrx/stdbrx. The update and finalize proofs track r14-r19, which only the compression function writes, through its ABI guarantee. As on the other targets, the proofs use 112 and 160 bytes of scratch, and Shared.lean widens them to the shared contracts' 560 and 608 (Verified.widen, which now allows frames). The SHA-256 API and its CAVP tests now build on little-endian powerpc64; they pass under qemu-ppc64le. The SHA-1 and SHA-512 CAVP tests, which share the test binary, are gated to the architectures those hashes support. Refs #55 Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01Fw6RULWHCeVgMDGc3wRrwE --- README.md | 2 +- bench/benches/primitives/sha256.rs | 14 - .../Artifacts/Sha256/PPC64LE.lean | 51 + lean/VerifiedGarbage/Impl/Sha256/PPC64LE.lean | 149 + .../Impl/Sha256/PPC64LE/Stream.lean | 147 + .../Proof/Framework/PPC64LE/Inline.lean | 5 +- .../Proof/Sha256/PPC64LE/Compress.lean | 548 +++ .../Proof/Sha256/PPC64LE/Contract.lean | 110 + .../Proof/Sha256/PPC64LE/Rounds.lean | 239 ++ .../Proof/Sha256/PPC64LE/Shared.lean | 137 + .../Proof/Sha256/PPC64LE/Stream/Common.lean | 473 +++ .../Proof/Sha256/PPC64LE/Stream/Finalize.lean | 772 +++++ .../Proof/Sha256/PPC64LE/Stream/Init.lean | 101 + .../Proof/Sha256/PPC64LE/Stream/Update.lean | 773 +++++ lean/VerifiedGarbage/Proof/Sha256/Stream.lean | 75 +- src/asm/powerpc64le/mod.rs | 3 + src/asm/powerpc64le/sha256.rs | 2954 +++++++++++++++++ src/hashes/mod.rs | 3 +- src/hashes/sha256.rs | 3 +- src/zeroize.rs | 21 - tests/cavp/main.rs | 3 +- tests/cavp/sha1.rs | 7 + tests/cavp/sha224.rs | 7 + tests/cavp/sha384.rs | 7 + tests/cavp/sha512.rs | 7 + tests/cavp/sha512_224.rs | 7 + tests/cavp/sha512_256.rs | 7 + 27 files changed, 6567 insertions(+), 58 deletions(-) create mode 100644 lean/VerifiedGarbage/Artifacts/Sha256/PPC64LE.lean create mode 100644 lean/VerifiedGarbage/Impl/Sha256/PPC64LE.lean create mode 100644 lean/VerifiedGarbage/Impl/Sha256/PPC64LE/Stream.lean create mode 100644 lean/VerifiedGarbage/Proof/Sha256/PPC64LE/Compress.lean create mode 100644 lean/VerifiedGarbage/Proof/Sha256/PPC64LE/Contract.lean create mode 100644 lean/VerifiedGarbage/Proof/Sha256/PPC64LE/Rounds.lean create mode 100644 lean/VerifiedGarbage/Proof/Sha256/PPC64LE/Shared.lean create mode 100644 lean/VerifiedGarbage/Proof/Sha256/PPC64LE/Stream/Common.lean create mode 100644 lean/VerifiedGarbage/Proof/Sha256/PPC64LE/Stream/Finalize.lean create mode 100644 lean/VerifiedGarbage/Proof/Sha256/PPC64LE/Stream/Init.lean create mode 100644 lean/VerifiedGarbage/Proof/Sha256/PPC64LE/Stream/Update.lean create mode 100644 src/asm/powerpc64le/sha256.rs diff --git a/README.md b/README.md index 1a1aed9e5..3704a28e9 100644 --- a/README.md +++ b/README.md @@ -166,7 +166,7 @@ yours to keep: ✅ SHA extensions -❌ +✅ diff --git a/bench/benches/primitives/sha256.rs b/bench/benches/primitives/sha256.rs index adc25a827..e4eed160e 100644 --- a/bench/benches/primitives/sha256.rs +++ b/bench/benches/primitives/sha256.rs @@ -8,20 +8,6 @@ use crate::hash_group; pub const USES: &[&str] = &["sha256"]; -#[cfg(not(any( - target_arch = "x86_64", - target_arch = "aarch64", - target_arch = "arm", - target_arch = "x86" -)))] -pub fn bench(_: &mut Criterion) {} - -#[cfg(any( - target_arch = "x86_64", - target_arch = "aarch64", - target_arch = "arm", - target_arch = "x86" -))] pub fn bench(c: &mut Criterion) { hash_group(c, "sha256", Sha256::digest, MessageDigest::sha256()); } diff --git a/lean/VerifiedGarbage/Artifacts/Sha256/PPC64LE.lean b/lean/VerifiedGarbage/Artifacts/Sha256/PPC64LE.lean new file mode 100644 index 000000000..1d3f71774 --- /dev/null +++ b/lean/VerifiedGarbage/Artifacts/Sha256/PPC64LE.lean @@ -0,0 +1,51 @@ +import VerifiedGarbage.TCB.PPC64LE.Target +import VerifiedGarbage.Proof.Sha256.PPC64LE.Shared + +/-! +# SHA-256 (FIPS 180-4) on PPC64LE + +A registration file (see `TCB/Emit.lean`): the artifacts it lists are +emitted. **Review note**: `sig` and `doc` are trusted, as they tie the Rust +caller to the contract; check them against the contract's `pre`/`post`. An +artifact made from a function's `Api` (in `Spec/`, reviewed with the +contract) takes them from there, and this file adds only notes on the +implementation. The emitter adds the `# Safety` items that depend on the +target (`Sig.layoutDoc`), from `stack` and `writeArgs`, which `ofSig` checks +against the contract. +-/ + +namespace VG.Artifacts.Sha256.PPC64LE + +def artifacts : List Artifact := [ + { Spec.Sha256.compressApi with + target := PPC64LE.target + doc := Spec.Sha256.compressApi.doc + code := Impl.Sha256.PPC64LE.compress + contract := Spec.Sha256.compressContract PPC64LE.abi + verified := Proof.Sha256.PPC64LE.Shared.compress + spSafe := Code.all_of_forall (fun _ => rfl) _ }, + { Spec.Sha256.initApi with + target := PPC64LE.target + doc := Spec.Sha256.initApi.doc + code := Impl.Sha256.PPC64LE.Stream.init + contract := Spec.Sha256.initContract PPC64LE.abi + verified := Proof.Sha256.PPC64LE.Shared.init + spSafe := Code.all_of_forall (fun _ => rfl) _ }, + { Spec.Sha256.updateApi with + target := PPC64LE.target + doc := Spec.Sha256.updateApi.doc + code := Impl.Sha256.PPC64LE.Stream.update + contract := Spec.Sha256.updateContract PPC64LE.abi 48 + stack := 48 + verified := Proof.Sha256.PPC64LE.Shared.update + spSafe := Code.all_of_forall (fun _ => rfl) _ }, + { Spec.Sha256.finalizeApi with + target := PPC64LE.target + doc := Spec.Sha256.finalizeApi.doc + code := Impl.Sha256.PPC64LE.Stream.finalize + contract := Spec.Sha256.finalizeContract PPC64LE.abi 48 + stack := 48 + verified := Proof.Sha256.PPC64LE.Shared.finalize + spSafe := Code.all_of_forall (fun _ => rfl) _ }] + +end VG.Artifacts.Sha256.PPC64LE diff --git a/lean/VerifiedGarbage/Impl/Sha256/PPC64LE.lean b/lean/VerifiedGarbage/Impl/Sha256/PPC64LE.lean new file mode 100644 index 000000000..a0046f583 --- /dev/null +++ b/lean/VerifiedGarbage/Impl/Sha256/PPC64LE.lean @@ -0,0 +1,149 @@ +import VerifiedGarbage.Spec.Sha256 +import VerifiedGarbage.TCB.PPC64LE.Isa + +/-! +# SHA-256 compression function: PPC64LE implementation + +`vg_sha256_compress(state = r3, blocks = r4, n = r5, scratch = r6)`. + +The same structure as the AArch64 implementation: +* The working variables `a … h` live in the low words of `r7`–`r12`, `r14` + and `r15`; the fully unrolled rounds rename them: in round `t`, variable + `k` is in `var t k`. The additions act on all 64 bits, so the high words + hold carries, which the word rotates, shifts and stores ignore. +* The message schedule is a 16-word window in `scratch[0..64)`. The words + of a block are loaded big-endian with `lwbrx`, indexed by `r0`. +* `r14`–`r19` are nonvolatile: they are saved in `scratch[64..112)` first and + restored last. +* `r3`–`r6` (the pointers and the block count) are public; no address and + no branch depends on anything else. +-/ + +namespace VG.Impl.Sha256.PPC64LE + +open VG.PPC64LE +open VG.Spec.Sha256 (K) + +/-- The registers holding the working variables. -/ +def work : List Reg := [.r7, .r8, .r9, .r10, .r11, .r12, .r14, .r15] + +/-- The register holding working variable `k` (`a = 0, …, h = 7`) at the start of round `t`. -/ +def var (t k : Nat) : Reg := work.getD ((k + 8 - t % 8) % 8) .r7 + +/-- Temporaries; `T0` holds `Wₜ` at the start of each round. -/ +def T0 : Reg := .r16 +def T1 : Reg := .r17 +def T2 : Reg := .r18 +def T3 : Reg := .r19 + +/-- The nonvolatile registers used, in the order they are saved. -/ +def saved (i : Nat) : Reg := [.r14, .r15, .r16, .r17, .r18, .r19].getD i .r14 + +/-- Save them in `scratch[64..112)`. -/ +def save : List Instr := (List.range 6).flatMap fun i => [.store .d (saved i) .r6 (64 + 8 * i)] + +/-- Restore them. -/ +def restore : List Instr := (List.range 6).flatMap fun i => [.load .d (saved i) .r6 (64 + 8 * i)] + +/-- The offset of `W[i mod 16]` in the scratch buffer. -/ +def slot (i : Nat) : Nat := 4 * (i % 16) + +/-- Leave `Wₜ` in the low word of `T0` and in its slot. The additions are in +the order of the specification. -/ +def schedule (t : Nat) : List Instr := + if t < 16 then [ + .li .r0 (4 * t), + .loadRev .w T0 .r4 .r0, + .store .w T0 .r6 (slot t)] + else [ + -- T0 := σ₁(Wₜ₋₂) + .load .w T1 .r6 (slot (t + 14)), + .rotr .w T0 T1 17, + .rotr .w T2 T1 19, + .logic .xor T0 T0 T2, + .lsr .w T2 T1 10, + .logic .xor T0 T0 T2, + -- T0 := T0 + Wₜ₋₇ + .load .w T2 .r6 (slot (t + 9)), + .add T0 T0 T2, + -- T0 := T0 + σ₀(Wₜ₋₁₅) + .load .w T1 .r6 (slot (t + 1)), + .rotr .w T2 T1 7, + .rotr .w T3 T1 18, + .logic .xor T2 T2 T3, + .lsr .w T3 T1 3, + .logic .xor T2 T2 T3, + .add T0 T0 T2, + -- T0 := T0 + Wₜ₋₁₆ + .load .w T2 .r6 (slot t), + .add T0 T0 T2, + .store .w T0 .r6 (slot t)] + +/-- Round `t`, with `Wₜ` in `T0`. The additions are in the order of the +specification. -/ +def round (t : Nat) : List Instr := + let a := var t 0; let b := var t 1; let c := var t 2; let d := var t 3 + let e := var t 4; let f := var t 5; let g := var t 6; let h := var t 7 + [ -- h := h + Σ₁(e) + .rotr .w T1 e 6, + .rotr .w T2 e 11, + .logic .xor T1 T1 T2, + .rotr .w T2 e 25, + .logic .xor T1 T1 T2, + .add h h T1, + -- h := h + Ch(e, f, g), as ((f ⊕ g) ∧ e) ⊕ g + .logic .xor T1 f g, + .logic .and T1 T1 e, + .logic .xor T1 T1 g, + .add h h T1, + -- h := h + Kₜ + Wₜ, which is T₁ + .lis T1 ((K t).extractLsb' 16 16), + .ori T1 T1 ((K t).extractLsb' 0 16), + .add h h T1, + .add h h T0, + -- e' := d + T₁ + .add d d h, + -- h := h + Σ₀(a) + .rotr .w T1 a 2, + .rotr .w T2 a 13, + .logic .xor T1 T1 T2, + .rotr .w T2 a 22, + .logic .xor T1 T1 T2, + .add h h T1, + -- h := h + Maj(a, b, c), as ((a ∨ b) ∧ c) ∨ (a ∧ b); now h = a' = T₁ + T₂ + .logic .or T1 a b, + .logic .and T1 T1 c, + .logic .and T2 a b, + .logic .or T1 T1 T2, + .add h h T1] + +/-- Rounds `0 … n-1`. -/ +def rounds : Nat → Prog isa + | 0 => .block [] + | n + 1 => .seq (rounds n) (.block (schedule n ++ round n)) + +/-- Load the hash value (`64 % 8 = 0`, so the variables are in the same +registers after the 64 rounds). -/ +def load : List Instr := (List.range 8).map fun k => .load .w (var 0 k) .r3 (4 * k) + +/-- Add the hash value into the working variables (loading all of it before +storing any of it), and store the result. -/ +def update : List Instr := + (List.range 4).map (fun k => .load .w ([T0, T1, T2, T3].getD k T0) .r3 (4 * k)) ++ + (List.range 4).map (fun k => .add (var 0 k) (var 0 k) ([T0, T1, T2, T3].getD k T0)) ++ + (List.range 4).map (fun k => .load .w ([T0, T1, T2, T3].getD k T0) .r3 (4 * (k + 4))) ++ + (List.range 4).map (fun k => .add (var 0 (k + 4)) (var 0 (k + 4)) ([T0, T1, T2, T3].getD k T0)) ++ + (List.range 8).map (fun k => .store .w (var 0 k) .r3 (4 * k)) + +/-- Advance to the next block and decrement the count. -/ +def advance : List Instr := [.addi .r4 .r4 64, .subi .r5 .r5 1] + +/-- One block. -/ +def body : Prog isa := .seq (.block load) (.seq (rounds 64) (.block (update ++ advance))) + +/-- The blocks. -/ +def blocks : Prog isa := .ite (.zero .d .r5) (.block []) (.loop body (.nonzero .d .r5)) + +def compress : Prog isa := .seq (.block save) (.seq blocks (.block restore)) + +end VG.Impl.Sha256.PPC64LE diff --git a/lean/VerifiedGarbage/Impl/Sha256/PPC64LE/Stream.lean b/lean/VerifiedGarbage/Impl/Sha256/PPC64LE/Stream.lean new file mode 100644 index 000000000..3f13db9d3 --- /dev/null +++ b/lean/VerifiedGarbage/Impl/Sha256/PPC64LE/Stream.lean @@ -0,0 +1,147 @@ +import VerifiedGarbage.Impl.Sha256.PPC64LE + +/-! +# Streaming SHA-256: PPC64LE implementation + +The streaming state (96 bytes at `state`) is the hash value followed by a +64-byte buffer (see `VG.Spec.Sha256.Repr`). + +* `init(state = r3)` stores `H⁽⁰⁾`. +* `update(state = r3, count = r4, data = r5, len = r6, scratch = r7)` + processes one block per iteration: straight from `data` while the buffer is + empty and a whole block remains, otherwise by copying bytes into the buffer, + compressing it once it is full. +* `finalize(state = r3, count = r4, out = r5, scratch = r6)` pads the + buffered bytes (one or two blocks), compresses them and writes the digest. + +`update` and `finalize` call the compression function (`vg_sha256_compress`) +with `scratch[0..112)` as its scratch space. It preserves `r14`–`r31`, so our +own variables live in `r26`–`r31` (`r26` = `state`, `r27` = `scratch`), and +our caller's values of those registers are saved in `scratch[112..160)`. Our +return address (the link register), which each call replaces, is moved to +`r0` and saved in a stack frame around the whole function. + +Only register-plus-displacement addressing is used, so byte `r` of the buffer +is addressed as `32(r11)` with `r11 = state + r` computed just before the +access, and `data` is consumed through a pointer that advances. Every +comparison is a shift (`len ≥ 64` iff `len >> 6 ≠ 0`) or a subtraction +tested against zero. Every address and branch depends only on the pointers, +`count` and `len`. +-/ + +namespace VG.Impl.Sha256.PPC64LE.Stream + +open VG.PPC64LE +open VG.Impl.Sha256.PPC64LE (compress) + +/-- `mr d, n` (as `addi d, n, 0`; `n` is not `r0`). -/ +def mov (d n : Reg) : Instr := .addi d n 0 + +def init : Prog isa := + .block ((List.range 8).flatMap fun k => + [.lis .r8 (Spec.Sha256.H0[k]!.extractLsb' 16 16), + .ori .r8 .r8 (Spec.Sha256.H0[k]!.extractLsb' 0 16), + .store .w .r8 .r3 (4 * k)]) + +/-- The nonvolatile registers we use, and where they are saved in `scratch`. -/ +def saved : List (Reg × Nat) := + [(.r26, 112), (.r27, 120), (.r28, 128), (.r29, 136), (.r30, 144), (.r31, 152)] + +/-- Save them, with `scratch` in `b`. -/ +def save (b : Reg) : List Instr := saved.map fun (r, d) => .store .d r b d + +/-- Restore them from `scratch` in `r27` (`r27`, the base, last). -/ +def restore : List Instr := + (saved.filter (·.1 != .r27)).map (fun (r, d) => .load .d r .r27 d) ++ [.load .d .r27 .r27 120] + +/-- Compress the block at `r4` into the hash value at `r26`, with scratch +space `r27`. -/ +def compressAt : Prog isa := + .seq (.block [mov .r3 .r26, .li .r5 1, mov .r6 .r27]) (.call "vg_sha256_compress" compress) + +/-! ## `update` + +Registers: `r28` = `data`, `r29` = bytes of `data` left, `r30` = bytes in the +buffer (`r`), `r9` = whether this iteration compresses a block (at `r4`). +The loop runs while `r29 ≠ 0`, so each iteration starts with `r29 ≥ 1` and +`r30 < 64`. -/ + +/-- A whole block straight from `data`. -/ +def direct : List Instr := + [mov .r4 .r28, .addi .r28 .r28 64, .subi .r29 .r29 64, .li .r9 1] + +/-- Copy `n = min(64 - r, len) ≥ 1` bytes of `data` into the buffer; if that +fills it, compress it. -/ +def fill : Prog isa := + -- r10 := 64 - r; if len < 64 and len + r < 64 (i.e. len < 64 - r), r10 := len. + .seq (.block [.li .r10 64, .sub .r10 .r10 .r30, .lsr .d .r8 .r29 6]) + (.seq (.ite (.zero .d .r8) + (.seq (.block [.add .r8 .r29 .r30, .lsr .d .r8 .r8 6]) + (.ite (.zero .d .r8) (.block [mov .r10 .r29]) (.block []))) + (.block [])) + (.seq (.block [.sub .r29 .r29 .r10]) + (.seq (.loop (.block [.lbz .r8 .r28 0, .add .r11 .r26 .r30, .stb .r8 .r11 32, + .addi .r28 .r28 1, .addi .r30 .r30 1, .subi .r10 .r10 1]) (.nonzero .d .r10)) + -- Full: compress the buffer. + (.seq (.block [.subi .r8 .r30 64]) + (.ite (.zero .d .r8) (.block [.addi .r4 .r26 32, .li .r30 0, .li .r9 1]) + (.block [])))))) + +def updateBody : Prog isa := + .seq (.block [.li .r9 0]) + (.seq (.ite (.zero .d .r30) + (.seq (.block [.lsr .d .r8 .r29 6]) (.ite (.zero .d .r8) fill (.block direct))) + fill) + (.ite (.zero .d .r9) (.block []) compressAt)) + +/-- `update`, but for saving the link register. -/ +def updateMain : Prog isa := + .seq (.block (save .r7 ++ [mov .r26 .r3, mov .r27 .r7, mov .r28 .r5, mov .r29 .r6, + .li .r8 63, .logic .and .r30 .r4 .r8])) + (.seq (.ite (.zero .d .r29) (.block []) (.loop updateBody (.nonzero .d .r29))) + (.block restore)) + +def update : Prog isa := + .seq (.block [.mflr .r0]) + (.seq (.frame (.push .r0) updateMain (.pop .r0)) (.block [.mtlr .r0])) + +/-! ## `finalize` + +Registers: `r28` = `out`, `r29` = `count`, `r30` = bytes in the buffer (`r`), +`r31` = 1 while the block being padded is not the last one (then 0). -/ + +def finalizeBody : Prog isa := + -- Zero the buffer from `r` to 64, or to 56 in the last block. + .seq (.block [.li .r10 64]) + (.seq (.ite (.zero .d .r31) (.block [.li .r10 56]) (.block [])) + (.seq (.block [.li .r8 0, .sub .r10 .r10 .r30]) + (.seq (.ite (.zero .d .r10) (.block []) + (.loop (.block [.add .r11 .r26 .r30, .stb .r8 .r11 32, .addi .r30 .r30 1, + .subi .r10 .r10 1]) (.nonzero .d .r10))) + -- In the last block, the message length in bits (`8 * count`), big-endian. + (.seq (.ite (.zero .d .r31) + (.block [.add .r8 .r29 .r29, .add .r8 .r8 .r8, .add .r8 .r8 .r8, .li .r11 88, + .storeRev .d .r8 .r26 .r11]) + (.block [])) + (.seq (.block [.addi .r4 .r26 32]) + (.seq compressAt + (.block [.li .r30 0, .subi .r31 .r31 1]))))))) + +/-- `finalize`, but for saving the link register. -/ +def finalizeMain : Prog isa := + .seq (.block (save .r6 ++ [mov .r26 .r3, mov .r27 .r6, mov .r28 .r5, mov .r29 .r4, + .li .r8 63, .logic .and .r30 .r29 .r8, + -- The `0x80` byte. + .li .r8 0x80, .add .r11 .r26 .r30, .stb .r8 .r11 32, .addi .r30 .r30 1, + -- Two blocks iff that leaves fewer than 8 bytes for the length (r ≥ 57). + .addi .r31 .r30 7, .lsr .d .r31 .r31 6])) + (.seq (.loop finalizeBody (.zero .d .r31)) + (.block ((List.range 8).flatMap (fun k => + [.load .w .r8 .r26 (4 * k), .li .r11 (4 * k), .storeRev .w .r8 .r28 .r11]) ++ + restore))) + +def finalize : Prog isa := + .seq (.block [.mflr .r0]) + (.seq (.frame (.push .r0) finalizeMain (.pop .r0)) (.block [.mtlr .r0])) + +end VG.Impl.Sha256.PPC64LE.Stream diff --git a/lean/VerifiedGarbage/Proof/Framework/PPC64LE/Inline.lean b/lean/VerifiedGarbage/Proof/Framework/PPC64LE/Inline.lean index 759362099..8558ea608 100644 --- a/lean/VerifiedGarbage/Proof/Framework/PPC64LE/Inline.lean +++ b/lean/VerifiedGarbage/Proof/Framework/PPC64LE/Inline.lean @@ -472,14 +472,13 @@ theorem Verified.widen {c : Prog isa} {k k' : Contract isa} (h : Verified target k.post (s.withRegions s.rd (wr s)) (s'.withRegions s.rd (wr s)) → k'.post s s') (hpub : ∀ s₁ s₂, k'.pre s₁ → k'.pre s₂ → k'.pub s₁ s₂ → k.pub (s₁.withRegions s₁.rd (wr s₁)) (s₂.withRegions s₂.rd (wr s₂))) - (hsat : ∃ s, k'.pre s) (hn : c.noFrames = true := by decide +kernel) : - Verified target c k' := by + (hsat : ∃ s, k'.pre s) : Verified target c k' := by refine h.of_narrow (fun s => s.withRegions s.rd (wr s)) (fun s s₁ => s₁.withRegions s.rd s.wr) hpre (fun s t s₁ hs he => ?_) (fun s t s₁ hs he ha hq => ?_) hpub hsat · have hw : Covers (wr s) s.wr := fun _ _ => InRegions.of_prefix (hwr s hs) have := Exec.widen (rd := s.rd) (wr := s.wr) he (Covers.append (fun _ _ h => h) hw) hw rwa [State.withRegions_withRegions, State.withRegions_self] at this - · obtain ⟨hr, hw, -⟩ := Exec.regions he hn + · obtain ⟨hr, hw, -⟩ := Exec.rdwr he simp only [State.withRegions_rd, State.withRegions_wr] at hr hw have : (s₁.withRegions s.rd s.wr).withRegions s.rd (wr s) = s₁ := by rw [State.withRegions_withRegions, ← hr, ← hw]; rfl diff --git a/lean/VerifiedGarbage/Proof/Sha256/PPC64LE/Compress.lean b/lean/VerifiedGarbage/Proof/Sha256/PPC64LE/Compress.lean new file mode 100644 index 000000000..20550176c --- /dev/null +++ b/lean/VerifiedGarbage/Proof/Sha256/PPC64LE/Compress.lean @@ -0,0 +1,548 @@ +import VerifiedGarbage.Proof.Sha256.PPC64LE.Rounds +import VerifiedGarbage.Proof.Sha256.PPC64LE.Contract +import VerifiedGarbage.Proof.Framework.Range + +/-! +# SHA-256 compression function on PPC64LE: the whole function + +Untrusted: everything here is checked by Lean. +-/ + +namespace VG.Proof.Sha256.PPC64LE + +open VG VG.PPC64LE VG.Impl.Sha256.PPC64LE +open VG.Spec.Sha256 (HashValue Word Block K W stateAt blockAt compressBlocks compress parseBlock) + +/-! ## Addresses and regions -/ + +theorem toNat_ofNat_lt {n : Nat} (h : n < 2 ^ 64) : (BitVec.ofNat 64 n).toNat = n := by + rw [BitVec.toNat_ofNat]; exact Nat.mod_eq_of_lt h + +theorem contains_offset {base : Addr} {len off n : Nat} (h : off + n ≤ len) (ho : off < 2 ^ 64) : + (⟨base, len⟩ : Region).Contains (base + BitVec.ofNat 64 off) n := by + simp only [Region.Contains] + rw [show base + BitVec.ofNat 64 off - base = BitVec.ofNat 64 off by bv_omega, toNat_ofNat_lt ho] + exact h + +theorem sub_offset {base : Addr} {off len len' : Nat} (h : off + len ≤ len') (ho : off < 2 ^ 64) : + Region.Sub ⟨base + BitVec.ofNat 64 off, len⟩ ⟨base, len'⟩ := by + intro a ha + simp only [Region.Contains] at * + have : (a - base).toNat ≤ (a - (base + BitVec.ofNat 64 off)).toNat + off := by + rw [show a - base = (a - (base + BitVec.ofNat 64 off)) + BitVec.ofNat 64 off by bv_omega, + BitVec.toNat_add, toNat_ofNat_lt ho] + exact Nat.mod_le _ _ + omega + +theorem word_sep (p : Addr) {j k : Nat} (hj : j < 8) (hk : k < 8) (h : j ≠ k) : + Mem.Sep (p + BitVec.ofNat 64 (4 * j)) 4 (p + BitVec.ofNat 64 (4 * k)) 4 := by + intro x hx hy + bv_omega + +theorem readW_writeW_word (m : Mem) (p : Addr) (v : Word) {j k : Nat} (hj : j < 8) (hk : k < 8) + (h : j ≠ k) : + (m.writeW (p + BitVec.ofNat 64 (4 * k)) v).readW (p + BitVec.ofNat 64 (4 * j)) 32 = + m.readW (p + BitVec.ofNat 64 (4 * j)) 32 := + Mem.readW_writeW_sep (word_sep p hj hk h) (by decide) + +theorem stateAt_eq {m : Mem} {p : Addr} {v : HashValue} + (h : ∀ k : Nat, (hk : k < 8) → m.readW (p + BitVec.ofNat 64 (4 * k)) 32 = v[k]) : + stateAt m p = v := by + apply Vector.ext + intro k hk + simp only [stateAt, Vector.getElem_ofFn] + exact h k hk + +theorem stateAt_get (m : Mem) (p : Addr) {k : Nat} (hk : k < 8) : + (stateAt m p)[k] = m.readW (p + BitVec.ofNat 64 (4 * k)) 32 := by + simp only [stateAt, Vector.getElem_ofFn] + +/-! ## The precondition -/ + +section +variable (s₀ : State) + +abbrev st : Addr := s₀.gpr .r3 +abbrev bp : Addr := s₀.gpr .r4 +abbrev nb : Nat := (s₀.gpr .r5).toNat +abbrev scr : Addr := s₀.gpr .r6 +abbrev stR : Region := ⟨st s₀, 32⟩ +abbrev blR : Region := ⟨bp s₀, 64 * nb s₀⟩ +abbrev scrR : Region := ⟨scr s₀, 112⟩ +abbrev H₀ : HashValue := stateAt s₀.mem (st s₀) +/-- Where the nonvolatile registers are saved. -/ +abbrev savR : Region := ⟨scr s₀ + BitVec.ofNat 64 64, 48⟩ +/-- Where nonvolatile register `i` is saved. -/ +abbrev savAddr (i : Nat) : Addr := scr s₀ + BitVec.ofNat 64 (64 + 8 * i) + +/-- Block `i`, and where it starts. -/ +abbrev blkAddr (i : Nat) : Addr := bp s₀ + BitVec.ofNat 64 (64 * i) +abbrev blk (i : Nat) : Block := blockAt s₀.mem (blkAddr s₀ i) + +end + +structure Pre (s₀ : State) : Prop where + rd : s₀.rd = [blR s₀] + wr : s₀.wr = [stR s₀, scrR s₀] + st_scr : (stR s₀).Disjoint (scrR s₀) + blk_st : (blR s₀).Disjoint (stR s₀) + blk_scr : (blR s₀).Disjoint (scrR s₀) + +theorem pre_of (s₀ : State) (h : Proof.Sha256.compressPPC64LE.pre s₀) : Pre s₀ := by + obtain ⟨h1, h2, h3, h4, h5⟩ := h + exact ⟨h1, h2, h3, h4, h5⟩ + +namespace Pre +variable {s₀ : State} (h : Pre s₀) +include h + +theorem nb_lt : 64 * nb s₀ < 2 ^ 64 := by + by_contra hn + refine h.blk_st (st s₀) ?_ (by simp [Region.Contains]) + simp only [Region.Contains] + have := (st s₀ - bp s₀).isLt + omega + +theorem in_state {k : Nat} (hk : k < 8) : + InRegions (s₀.rd ++ s₀.wr) (st s₀ + BitVec.ofNat 64 (4 * k)) 4 := + ⟨stR s₀, by simp [h.wr], contains_offset (by omega) (by omega)⟩ + +theorem out_state {k : Nat} (hk : k < 8) : + InRegions s₀.wr (st s₀ + BitVec.ofNat 64 (4 * k)) 4 := + ⟨stR s₀, by simp [h.wr], contains_offset (by omega) (by omega)⟩ + +theorem in_slot (j : Nat) : InRegions (s₀.rd ++ s₀.wr) (slotAddr (scr s₀) j) 4 := + ⟨scrR s₀, by simp [h.wr], contains_offset (by simp only [slot]; omega) (by simp only [slot]; omega)⟩ + +theorem out_slot (j : Nat) : InRegions s₀.wr (slotAddr (scr s₀) j) 4 := + ⟨scrR s₀, by simp [h.wr], contains_offset (by simp only [slot]; omega) (by simp only [slot]; omega)⟩ + +theorem blk_contains {i t : Nat} (hi : i < nb s₀) (ht : t < 16) : + (blR s₀).Contains (blkAddr s₀ i + BitVec.ofNat 64 (4 * t)) 4 := by + have := h.nb_lt + rw [show blkAddr s₀ i + BitVec.ofNat 64 (4 * t) = + bp s₀ + BitVec.ofNat 64 (64 * i + 4 * t) by simp only [blkAddr]; bv_omega] + exact contains_offset (by omega) (by omega) + +theorem in_sav {i : Nat} (hi : i < 6) (rs : List Region) : + InRegions (rs ++ s₀.wr) (scr s₀ + BitVec.ofNat 64 (64 + 8 * i)) 8 := + ⟨scrR s₀, by simp [h.wr], contains_offset (by omega) (by omega)⟩ + +theorem out_sav {i : Nat} (hi : i < 6) : InRegions s₀.wr (scr s₀ + BitVec.ofNat 64 (64 + 8 * i)) 8 := + ⟨scrR s₀, by simp [h.wr], contains_offset (by omega) (by omega)⟩ + +theorem in_blk {i t : Nat} (hi : i < nb s₀) (ht : t < 16) : + InRegions (s₀.rd ++ s₀.wr) (blkAddr s₀ i + BitVec.ofNat 64 (4 * t)) 4 := + ⟨blR s₀, by simp [h.rd], h.blk_contains hi ht⟩ + +end Pre + +/-! ## Saving and restoring the nonvolatile registers -/ + +/-- The nonvolatile registers the code does not use: never written. -/ +def keepRegs : List Reg := [.r2, .r20, .r21, .r22, .r23, .r24, .r25, .r26, .r27, .r28, .r29, .r30, + .r31] + +theorem keepRegs_pub : ∀ r ∈ keepRegs, r ∈ pubRegs := by decide + +/-- A preserved register is saved, or kept. -/ +theorem preserved_cases : ∀ r ∈ preserved, (∃ i < 6, r = saved i) ∨ r ∈ keepRegs := by decide + +theorem saved_inj {i j : Nat} (hi : i < 6) (hj : j < 6) (h : saved i = saved j) : i = j := by + have key : ∀ i < 6, ∀ j < 6, saved i = saved j → i = j := by decide + exact key i hi j hj h + +theorem saved_ne {i : Nat} (hi : i < 6) : saved i ≠ .r3 ∧ saved i ≠ .r6 ∧ saved i ∉ keepRegs := by + have key : ∀ i < 6, saved i ≠ .r3 ∧ saved i ≠ .r6 ∧ saved i ∉ keepRegs := by decide + exact key i hi + +theorem sav_sep (p : Addr) {i j : Nat} (hi : i < 6) (hj : j < 6) (h : i ≠ j) : + Mem.Sep (p + BitVec.ofNat 64 (64 + 8 * i)) 8 (p + BitVec.ofNat 64 (64 + 8 * j)) 8 := by + intro x hx hy + bv_omega + +theorem savR_sub (s₀ : State) : Region.Sub (savR s₀) (scrR s₀) := sub_offset (by omega) (by omega) + +theorem win_sav (s₀ : State) : (winRegion (scr s₀)).Disjoint (savR s₀) := by + intro a h₁ h₂ + simp only [Region.Contains] at h₁ h₂ + bv_omega + +theorem sav_contains (s₀ : State) {i : Nat} (hi : i < 6) : (savR s₀).Contains (savAddr s₀ i) 8 := by + simp only [Region.Contains]; bv_omega + +/-- The first `n` registers are saved. -/ +structure SI (s₀ : State) (n : Nat) (s : State) : Prop where + gpr : s.gpr = s₀.gpr + rd : s.rd = s₀.rd + wr : s.wr = s₀.wr + frame : Frame [savR s₀] s₀.mem s.mem + saved : ∀ i < n, s.mem.readW (savAddr s₀ i) 64 = s₀.gpr (saved i) + +theorem save_step {s₀ : State} (hp : Pre s₀) {n : Nat} (hn : n < 6) {s : State} (h : SI s₀ n s) : + WP isa (.block [.store .d (saved n) .r6 (64 + 8 * n)]) s (SI s₀ (n + 1)) := by + have hr6 : s.gpr .r6 = scr s₀ := by rw [h.gpr] + have hout : InRegions s.wr (s.gpr .r6 + BitVec.ofNat 64 (64 + 8 * n)) 8 := by + rw [h.wr, hr6]; exact hp.out_sav hn + apply WP.of_runBlock + simp only [runBlock_cons, runStep_some, runBlock_nil, + exec_store_d (by decide) (show 64 + 8 * n < 2 ^ 15 ∧ (64 + 8 * n) % 4 = 0 by omega) hout, + Option.some.injEq, exists_eq_left', hr6] + refine ⟨h.gpr, h.rd, h.wr, h.frame.writeW (List.mem_singleton_self _) _ (sav_contains s₀ hn), + fun i hi => ?_⟩ + rcases Nat.lt_succ_iff_lt_or_eq.mp hi with hi | rfl + · rw [Mem.readW_writeW_sep (sav_sep _ (by omega) hn (by omega)) (by decide)] + exact h.saved i hi + · rw [Mem.readW_writeW_self64, h.gpr] + +/-- The first `n` registers are restored, from the state `sB` the restoring +starts in. -/ +structure RI (s₀ sB : State) (n : Nat) (s : State) : Prop where + restored : ∀ i < n, s.gpr (saved i) = s₀.gpr (saved i) + others : ∀ r, (∀ i < 6, r ≠ saved i) → s.gpr r = sB.gpr r + mem : s.mem = sB.mem + rd : s.rd = s₀.rd + wr : s.wr = s₀.wr + +theorem restore_step {s₀ sB : State} (hp : Pre s₀) (hr6 : sB.gpr .r6 = scr s₀) + (hsav : ∀ i < 6, sB.mem.readW (savAddr s₀ i) 64 = s₀.gpr (saved i)) + {n : Nat} (hn : n < 6) {s : State} (h : RI s₀ sB n s) : + WP isa (.block [.load .d (saved n) .r6 (64 + 8 * n)]) s (RI s₀ sB (n + 1)) := by + have hr6' : s.gpr .r6 = scr s₀ := by + rw [h.others _ fun i hi e => (saved_ne hi).2.1 e.symm, hr6] + have hin : InRegions (s.rd ++ s.wr) (s.gpr .r6 + BitVec.ofNat 64 (64 + 8 * n)) 8 := by + rw [h.rd, h.wr, hr6']; exact hp.in_sav hn _ + have hv : s.mem.readW (scr s₀ + BitVec.ofNat 64 (64 + 8 * n)) 64 = s₀.gpr (saved n) := by + rw [h.mem]; exact hsav n hn + apply WP.of_runBlock + simp only [runBlock_cons, runStep_some, runBlock_nil, + exec_load_d (by decide) (show 64 + 8 * n < 2 ^ 15 ∧ (64 + 8 * n) % 4 = 0 by omega) hin, + Option.some.injEq, exists_eq_left', hr6', hv] + refine ⟨fun i hi => ?_, fun r hr => ?_, h.mem, h.rd, h.wr⟩ + · simp only [State.write] + rcases Nat.lt_succ_iff_lt_or_eq.mp hi with hi | rfl + · have e : saved i ≠ saved n := fun e => absurd (saved_inj (by omega) hn e) (by omega) + simp only [e, ite_false]; exact h.restored i hi + · simp + · simp only [State.write, hr n hn, ite_false]; exact h.others r hr + +/-! ## The loop invariant -/ + +/-- What holds between blocks, after `i` of them. -/ +structure Common (s₀ : State) (i : Nat) (s : State) : Prop where + r3 : s.gpr .r3 = st s₀ + r6 : s.gpr .r6 = scr s₀ + kept : ∀ r ∈ keepRegs, s.gpr r = s₀.gpr r + rd : s.rd = s₀.rd + wr : s.wr = s₀.wr + frame : Frame [stR s₀, scrR s₀] s₀.mem s.mem + sav : ∀ i < 6, s.mem.readW (savAddr s₀ i) 64 = s₀.gpr (saved i) + state : stateAt s.mem (st s₀) = compressBlocks (H₀ s₀) s₀.mem (bp s₀) i + +/-- The loop invariant, at the start of block `i`. -/ +structure LInv (s₀ : State) (i : Nat) (s : State) : Prop extends Common s₀ i s where + r4 : s.gpr .r4 = blkAddr s₀ i + r5 : s.gpr .r5 = BitVec.ofNat 64 (nb s₀ - i) + +/-! ## One block -/ + +theorem load_eq : load = [ + .load .w .r7 .r3 (4 * 0), .load .w .r8 .r3 (4 * 1), .load .w .r9 .r3 (4 * 2), + .load .w .r10 .r3 (4 * 3), .load .w .r11 .r3 (4 * 4), .load .w .r12 .r3 (4 * 5), + .load .w .r14 .r3 (4 * 6), .load .w .r15 .r3 (4 * 7)] := by + decide + +theorem update_eq : update ++ advance = [ + .load .w .r16 .r3 (4 * 0), .load .w .r17 .r3 (4 * 1), .load .w .r18 .r3 (4 * 2), + .load .w .r19 .r3 (4 * 3), + .add .r7 .r7 .r16, .add .r8 .r8 .r17, .add .r9 .r9 .r18, .add .r10 .r10 .r19, + .load .w .r16 .r3 (4 * (0 + 4)), .load .w .r17 .r3 (4 * (1 + 4)), + .load .w .r18 .r3 (4 * (2 + 4)), .load .w .r19 .r3 (4 * (3 + 4)), + .add .r11 .r11 .r16, .add .r12 .r12 .r17, .add .r14 .r14 .r18, .add .r15 .r15 .r19, + .store .w .r7 .r3 (4 * 0), .store .w .r8 .r3 (4 * 1), .store .w .r9 .r3 (4 * 2), + .store .w .r10 .r3 (4 * 3), .store .w .r11 .r3 (4 * 4), .store .w .r12 .r3 (4 * 5), + .store .w .r14 .r3 (4 * 6), .store .w .r15 .r3 (4 * 7), + .addi .r4 .r4 64, .subi .r5 .r5 1] := by + decide + +theorem vars0 (s : State) (v : HashValue) : Vars 0 s v ↔ + (s.gpr .r7).setWidth 32 = v[0] ∧ (s.gpr .r8).setWidth 32 = v[1] ∧ + (s.gpr .r9).setWidth 32 = v[2] ∧ (s.gpr .r10).setWidth 32 = v[3] ∧ + (s.gpr .r11).setWidth 32 = v[4] ∧ (s.gpr .r12).setWidth 32 = v[5] ∧ + (s.gpr .r14).setWidth 32 = v[6] ∧ (s.gpr .r15).setWidth 32 = v[7] := Iff.rfl + +set_option simprocs false in +theorem load_ok {s₀ : State} (hp : Pre s₀) {s : State} (hr3 : s.gpr .r3 = st s₀) + (hrd : s.rd = s₀.rd) (hwr : s.wr = s₀.wr) : + WP isa (.block load) s fun s₁ => + Vars 0 s₁ (stateAt s.mem (st s₀)) ∧ (∀ r ∈ pubRegs, s₁.gpr r = s.gpr r) ∧ + s₁.rd = s.rd ∧ s₁.wr = s.wr ∧ s₁.mem = s.mem := by + have hin : ∀ k : Nat, k < 8 → InRegions (s.rd ++ s.wr) (st s₀ + BitVec.ofNat 64 (4 * k)) 4 := by + rw [hrd, hwr]; exact fun k hk => hp.in_state hk + have h0 := hin 0 (by decide); have h1 := hin 1 (by decide); have h2 := hin 2 (by decide) + have h3 := hin 3 (by decide); have h4 := hin 4 (by decide); have h5 := hin 5 (by decide) + have h6 := hin 6 (by decide); have h7 := hin 7 (by decide) + apply WP.of_runBlock + rw [load_eq] + simp (config := {decide := true}) only [vars0, runBlock_cons, runStep_some, + runBlock_nil, exec_load_w, isa, State.write, hr3, + h0, h1, h2, h3, h4, h5, h6, h7, ite_true, ite_false, Option.some.injEq, + exists_eq_left'] + simp only [stateAt_get _ _ (show 0 < 8 by decide), stateAt_get _ _ (show 1 < 8 by decide), + stateAt_get _ _ (show 2 < 8 by decide), stateAt_get _ _ (show 3 < 8 by decide), + stateAt_get _ _ (show 4 < 8 by decide), stateAt_get _ _ (show 5 < 8 by decide), + stateAt_get _ _ (show 6 < 8 by decide), stateAt_get _ _ (show 7 < 8 by decide)] + simp (config := {decide := true}) [pubRegs] + +/-- Eight 32-bit words written to consecutive addresses. -/ +def writeState (m : Mem) (p : Addr) (v : HashValue) : Mem := + ((((((((m.writeW (p + BitVec.ofNat 64 (4 * 0)) v[0]).writeW + (p + BitVec.ofNat 64 (4 * 1)) v[1]).writeW + (p + BitVec.ofNat 64 (4 * 2)) v[2]).writeW + (p + BitVec.ofNat 64 (4 * 3)) v[3]).writeW + (p + BitVec.ofNat 64 (4 * 4)) v[4]).writeW + (p + BitVec.ofNat 64 (4 * 5)) v[5]).writeW + (p + BitVec.ofNat 64 (4 * 6)) v[6]).writeW + (p + BitVec.ofNat 64 (4 * 7)) v[7]) + +set_option simprocs false in +theorem stateAt_writeState (m : Mem) (p : Addr) (v : HashValue) : stateAt (writeState m p v) p = v := by + apply stateAt_eq + intro k hk + simp only [writeState] + interval_cases k <;> + simp (config := {decide := true}) only [Mem.readW_writeW_self32, readW_writeW_word] + +theorem frame_writeState {s₀ : State} {m m' : Mem} (h : Frame [stR s₀] m m') (v : HashValue) : + Frame [stR s₀] m (writeState m' (st s₀) v) := by + have c : ∀ k, k < 8 → (stR s₀).Contains (st s₀ + BitVec.ofNat 64 (4 * k)) (32 / 8) := + fun k hk => contains_offset (by omega) (by omega) + simp only [writeState] + refine (((((((h.writeW ?_ _ (c 0 ?_)).writeW ?_ _ (c 1 ?_)).writeW ?_ _ (c 2 ?_)).writeW ?_ _ + (c 3 ?_)).writeW ?_ _ (c 4 ?_)).writeW ?_ _ (c 5 ?_)).writeW ?_ _ (c 6 ?_)).writeW ?_ _ (c 7 ?_) <;> + simp + +set_option simprocs false in +theorem update_ok {s₀ : State} (hp : Pre s₀) {s : State} (V H : HashValue) (hv : Vars 0 s V) + (hr3 : s.gpr .r3 = st s₀) (hrd : s.rd = s₀.rd) (hwr : s.wr = s₀.wr) + (hH : ∀ k : Nat, (hk : k < 8) → s.mem.readW (st s₀ + BitVec.ofNat 64 (4 * k)) 32 = H[k]) : + WP isa (.block (update ++ advance)) s fun s' => + s'.mem = writeState s.mem (st s₀) (Vector.zipWith (· + ·) V H) ∧ + s'.gpr .r4 = s.gpr .r4 + 64 ∧ s'.gpr .r5 = s.gpr .r5 - 1 ∧ + s'.gpr .r3 = s.gpr .r3 ∧ s'.gpr .r6 = s.gpr .r6 ∧ + (∀ r ∈ keepRegs, s'.gpr r = s.gpr r) ∧ s'.rd = s.rd ∧ s'.wr = s.wr := by + have hin : ∀ k : Nat, k < 8 → InRegions (s.rd ++ s.wr) (st s₀ + BitVec.ofNat 64 (4 * k)) 4 := by + rw [hrd, hwr]; exact fun k hk => hp.in_state hk + have hout : ∀ k : Nat, k < 8 → InRegions s.wr (st s₀ + BitVec.ofNat 64 (4 * k)) 4 := by + rw [hwr]; exact fun k hk => hp.out_state hk + have i0 := hin 0 (by decide); have i1 := hin 1 (by decide); have i2 := hin 2 (by decide) + have i3 := hin 3 (by decide); have i4 := hin (0 + 4) (by decide); have i5 := hin (1 + 4) (by decide) + have i6 := hin (2 + 4) (by decide); have i7 := hin (3 + 4) (by decide) + have o0 := hout 0 (by decide); have o1 := hout 1 (by decide); have o2 := hout 2 (by decide) + have o3 := hout 3 (by decide); have o4 := hout 4 (by decide); have o5 := hout 5 (by decide) + have o6 := hout 6 (by decide); have o7 := hout 7 (by decide) + have m0 := hH 0 (by decide); have m1 := hH 1 (by decide); have m2 := hH 2 (by decide) + have m3 := hH 3 (by decide); have m4 := hH (0 + 4) (by decide); have m5 := hH (1 + 4) (by decide) + have m6 := hH (2 + 4) (by decide); have m7 := hH (3 + 4) (by decide) + rw [vars0] at hv + obtain ⟨v0, v1, v2, v3, v4, v5, v6, v7⟩ := hv + apply WP.of_runBlock + rw [update_eq] + simp (config := {decide := true}) only [runBlock_cons, runStep_some, + runBlock_nil, exec_load_w, exec_store_w, exec_add, exec_addi, exec_subi, State.write, hr3, + i0, i1, i2, i3, i4, i5, i6, i7, o0, o1, o2, o3, o4, o5, o6, o7, ite_true, ite_false, + Option.some.injEq, exists_eq_left'] + simp (config := {decide := true}) only [lo32_add, BitVec.setWidth_setWidth_of_le, + BitVec.setWidth_eq, m0, m1, m2, m3, m4, m5, m6, m7, v0, v1, v2, v3, v4, v5, v6, v7] + refine ⟨?_, ?_⟩ + · simp only [writeState, Vector.getElem_zipWith] + and_intros + all_goals first + | trivial + | rfl + | (intro r hr + simp only [keepRegs, List.mem_cons, List.not_mem_nil, or_false] at hr + rcases hr with rfl | rfl | rfl | rfl | rfl | rfl | rfl | rfl | rfl | rfl | rfl | rfl | rfl <;> + simp (config := {decide := true})) + +theorem compressBlocks_succ (H : HashValue) (m : Mem) (p : Addr) (i : Nat) : + compressBlocks H m p (i + 1) = + compress (compressBlocks H m p i) (blockAt m (p + BitVec.ofNat 64 (64 * i))) := by + simp [compressBlocks, List.range_succ, List.foldl_append] + +theorem blk_word {s₀ : State} (i t : Nat) (ht : t < 16) : + rev32 (s₀.mem.readW (blkAddr s₀ i + BitVec.ofNat 64 (4 * t)) 32) = W (blk s₀ i) t := by + rw [W_lt _ ht, rev32_readW] + simp only [blk, blockAt, parseBlock] + rw [show blkAddr s₀ i + BitVec.ofNat 64 (4 * t) + 1 = blkAddr s₀ i + BitVec.ofNat 64 (4 * t + 1) by + bv_omega, + show blkAddr s₀ i + BitVec.ofNat 64 (4 * t + 1) + 1 = blkAddr s₀ i + BitVec.ofNat 64 (4 * t + 2) by + bv_omega, + show blkAddr s₀ i + BitVec.ofNat 64 (4 * t + 2) + 1 = blkAddr s₀ i + BitVec.ofNat 64 (4 * t + 3) by + bv_omega] + +theorem win_sub (p : Addr) : Region.Sub (winRegion p) ⟨p, 112⟩ := Region.sub_prefix (by omega) + +theorem body_ok {s₀ : State} (hp : Pre s₀) {i : Nat} (hi : i < nb s₀) {s : State} + (hL : LInv s₀ i s) : + WP isa body s fun s' => + (eval (.nonzero .d .r5) s' = some false ∧ Common s₀ (nb s₀) s') ∨ + (eval (.nonzero .d .r5) s' = some true ∧ i + 1 < nb s₀ ∧ LInv s₀ (i + 1) s') := by + refine WP.seq (WP.mono (load_ok hp hL.r3 hL.rd hL.wr) fun s₁ ⟨hv₁, hpub₁, hrd₁, hwr₁, hm₁⟩ => ?_) + have hwin : ∀ r' ∈ [winRegion (scr s₀)], (blR s₀).Disjoint r' := by + simpa using Region.Disjoint.sub_right hp.blk_scr (win_sub _) + have hblk : ∀ m, Frame [winRegion (scr s₀)] s₁.mem m → ∀ t : Nat, t < 16 → + rev32 (m.readW (blkAddr s₀ i + BitVec.ofNat 64 (4 * t)) 32) = W (blk s₀ i) t := by + intro m hm t ht + rw [hm.readW (hp.blk_contains hi ht) hwin (by decide), hm₁, + hL.frame.readW (hp.blk_contains hi ht) (by simpa using ⟨hp.blk_st, hp.blk_scr⟩) (by decide)] + exact blk_word i t ht + have hr4₁ : s₁.gpr .r4 = blkAddr s₀ i := (hpub₁ .r4 (by decide)).trans hL.r4 + have hr6₁ : s₁.gpr .r6 = scr s₀ := (hpub₁ .r6 (by decide)).trans hL.r6 + refine WP.seq (WP.mono (rounds_ok _ (blk s₀ i) _ (scr s₀) s₁ hr4₁ hr6₁ + (by rw [hrd₁, hwr₁, hL.rd, hL.wr]; exact hp.in_slot) + (by rw [hwr₁, hL.wr]; exact hp.out_slot) + (fun t ht => by rw [hrd₁, hwr₁, hL.rd, hL.wr]; exact hp.in_blk hi ht) hblk hv₁ 64 le_rfl) + fun s₂ hR => ?_) + have hst : ∀ r' ∈ [winRegion (scr s₀)], (stR s₀).Disjoint r' := by + simpa using Region.Disjoint.sub_right hp.st_scr (win_sub _) + have pub₂ : ∀ r ∈ pubRegs, s₂.gpr r = s.gpr r := fun r hr => by + rw [hR.pub r hr, hpub₁ r hr] + have hr3₂ : s₂.gpr .r3 = st s₀ := by rw [pub₂ .r3 (by decide), hL.r3] + refine WP.mono (update_ok hp _ (stateAt s.mem (st s₀)) hR.vars hr3₂ + (by rw [hR.rd, hrd₁, hL.rd]) (by rw [hR.wr, hwr₁, hL.wr]) fun k hk => ?_) fun s₃ h₃ => ?_ + · rw [hR.frame.readW (contains_offset (by omega) (by omega)) hst (by decide), hm₁, + stateAt_get _ _ hk] + obtain ⟨hm₃, hr4₃, hr5₃, hr3₃, hr6₃, hkept₃, hrd₃, hwr₃⟩ := h₃ + have hr5 : s₂.gpr .r5 - 1 = BitVec.ofNat 64 (nb s₀ - (i + 1)) := by + rw [pub₂ .r5 (by decide), hL.r5] + have := (s₀.gpr .r5).isLt + bv_omega + have hframe : Frame [stR s₀, scrR s₀] s₀.mem s₃.mem := by + refine hL.frame.trans ?_ + rw [← hm₁] + refine Frame.trans (hR.frame.sub fun r hr => ⟨scrR s₀, by simp, by simp at hr; subst hr; exact win_sub _⟩) ?_ + rw [hm₃] + exact (frame_writeState (Frame.refl _ _) _).sub fun r hr => ⟨r, by simp at hr; simp [hr], fun _ h => h⟩ + have hsav : ∀ j < 6, s₃.mem.readW (savAddr s₀ j) 64 = s₀.gpr (saved j) := by + intro j hj + have hd : (savR s₀).Disjoint (stR s₀) := + Region.Disjoint.sub_left hp.st_scr.symm (savR_sub s₀) + rw [hm₃, writeState] + simp only [savAddr] + iterate 8 rw [Mem.readW_writeW_sep (hd.sep (sav_contains s₀ hj) (contains_offset (by omega) + (by omega))) (by decide)] + rw [hR.frame.readW (r := savR s₀) (sav_contains s₀ hj) (by simpa using (win_sav s₀).symm) + (by decide), hm₁] + exact hL.sav j hj + have hcommon : ∀ j, j = i + 1 → Common s₀ j s₃ := by + rintro j rfl + refine ⟨by rw [hr3₃, hr3₂], by rw [hr6₃, pub₂ .r6 (by decide), hL.r6], + fun r hr => by rw [hkept₃ r hr, pub₂ r (keepRegs_pub r hr), hL.kept r hr], + by rw [hrd₃, hR.rd, hrd₁, hL.rd], by rw [hwr₃, hR.wr, hwr₁, hL.wr], hframe, hsav, ?_⟩ + rw [hm₃, stateAt_writeState, compressBlocks_succ, ← hL.state] + rfl + have hev : eval (.nonzero .d .r5) s₃ = some (BitVec.ofNat 64 (nb s₀ - (i + 1)) != 0) := by + simp only [eval, State.read, Size.bits, BitVec.setWidth_eq, hr5₃, hr5] + have := hp.nb_lt + by_cases hlast : i + 1 = nb s₀ + · left + refine ⟨by rw [hev, hlast]; simp, hlast ▸ hcommon _ rfl⟩ + · right + have hne : nb s₀ - (i + 1) ≠ 0 := by omega + have h0 : BitVec.ofNat 64 (nb s₀ - (i + 1)) ≠ 0 := by + intro h + have h' := congrArg BitVec.toNat h + rw [BitVec.toNat_ofNat, Nat.mod_eq_of_lt (by omega)] at h' + exact hne h' + refine ⟨by rw [hev]; simpa using h0, by omega, { hcommon _ rfl with r4 := ?_, r5 := ?_ }⟩ + · rw [hr4₃, pub₂ .r4 (by decide), hL.r4] + simp only [blkAddr] + bv_omega + · rw [hr5₃, hr5] + +/-! ## The whole function -/ + +theorem blocks_ok {s₀ : State} (hp : Pre s₀) {s₁ : State} (hc₀ : Common s₀ 0 s₁) + (hr4 : s₁.gpr .r4 = bp s₀) (hr5 : s₁.gpr .r5 = s₀.gpr .r5) : + WP isa blocks s₁ (Common s₀ (nb s₀)) := by + refine WP.ite (s₁.gpr .r5 == 0) (by simp [eval, State.read]) (fun h => ?_) (fun h => ?_) + · have h0 : nb s₀ = 0 := by simp [hr5] at h; simp [nb, h] + exact WP.block_nil (M := isa) (h0 ▸ hc₀) + · have hpos : 0 < nb s₀ := by + simp only [beq_eq_false_iff_ne, ne_eq, hr5] at h + exact Nat.pos_of_ne_zero fun h' => h (BitVec.eq_of_toNat_eq (by simpa using h')) + let Inv : Nat → State → Prop := fun m s => ∃ i, m = nb s₀ - i ∧ i < nb s₀ ∧ LInv s₀ i s + have hstep : ∀ m s, Inv m s → WP isa body s (fun s' => + (eval (.nonzero .d .r5) s' = some false ∧ Common s₀ (nb s₀) s') ∨ + (eval (.nonzero .d .r5) s' = some true ∧ ∃ m' < m, Inv m' s')) := by + rintro m s ⟨i, rfl, hi, hL⟩ + refine WP.mono (body_ok hp hi hL) fun s' h => ?_ + rcases h with ⟨he, hc⟩ | ⟨he, hi', hL'⟩ + · exact .inl ⟨he, hc⟩ + · exact .inr ⟨he, nb s₀ - (i + 1), by omega, i + 1, rfl, hi', hL'⟩ + have hL₀ : LInv s₀ 0 s₁ := + { hc₀ with + r4 := by simp [blkAddr, hr4] + r5 := by simp [nb, hr5] } + exact WP.loop (M := isa) Inv hstep (nb s₀) s₁ ⟨0, rfl, hpos, hL₀⟩ + +theorem correct {s₀ : State} (hp : Pre s₀) : + WP isa compress s₀ fun s' => + (∀ r ∈ preserved, s'.gpr r = s₀.gpr r) ∧ Proof.Sha256.compressPPC64LE.post s₀ s' := by + have hs₀ : SI s₀ 0 s₀ := ⟨rfl, rfl, rfl, Frame.refl _ _, fun _ h => absurd h (by omega)⟩ + have hsave : WP isa (.block save) s₀ (SI s₀ 6) := by + unfold save + exact wp_range_flatMap (M := isa) (SI s₀) (fun k s hk h => save_step hp hk h) 6 le_rfl s₀ hs₀ + refine WP.seq (WP.mono hsave fun s₁ h₁ => ?_) + have hc₀ : Common s₀ 0 s₁ := by + refine ⟨by rw [h₁.gpr], by rw [h₁.gpr], fun r _ => by rw [h₁.gpr], h₁.rd, h₁.wr, + h₁.frame.sub fun r hr => ?_, h₁.saved, ?_⟩ + · simp only [List.mem_singleton] at hr; subst hr + exact ⟨scrR s₀, by simp, savR_sub s₀⟩ + · show stateAt s₁.mem (st s₀) = H₀ s₀ + apply stateAt_eq + intro k hk + rw [h₁.frame.readW (r := stR s₀) (contains_offset (by omega) (by omega)) + (by simpa using Region.Disjoint.sub_right hp.st_scr (savR_sub s₀)) (by decide), + ← stateAt_get _ _ hk] + refine WP.seq (WP.mono (blocks_ok hp hc₀ (by rw [h₁.gpr]) (by rw [h₁.gpr])) fun s₂ h₂ => ?_) + have hr₀ : RI s₀ s₂ 0 s₂ := ⟨fun _ h => absurd h (by omega), fun _ _ => rfl, rfl, h₂.rd, h₂.wr⟩ + unfold restore + refine WP.mono (wp_range_flatMap (M := isa) (RI s₀ s₂) + (fun k s hk h => restore_step hp h₂.r6 h₂.sav hk h) 6 le_rfl s₂ hr₀) fun s' h => ⟨?_, ?_⟩ + · intro r hr + rcases preserved_cases r hr with ⟨i, hi, rfl⟩ | hk + · exact h.restored i hi + · rw [h.others r fun i hi e => (saved_ne hi).2.2 (e ▸ hk), h₂.kept r hk] + · show stateAt s'.mem (s₀.gpr .r3) = _ + rw [h.mem] + exact h₂.state + +/-- A state satisfying the precondition (with no blocks). -/ +def satState : State where + gpr r := match r with + | .r3 => 0x1000 | .r4 => 0x2000 | .r6 => 0x3000 | _ => 0 + lr := 0 + sp := 0x4000 + mem _ := 0 + rd := [⟨0x2000, 0⟩] + wr := [⟨0x1000, 32⟩, ⟨0x3000, 112⟩] + +theorem compress_verified : + Verified PPC64LE.target Impl.Sha256.PPC64LE.compress Proof.Sha256.compressPPC64LE := by + refine ⟨fun s hs => ?_, ?_, ?_⟩ + · obtain ⟨t, s', he, h₁, h₂⟩ := correct (pre_of s hs) + exact ⟨t, s', he, ⟨h₁, Exec.sp he, Exec.lr he (by decide +kernel) + (by rw [← Code.allInstrs_eq]; decide +kernel)⟩, h₂⟩ + · refine VG.Taint.constantTime (A := taint) (Taint.ofRegs [.r3, .r4, .r5, .r6]) ?_ (by taint_decide) + intro s₁ s₂ _ _ ⟨h1, h2, h3, h4, hsp⟩ + refine ⟨hsp, fun r hr => ?_⟩ + simp only [VG.PPC64LE.Taint.mem_ofRegs, List.mem_cons, List.not_mem_nil, or_false] at hr + rcases hr with rfl | rfl | rfl | rfl <;> assumption + · refine ⟨satState, rfl, rfl, ?_, ?_, ?_⟩ <;> + · intro a h₁ h₂ + simp only [Region.Contains, satState] at h₁ h₂ + bv_omega + +end VG.Proof.Sha256.PPC64LE diff --git a/lean/VerifiedGarbage/Proof/Sha256/PPC64LE/Contract.lean b/lean/VerifiedGarbage/Proof/Sha256/PPC64LE/Contract.lean new file mode 100644 index 000000000..89d79afcd --- /dev/null +++ b/lean/VerifiedGarbage/Proof/Sha256/PPC64LE/Contract.lean @@ -0,0 +1,110 @@ +import VerifiedGarbage.Spec.Sha256 +import VerifiedGarbage.TCB.PPC64LE.Target + +/-! +# SHA-256: the PPC64LE contract + +**Untrusted**: the contracts the proofs are written against; the artifacts are emitted with the shared contracts of `Spec/`, which imply these (`Contract.Implies`). The contracts of the PPC64LE +implementations of the compression function and the streaming interface, in +terms of `Spec/Sha256.lean`. + +The return address is in the link register, which the target's calling +convention requires to be preserved (`VG.PPC64LE.abiPreserved`), not on the +stack, so unlike on x86-64 no region needs to be kept disjoint from it. +-/ + +namespace VG.Proof.Sha256 + +open Spec.Sha256 + +open PPC64LE in +/-- PPC64LE contract for +`vg_sha256_compress(state: *mut [u32; 8], blocks: *const [u8; 64], n: usize, scratch: *mut [u64; 14])`: +updates the hash value at `state` with the `n` 64-byte blocks at `blocks`. + +The code may read `blocks` (`64 * n` bytes) and read and write `state` +(32 bytes) and `scratch` (112 bytes, whose contents on exit are unspecified). +These may not overlap each other. The pointers and `n` are public; the hash +value and the blocks are secret. -/ +def compressPPC64LE : Contract PPC64LE.isa where + pre s := + let state : Region := ⟨s.gpr .r3, 32⟩ + let blocks : Region := ⟨s.gpr .r4, 64 * (s.gpr .r5).toNat⟩ + let scratch : Region := ⟨s.gpr .r6, 112⟩ + s.rd = [blocks] ∧ s.wr = [state, scratch] ∧ + state.Disjoint scratch ∧ blocks.Disjoint state ∧ blocks.Disjoint scratch + post s s' := + stateAt s'.mem (s.gpr .r3) = + compressBlocks (stateAt s.mem (s.gpr .r3)) s.mem (s.gpr .r4) (s.gpr .r5).toNat + pub s₁ s₂ := + s₁.gpr .r3 = s₂.gpr .r3 ∧ s₁.gpr .r4 = s₂.gpr .r4 ∧ + s₁.gpr .r5 = s₂.gpr .r5 ∧ s₁.gpr .r6 = s₂.gpr .r6 ∧ s₁.sp = s₂.sp + +open PPC64LE in +/-- PPC64LE contract for `vg_sha256_init(state: *mut [u8; 96])`: makes the +streaming state at `state` represent the empty message. + +The code may write `state` (96 bytes). The pointer is public. -/ +def initPPC64LE : Contract PPC64LE.isa where + pre s := + let state : Region := ⟨s.gpr .r3, 96⟩ + s.rd = [] ∧ s.wr = [state] + post s s' := Repr s'.mem (s.gpr .r3) [] + pub s₁ s₂ := s₁.gpr .r3 = s₂.gpr .r3 ∧ s₁.sp = s₂.sp + +open PPC64LE in +/-- PPC64LE contract for +`vg_sha256_update(state: *mut [u8; 96], count: u64, data: *const u8, len: usize, scratch: *mut [u64; 20])`: +if the streaming state at `state` represents a message `m` of `count` bytes +(modulo 2⁶⁴), hashed from any initial hash value `iv`, then afterwards it +represents `m` followed by the `len` bytes at `data`, from `iv`. + +The code may read `data` (`len` bytes) and read and write `state` (96 +bytes) and `scratch` (160 bytes, whose contents on exit are unspecified). +These may not overlap each other, nor the 48 bytes below the stack pointer +(the frame saving the link register), which do not wrap around. The pointers, `count` and +`len` are public; the state and the data are secret. -/ +def updatePPC64LE : Contract PPC64LE.isa where + pre s := + let state : Region := ⟨s.gpr .r3, 96⟩ + let data : Region := ⟨s.gpr .r5, (s.gpr .r6).toNat⟩ + let scratch : Region := ⟨s.gpr .r7, 160⟩ + let stack : Region := ⟨s.sp - 48, 48⟩ + s.rd = [data] ∧ s.wr = [state, scratch] ∧ + state.Disjoint scratch ∧ data.Disjoint state ∧ data.Disjoint scratch ∧ + 48 ≤ s.sp.toNat ∧ stack.Disjoint state ∧ stack.Disjoint data ∧ stack.Disjoint scratch + post s s' := ∀ iv m, ReprFrom iv s.mem (s.gpr .r3) m → s.gpr .r4 = BitVec.ofNat 64 m.length → + ReprFrom iv s'.mem (s.gpr .r3) (m ++ bytesAt s.mem (s.gpr .r5) (s.gpr .r6).toNat) + pub s₁ s₂ := + s₁.gpr .r3 = s₂.gpr .r3 ∧ s₁.gpr .r4 = s₂.gpr .r4 ∧ s₁.gpr .r5 = s₂.gpr .r5 ∧ + s₁.gpr .r6 = s₂.gpr .r6 ∧ s₁.gpr .r7 = s₂.gpr .r7 ∧ s₁.sp = s₂.sp + +open PPC64LE in +/-- PPC64LE contract for +`vg_sha256_finalize(state: *mut [u8; 96], count: u64, out: *mut [u8; 32], scratch: *mut [u64; 20])`: +if the streaming state at `state` represents a message `m` of `count` bytes +(modulo 2⁶⁴), hashed from the initial hash value `iv`, writes the final hash +value of `m` from `iv` to `out` (the SHA-256 digest if `iv` is `H0`). + +The code may read and write `state` (96 bytes, whose contents on exit are +unspecified), `out` (32 bytes) and `scratch` (160 bytes, whose contents on +exit are unspecified). These may not overlap each other, nor the 48 bytes +below the stack pointer (the frame saving the link register), which do not +wrap around. +The pointers and `count` are public; the state is secret. -/ +def finalizePPC64LE : Contract PPC64LE.isa where + pre s := + let state : Region := ⟨s.gpr .r3, 96⟩ + let out : Region := ⟨s.gpr .r5, 32⟩ + let scratch : Region := ⟨s.gpr .r6, 160⟩ + let stack : Region := ⟨s.sp - 48, 48⟩ + s.rd = [] ∧ s.wr = [state, out, scratch] ∧ + state.Disjoint out ∧ state.Disjoint scratch ∧ out.Disjoint scratch ∧ + 48 ≤ s.sp.toNat ∧ stack.Disjoint state ∧ stack.Disjoint out ∧ stack.Disjoint scratch + post s s' := ∀ iv m, ReprFrom iv s.mem (s.gpr .r3) m → s.gpr .r4 = BitVec.ofNat 64 m.length → + bytesAt s'.mem (s.gpr .r5) 32 = Spec.Sha256.finalHash iv m + pub s₁ s₂ := + s₁.gpr .r3 = s₂.gpr .r3 ∧ s₁.gpr .r4 = s₂.gpr .r4 ∧ s₁.gpr .r5 = s₂.gpr .r5 ∧ + s₁.gpr .r6 = s₂.gpr .r6 ∧ s₁.sp = s₂.sp + +end VG.Proof.Sha256 diff --git a/lean/VerifiedGarbage/Proof/Sha256/PPC64LE/Rounds.lean b/lean/VerifiedGarbage/Proof/Sha256/PPC64LE/Rounds.lean new file mode 100644 index 000000000..0bb42cd34 --- /dev/null +++ b/lean/VerifiedGarbage/Proof/Sha256/PPC64LE/Rounds.lean @@ -0,0 +1,239 @@ +import Mathlib.Data.List.Nodup +import VerifiedGarbage.Proof.Framework.Block +import VerifiedGarbage.Proof.Framework.Mem +import VerifiedGarbage.Proof.Framework.PPC64LE.Taint +import VerifiedGarbage.Proof.Framework.PPC64LE.Exec +import VerifiedGarbage.Proof.Sha256.Spec +import VerifiedGarbage.Impl.Sha256.PPC64LE + +/-! +# SHA-256 compression function on PPC64LE: the message schedule and the rounds + +Untrusted: everything here is checked by Lean. +-/ + +namespace VG.Proof.Sha256.PPC64LE + +open VG VG.PPC64LE VG.Impl.Sha256.PPC64LE +open VG.Spec.Sha256 (HashValue Word Block K W bsig0 bsig1 ch maj ssig0 ssig1) + +/-- The working variables `v` are in the registers of round `t`. -/ +def Vars (t : Nat) (s : State) (v : HashValue) : Prop := + (s.gpr (var t 0)).setWidth 32 = v[0] ∧ (s.gpr (var t 1)).setWidth 32 = v[1] ∧ + (s.gpr (var t 2)).setWidth 32 = v[2] ∧ (s.gpr (var t 3)).setWidth 32 = v[3] ∧ + (s.gpr (var t 4)).setWidth 32 = v[4] ∧ (s.gpr (var t 5)).setWidth 32 = v[5] ∧ + (s.gpr (var t 6)).setWidth 32 = v[6] ∧ (s.gpr (var t 7)).setWidth 32 = v[7] + +/-- The pointers, the count and the nonvolatile registers the rounds do not +use: never written by the rounds. -/ +def pubRegs : List Reg := [.r3, .r4, .r5, .r6, .r2, .r20, .r21, .r22, .r23, .r24, .r25, .r26, + .r27, .r28, .r29, .r30, .r31] + +/-- The working variables move one register along each round. -/ +theorem var_succ (t k : Nat) (hk : k < 7) : var (t + 1) (k + 1) = var t k := by + simp only [var]; congr 1; omega + +theorem var_succ_zero (t : Nat) : var (t + 1) 0 = var t 7 := by + simp only [var]; congr 1; omega + +/-- The registers of a round are all different. -/ +theorem round_nodup (t : Nat) : + ([var t 0, var t 1, var t 2, var t 3, var t 4, var t 5, var t 6, var t 7, T0, T1, T2, T3] ++ + pubRegs).Nodup := by + simp only [var] + have := Nat.mod_lt t (show 8 > 0 by omega) + generalize t % 8 = c at * + interval_cases c <;> decide + +/-- The round is symbolically executed once, for any registers `a … h` +(which `round_nodup` says are different from each other and the others). -/ +theorem round_ok (t : Nat) (s : State) (v : HashValue) (w : Word) + (hv : Vars t s v) (hw : (s.gpr T0).setWidth 32 = w) : + WP isa (.block (round t)) s fun s' => + Vars (t + 1) s' (roundKW v (K t) w) ∧ + s'.mem = s.mem ∧ s'.rd = s.rd ∧ s'.wr = s.wr ∧ ∀ r ∈ pubRegs, s'.gpr r = s.gpr r := by + have hd' := List.nodup_reverse.mpr (round_nodup t) + -- The registers the round reads and writes. + have hs := (List.nodup_append.mp (round_nodup t)).1 + have hs' := List.nodup_reverse.mpr hs + simp only [Vars, var_succ_zero, var_succ t _ (show 0 < 7 by omega), + var_succ t _ (show 1 < 7 by omega), var_succ t _ (show 2 < 7 by omega), + var_succ t _ (show 3 < 7 by omega), var_succ t _ (show 4 < 7 by omega), + var_succ t _ (show 5 < 7 by omega), var_succ t _ (show 6 < 7 by omega)] at hv ⊢ + obtain ⟨h0, h1, h2, h3, h4, h5, h6, h7⟩ := hv + apply WP.of_runBlock + simp only [Impl.Sha256.PPC64LE.round] + generalize var t 0 = a at * + generalize var t 1 = b at * + generalize var t 2 = c at * + generalize var t 3 = d at * + generalize var t 4 = e at * + generalize var t 5 = f at * + generalize var t 6 = g at * + generalize var t 7 = h at * + simp only [T0, T1, T2, T3, pubRegs, List.nodup_cons, List.mem_cons, List.not_mem_nil, + List.reverse_cons, List.reverse_nil, List.nil_append, List.cons_append, or_false, not_or, + List.nodup_nil, and_true] at hs hs' hd' hw ⊢ + simp (config := {decide := true}) only [runBlock_cons, runStep_some, + runBlock_nil, exec, isa, State.read, State.write, Size.bits, Size.ext, + ite_true, ite_false, hs, hs', Option.some.injEq, exists_eq_left'] + refine ⟨⟨?_, ?_, ?_, ?_, ?_, ?_, ?_, ?_⟩, trivial, trivial, trivial, fun r hr => ?_⟩ + rotate_right + · rcases hr with rfl | rfl | rfl | rfl | rfl | rfl | rfl | rfl | rfl | rfl | rfl | rfl | rfl | + rfl | rfl | rfl | rfl <;> simp [hd'] + all_goals + simp (config := {decide := true}) only [lo32_add, BitVec.setWidth_xor, BitVec.setWidth_and, + BitVec.setWidth_or, BitVec.setWidth_setWidth_of_le, BitVec.setWidth_eq, lis_ori', h0, h1, h2, + h3, h4, h5, h6, h7, hw] + all_goals + simp (config := {failIfUnchanged := false}) only [roundKW, bsig1, ch_eq, bsig0, maj_eq, + Vector.getElem_mk, List.getElem_toArray, List.getElem_cons_zero, + List.getElem_cons_succ] <;> + simp (config := {failIfUnchanged := false}) only [BitVec.add_assoc] + +theorem slot_ok (j : Nat) : slot j < 2 ^ 15 := by + simp only [slot]; omega + +/-- The address of `W[j mod 16]`. -/ +abbrev slotAddr (scr : Addr) (j : Nat) : Addr := scr + BitVec.ofNat 64 (slot j) + +theorem schedule_ok (t : Nat) (s : State) (M : Block) (bp scr : Addr) + (hr4 : s.gpr .r4 = bp) (hr6 : s.gpr .r6 = scr) + (hin : ∀ j, InRegions (s.rd ++ s.wr) (slotAddr scr j) 4) + (hout : ∀ j, InRegions s.wr (slotAddr scr j) 4) + (hbin : t < 16 → InRegions (s.rd ++ s.wr) (bp + BitVec.ofNat 64 (4 * t)) 4) + (hblk : t < 16 → rev32 (s.mem.readW (bp + BitVec.ofNat 64 (4 * t)) 32) = W M t) + (hwin : 16 ≤ t → ∀ j, j < t → t ≤ j + 16 → s.mem.readW (slotAddr scr j) 32 = W M j) : + WP isa (.block (schedule t)) s fun s' => + (s'.gpr T0).setWidth 32 = W M t ∧ + s'.mem = s.mem.writeW (slotAddr scr t) (W M t) ∧ + s'.rd = s.rd ∧ s'.wr = s.wr ∧ + ∀ r, r ≠ T0 → r ≠ T1 → r ≠ T2 → r ≠ T3 → r ≠ .r0 → s'.gpr r = s.gpr r := by + simp only [slotAddr] at hin hout hwin ⊢ + apply WP.of_runBlock + by_cases ht : t < 16 + · have hi := hbin ht + have hb := hblk ht + simp only [Impl.Sha256.PPC64LE.schedule, ht, ite_true, T0, T1, T2, T3] + simp (config := {decide := true}) only [runBlock_cons, runStep_some, + runBlock_nil, exec_li (show 4 * t < 2 ^ 15 by omega), exec_loadRev_w, exec_store_w, + slot_ok, isa, State.write, hr4, hr6, hi, hout, ite_true, + ite_false, BitVec.setWidth_setWidth_of_le, BitVec.setWidth_eq, hb, + Option.some.injEq, exists_eq_left'] + refine ⟨trivial, trivial, trivial, trivial, fun r h0 _ _ _ h4 => ?_⟩ + simp [h0, h4] + · have hw := hwin (by omega) + have e2 := hw (t - 2) (by omega) (by omega) + have e7 := hw (t - 7) (by omega) (by omega) + have e15 := hw (t - 15) (by omega) (by omega) + have e16 := hw (t - 16) (by omega) (by omega) + rw [show slot (t - 2) = slot (t + 14) by simp only [slot]; omega] at e2 + rw [show slot (t - 7) = slot (t + 9) by simp only [slot]; omega] at e7 + rw [show slot (t - 15) = slot (t + 1) by simp only [slot]; omega] at e15 + rw [show slot (t - 16) = slot t by simp only [slot]; omega] at e16 + simp only [Impl.Sha256.PPC64LE.schedule, ht, ite_false, T0, T1, T2, T3] + simp (config := {decide := true}) only [runBlock_cons, runStep_some, + runBlock_nil, exec_load_w, exec_store_w, slot_ok, exec_add, exec_logic, exec_rotr_w, + exec_lsr_w, isa, State.write, hr6, hin, hout, ite_true, ite_false, Option.some.injEq, + exists_eq_left'] + simp (config := {decide := true}) only [lo32_add, BitVec.setWidth_xor, + BitVec.setWidth_setWidth_of_le, BitVec.setWidth_eq, e2, e7, e15, e16] + have hW := W_ge M (t := t) (by omega) + refine ⟨by rw [hW]; rfl, by rw [hW]; rfl, trivial, trivial, fun r h0 h1 h2 h3 _ => ?_⟩ + simp [h0, h1, h2, h3] + +/-! ## The 64 rounds -/ + +theorem var_mem (t k : Nat) : var t k ∈ work := by + unfold var List.getD + cases h : work[(k + 8 - t % 8) % 8]? + · simp [work] + · exact List.mem_of_getElem? h + +theorem work_ne' : ∀ r ∈ work, r ≠ T0 ∧ r ≠ T1 ∧ r ≠ T2 ∧ r ≠ T3 ∧ r ≠ .r0 := by decide + +theorem work_ne {r : Reg} (h : r ∈ work) : r ≠ T0 ∧ r ≠ T1 ∧ r ≠ T2 ∧ r ≠ T3 ∧ r ≠ .r0 := + work_ne' r h + +theorem pubRegs_ne' : ∀ r ∈ pubRegs, r ≠ T0 ∧ r ≠ T1 ∧ r ≠ T2 ∧ r ≠ T3 ∧ r ≠ .r0 := by decide + +theorem pubRegs_ne {r : Reg} (h : r ∈ pubRegs) : r ≠ T0 ∧ r ≠ T1 ∧ r ≠ T2 ∧ r ≠ T3 ∧ r ≠ .r0 := + pubRegs_ne' r h + +/-- The window `⟨scr, 64⟩`. -/ +abbrev winRegion (scr : Addr) : Region := ⟨scr, 64⟩ + +theorem win_contains (scr : Addr) (j : Nat) : (winRegion scr).Contains (slotAddr scr j) 4 := by + simp only [Region.Contains, slotAddr, slot] + have : j % 16 < 16 := Nat.mod_lt _ (by omega) + generalize j % 16 = p at * + rw [show scr + BitVec.ofNat 64 (4 * p) - scr = BitVec.ofNat 64 (4 * p) by bv_omega] + simp only [BitVec.toNat_ofNat] + omega + +theorem slot_sep (scr : Addr) {i j : Nat} (h : i % 16 ≠ j % 16) : + Mem.Sep (slotAddr scr i) 4 (slotAddr scr j) 4 := by + intro x hx hy + simp only [slotAddr, slot] at hx hy + have hi : i % 16 < 16 := Nat.mod_lt _ (by omega) + have hj : j % 16 < 16 := Nat.mod_lt _ (by omega) + generalize i % 16 = p at * + generalize j % 16 = q at * + bv_omega + +/-- Rounds invariant, relative to the state `sB` at the start of the rounds. -/ +structure RInv (H : HashValue) (M : Block) (scr : Addr) (sB : State) (t : Nat) (s : State) : Prop where + vars : Vars t s (VG.Spec.Sha256.rounds H M t) + pub : ∀ r ∈ pubRegs, s.gpr r = sB.gpr r + rd : s.rd = sB.rd + wr : s.wr = sB.wr + frame : Frame [winRegion scr] sB.mem s.mem + win : ∀ j < t, t ≤ j + 16 → s.mem.readW (slotAddr scr j) 32 = W M j + +theorem rounds_ok (H : HashValue) (M : Block) (bp scr : Addr) (sB : State) + (hrsi : sB.gpr .r4 = bp) (hrcx : sB.gpr .r6 = scr) + (hin : ∀ j, InRegions (sB.rd ++ sB.wr) (slotAddr scr j) 4) + (hout : ∀ j, InRegions sB.wr (slotAddr scr j) 4) + (hbin : ∀ t : Nat, t < 16 → InRegions (sB.rd ++ sB.wr) (bp + BitVec.ofNat 64 (4 * t)) 4) + (hblk : ∀ m, Frame [winRegion scr] sB.mem m → + ∀ t : Nat, t < 16 → rev32 (m.readW (bp + BitVec.ofNat 64 (4 * t)) 32) = W M t) + (h0 : Vars 0 sB H) : + ∀ t ≤ 64, WP isa (rounds t) sB (RInv H M scr sB t) := by + intro t ht + induction t with + | zero => + refine WP.block_nil (M := isa) ⟨?_, fun _ _ => rfl, rfl, rfl, Frame.refl _ _, fun j hj => absurd hj (by omega)⟩ + rw [rounds_zero]; exact h0 + | succ t ih => + refine WP.seq (WP.mono (ih (by omega)) fun s hs => ?_) + rw [WP.block_append_iff] + have hs_rsi : s.gpr .r4 = bp := (hs.pub .r4 (by decide)).trans hrsi + have hs_rcx : s.gpr .r6 = scr := (hs.pub .r6 (by decide)).trans hrcx + refine WP.mono (schedule_ok t s M bp scr hs_rsi hs_rcx + (by rw [hs.rd, hs.wr]; exact hin) (by rw [hs.wr]; exact hout) + (fun h => by rw [hs.rd, hs.wr]; exact hbin t h) (hblk _ hs.frame t) + (fun _ => hs.win)) fun s₁ ⟨hT0, hm₁, hrd₁, hwr₁, hr₁⟩ => ?_ + have hv₁ : Vars t s₁ (VG.Spec.Sha256.rounds H M t) := by + have hv := hs.vars + have e : ∀ k, s₁.gpr (var t k) = s.gpr (var t k) := fun k => + have := work_ne (var_mem t k); hr₁ _ this.1 this.2.1 this.2.2.1 this.2.2.2.1 this.2.2.2.2 + simp only [Vars, e] at hv ⊢ + exact hv + refine WP.mono (round_ok t s₁ _ _ hv₁ hT0) fun s₂ ⟨hv₂, hm₂, hrd₂, hwr₂, hr₂⟩ => ?_ + refine ⟨?_, fun r hr => ?_, by rw [hrd₂, hrd₁, hs.rd], by rw [hwr₂, hwr₁, hs.wr], ?_, ?_⟩ + · have e : VG.Spec.Sha256.rounds H M (t + 1) = + roundKW (VG.Spec.Sha256.rounds H M t) (K t) (W M t) := by + rw [rounds_succ, round_eq] + rw [e]; exact hv₂ + · have := pubRegs_ne hr + rw [hr₂ r hr, hr₁ r this.1 this.2.1 this.2.2.1 this.2.2.2.1 this.2.2.2.2, hs.pub r hr] + · rw [hm₂, hm₁] + exact hs.frame.writeW (List.mem_singleton_self _) _ (win_contains scr t) + · intro j hj hj' + rw [hm₂, hm₁] + by_cases hjt : j = t + · subst hjt; exact Mem.readW_writeW_self32 _ _ _ + · rw [Mem.readW_writeW_sep (slot_sep scr (by omega)) (by decide)] + exact hs.win j (by omega) (by omega) + +end VG.Proof.Sha256.PPC64LE diff --git a/lean/VerifiedGarbage/Proof/Sha256/PPC64LE/Shared.lean b/lean/VerifiedGarbage/Proof/Sha256/PPC64LE/Shared.lean new file mode 100644 index 000000000..d6d8f051a --- /dev/null +++ b/lean/VerifiedGarbage/Proof/Sha256/PPC64LE/Shared.lean @@ -0,0 +1,137 @@ +import VerifiedGarbage.Proof.Framework.Contract +import VerifiedGarbage.Proof.Framework.PPC64LE.Inline +import VerifiedGarbage.Proof.Sha256.PPC64LE.Compress +import VerifiedGarbage.Proof.Sha256.PPC64LE.Stream.Finalize +import VerifiedGarbage.Proof.Sha256.PPC64LE.Stream.Init +import VerifiedGarbage.Proof.Sha256.PPC64LE.Stream.Update +import VerifiedGarbage.Spec.Sha256.Contract + +/-! +# Sha256 on PPC64LE: the shared contracts + +Untrusted: everything here is checked by Lean. The proofs are written against +per-target contracts (`Proof/Sha256/PPC64LE/Contract.lean`); these theorems move +them to the shared contracts of `Spec/Sha256/Contract.lean`, which the +artifacts are emitted with. + +The shared contracts give the functions more scratch than these ones use (560 +bytes for `compress`, 608 for `update` and `finalize`, sized for x86-64's AVX2 +compression function): the per-target contracts are first widened to that +scratch (`Verified.widen`, the same code running with the same trace and +result), then moved to the shared ones. +-/ + +namespace VG.Proof.Sha256.PPC64LE.Shared + +open _root_.VG.PPC64LE + +/-- `compressPPC64LE` with 560 bytes of scratch. -/ +def compressWide : Contract PPC64LE.isa := + { Proof.Sha256.compressPPC64LE with + pre := fun s => + let state : Region := ⟨s.gpr .r3, 32⟩ + let blocks : Region := ⟨s.gpr .r4, 64 * (s.gpr .r5).toNat⟩ + let scratch : Region := ⟨s.gpr .r6, 560⟩ + s.rd = [blocks] ∧ s.wr = [state, scratch] ∧ + state.Disjoint scratch ∧ blocks.Disjoint state ∧ blocks.Disjoint scratch } + +/-- `updatePPC64LE` with 608 bytes of scratch. -/ +def updateWide : Contract PPC64LE.isa := + { Proof.Sha256.updatePPC64LE with + pre := fun s => + let state : Region := ⟨s.gpr .r3, 96⟩ + let data : Region := ⟨s.gpr .r5, (s.gpr .r6).toNat⟩ + let scratch : Region := ⟨s.gpr .r7, 608⟩ + let stack : Region := ⟨s.sp - 48, 48⟩ + s.rd = [data] ∧ s.wr = [state, scratch] ∧ + state.Disjoint scratch ∧ data.Disjoint state ∧ data.Disjoint scratch ∧ + 48 ≤ s.sp.toNat ∧ stack.Disjoint state ∧ stack.Disjoint data ∧ stack.Disjoint scratch } + +/-- `finalizePPC64LE` with 608 bytes of scratch. -/ +def finalizeWide : Contract PPC64LE.isa := + { Proof.Sha256.finalizePPC64LE with + pre := fun s => + let state : Region := ⟨s.gpr .r3, 96⟩ + let out : Region := ⟨s.gpr .r5, 32⟩ + let scratch : Region := ⟨s.gpr .r6, 608⟩ + let stack : Region := ⟨s.sp - 48, 48⟩ + s.rd = [] ∧ s.wr = [state, out, scratch] ∧ + state.Disjoint out ∧ state.Disjoint scratch ∧ out.Disjoint scratch ∧ + 48 ≤ s.sp.toNat ∧ stack.Disjoint state ∧ stack.Disjoint out ∧ stack.Disjoint scratch } + +theorem pfx {a : Addr} {m n : Nat} (h : Nat.ble m n = true) : Region.Prefix ⟨a, m⟩ ⟨a, n⟩ := + ⟨rfl, Nat.le_of_ble_eq_true h⟩ +theorem sub112 (a : Addr) : Region.Sub ⟨a, 112⟩ ⟨a, 560⟩ := Region.sub_prefix (by decide) +theorem sub160 (a : Addr) : Region.Sub ⟨a, 160⟩ ⟨a, 608⟩ := Region.sub_prefix (by decide) + +theorem compressWide_verified (hsat : ∃ s, compressWide.pre s) : + Verified PPC64LE.target Impl.Sha256.PPC64LE.compress compressWide := + Verified.widen Proof.Sha256.PPC64LE.compress_verified + (fun s => [⟨s.gpr .r3, 32⟩, ⟨s.gpr .r6, 112⟩]) + (fun _ ⟨h₁, _, h₃, h₄, h₅⟩ => ⟨h₁, rfl, h₃.sub_right (sub112 _), h₄, h₅.sub_right (sub112 _)⟩) + (fun _ ⟨_, h₂, _⟩ => h₂ ▸ .cons (pfx rfl) (.cons (pfx rfl) .nil)) + (fun _ _ _ h => h) (fun _ _ _ _ h => h) hsat + +theorem updateWide_verified (hsat : ∃ s, updateWide.pre s) : + Verified PPC64LE.target Impl.Sha256.PPC64LE.Stream.update updateWide := + Verified.widen Proof.Sha256.PPC64LE.Stream.Update.update_verified + (fun s => [⟨s.gpr .r3, 96⟩, ⟨s.gpr .r7, 160⟩]) + (fun _ ⟨h₁, _, h₃, h₄, h₅, h₆, h₇, h₈, h₉⟩ => + ⟨h₁, rfl, h₃.sub_right (sub160 _), h₄, h₅.sub_right (sub160 _), h₆, h₇, h₈, + h₉.sub_right (sub160 _)⟩) + (fun _ ⟨_, h₂, _⟩ => h₂ ▸ .cons (pfx rfl) (.cons (pfx rfl) .nil)) + (fun _ _ _ h => h) (fun _ _ _ _ h => h) hsat + +theorem finalizeWide_verified (hsat : ∃ s, finalizeWide.pre s) : + Verified PPC64LE.target Impl.Sha256.PPC64LE.Stream.finalize finalizeWide := + Verified.widen Proof.Sha256.PPC64LE.Stream.Finalize.finalize_verified + (fun s => [⟨s.gpr .r3, 96⟩, ⟨s.gpr .r5, 32⟩, ⟨s.gpr .r6, 160⟩]) + (fun _ ⟨h₁, _, h₃, h₄, h₅, h₆, h₇, h₈, h₉⟩ => + ⟨h₁, rfl, h₃, h₄.sub_right (sub160 _), h₅.sub_right (sub160 _), h₆, h₇, h₈, + h₉.sub_right (sub160 _)⟩) + (fun _ ⟨_, h₂, _⟩ => h₂ ▸ .cons (pfx rfl) (.cons (pfx rfl) (.cons (pfx rfl) .nil))) + (fun _ _ _ h => h) (fun _ _ _ _ h => h) hsat + +/-- A state satisfying `compressWide.pre`. -/ +def compressSat : State := { Proof.Sha256.PPC64LE.satState with wr := [⟨0x1000, 32⟩, ⟨0x3000, 560⟩] } + +/-- A state satisfying `updateWide.pre`. -/ +def updateSat : State := + { Proof.Sha256.PPC64LE.Stream.Update.sat with wr := [⟨0x1000, 96⟩, ⟨0x3000, 608⟩] } + +/-- A state satisfying `finalizeWide.pre`. -/ +def finalizeSat : State := + { Proof.Sha256.PPC64LE.Stream.Finalize.sat with wr := [⟨0x1000, 96⟩, ⟨0x2000, 32⟩, ⟨0x3000, 608⟩] } + +theorem compress : + Verified PPC64LE.target Impl.Sha256.PPC64LE.compress (Spec.Sha256.compressContract PPC64LE.abi) := by + have hi : compressWide.Implies (Spec.Sha256.compressContract PPC64LE.abi) := by + contract_implies [Spec.Sha256.compressContract, Spec.Sha256.compressSig, compressWide, + Proof.Sha256.compressPPC64LE, PPC64LE.abi, PPC64LE.argRegs] + [compressSat, Proof.Sha256.PPC64LE.satState] using compressSat + exact (compressWide_verified hi.sat_left).of_implies hi + +theorem init : + Verified PPC64LE.target Impl.Sha256.PPC64LE.Stream.init (Spec.Sha256.initContract PPC64LE.abi) := + Proof.Sha256.PPC64LE.Stream.init_verified.of_implies (by + contract_implies [Spec.Sha256.initContract, Spec.Sha256.initSig, Proof.Sha256.initPPC64LE, + PPC64LE.abi, PPC64LE.argRegs] + [Proof.Sha256.PPC64LE.Stream.initSat] using Proof.Sha256.PPC64LE.Stream.initSat) + +theorem update : + Verified PPC64LE.target Impl.Sha256.PPC64LE.Stream.update (Spec.Sha256.updateContract PPC64LE.abi 48) := by + have hi : updateWide.Implies (Spec.Sha256.updateContract PPC64LE.abi 48) := by + contract_implies [Spec.Sha256.updateContract, Spec.Sha256.updateSig, updateWide, + Proof.Sha256.updatePPC64LE, PPC64LE.abi, PPC64LE.argRegs] + [updateSat, Proof.Sha256.PPC64LE.Stream.Update.sat] using updateSat + exact (updateWide_verified hi.sat_left).of_implies hi + +theorem finalize : + Verified PPC64LE.target Impl.Sha256.PPC64LE.Stream.finalize (Spec.Sha256.finalizeContract PPC64LE.abi 48) := by + have hi : finalizeWide.Implies (Spec.Sha256.finalizeContract PPC64LE.abi 48) := by + contract_implies [Spec.Sha256.finalizeContract, Spec.Sha256.finalizeSig, finalizeWide, + Proof.Sha256.finalizePPC64LE, PPC64LE.abi, PPC64LE.argRegs] + [finalizeSat, Proof.Sha256.PPC64LE.Stream.Finalize.sat] using finalizeSat + exact (finalizeWide_verified hi.sat_left).of_implies hi + +end VG.Proof.Sha256.PPC64LE.Shared diff --git a/lean/VerifiedGarbage/Proof/Sha256/PPC64LE/Stream/Common.lean b/lean/VerifiedGarbage/Proof/Sha256/PPC64LE/Stream/Common.lean new file mode 100644 index 000000000..b1101ef29 --- /dev/null +++ b/lean/VerifiedGarbage/Proof/Sha256/PPC64LE/Stream/Common.lean @@ -0,0 +1,473 @@ +import VerifiedGarbage.Proof.Sha256.PPC64LE.Compress +import VerifiedGarbage.Proof.Sha256.Stream +import VerifiedGarbage.Proof.Framework.PPC64LE.Call +import VerifiedGarbage.Impl.Sha256.PPC64LE.Stream + +/-! +# Streaming SHA-256 on PPC64LE: common lemmas + +Untrusted: everything here is checked by Lean. Weakest-precondition rules for +the instruction forms used, and the call of the compression function +(`compressAt`). +-/ + +namespace VG.Proof.Sha256.PPC64LE.Stream + +open VG VG.PPC64LE VG.Impl.Sha256.PPC64LE.Stream +open VG.Proof.Sha256.PPC64LE (compress_verified) +open VG.Spec.Sha256 (HashValue stateAt blockAt compressBlocks compress parseBlock bytesAt) + +/-! ## One instruction at a time -/ + +/-- `s'` is `s` with register `d` set to `v`. -/ +structure Upd (s s' : State) (d : Reg) (v : BitVec 64) : Prop where + gpr : s'.gpr d = v + other : ∀ r, r ≠ d → s'.gpr r = s.gpr r + mem : s'.mem = s.mem + rd : s'.rd = s.rd + wr : s'.wr = s.wr + sp : s'.sp = s.sp + +theorem Upd.write (s : State) (d : Reg) (v : BitVec 64) : Upd s (s.write d v) d v := + ⟨by simp [State.write], fun r h => by simp [State.write, h], rfl, rfl, rfl, rfl⟩ + +theorem read_one (m : Mem) (a : Addr) : (m.read a 1 : BitVec 8) = m a := by + simp only [Mem.read] + ext i hi + rw [BitVec.getElem_append] + simp only [show i < 8 by omega, dite_true] + +/-- `s'` is `s` with memory `m`. -/ +structure Mupd (s s' : State) (m : Mem) : Prop where + gpr : s'.gpr = s.gpr + mem : s'.mem = m + rd : s'.rd = s.rd + wr : s'.wr = s.wr + sp : s'.sp = s.sp + +theorem WP.cons {i : Instr} {is : List Instr} {s s' : State} {Q : State → Prop} + (h : exec i s = some s') (k : WP isa (.block is) s' Q) : WP isa (.block (i :: is)) s Q := + WP.block_cons_iff.mpr ⟨s', h, k⟩ + +section +variable {is : List Instr} {s : State} {Q : State → Prop} + +theorem wp_addi {d n : Reg} {imm : Nat} (hn : n ≠ .r0) (h : imm < 2 ^ 15) + (k : ∀ s', Upd s s' d (s.gpr n + BitVec.ofNat 64 imm) → WP isa (.block is) s' Q) : + WP isa (.block (.addi d n imm :: is)) s Q := + WP.cons (exec_addi hn h) (k _ (Upd.write _ _ _)) + +theorem wp_mov {d n : Reg} (k : ∀ s', Upd s s' d (s.gpr n) → WP isa (.block is) s' Q) + (hn : n ≠ .r0 := by decide) : + WP isa (.block (mov d n :: is)) s Q := + wp_addi hn (by decide) fun s' u => k s' (by simpa using u) + +theorem wp_subi {d n : Reg} {imm : Nat} (hn : n ≠ .r0) (h : imm ≤ 2 ^ 15) + (k : ∀ s', Upd s s' d (s.gpr n - BitVec.ofNat 64 imm) → WP isa (.block is) s' Q) : + WP isa (.block (.subi d n imm :: is)) s Q := + WP.cons (exec_subi hn h) (k _ (Upd.write _ _ _)) + +theorem wp_li {d : Reg} {imm : Nat} (h : imm < 2 ^ 15) + (k : ∀ s', Upd s s' d (BitVec.ofNat 64 imm) → WP isa (.block is) s' Q) : + WP isa (.block (.li d imm :: is)) s Q := + WP.cons (exec_li h) (k _ (Upd.write _ _ _)) + +theorem wp_add {d n m : Reg} + (k : ∀ s', Upd s s' d (s.gpr n + s.gpr m) → WP isa (.block is) s' Q) : + WP isa (.block (.add d n m :: is)) s Q := + WP.cons exec_add (k _ (Upd.write _ _ _)) + +theorem wp_sub {d n m : Reg} + (k : ∀ s', Upd s s' d (s.gpr n - s.gpr m) → WP isa (.block is) s' Q) : + WP isa (.block (.sub d n m :: is)) s Q := + WP.cons exec_sub (k _ (Upd.write _ _ _)) + +theorem wp_and {d n m : Reg} + (k : ∀ s', Upd s s' d (s.gpr n &&& s.gpr m) → WP isa (.block is) s' Q) : + WP isa (.block (.logic .and d n m :: is)) s Q := + WP.cons exec_logic (k _ (Upd.write _ _ _)) + +theorem wp_lsr {d n : Reg} {sh : Nat} (h : sh < 64) + (k : ∀ s', Upd s s' d (s.gpr n >>> sh) → WP isa (.block is) s' Q) : + WP isa (.block (.lsr .d d n sh :: is)) s Q := + WP.cons (exec_lsr_d h) (k _ (Upd.write _ _ _)) + +theorem wp_lbz {t n : Reg} {off : Nat} {a : Addr} (hn : n ≠ .r0) (ho : off < 2 ^ 15) + (ha : s.gpr n + BitVec.ofNat 64 off = a) (hin : InRegions (s.rd ++ s.wr) a 1) + (k : ∀ s', Upd s s' t ((s.mem a).setWidth 64) → WP isa (.block is) s' Q) : + WP isa (.block (.lbz t n off :: is)) s Q := by + refine WP.cons (s' := s.write t ((s.mem a).setWidth 64)) ?_ (k _ (Upd.write _ _ _)) + rw [exec_lbz hn ho (by rw [ha]; exact hin), ha, read_one] + +theorem wp_stb {t n : Reg} {off : Nat} {a : Addr} (hn : n ≠ .r0) (ho : off < 2 ^ 15) + (ha : s.gpr n + BitVec.ofNat 64 off = a) (hout : InRegions s.wr a 1) + (k : ∀ s', Mupd s s' (s.mem.writeW a ((s.gpr t).setWidth 8)) → WP isa (.block is) s' Q) : + WP isa (.block (.stb t n off :: is)) s Q := by + refine WP.cons (s' := { s with mem := s.mem.writeW a ((s.gpr t).setWidth 8) }) ?_ + (k _ ⟨rfl, rfl, rfl, rfl, rfl⟩) + rw [exec_stb hn ho (by rw [ha]; exact hout), ha] + rfl + +theorem wp_std {t n : Reg} {off : Nat} {a : Addr} (hn : n ≠ .r0) (ho : off < 2 ^ 15 ∧ off % 4 = 0) + (ha : s.gpr n + BitVec.ofNat 64 off = a) (hout : InRegions s.wr a 8) + (k : ∀ s', Mupd s s' (s.mem.writeW a (s.gpr t)) → WP isa (.block is) s' Q) : + WP isa (.block (.store .d t n off :: is)) s Q := by + refine WP.cons (s' := { s with mem := s.mem.writeW a (s.gpr t) }) ?_ (k _ ⟨rfl, rfl, rfl, rfl, rfl⟩) + rw [exec_store_d hn ho (by rw [ha]; exact hout), ha] + +theorem wp_stw {t n : Reg} {off : Nat} {a : Addr} (hn : n ≠ .r0) (ho : off < 2 ^ 15) + (ha : s.gpr n + BitVec.ofNat 64 off = a) (hout : InRegions s.wr a 4) + (k : ∀ s', Mupd s s' (s.mem.writeW a ((s.gpr t).setWidth 32)) → WP isa (.block is) s' Q) : + WP isa (.block (.store .w t n off :: is)) s Q := by + refine WP.cons (s' := { s with mem := s.mem.writeW a ((s.gpr t).setWidth 32) }) ?_ + (k _ ⟨rfl, rfl, rfl, rfl, rfl⟩) + rw [exec_store_w hn ho (by rw [ha]; exact hout), ha] + +theorem wp_ld {t n : Reg} {off : Nat} {a : Addr} (hn : n ≠ .r0) (ho : off < 2 ^ 15 ∧ off % 4 = 0) + (ha : s.gpr n + BitVec.ofNat 64 off = a) (hin : InRegions (s.rd ++ s.wr) a 8) + (k : ∀ s', Upd s s' t (s.mem.readW a 64) → WP isa (.block is) s' Q) : + WP isa (.block (.load .d t n off :: is)) s Q := by + refine WP.cons (s' := s.write t (s.mem.readW a 64)) ?_ (k _ (Upd.write _ _ _)) + rw [exec_load_d hn ho (by rw [ha]; exact hin), ha] + +theorem wp_lwz {t n : Reg} {off : Nat} {a : Addr} (hn : n ≠ .r0) (ho : off < 2 ^ 15) + (ha : s.gpr n + BitVec.ofNat 64 off = a) (hin : InRegions (s.rd ++ s.wr) a 4) + (k : ∀ s', Upd s s' t ((s.mem.readW a 32).setWidth 64) → WP isa (.block is) s' Q) : + WP isa (.block (.load .w t n off :: is)) s Q := by + refine WP.cons (s' := s.write t ((s.mem.readW a 32).setWidth 64)) ?_ (k _ (Upd.write _ _ _)) + rw [exec_load_w hn ho (by rw [ha]; exact hin), ha] + +theorem wp_stwbrx {t n m : Reg} {a : Addr} (hn : n ≠ .r0) + (ha : s.gpr n + s.gpr m = a) (hout : InRegions s.wr a 4) + (k : ∀ s', Mupd s s' (s.mem.writeW a (rev32 ((s.gpr t).setWidth 32))) → WP isa (.block is) s' Q) : + WP isa (.block (.storeRev .w t n m :: is)) s Q := by + refine WP.cons (s' := { s with mem := s.mem.writeW a (rev32 ((s.gpr t).setWidth 32)) }) ?_ + (k _ ⟨rfl, rfl, rfl, rfl, rfl⟩) + rw [exec_storeRev_w hn (by rw [ha]; exact hout), ha] + +theorem wp_stdbrx {t n m : Reg} {a : Addr} (hn : n ≠ .r0) + (ha : s.gpr n + s.gpr m = a) (hout : InRegions s.wr a 8) + (k : ∀ s', Mupd s s' (s.mem.writeW a (rev64 (s.gpr t))) → WP isa (.block is) s' Q) : + WP isa (.block (.storeRev .d t n m :: is)) s Q := by + refine WP.cons (s' := { s with mem := s.mem.writeW a (rev64 (s.gpr t)) }) ?_ + (k _ ⟨rfl, rfl, rfl, rfl, rfl⟩) + rw [exec_storeRev_d hn (by rw [ha]; exact hout), ha] + +end + +/-! ## The inlined compression function -/ + +theorem compressBlocks_one (H : HashValue) (m : Mem) (p : Addr) : + compressBlocks H m p 1 = compress H (blockAt m p) := by + simp [compressBlocks] + +theorem one_toNat : (BitVec.ofNat 64 1).toNat = 1 := rfl + +theorem compress_noFrames : Impl.Sha256.PPC64LE.compress.noFrames = true := by decide +kernel + +/-- Compressing the block at `r4` into the hash value at `r26`, with scratch +space at `r27`: the callee-saved registers are kept. -/ +theorem compressAt_ok {s : State} {st scr src : Addr} + (h26 : s.gpr .r26 = st) (h27 : s.gpr .r27 = scr) (h4 : s.gpr .r4 = src) + (d₁ : Region.Disjoint ⟨st, 32⟩ ⟨scr, 112⟩) (d₂ : Region.Disjoint ⟨src, 64⟩ ⟨st, 32⟩) + (d₃ : Region.Disjoint ⟨src, 64⟩ ⟨scr, 112⟩) + (hc : Covers [⟨src, 64⟩, ⟨st, 32⟩, ⟨scr, 112⟩] (s.rd ++ s.wr)) + (hw : Covers [⟨st, 32⟩, ⟨scr, 112⟩] s.wr) {Q : State → Prop} + (hQ : ∀ s', s'.rd = s.rd → s'.wr = s.wr → (∀ r ∈ preserved, s'.gpr r = s.gpr r) → + s'.sp = s.sp → Frame [⟨st, 32⟩, ⟨scr, 112⟩] s.mem s'.mem → + stateAt s'.mem st = compress (stateAt s.mem st) (blockAt s.mem src) → Q s') : + WP isa compressAt s Q := by + unfold compressAt + refine WP.seq (wp_mov fun s₁ u₁ => wp_li (by decide) fun s₂ u₂ => + wp_mov fun s₃ u₃ => WP.block_nil ?_) + have e3 : s₃.gpr .r3 = st := by + rw [u₃.other _ (by decide), u₂.other _ (by decide), u₁.gpr, h26] + have e4 : s₃.gpr .r4 = src := by + rw [u₃.other _ (by decide), u₂.other _ (by decide), u₁.other _ (by decide), h4] + have e5 : s₃.gpr .r5 = BitVec.ofNat 64 1 := by + rw [u₃.other _ (by decide), u₂.gpr] + have e6 : s₃.gpr .r6 = scr := by + rw [u₃.gpr, u₂.other _ (by decide), u₁.other _ (by decide), h27] + have keep : ∀ r ∈ preserved, s₃.gpr r = s.gpr r := by + intro r hr + have : r ≠ .r3 ∧ r ≠ .r5 ∧ r ≠ .r6 := by + revert r; decide + rw [u₃.other _ this.2.2, u₂.other _ this.2.1, u₁.other _ this.1] + have m₃ : s₃.mem = s.mem := by rw [u₃.mem, u₂.mem, u₁.mem] + have rd₃ : s₃.rd = s.rd := by rw [u₃.rd, u₂.rd, u₁.rd] + have wr₃ : s₃.wr = s.wr := by rw [u₃.wr, u₂.wr, u₁.wr] + have sp₃ : s₃.sp = s.sp := by rw [u₃.sp, u₂.sp, u₁.sp] + have c3 : s₃.callEntry.gpr .r3 = st := (State.callEntry_gpr _ (by decide)).trans e3 + have c4 : s₃.callEntry.gpr .r4 = src := (State.callEntry_gpr _ (by decide)).trans e4 + have c5 : s₃.callEntry.gpr .r5 = BitVec.ofNat 64 1 := + (State.callEntry_gpr _ (by decide)).trans e5 + have c6 : s₃.callEntry.gpr .r6 = scr := (State.callEntry_gpr _ (by decide)).trans e6 + refine WP.call (k := Proof.Sha256.compressPPC64LE) compress_verified.1 + (rd := [⟨src, 64 * 1⟩]) (wr := [⟨st, 32⟩, ⟨scr, 112⟩]) ?_ ?_ ?_ ?_ compress_noFrames + · simp only [Proof.Sha256.compressPPC64LE, State.withRegions_gpr, State.withRegions_rd, + State.withRegions_wr, c3, c4, c5, c6, one_toNat] + exact ⟨trivial, trivial, d₁, d₂, d₃⟩ + · rw [rd₃, wr₃]; simpa using hc + · rw [wr₃]; exact hw + · intro s' hrd hwr hsp hf hcs _ hpost + simp only [Proof.Sha256.compressPPC64LE, State.withRegions_gpr, State.withRegions_mem, + State.callEntry_mem, c3, c4, c5, one_toNat, compressBlocks_one, m₃] at hpost + exact hQ s' (hrd.trans rd₃) (hwr.trans wr₃) (fun r hr => (hcs r hr).trans (keep r hr)) + (hsp.trans sp₃) (m₃ ▸ hf) hpost + +/-! ## Arithmetic -/ + +theorem ofNat_succ (k : Nat) : BitVec.ofNat 64 (k + 1) = BitVec.ofNat 64 k + 1 := by + rw [BitVec.ofNat_add]; rfl + +theorem ofNat_pred {k : Nat} (h : 1 ≤ k) : BitVec.ofNat 64 k - 1 = BitVec.ofNat 64 (k - 1) := by + rw [show k = (k - 1) + 1 by omega, ofNat_succ, Nat.add_sub_cancel, BitVec.add_sub_cancel] + +theorem ofNat_beq_zero {k : Nat} (h : k < 2 ^ 64) : (BitVec.ofNat 64 k == 0) = decide (k = 0) := by + by_cases hk : k = 0 + · simp [hk] + · simp only [hk, decide_false, beq_eq_false_iff_ne, ne_eq] + intro h' + have := congrArg BitVec.toNat h' + rw [BitVec.toNat_ofNat, Nat.mod_eq_of_lt h] at this + exact hk this + +theorem sub_ofNat {a b : Nat} (h : b ≤ a) : + BitVec.ofNat 64 a - BitVec.ofNat 64 b = BitVec.ofNat 64 (a - b) := by + conv_lhs => rw [show a = (a - b) + b by omega, BitVec.ofNat_add] + rw [BitVec.add_sub_cancel] + +theorem sub_beq {a b : Nat} (ha : a < 2 ^ 64) (hb : b < 2 ^ 64) : + (BitVec.ofNat 64 a - BitVec.ofNat 64 b == 0) = decide (a = b) := by + by_cases h : a = b + · simp [h] + · simp only [h, decide_false, beq_eq_false_iff_ne, ne_eq] + intro h' + apply h + have := congrArg BitVec.toNat h' + rw [BitVec.toNat_sub, BitVec.toNat_ofNat, BitVec.toNat_ofNat, Nat.mod_eq_of_lt ha, + Nat.mod_eq_of_lt hb] at this + change _ = 0 at this + omega + +/-- `x >>> 6`, of a number below 2⁶⁴. -/ +theorem ofNat_shr6 {a : Nat} (h : a < 2 ^ 64) : BitVec.ofNat 64 a >>> 6 = BitVec.ofNat 64 (a / 64) := by + apply BitVec.eq_of_toNat_eq + rw [BitVec.toNat_ushiftRight, BitVec.toNat_ofNat, BitVec.toNat_ofNat, Nat.mod_eq_of_lt h, + Nat.shiftRight_eq_div_pow, Nat.mod_eq_of_lt (by omega)] + +theorem bytesAt_getD {m : Mem} {p : Addr} {n : Nat} {l : List Byte} (h : bytesAt m p n = l) {k : Nat} + (hk : k < n) : m (p + BitVec.ofNat 64 k) = l.getD k 0 := by + subst h; simp [bytesAt, List.getD_eq_getElem?_getD, hk] + +/-- `eval` of the branch conditions. -/ +theorem eval_zero (s : State) (r : Reg) : eval (.zero .d r) s = some (s.gpr r == 0) := by + simp [eval, State.read] + +theorem eval_nonzero (s : State) (r : Reg) : eval (.nonzero .d r) s = some (s.gpr r != 0) := by + simp [eval, State.read] + +/-! ## Saving the caller's registers -/ + +/-- The memory after saving `r26`–`r31` (values `g`) at `b + 112 … b + 152`. -/ +def saveMem (m : Mem) (b : Addr) (g : Reg → BitVec 64) : Mem := + (((((m.writeW (b + BitVec.ofNat 64 112) (g .r26)).writeW (b + BitVec.ofNat 64 120) (g .r27)).writeW + (b + BitVec.ofNat 64 128) (g .r28)).writeW (b + BitVec.ofNat 64 136) (g .r29)).writeW + (b + BitVec.ofNat 64 144) (g .r30)).writeW (b + BitVec.ofNat 64 152) (g .r31) + +theorem save_sep (b : Addr) {d e : Nat} (hd : d < 2 ^ 32) (he : e < 2 ^ 32) + (h : d + 8 ≤ e ∨ e + 8 ≤ d) : Mem.Sep (b + BitVec.ofNat 64 d) 8 (b + BitVec.ofNat 64 e) 8 := by + intro x hx hy + bv_omega + +theorem readW_writeW_save (m : Mem) (b : Addr) (v : BitVec 64) {d e : Nat} (hd : d < 2 ^ 32) + (he : e < 2 ^ 32) (h : d + 8 ≤ e ∨ e + 8 ≤ d) : + (m.writeW (b + BitVec.ofNat 64 e) v).readW (b + BitVec.ofNat 64 d) 64 = m.readW (b + BitVec.ofNat 64 d) 64 := + Mem.readW_writeW_sep (save_sep b hd he h) (by decide) + +set_option simprocs false in +theorem saveMem_saved (m : Mem) (b : Addr) (g : Reg → BitVec 64) : + ∀ p ∈ saved, (saveMem m b g).readW (b + BitVec.ofNat 64 p.2) 64 = g p.1 := by + intro p hp + simp only [saved, List.mem_cons, List.not_mem_nil, or_false] at hp + rcases hp with rfl | rfl | rfl | rfl | rfl | rfl <;> + simp (config := {decide := true}) only [saveMem, Mem.readW_writeW_self64, readW_writeW_save] + +theorem saveMem_frame (m : Mem) (b : Addr) (g : Reg → BitVec 64) : + Frame [⟨b, 160⟩] m (saveMem m b g) := by + have c : ∀ d : Nat, d + 8 ≤ 160 → (⟨b, 160⟩ : Region).Contains (b + BitVec.ofNat 64 d) (64 / 8) := + fun d hd => Proof.Sha256.PPC64LE.contains_offset hd (by omega) + simp only [saveMem] + exact (((((Frame.refl _ _).writeW (List.mem_singleton_self _) _ (c 112 (by omega))).writeW + (List.mem_singleton_self _) _ (c 120 (by omega))).writeW (List.mem_singleton_self _) _ + (c 128 (by omega))).writeW (List.mem_singleton_self _) _ (c 136 (by omega))).writeW + (List.mem_singleton_self _) _ (c 144 (by omega)) |>.writeW (List.mem_singleton_self _) _ + (c 152 (by omega)) + +theorem save_eq (b : Reg) : save b = [.store .d .r26 b 112, .store .d .r27 b 120, + .store .d .r28 b 128, .store .d .r29 b 136, .store .d .r30 b 144, .store .d .r31 b 152] := rfl + +/-- Saving `r26`–`r31` with the scratch pointer in `b`. -/ +theorem save_ok {b : Reg} (hb : b ≠ .r0) {rest : List Instr} {s : State} {Q : State → Prop} + (hin : ∀ d, 112 ≤ d → d + 8 ≤ 160 → InRegions s.wr (s.gpr b + BitVec.ofNat 64 d) 8) + (k : ∀ s', s'.gpr = s.gpr → s'.rd = s.rd → s'.wr = s.wr → s'.sp = s.sp → + s'.mem = saveMem s.mem (s.gpr b) s.gpr → WP isa (.block rest) s' Q) : + WP isa (.block (save b ++ rest)) s Q := by + rw [save_eq] + simp only [List.cons_append, List.nil_append] + refine wp_std hb (by decide) rfl (hin 112 (by omega) (by omega)) fun s₁ g₁ => ?_ + refine wp_std hb (by decide) (by rw [g₁.gpr]) (by rw [g₁.wr]; exact hin 120 (by omega) (by omega)) + fun s₂ g₂ => ?_ + refine wp_std hb (by decide) (by rw [g₂.gpr, g₁.gpr]) + (by rw [g₂.wr, g₁.wr]; exact hin 128 (by omega) (by omega)) fun s₃ g₃ => ?_ + refine wp_std hb (by decide) (by rw [g₃.gpr, g₂.gpr, g₁.gpr]) + (by rw [g₃.wr, g₂.wr, g₁.wr]; exact hin 136 (by omega) (by omega)) fun s₄ g₄ => ?_ + refine wp_std hb (by decide) (by rw [g₄.gpr, g₃.gpr, g₂.gpr, g₁.gpr]) + (by rw [g₄.wr, g₃.wr, g₂.wr, g₁.wr]; exact hin 144 (by omega) (by omega)) fun s₅ g₅ => ?_ + refine wp_std hb (by decide) (by rw [g₅.gpr, g₄.gpr, g₃.gpr, g₂.gpr, g₁.gpr]) + (by rw [g₅.wr, g₄.wr, g₃.wr, g₂.wr, g₁.wr]; exact hin 152 (by omega) (by omega)) fun s₆ g₆ => ?_ + refine k s₆ (by rw [g₆.gpr, g₅.gpr, g₄.gpr, g₃.gpr, g₂.gpr, g₁.gpr]) + (by rw [g₆.rd, g₅.rd, g₄.rd, g₃.rd, g₂.rd, g₁.rd]) (by rw [g₆.wr, g₅.wr, g₄.wr, g₃.wr, g₂.wr, g₁.wr]) + (by rw [g₆.sp, g₅.sp, g₄.sp, g₃.sp, g₂.sp, g₁.sp]) ?_ + rw [g₆.mem, g₅.mem, g₄.mem, g₃.mem, g₂.mem, g₁.mem] + simp only [saveMem, g₅.gpr, g₄.gpr, g₃.gpr, g₂.gpr, g₁.gpr] + +theorem frame_bytes {rs : List Region} {m m' : Mem} (hf : Frame rs m m') {R : Region} + (hd : ∀ r ∈ rs, R.Disjoint r) (hR : R.len ≤ 2 ^ 64) {i : Nat} (hi : i < R.len) : + m' (R.base + BitVec.ofNat 64 i) = m (R.base + BitVec.ofNat 64 i) := by + refine hf _ fun r hr hc => hd r hr _ ?_ hc + simp only [Region.Contains] + rw [show R.base + BitVec.ofNat 64 i - R.base = BitVec.ofNat 64 i by bv_omega, + Proof.Sha256.PPC64LE.toNat_ofNat_lt (by omega)] + omega + +/-- Registers that no instruction writes keep their values, as a postcondition. -/ +theorem WP.gprs {c : Prog isa} {s : State} {Q : State → Prop} (h : WP isa c s Q) {rs : List Reg} + (hc : ∀ r ∈ rs, ∀ i ∈ instrs c, dstOf i ≠ some r) + (hn : c.noCalls = true ∨ ∀ r ∈ rs, r ∉ linkRegs := + by first | exact .inr (by decide) | exact .inl (by decide +kernel)) : + WP isa c s fun s' => Q s' ∧ ∀ r ∈ rs, s'.gpr r = s.gpr r := by + obtain ⟨t, s', he, hq⟩ := h + exact ⟨t, s', he, hq, fun r hr => Exec.gpr (hc r hr) he (hn.imp id fun h => h r hr)⟩ + +/-- The callee-saved registers no instruction writes, including those of +the compression function. -/ +def untouched : List Reg := [.r2, .r20, .r21, .r22, .r23, .r24, .r25] + +/-- The callee-saved registers only the compression function writes (it +saves and restores them). -/ +def nvRegs : List Reg := [.r14, .r15, .r16, .r17, .r18, .r19] + +theorem nv_pres : ∀ r ∈ nvRegs, r ∈ preserved := by decide + +/-- The memory a frame's push writes: the back chain and the register. -/ +abbrev pushMem (m : Mem) (sp v : BitVec 64) : Mem := + (m.write (sp - 48) 8 sp).write (sp - 48 + 32) 8 v + +/-- A byte of a region disjoint from a frame is unchanged by the push. -/ +theorem write_frame_apply {m : Mem} {sp v : BitVec 64} {R : Region} + (hd : Region.Disjoint ⟨sp - 48, 48⟩ R) {x : Addr} (hx : R.Contains x 1) : + pushMem m sp v x = m x := by + simp only [pushMem] + rw [Mem.write_apply fun h => hd x (by simp only [Region.Contains] at h ⊢; bv_omega) hx, + Mem.write_apply fun h => hd x (by simp only [Region.Contains] at h ⊢; omega) hx] + +/-- The bytes of a region disjoint from a frame are unchanged by the push. -/ +theorem write_frame_bytes {m : Mem} {sp v : BitVec 64} {R : Region} + (hd : Region.Disjoint ⟨sp - 48, 48⟩ R) (hR : R.len < 2 ^ 64) {i : Nat} (hi : i < R.len) : + pushMem m sp v (R.base + BitVec.ofNat 64 i) = m (R.base + BitVec.ofNat 64 i) := + write_frame_apply hd (by + simp only [Region.Contains] + rw [show R.base + BitVec.ofNat 64 i - R.base = BitVec.ofNat 64 i by bv_omega, + BitVec.toNat_ofNat, Nat.mod_eq_of_lt (by omega)] + omega) + +/-- The frame's local variable space is in the frame. -/ +theorem frame_sub (sp : Addr) : Region.Sub ⟨sp - 48 + 32, 16⟩ ⟨sp - 48, 48⟩ := by + intro x h + simp only [Region.Contains] at h ⊢ + bv_omega + +theorem restore_eq : restore = [.load .d .r26 .r27 112, .load .d .r28 .r27 128, + .load .d .r29 .r27 136, .load .d .r30 .r27 144, .load .d .r31 .r27 152, + .load .d .r27 .r27 120] := rfl + +/-- Restoring `r26`–`r31` from the save area at `scr`. -/ +theorem restore_ok {s : State} {scr : Addr} (h27 : s.gpr .r27 = scr) + (hin : ∀ d, 112 ≤ d → d + 8 ≤ 160 → InRegions (s.rd ++ s.wr) (scr + BitVec.ofNat 64 d) 8) + (g : Reg → BitVec 64) (hsv : ∀ p ∈ saved, s.mem.readW (scr + BitVec.ofNat 64 p.2) 64 = g p.1) + {Q : State → Prop} + (k : ∀ s', (∀ p ∈ saved, s'.gpr p.1 = g p.1) → (∀ r, r ∉ saved.map Prod.fst → s'.gpr r = s.gpr r) → + s'.mem = s.mem → s'.rd = s.rd → s'.wr = s.wr → s'.sp = s.sp → Q s') : + WP isa (.block restore) s Q := by + have v : ∀ r d, (r, d) ∈ saved → s.mem.readW (scr + BitVec.ofNat 64 d) 64 = g r := + fun r d h => hsv (r, d) h + rw [restore_eq] + refine wp_ld (by decide) (by decide) (by rw [h27]) (hin 112 (by omega) (by omega)) fun s₁ u₁ => ?_ + refine wp_ld (by decide) (by decide) (by rw [u₁.other _ (by decide), h27]) + (by rw [u₁.rd, u₁.wr]; exact hin 128 (by omega) (by omega)) fun s₂ u₂ => ?_ + refine wp_ld (by decide) (by decide) (by rw [u₂.other _ (by decide), u₁.other _ (by decide), h27]) + (by rw [u₂.rd, u₂.wr, u₁.rd, u₁.wr]; exact hin 136 (by omega) (by omega)) fun s₃ u₃ => ?_ + refine wp_ld (by decide) (by decide) + (by rw [u₃.other _ (by decide), u₂.other _ (by decide), u₁.other _ (by decide), h27]) + (by rw [u₃.rd, u₃.wr, u₂.rd, u₂.wr, u₁.rd, u₁.wr]; exact hin 144 (by omega) (by omega)) + fun s₄ u₄ => ?_ + refine wp_ld (by decide) (by decide) + (by rw [u₄.other _ (by decide), u₃.other _ (by decide), u₂.other _ (by decide), + u₁.other _ (by decide), h27]) + (by rw [u₄.rd, u₄.wr, u₃.rd, u₃.wr, u₂.rd, u₂.wr, u₁.rd, u₁.wr]; exact hin 152 (by omega) (by omega)) + fun s₅ u₅ => ?_ + refine wp_ld (by decide) (by decide) + (by rw [u₅.other _ (by decide), u₄.other _ (by decide), u₃.other _ (by decide), + u₂.other _ (by decide), u₁.other _ (by decide), h27]) + (by rw [u₅.rd, u₅.wr, u₄.rd, u₄.wr, u₃.rd, u₃.wr, u₂.rd, u₂.wr, u₁.rd, u₁.wr] + exact hin 120 (by omega) (by omega)) + fun s₆ u₆ => WP.block_nil ?_ + have m5 : s₅.mem = s.mem := by rw [u₅.mem, u₄.mem, u₃.mem, u₂.mem, u₁.mem] + refine k s₆ (fun p hp => ?_) (fun r hr => ?_) (by rw [u₆.mem, m5]) (by rw [u₆.rd, u₅.rd, u₄.rd, + u₃.rd, u₂.rd, u₁.rd]) (by rw [u₆.wr, u₅.wr, u₄.wr, u₃.wr, u₂.wr, u₁.wr]) + (by rw [u₆.sp, u₅.sp, u₄.sp, u₃.sp, u₂.sp, u₁.sp]) + · simp only [saved, List.mem_cons, List.not_mem_nil, or_false] at hp + rcases hp with rfl | rfl | rfl | rfl | rfl | rfl + · rw [u₆.other _ (by decide), u₅.other _ (by decide), u₄.other _ (by decide), u₃.other _ (by decide), + u₂.other _ (by decide), u₁.gpr, v .r26 112 (by simp [saved])] + · rw [u₆.gpr, m5, v .r27 120 (by simp [saved])] + · rw [u₆.other _ (by decide), u₅.other _ (by decide), u₄.other _ (by decide), u₃.other _ (by decide), + u₂.gpr, u₁.mem, v .r28 128 (by simp [saved])] + · rw [u₆.other _ (by decide), u₅.other _ (by decide), u₄.other _ (by decide), u₃.gpr, u₂.mem, u₁.mem, + v .r29 136 (by simp [saved])] + · rw [u₆.other _ (by decide), u₅.other _ (by decide), u₄.gpr, u₃.mem, u₂.mem, u₁.mem, + v .r30 144 (by simp [saved])] + · rw [u₆.other _ (by decide), u₅.gpr, u₄.mem, u₃.mem, u₂.mem, u₁.mem, v .r31 152 (by simp [saved])] + · simp only [saved, List.map_cons, List.map_nil, List.mem_cons, List.not_mem_nil, or_false, + not_or] at hr + obtain ⟨h1, h2, h3, h4, h5, h6⟩ := hr + rw [u₆.other _ h2, u₅.other _ h6, u₄.other _ h5, u₃.other _ h4, u₂.other _ h3, u₁.other _ h1] + +/-- `x &&& 63`. -/ +theorem and63 (x : BitVec 64) : x &&& BitVec.ofNat 64 63 = BitVec.ofNat 64 (x.toNat % 64) := by + apply BitVec.eq_of_toNat_eq + rw [BitVec.toNat_and, show (BitVec.ofNat 64 63).toNat = 2 ^ 6 - 1 from rfl, + Nat.and_two_pow_sub_one_eq_mod, BitVec.toNat_ofNat] + omega + +/-! ## Byte order -/ + +theorem rev32_bytes (w : BitVec 32) : + (List.range 4).map (fun j => (rev32 w).extractLsb' (8 * j) 8) = Spec.Sha256.wordBytes w := by + simp only [List.range_succ, List.range_zero, List.nil_append, List.map_cons, List.map_nil, + List.cons_append, Spec.Sha256.wordBytes, List.cons.injEq, and_true] + refine ⟨?_, ?_, ?_, ?_⟩ <;> + · simp (disch := decide) only [rev32, Nat.mul_zero, Nat.reduceMul, extractLsb'_append_byte_lo, + extractLsb'_append_byte_hi, Nat.reduceSub, BitVec.extractLsb'_eq_self] + +theorem rev64_bytes (x : BitVec 64) : + (List.range 8).map (fun j => (rev64 x).extractLsb' (8 * j) 8) = + (List.range 8).reverse.map (fun i => x.extractLsb' (8 * i) 8) := by + simp only [List.range_succ, List.range_zero, List.nil_append, List.map_cons, List.map_nil, + List.cons_append, List.reverse_cons, List.reverse_nil, List.cons.injEq, and_true] + refine ⟨?_, ?_, ?_, ?_, ?_, ?_, ?_, ?_⟩ <;> + · simp (disch := decide) only [rev64, Nat.mul_zero, Nat.reduceMul, extractLsb'_append_byte_lo, + extractLsb'_append_byte_hi, Nat.reduceSub, BitVec.extractLsb'_eq_self] + +end VG.Proof.Sha256.PPC64LE.Stream diff --git a/lean/VerifiedGarbage/Proof/Sha256/PPC64LE/Stream/Finalize.lean b/lean/VerifiedGarbage/Proof/Sha256/PPC64LE/Stream/Finalize.lean new file mode 100644 index 000000000..2ab617e04 --- /dev/null +++ b/lean/VerifiedGarbage/Proof/Sha256/PPC64LE/Stream/Finalize.lean @@ -0,0 +1,772 @@ +import VerifiedGarbage.Proof.Sha256.PPC64LE.Stream.Common + +/-! +# Streaming SHA-256 on PPC64LE: `finalize` + +Untrusted: everything here is checked by Lean. The same structure as the +x86-64 proof (`VG.Proof.Sha256.X86_64.Stream.Finalize`). +-/ + +namespace VG.Proof.Sha256.PPC64LE.Stream.Finalize + +open VG VG.PPC64LE VG.Impl.Sha256.PPC64LE.Stream +open VG.Proof.Sha256.PPC64LE (contains_offset toNat_ofNat_lt sub_offset) +open VG.Proof.Sha256.PPC64LE.Stream +open VG.Proof.Sha256.Stream +open VG.Spec.Sha256 (HashValue stateAt blockAt compress parseBlock bytesAt wordBytes) + +/-! ## The precondition -/ + +section +variable (s₀ : State) + +abbrev st : Addr := s₀.gpr .r3 +abbrev cnt : Nat := (s₀.gpr .r4).toNat +abbrev out : Addr := s₀.gpr .r5 +abbrev scr : Addr := s₀.gpr .r6 +abbrev stR : Region := ⟨st s₀, 96⟩ +abbrev outR : Region := ⟨out s₀, 32⟩ +abbrev scR : Region := ⟨scr s₀, 160⟩ + +/-- The messages the initial state represents. -/ +def R₀ (iv : HashValue) (m : List Byte) : Prop := + Spec.Sha256.ReprFrom iv s₀.mem (st s₀) m ∧ s₀.gpr .r4 = BitVec.ofNat 64 m.length + +/-- The caller's registers are saved in the scratch space. -/ +def Saved (m : Mem) : Prop := + ∀ p ∈ saved, m.readW (scr s₀ + BitVec.ofNat 64 p.2) 64 = s₀.gpr p.1 + +/-- The digest, if `n` bytes are buffered in a block that is not the last. -/ +def Fin1 (mem : Mem) (n : Nat) (m : List Byte) : HashValue := + compress (compress (stateAt mem (st s₀)) + (parseBlock fun t => (bytesAt mem (st s₀ + 32) n ++ List.replicate (64 - n) 0).getD t 0)) + (parseBlock fun t => (List.replicate 56 0 ++ lenBytes m).getD t 0) + +/-- The digest, if `n` bytes are buffered in the last block. -/ +def Fin0 (mem : Mem) (n : Nat) (m : List Byte) : HashValue := + compress (stateAt mem (st s₀)) + (parseBlock fun t => (bytesAt mem (st s₀ + 32) n ++ List.replicate (56 - n) 0 ++ lenBytes m).getD t 0) + +end + +structure Pre (s₀ : State) : Prop where + rd : s₀.rd = [] + wr : s₀.wr = [stR s₀, outR s₀, scR s₀] + st_out : (stR s₀).Disjoint (outR s₀) + st_scr : (stR s₀).Disjoint (scR s₀) + out_scr : (outR s₀).Disjoint (scR s₀) + +/-- The frame saving the link register, below the stack pointer. -/ +abbrev stkR (s₀ : State) : Region := ⟨s₀.sp - 48, 48⟩ + +/-- The frame is below the stack pointer, and disjoint from the buffers. -/ +structure Stack (s₀ : State) : Prop where + sp48 : 48 ≤ s₀.sp.toNat + st : (stkR s₀).Disjoint (stR s₀) + out : (stkR s₀).Disjoint (outR s₀) + scr : (stkR s₀).Disjoint (scR s₀) + +theorem pre_of {s₀ : State} (h : Proof.Sha256.finalizePPC64LE.pre s₀) : Pre s₀ ∧ Stack s₀ := by + obtain ⟨h1, h2, h3, h4, h5, h6, h7, h8, h9⟩ := h + exact ⟨⟨h1, h2, h3, h4, h5⟩, ⟨h6, h7, h8, h9⟩⟩ + +theorem R₀.length {s₀ : State} {iv : HashValue} {m : List Byte} (h : R₀ s₀ iv m) : cnt s₀ % 64 = m.length % 64 := by + rw [cnt, h.2, BitVec.toNat_ofNat] + omega + +theorem st_add (s₀ : State) (n : Nat) : + st s₀ + 32 + BitVec.ofNat 64 n = st s₀ + BitVec.ofNat 64 (32 + n) := by + simp only [BitVec.ofNat_add]; rw [BitVec.add_assoc]; rfl + +/-! ## Invariants -/ + +structure Common (s₀ : State) (s : State) : Prop where + rd : s.rd = s₀.rd + wr : s.wr = s₀.wr + r26 : s.gpr .r26 = st s₀ + r27 : s.gpr .r27 = scr s₀ + r28 : s.gpr .r28 = out s₀ + r29 : s.gpr .r29 = s₀.gpr .r4 + sp : s.sp = s₀.sp + frame : Frame [stR s₀, scR s₀] s₀.mem s.mem + saved : Saved s₀ s.mem + +/-- The loop invariant: `k = 1` while the block being padded is not the last +one, with `n` bytes of it buffered. -/ +structure LInv (s₀ : State) (k n : Nat) (s : State) : Prop extends Common s₀ s where + k_le : k ≤ 1 + n_le : n ≤ 56 + 8 * k + r30 : s.gpr .r30 = BitVec.ofNat 64 n + r31 : s.gpr .r31 = BitVec.ofNat 64 k + hash : ∀ iv m, R₀ s₀ iv m → Spec.Sha256.finalHash iv m = + (if k = 1 then Fin1 s₀ s.mem n m else Fin0 s₀ s.mem n m).toList.flatMap wordBytes + +/-- All blocks are compressed. -/ +def Done (s₀ : State) (s : State) : Prop := + Common s₀ s ∧ ∀ iv m, R₀ s₀ iv m → Spec.Sha256.finalHash iv m = (stateAt s.mem (st s₀)).toList.flatMap wordBytes + +theorem Common.of_gpr {s₀ : State} {s s' : State} (h : Common s₀ s) + (hg : ∀ r ∈ [Reg.r26, .r27, .r28, .r29], s'.gpr r = s.gpr r) + (hm : s'.mem = s.mem) (hrd : s'.rd = s.rd) (hwr : s'.wr = s.wr) (hsp : s'.sp = s.sp) : + Common s₀ s' where + rd := hrd.trans h.rd + wr := hwr.trans h.wr + r26 := by rw [hg _ (by simp)]; exact h.r26 + r27 := by rw [hg _ (by simp)]; exact h.r27 + r28 := by rw [hg _ (by simp)]; exact h.r28 + r29 := by rw [hg _ (by simp)]; exact h.r29 + sp := hsp.trans h.sp + frame := by rw [hm]; exact h.frame + saved := by rw [hm]; exact h.saved + +/-- Where the caller's registers are saved. -/ +theorem saved_sub {s₀ : State} {p : Reg × Nat} (hp : p ∈ saved) : + Region.Sub ⟨scr s₀ + BitVec.ofNat 64 p.2, 8⟩ (scR s₀) := by + simp only [Impl.Sha256.PPC64LE.Stream.saved, List.mem_cons, List.not_mem_nil, or_false] at hp + rcases hp with rfl | rfl | rfl | rfl | rfl | rfl <;> exact sub_offset (by omega) (by omega) + +/-- Writing buffer bytes `[n, n + |xs|)` keeps `Common`'s memory facts. -/ +theorem Common.writeBuf {s₀ : State} (hp : Pre s₀) {s : State} (h : Common s₀ s) {n : Nat} + {xs : List Byte} (hn : n + xs.length ≤ 64) : + Frame [stR s₀] s.mem (writeBytes s.mem (st s₀ + 32 + BitVec.ofNat 64 n) xs) ∧ + Frame [stR s₀, scR s₀] s₀.mem (writeBytes s.mem (st s₀ + 32 + BitVec.ofNat 64 n) xs) ∧ + Saved s₀ (writeBytes s.mem (st s₀ + 32 + BitVec.ofNat 64 n) xs) := by + have hf : Frame [stR s₀] s.mem (writeBytes s.mem (st s₀ + 32 + BitVec.ofNat 64 n) xs) := by + refine writeBytes_frame _ _ _ ?_ + rw [st_add] + exact contains_offset (by omega) (by omega) + refine ⟨hf, h.frame.trans (hf.mono (by simp)), fun p hp' => ?_⟩ + rw [← h.saved p hp'] + refine hf.readW (r := ⟨scr s₀ + BitVec.ofNat 64 p.2, 8⟩) (Region.contains_self _ _) ?_ (by decide) + intro r' hr' + simp only [List.mem_cons, List.not_mem_nil, or_false] at hr' + subst hr' + exact hp.st_scr.symm.sub_left (saved_sub hp') + +/-! ## Zeroing the buffer -/ + +/-- Zeroing buffer bytes `[n, lim)` from state `sI`: `j` of them done. -/ +structure Zero (s₀ : State) (sI : State) (n lim j : Nat) (s : State) : Prop where + j_le : j ≤ lim - n + keep : ∀ r ∈ [Reg.r26, .r27, .r28, .r29, .r31] ++ nvRegs, s.gpr r = sI.gpr r + rd : s.rd = sI.rd + wr : s.wr = sI.wr + sp : s.sp = sI.sp + r8 : s.gpr .r8 = 0 + r30 : s.gpr .r30 = BitVec.ofNat 64 (n + j) + r10 : s.gpr .r10 = BitVec.ofNat 64 (lim - n - j) + mem : s.mem = writeBytes sI.mem (st s₀ + 32 + BitVec.ofNat 64 n) (List.replicate j 0) + +/-- The zeroing loop's body. -/ +def zeroBody : List Instr := + [.add .r11 .r26 .r30, .stb .r8 .r11 32, .addi .r30 .r30 1, .subi .r10 .r10 1] + +theorem zero_step {s₀ : State} (hp : Pre s₀) {sI : State} (hC : Common s₀ sI) {n lim j : Nat} + (hlim : lim ≤ 64) (hj : j < lim - n) {s : State} (h : Zero s₀ sI n lim j s) : + WP isa (.block zeroBody) s fun s' => + Zero s₀ sI n lim (j + 1) s' ∧ s'.gpr .r10 = BitVec.ofNat 64 (lim - n - (j + 1)) := by + have hx19 : s.gpr .r26 = st s₀ := by rw [h.keep _ (by simp), hC.r26] + have hout : InRegions s.wr (st s₀ + 32 + BitVec.ofNat 64 n + BitVec.ofNat 64 j) 1 := by + refine ⟨stR s₀, by simp [h.wr, hC.wr, hp.wr], ?_⟩ + rw [show st s₀ + 32 + BitVec.ofNat 64 n + BitVec.ofNat 64 j = st s₀ + BitVec.ofNat 64 (32 + n + j) by + simp only [BitVec.ofNat_add]; ac_rfl] + exact contains_offset (by omega) (by omega) + unfold zeroBody + refine wp_add fun s₁ u₁ => wp_stb (a := st s₀ + 32 + BitVec.ofNat 64 n + BitVec.ofNat 64 j) (by decide) (by omega) + ?_ (by rw [u₁.wr]; exact hout) fun s₂ g₂ => ?_ + · rw [u₁.gpr, hx19, h.r30, BitVec.ofNat_add, show BitVec.ofNat 64 32 = (32 : BitVec 64) from rfl] + ac_rfl + refine wp_addi (by decide) (by omega) fun s₃ u₃ => wp_subi (by decide) (by omega) fun s₄ u₄ => WP.block_nil ⟨⟨by omega, + fun r hr => ?_, by rw [u₄.rd, u₃.rd, g₂.rd, u₁.rd, h.rd], by rw [u₄.wr, u₃.wr, g₂.wr, u₁.wr, h.wr], + by rw [u₄.sp, u₃.sp, g₂.sp, u₁.sp, h.sp], ?_, ?_, ?_, ?_⟩, ?_⟩ + · have : r ≠ .r10 ∧ r ≠ .r30 ∧ r ≠ .r11 := by revert r hr; decide + rw [u₄.other r this.1, u₃.other r this.2.1, g₂.gpr, u₁.other r this.2.2, h.keep r hr] + · rw [u₄.other _ (by decide), u₃.other _ (by decide), g₂.gpr, u₁.other _ (by decide), h.r8] + · rw [u₄.other _ (by decide), u₃.gpr, g₂.gpr, u₁.other _ (by decide), h.r30, ← BitVec.ofNat_add, + Nat.add_assoc] + · rw [u₄.gpr, u₃.other _ (by decide), g₂.gpr, u₁.other _ (by decide), h.r10, + sub_ofNat (by omega), Nat.sub_sub] + · rw [u₄.mem, u₃.mem, g₂.mem, u₁.mem, u₁.other _ (by decide), h.r8, h.mem, List.replicate_succ', + writeBytes_snoc _ _ _ _ (by simp only [List.length_replicate]; omega), List.length_replicate] + rfl + · rw [u₄.gpr, u₃.other _ (by decide), g₂.gpr, u₁.other _ (by decide), h.r10, + sub_ofNat (by omega), Nat.sub_sub, Nat.sub_sub] + +theorem zero_ok {s₀ : State} (hp : Pre s₀) {sI : State} (hC : Common s₀ sI) {n lim : Nat} + (hlim : lim ≤ 64) (hn : n ≤ lim) {s : State} (h : Zero s₀ sI n lim 0 s) : + WP isa (.ite (.zero .d .r10) (.block []) (.loop (.block zeroBody) (.nonzero .d .r10))) s + (Zero s₀ sI n lim (lim - n)) := by + have hz : eval (.zero .d .r10) s = some (decide (lim - n = 0)) := by + rw [eval_zero, h.r10, Nat.sub_zero, ofNat_beq_zero (by omega)] + refine WP.ite (decide (lim - n = 0)) hz (fun hb => ?_) (fun hb => ?_) + · simp only [decide_eq_true_eq] at hb + exact WP.block_nil (hb ▸ h) + · simp only [decide_eq_false_iff_not] at hb + refine WP.loop (M := isa) (fun k s => ∃ j, k = lim - n - j ∧ j < lim - n ∧ Zero s₀ sI n lim j s) + ?_ (lim - n) s ⟨0, rfl, by omega, h⟩ + rintro k s ⟨j, rfl, hj, hZ⟩ + refine WP.mono (zero_step hp hC hlim hj hZ) fun s' ⟨hZ', h11⟩ => ?_ + have hz' : isa.eval (.nonzero .d .r10) s' = some (decide (lim - n - (j + 1) ≠ 0)) := by + show VG.PPC64LE.eval (.nonzero .d .r10) s' = _ + rw [eval_nonzero, h11, bne, ofNat_beq_zero (by omega)] + simp + by_cases hl : lim - n - (j + 1) = 0 + · refine .inl ⟨by rw [hz']; simp [hl], ?_⟩ + rwa [show j + 1 = lim - n by omega] at hZ' + · exact .inr ⟨by rw [hz']; simp [hl], _, by omega, j + 1, rfl, by omega, hZ'⟩ + +/-! ## One block -/ + +/-- The compression of the buffer. -/ +theorem compress_buf {s₀ : State} (hp : Pre s₀) {s : State} (hC : Common s₀ s) + (hx1 : s.gpr .r4 = st s₀ + 32) {Q : State → Prop} + (hQ : ∀ s', Common s₀ s' → (∀ r ∈ preserved, s'.gpr r = s.gpr r) → + stateAt s'.mem (st s₀) = compress (stateAt s.mem (st s₀)) (blockAt s.mem (st s₀ + 32)) → Q s') : + WP isa compressAt s Q := by + have e32 : Region.Sub ⟨st s₀, 32⟩ (stR s₀) := Region.sub_prefix (by omega) + have e112 : Region.Sub ⟨scr s₀, 112⟩ (scR s₀) := Region.sub_prefix (by omega) + have eb : Region.Sub ⟨st s₀ + 32, 64⟩ (stR s₀) := sub_offset (off := 32) (by omega) (by omega) + refine compressAt_ok hC.r26 hC.r27 hx1 ((hp.st_scr.sub_left e32).sub_right e112) ?_ + ((hp.st_scr.sub_left eb).sub_right e112) ?_ ?_ fun s' hrd hwr hcs hsp hf hstate => + hQ s' ?_ hcs hstate + · intro a h₁ h₂; simp only [Region.Contains] at h₁ h₂; bv_omega + · rw [hC.rd, hC.wr, hp.rd, hp.wr] + apply Covers.of_sub + intro r hr + simp only [List.mem_cons, List.not_mem_nil, or_false] at hr + rcases hr with rfl | rfl | rfl + · exact ⟨stR s₀, by simp, 32, rfl, by simp⟩ + · exact ⟨stR s₀, by simp, 0, by simp, by simp⟩ + · exact ⟨scR s₀, by simp, 0, by simp, by simp⟩ + · rw [hC.wr, hp.wr] + apply Covers.of_sub + intro r hr + simp only [List.mem_cons, List.not_mem_nil, or_false] at hr + rcases hr with rfl | rfl + · exact ⟨stR s₀, by simp, 0, by simp, by simp⟩ + · exact ⟨scR s₀, by simp, 0, by simp, by simp⟩ + · have cs : ∀ r, r ∈ preserved → s'.gpr r = s.gpr r := hcs + refine ⟨hrd.trans hC.rd, hwr.trans hC.wr, by rw [cs _ (by decide)]; exact hC.r26, + by rw [cs _ (by decide)]; exact hC.r27, + by rw [cs _ (by decide)]; exact hC.r28, + by rw [cs _ (by decide)]; exact hC.r29, hsp.trans hC.sp, hC.frame.trans (hf.sub ?_), + fun p hp' => ?_⟩ + · intro r hr + simp only [List.mem_cons, List.not_mem_nil, or_false] at hr + rcases hr with rfl | rfl + · exact ⟨stR s₀, by simp, e32⟩ + · exact ⟨scR s₀, by simp, e112⟩ + · rw [← hC.saved p hp'] + refine hf.readW (r := ⟨scr s₀ + BitVec.ofNat 64 p.2, 8⟩) (Region.contains_self _ _) ?_ (by decide) + intro r' hr' + simp only [List.mem_cons, List.not_mem_nil, or_false] at hr' + rcases hr' with rfl | rfl + · exact (hp.st_scr.symm.sub_left (saved_sub hp')).sub_right e32 + · simp only [Impl.Sha256.PPC64LE.Stream.saved, List.mem_cons, List.not_mem_nil, or_false] at hp' + rcases hp' with rfl | rfl | rfl | rfl | rfl | rfl <;> + · intro a h₁ h₂; simp only [Region.Contains] at h₁ h₂; bv_omega + +theorem times8 (x : BitVec 64) : x + x + (x + x) + (x + x + (x + x)) = BitVec.ofNat 64 (8 * x.toNat) := by + bv_omega + +theorem len_bits {m : List Byte} {x : BitVec 64} (hx : x = BitVec.ofNat 64 m.length) : + BitVec.ofNat 64 (8 * x.toNat) = BitVec.ofNat 64 (8 * m.length) := by + subst hx + apply BitVec.eq_of_toNat_eq + simp only [BitVec.toNat_ofNat, Nat.mul_mod, Nat.mod_mod] + +/-- The loop's postcondition for one iteration. -/ +def Step (s₀ : State) (k : Nat) (s : State) : Prop := + (eval (.zero .d .r31) s = some false ∧ Done s₀ s) ∨ + (eval (.zero .d .r31) s = some true ∧ k = 1 ∧ LInv s₀ 0 0 s) + +theorem body_eq : finalizeBody = + .seq (.block [.li .r10 64]) + (.seq (.ite (.zero .d .r31) (.block [.li .r10 56]) (.block [])) + (.seq (.block [.li .r8 0, .sub .r10 .r10 .r30]) + (.seq (.ite (.zero .d .r10) (.block []) (.loop (.block zeroBody) (.nonzero .d .r10))) + (.seq (.ite (.zero .d .r31) + (.block [.add .r8 .r29 .r29, .add .r8 .r8 .r8, .add .r8 .r8 .r8, .li .r11 88, + .storeRev .d .r8 .r26 .r11]) + (.block [])) + (.seq (.block [.addi .r4 .r26 32]) + (.seq compressAt (.block [.li .r30 0, .subi .r31 .r31 1]))))))) := rfl + +theorem body_ok {s₀ : State} (hp : Pre s₀) {k n : Nat} {s : State} (h : LInv s₀ k n s) : + WP isa finalizeBody s fun s' => Step s₀ k s' ∧ ∀ r ∈ nvRegs, s'.gpr r = s.gpr r := by + have hk := h.k_le; have hn := h.n_le + have hC := h.toCommon + rw [body_eq] + -- `r10 := 64` or `56`: the end of the zeros. + refine WP.seq (wp_li (by decide) fun s₁ u₁ => WP.block_nil ?_) + have hz₁ : eval (.zero .d .r31) s₁ = some (decide (k = 0)) := by + rw [eval_zero, u₁.other _ (by decide), h.r31, ofNat_beq_zero (by omega)] + refine WP.seq (WP.mono (Q := fun (s₃ : State) => s₃.gpr .r10 = BitVec.ofNat 64 (56 + 8 * k) ∧ + (∀ r, r ≠ .r10 → s₃.gpr r = s.gpr r) ∧ s₃.mem = s.mem ∧ s₃.rd = s.rd ∧ s₃.wr = s.wr ∧ + s₃.sp = s.sp) ?_ fun s₃ ⟨h11₃, g₃, m₃, rd₃, wr₃, sp₃⟩ => ?_) + · refine WP.ite (decide (k = 0)) hz₁ (fun hb => ?_) (fun hb => ?_) + · simp only [decide_eq_true_eq] at hb; subst hb + refine wp_li (by decide) fun s₃ u₃ => WP.block_nil ⟨by rw [u₃.gpr], fun r hr => ?_, + by rw [u₃.mem, u₁.mem], by rw [u₃.rd, u₁.rd], by rw [u₃.wr, u₁.wr], by rw [u₃.sp, u₁.sp]⟩ + rw [u₃.other r hr, u₁.other r hr] + · simp only [decide_eq_false_iff_not] at hb + refine WP.block_nil ⟨by rw [u₁.gpr, show k = 1 by omega], fun r hr => ?_, + u₁.mem, u₁.rd, u₁.wr, u₁.sp⟩ + rw [u₁.other r hr] + -- Zero the rest of the buffer, up to `lim`. + refine WP.seq (wp_li (by decide) fun s₄ u₄ => wp_sub fun s₅ u₅ => WP.block_nil ?_) + have hZ : Zero s₀ s n (56 + 8 * k) 0 s₅ := by + refine ⟨Nat.zero_le _, fun r hr => ?_, by rw [u₅.rd, u₄.rd, rd₃], by rw [u₅.wr, u₄.wr, wr₃], + by rw [u₅.sp, u₄.sp, sp₃], ?_, ?_, ?_, ?_⟩ + · have : r ≠ .r10 ∧ r ≠ .r8 := by revert r hr; decide + rw [u₅.other r this.1, u₄.other r this.2, g₃ r this.1] + · rw [u₅.other _ (by decide), u₄.gpr]; rfl + · rw [u₅.other _ (by decide), u₄.other _ (by decide), g₃ _ (by decide), h.r30, Nat.add_zero] + · rw [u₅.gpr, u₄.other _ (by decide), h11₃, u₄.other _ (by decide), g₃ _ (by decide), h.r30, + sub_ofNat (by omega), Nat.sub_zero] + · rw [u₅.mem, u₄.mem, m₃, List.replicate_zero, writeBytes_nil] + refine WP.seq (WP.mono (zero_ok hp hC (by omega) hn hZ) fun s₆ hZ₆ => ?_) + obtain ⟨hf₆, hfr₆, hsv₆⟩ := hC.writeBuf hp (n := n) (xs := List.replicate (56 + 8 * k - n) 0) + (by simp only [List.length_replicate]; omega) + have hC₆ : Common s₀ s₆ := + ⟨hZ₆.rd.trans hC.rd, hZ₆.wr.trans hC.wr, by rw [hZ₆.keep _ (by simp), hC.r26], + by rw [hZ₆.keep _ (by simp), hC.r27], by rw [hZ₆.keep _ (by simp), hC.r28], + by rw [hZ₆.keep _ (by simp), hC.r29], hZ₆.sp.trans hC.sp, + by rw [hZ₆.mem]; exact hfr₆, by rw [hZ₆.mem]; exact hsv₆⟩ + have hst₆ : stateAt s₆.mem (st s₀) = stateAt s.mem (st s₀) := by + rw [hZ₆.mem] + apply stateAt_congr + intro i hi + rw [st_add] + exact writeBytes_before _ _ _ (by omega) (by simp only [List.length_replicate]; omega) + have hby₆ : bytesAt s₆.mem (st s₀ + 32) (56 + 8 * k) = + bytesAt s.mem (st s₀ + 32) n ++ List.replicate (56 + 8 * k - n) 0 := by + rw [hZ₆.mem, ← bytesAt_writeBytes _ _ _ _ (by simp only [List.length_replicate]; omega)] + congr 1; simp only [List.length_replicate]; omega + have h24₆ : s₆.gpr .r31 = BitVec.ofNat 64 k := by rw [hZ₆.keep _ (by simp), h.r31] + have nv₆ : ∀ r ∈ nvRegs, s₆.gpr r = s.gpr r := fun r hr => hZ₆.keep r (by simp [hr]) + -- In the last block, the length. + have hz₆ : eval (.zero .d .r31) s₆ = some (decide (k = 0)) := by + rw [eval_zero, h24₆, ofNat_beq_zero (by omega)] + refine WP.seq (WP.mono (Q := fun (s₈ : State) => Common s₀ s₈ ∧ s₈.gpr .r31 = BitVec.ofNat 64 k ∧ + stateAt s₈.mem (st s₀) = stateAt s.mem (st s₀) ∧ + (∀ iv m, R₀ s₀ iv m → bytesAt s₈.mem (st s₀ + 32) 64 = bytesAt s.mem (st s₀ + 32) n ++ + (if k = 1 then List.replicate (64 - n) 0 else List.replicate (56 - n) 0 ++ lenBytes m)) ∧ + ∀ r ∈ nvRegs, s₈.gpr r = s.gpr r) ?_ + fun s₈ ⟨hC₈, h24₈, hst₈, hby₈, nv₈⟩ => ?_) + · refine WP.ite (decide (k = 0)) hz₆ (fun hb => ?_) (fun hb => ?_) + · simp only [decide_eq_true_eq] at hb; subst hb + have hout : InRegions s₆.wr (st s₀ + BitVec.ofNat 64 88) 8 := + ⟨stR s₀, by simp [hC₆.wr, hp.wr], contains_offset (by omega) (by omega)⟩ + refine wp_add fun s₇ u₇ => wp_add fun s₈ u₈ => wp_add fun s₉ u₉ => wp_li (by decide) fun s₁₀ u₁₀ => + wp_stdbrx (a := st s₀ + BitVec.ofNat 64 88) (by decide) ?_ ?_ fun s₁₁ g₁₁ => WP.block_nil ?_ + · rw [u₁₀.other _ (by decide), u₉.other _ (by decide), u₈.other _ (by decide), + u₇.other _ (by decide), hC₆.r26, u₁₀.gpr] + · rw [u₁₀.wr, u₉.wr, u₈.wr, u₇.wr]; exact hout + have keep : ∀ r, r ≠ .r8 → r ≠ .r11 → s₁₁.gpr r = s₆.gpr r := fun r h h' => by + rw [g₁₁.gpr, u₁₀.other r h', u₉.other r h, u₈.other r h, u₇.other r h] + have hv : rev64 (s₁₀.gpr .r8) = rev64 (BitVec.ofNat 64 (8 * (s₀.gpr .r4).toNat)) := by + rw [u₁₀.other _ (by decide), u₉.gpr, u₈.gpr, u₇.gpr, hC₆.r29, times8] + have hm₁₀ : s₁₀.mem = s₆.mem := by rw [u₁₀.mem, u₉.mem, u₈.mem, u₇.mem] + let L := (List.range 8).map fun j => + (rev64 (BitVec.ofNat 64 (8 * (s₀.gpr .r4).toNat))).extractLsb' (8 * j) 8 + have hw : s₁₁.mem = writeBytes s₆.mem (st s₀ + 32 + BitVec.ofNat 64 56) L := by + rw [g₁₁.mem, hm₁₀, hv, show st s₀ + 32 + BitVec.ofNat 64 56 = st s₀ + BitVec.ofNat 64 88 by + rw [BitVec.add_assoc]; rfl, Mem.writeW, write_eq_writeBytes] + rfl + obtain ⟨-, hfr, hsv⟩ := hC₆.writeBuf hp (n := 56) (xs := L) (by simp [L]) + refine ⟨⟨g₁₁.rd.trans (by rw [u₁₀.rd, u₉.rd, u₈.rd, u₇.rd]; exact hC₆.rd), + g₁₁.wr.trans (by rw [u₁₀.wr, u₉.wr, u₈.wr, u₇.wr]; exact hC₆.wr), + by rw [keep _ (by decide) (by decide), hC₆.r26], by rw [keep _ (by decide) (by decide), hC₆.r27], + by rw [keep _ (by decide) (by decide), hC₆.r28], by rw [keep _ (by decide) (by decide), hC₆.r29], + by rw [g₁₁.sp, u₁₀.sp, u₉.sp, u₈.sp, u₇.sp]; exact hC₆.sp, + by rw [hw]; exact hfr, by rw [hw]; exact hsv⟩, + by rw [keep _ (by decide) (by decide), h24₆], ?_, fun iv m hm => ?_, + fun r hr => (keep r (by revert r hr; decide) (by revert r hr; decide)).trans (nv₆ r hr)⟩ + · rw [hw, ← hst₆] + apply stateAt_congr + intro i hi + rw [st_add] + exact writeBytes_before _ _ _ (by omega) (by simp [L]) + · simp only [show ¬ ((0 : Nat) = 1) by decide, ite_false] + have e := bytesAt_writeBytes s₆.mem (st s₀ + 32) 56 L (by simp [L]) + simp only [L, List.length_map, List.length_range] at e + rw [hw, e, rev64_bytes, len_bits hm.2, hby₆] + simp [lenBytes, List.append_assoc] + · simp only [decide_eq_false_iff_not] at hb + have hk1 : k = 1 := by omega + subst hk1 + refine WP.block_nil ⟨hC₆, h24₆, hst₆, fun iv m _ => ?_, nv₆⟩ + rw [hby₆]; simp + -- Compress the block. + refine WP.seq (wp_addi (by decide) (by decide) fun s₉ u₉ => WP.block_nil ?_) + have hC₉ : Common s₀ s₉ := hC₈.of_gpr (fun r hr => by + have : r ≠ .r4 := by revert r hr; decide + rw [u₉.other r this]) u₉.mem u₉.rd u₉.wr u₉.sp + have hx1 : s₉.gpr .r4 = st s₀ + 32 := by rw [u₉.gpr, hC₈.r26]; rfl + have nv₉ : ∀ r ∈ nvRegs, s₉.gpr r = s.gpr r := fun r hr => + (u₉.other r (by revert r hr; decide)).trans (nv₈ r hr) + refine WP.seq (compress_buf hp hC₉ hx1 fun s₁₁ hC₁₁ cs₁₁ hst₁₁ => ?_) + have nv₁₁ : ∀ r ∈ nvRegs, s₁₁.gpr r = s.gpr r := fun r hr => (cs₁₁ r (nv_pres r hr)).trans (nv₉ r hr) + have h24₁₁ : s₁₁.gpr .r31 = BitVec.ofNat 64 k := by + rw [cs₁₁ _ (by decide), u₉.other _ (by decide), h24₈] + have hblk : ∀ iv m, R₀ s₀ iv m → blockAt s₉.mem (st s₀ + 32) = parseBlock fun t => + (bytesAt s.mem (st s₀ + 32) n ++ + (if k = 1 then List.replicate (64 - n) 0 else List.replicate (56 - n) 0 ++ lenBytes m)).getD t 0 := by + intro iv m hm + apply parseBlock_congr + intro t ht + rw [u₉.mem] + exact Stream.bytesAt_getD (hby₈ iv m hm) ht + -- Next block, if any. + refine wp_li (by decide) fun s₁₂ u₁₂ => wp_subi (by decide) (by decide) fun s₁₃ u₁₃ => WP.block_nil ?_ + have hC₁₃ : Common s₀ s₁₃ := hC₁₁.of_gpr (fun r hr => by + have : r ≠ .r31 ∧ r ≠ .r30 := by revert r hr; decide + rw [u₁₃.other r this.1, u₁₂.other r this.2]) (by rw [u₁₃.mem, u₁₂.mem]) (by rw [u₁₃.rd, u₁₂.rd]) + (by rw [u₁₃.wr, u₁₂.wr]) (by rw [u₁₃.sp, u₁₂.sp]) + have nv₁₃ : ∀ r ∈ nvRegs, s₁₃.gpr r = s.gpr r := fun r hr => + (u₁₃.other r (by revert r hr; decide)).trans ((u₁₂.other r (by revert r hr; decide)).trans (nv₁₁ r hr)) + have hz : eval (.zero .d .r31) s₁₃ = some (decide (k = 1)) := by + rw [eval_zero, u₁₃.gpr, u₁₂.other _ (by decide), h24₁₁, sub_beq (by omega) (by omega)] + have hst : ∀ iv m, R₀ s₀ iv m → stateAt s₁₃.mem (st s₀) = compress (stateAt s.mem (st s₀)) (parseBlock fun t => + (bytesAt s.mem (st s₀ + 32) n ++ + (if k = 1 then List.replicate (64 - n) 0 else List.replicate (56 - n) 0 ++ lenBytes m)).getD t 0) := by + intro iv m hm + rw [u₁₃.mem, u₁₂.mem, hst₁₁, u₉.mem, hst₈, ← hblk iv m hm, u₉.mem] + by_cases hk1 : k = 1 + · subst hk1 + refine ⟨.inr ⟨by rw [hz]; simp, rfl, ⟨hC₁₃, by omega, by omega, ?_, ?_, fun iv m hm => ?_⟩⟩, nv₁₃⟩ + · rw [u₁₃.other _ (by decide), u₁₂.gpr] + · rw [u₁₃.gpr, u₁₂.other _ (by decide), h24₁₁]; rfl + · rw [h.hash iv m hm] + simp only [ite_true, show ¬ (0 = 1) by decide, ite_false, Fin1, Fin0, hst iv m hm] + simp [bytesAt] + · have hk0 : k = 0 := by omega + subst hk0 + refine ⟨.inl ⟨by rw [hz]; simp, hC₁₃, fun iv m hm => ?_⟩, nv₁₃⟩ + rw [h.hash iv m hm, hst iv m hm] + simp only [show ¬ (0 = 1) by decide, ite_false, Fin0, List.append_assoc] + +/-! ## Prologue -/ + +/-- The prologue after saving. -/ +def prologue : List Instr := + [mov .r26 .r3, mov .r27 .r6, mov .r28 .r5, mov .r29 .r4, + .li .r8 63, .logic .and .r30 .r29 .r8, + .li .r8 0x80, .add .r11 .r26 .r30, .stb .r8 .r11 32, .addi .r30 .r30 1, + .addi .r31 .r30 7, .lsr .d .r31 .r31 6] + +theorem finalize_eq : finalizeMain = .seq (.block (save .r6 ++ prologue)) + (.seq (.loop finalizeBody (.zero .d .r31)) + (.block ((List.range 8).flatMap (fun k => + [.load .w .r8 .r26 (4 * k), .li .r11 (4 * k), .storeRev .w .r8 .r28 .r11]) ++ restore))) := rfl + +theorem prologue_ok {s₀ : State} (hp : Pre s₀) : + WP isa (.block (save .r6 ++ prologue)) s₀ fun s => ∃ k, LInv s₀ k (cnt s₀ % 64 + 1) s := by + have hr : cnt s₀ % 64 < 64 := Nat.mod_lt _ (by omega) + refine save_ok (by decide) (fun d hd₁ hd₂ => ⟨scR s₀, by simp [hp.wr], contains_offset (by omega) (by omega)⟩) + fun s₁ g₁ rd₁ wr₁ sp₁ m₁ => ?_ + unfold prologue + refine wp_mov fun s₂ u₂ => wp_mov fun s₃ u₃ => wp_mov fun s₄ u₄ => wp_mov fun s₅ u₅ => + wp_li (by decide) fun s₆ u₆ => wp_and fun s₇ u₇ => ?_ + have hC₇ : Common s₀ s₇ := by + refine ⟨?_, ?_, ?_, ?_, ?_, ?_, ?_, ?_, ?_⟩ + · rw [u₇.rd, u₆.rd, u₅.rd, u₄.rd, u₃.rd, u₂.rd, rd₁] + · rw [u₇.wr, u₆.wr, u₅.wr, u₄.wr, u₃.wr, u₂.wr, wr₁] + · rw [u₇.other _ (by decide), u₆.other _ (by decide), u₅.other _ (by decide), u₄.other _ (by decide), + u₃.other _ (by decide), u₂.gpr, g₁] + · rw [u₇.other _ (by decide), u₆.other _ (by decide), u₅.other _ (by decide), u₄.other _ (by decide), + u₃.gpr, u₂.other _ (by decide), g₁] + · rw [u₇.other _ (by decide), u₆.other _ (by decide), u₅.other _ (by decide), u₄.gpr, + u₃.other _ (by decide), u₂.other _ (by decide), g₁] + · rw [u₇.other _ (by decide), u₆.other _ (by decide), u₅.gpr, u₄.other _ (by decide), + u₃.other _ (by decide), u₂.other _ (by decide), g₁] + · rw [u₇.sp, u₆.sp, u₅.sp, u₄.sp, u₃.sp, u₂.sp, sp₁] + · rw [u₇.mem, u₆.mem, u₅.mem, u₄.mem, u₃.mem, u₂.mem, m₁] + exact (saveMem_frame _ _ _).mono (by simp) + · rw [u₇.mem, u₆.mem, u₅.mem, u₄.mem, u₃.mem, u₂.mem, m₁] + intro p hp' + exact saveMem_saved _ _ _ p hp' + have hm₇ : s₇.mem = saveMem s₀.mem (scr s₀) s₀.gpr := by + rw [u₇.mem, u₆.mem, u₅.mem, u₄.mem, u₃.mem, u₂.mem, m₁] + have hr23 : s₇.gpr .r30 = BitVec.ofNat 64 (cnt s₀ % 64) := by + rw [u₇.gpr, u₆.other .r29 (by decide), u₆.gpr, u₅.gpr, u₄.other .r4 (by decide), + u₃.other .r4 (by decide), u₂.other .r4 (by decide), g₁] + exact and63 _ + -- The `0x80` byte. + have hout : InRegions s₇.wr (st s₀ + 32 + BitVec.ofNat 64 (cnt s₀ % 64)) 1 := by + refine ⟨stR s₀, by simp [hC₇.wr, hp.wr], ?_⟩ + rw [st_add]; exact contains_offset (by omega) (by omega) + refine wp_li (by decide) fun s₈ u₈ => wp_add fun s₉ u₉ => + wp_stb (a := st s₀ + 32 + BitVec.ofNat 64 (cnt s₀ % 64)) (by decide) (by omega) ?_ + (by rw [u₉.wr, u₈.wr]; exact hout) fun s₁₀ g₁₀ => ?_ + · rw [u₉.gpr, u₈.other _ (by decide), u₈.other _ (by decide), hC₇.r26, hr23, + show BitVec.ofNat 64 32 = (32 : BitVec 64) from rfl] + ac_rfl + obtain ⟨-, hfr, hsv⟩ := hC₇.writeBuf hp (n := cnt s₀ % 64) (xs := [0x80]) (by simp; omega) + have hm₁₀ : s₁₀.mem = writeBytes s₇.mem (st s₀ + 32 + BitVec.ofNat 64 (cnt s₀ % 64)) [0x80] := by + rw [g₁₀.mem, u₉.mem, u₈.mem, u₉.other _ (by decide), u₈.gpr, ← List.nil_append [(0x80 : Byte)], + writeBytes_snoc _ _ _ _ (by simp), writeBytes_nil] + simp + refine wp_addi (by decide) (by decide) fun s₁₁ u₁₁ => wp_addi (by decide) (by decide) fun s₁₂ u₁₂ => + wp_lsr (by decide) fun s₁₃ u₁₃ => WP.block_nil ?_ + have keep : ∀ r, r ≠ .r30 → r ≠ .r31 → r ≠ .r8 → r ≠ .r11 → s₁₃.gpr r = s₇.gpr r := + fun r h1 h2 h3 h4 => by + rw [u₁₃.other r h2, u₁₂.other r h2, u₁₁.other r h1, g₁₀.gpr, u₉.other r h4, u₈.other r h3] + have hm₁₃ : s₁₃.mem = s₁₀.mem := by rw [u₁₃.mem, u₁₂.mem, u₁₁.mem] + have hC₁₃ : Common s₀ s₁₃ := + ⟨by rw [u₁₃.rd, u₁₂.rd, u₁₁.rd, g₁₀.rd, u₉.rd, u₈.rd, hC₇.rd], + by rw [u₁₃.wr, u₁₂.wr, u₁₁.wr, g₁₀.wr, u₉.wr, u₈.wr, hC₇.wr], + by rw [keep _ (by decide) (by decide) (by decide) (by decide), hC₇.r26], + by rw [keep _ (by decide) (by decide) (by decide) (by decide), hC₇.r27], + by rw [keep _ (by decide) (by decide) (by decide) (by decide), hC₇.r28], + by rw [keep _ (by decide) (by decide) (by decide) (by decide), hC₇.r29], + by rw [u₁₃.sp, u₁₂.sp, u₁₁.sp, g₁₀.sp, u₉.sp, u₈.sp, hC₇.sp], + by rw [hm₁₃, hm₁₀]; exact hfr, by rw [hm₁₃, hm₁₀]; exact hsv⟩ + have hr23' : s₁₃.gpr .r30 = BitVec.ofNat 64 (cnt s₀ % 64 + 1) := by + rw [u₁₃.other _ (by decide), u₁₂.other _ (by decide), u₁₁.gpr, g₁₀.gpr, u₉.other _ (by decide), + u₈.other _ (by decide), hr23, ← BitVec.ofNat_add] + have hr24 : s₁₃.gpr .r31 = BitVec.ofNat 64 ((cnt s₀ % 64 + 8) / 64) := by + rw [u₁₃.gpr, u₁₂.gpr, u₁₁.gpr, g₁₀.gpr, u₉.other _ (by decide), u₈.other _ (by decide), hr23, + ← BitVec.ofNat_add, ← BitVec.ofNat_add, ofNat_shr6 (by omega)] + -- The facts about the buffer. + have hbytes : ∀ iv m, R₀ s₀ iv m → bytesAt s₁₃.mem (st s₀ + 32) (cnt s₀ % 64 + 1) = rest m ++ [0x80] := by + intro iv m hm + have e := bytesAt_writeBytes s₇.mem (st s₀ + 32) (cnt s₀ % 64) [0x80] (by simp; omega) + simp only [List.length_singleton] at e + rw [hm₁₃, hm₁₀, e, hm₇] + congr 1 + rw [hm.length] + refine (bytesAt_congr ?_).trans hm.1.2 + intro i hi + have := frame_bytes (saveMem_frame s₀.mem (scr s₀) s₀.gpr) (R := stR s₀) (by simpa using hp.st_scr) + (by simp) (i := 32 + i) (by show 32 + i < 96; omega) + rwa [← st_add] at this + have hstate : stateAt s₁₃.mem (st s₀) = stateAt s₀.mem (st s₀) := by + apply stateAt_congr + intro i hi + rw [hm₁₃, hm₁₀, st_add, writeBytes_before _ _ _ (by omega) (by simp; omega), hm₇] + exact frame_bytes (saveMem_frame s₀.mem (scr s₀) s₀.gpr) (R := stR s₀) (by simpa using hp.st_scr) (by simp) + (by show i < 96; omega) + by_cases hb : 57 ≤ cnt s₀ % 64 + 1 + · have hk : (cnt s₀ % 64 + 8) / 64 = 1 := by omega + refine ⟨1, hC₁₃, le_rfl, by omega, hr23', by rw [hr24, hk], fun iv m hm => ?_⟩ + simp only [↓reduceIte] + rw [finalHash_two (by rw [← hm.length]; omega), Fin1, hbytes iv m hm, hstate, hm.1.1, + ← hm.length, show 64 - (cnt s₀ % 64 + 1) = 63 - cnt s₀ % 64 by omega] + · have hk : (cnt s₀ % 64 + 8) / 64 = 0 := by omega + refine ⟨0, hC₁₃, by omega, by omega, hr23', by rw [hr24, hk], fun iv m hm => ?_⟩ + simp only [show ((0 : Nat) = 1) = False by decide, ite_false] + rw [finalHash_one (by rw [← hm.length]; omega), Fin0, hbytes iv m hm, hstate, hm.1.1, + ← hm.length, show 56 - (cnt s₀ % 64 + 1) = 55 - cnt s₀ % 64 by omega] + +/-! ## Output and epilogue -/ + +/-- Word `k` of the digest. -/ +def outW (k : Nat) : List Instr := [.load .w .r8 .r26 (4 * k), .li .r11 (4 * k), .storeRev .w .r8 .r28 .r11] + +/-- `k` words of the digest are written. -/ +structure Out (s₀ sD : State) (k : Nat) (s : State) : Prop where + rd : s.rd = s₀.rd + wr : s.wr = s₀.wr + keep : ∀ r ∈ [Reg.r26, .r27, .r28], s.gpr r = sD.gpr r + sp : s.sp = sD.sp + mem : s.mem = writeBytes sD.mem (out s₀) (((stateAt sD.mem (st s₀)).toList.take k).flatMap wordBytes) + +theorem flat_length (H : HashValue) (k : Nat) (hk : k ≤ 8) : + ((H.toList.take k).flatMap wordBytes).length = 4 * k := by + rw [List.length_flatMap] + have : ∀ w ∈ H.toList.take k, (wordBytes w).length = 4 := fun w _ => rfl + rw [List.map_congr_left this, List.map_const', List.sum_replicate_nat, List.length_take] + simp; omega + +theorem out_frame (s₀ : State) (m : Mem) (xs : List Byte) (hx : xs.length ≤ 32) : + Frame [outR s₀] m (writeBytes m (out s₀) xs) := + writeBytes_frame _ _ _ (by + rw [show out s₀ = out s₀ + BitVec.ofNat 64 0 by simp] + exact contains_offset (by omega) (by omega)) + +theorem writeW_rev32 (m : Mem) (a : Addr) (w : BitVec 32) : + m.writeW a (rev32 w) = writeBytes m a (wordBytes w) := by + rw [Mem.writeW, write_eq_writeBytes, ← rev32_bytes]; rfl + +theorem sw32 (v : BitVec 32) : (v.setWidth 64).setWidth 32 = v := by ext i hi; simp + +theorem out_step {s₀ : State} (hp : Pre s₀) {sD : State} (hD : Done s₀ sD) {k : Nat} (hk : k < 8) + {s : State} (h : Out s₀ sD k s) {rest : List Instr} {Q : State → Prop} + (hnext : ∀ s', Out s₀ sD (k + 1) s' → WP isa (.block rest) s' Q) : + WP isa (.block (outW k ++ rest)) s Q := by + have hC := hD.1 + have hx19 : s.gpr .r26 = st s₀ := by rw [h.keep _ (by simp), hC.r26] + have hx21 : s.gpr .r28 = out s₀ := by rw [h.keep _ (by simp), hC.r28] + have hP := flat_length (stateAt sD.mem (st s₀)) k hk.le + simp only [outW, List.cons_append, List.nil_append] + refine wp_lwz (a := st s₀ + BitVec.ofNat 64 (4 * k)) (by decide) (by omega) (by rw [hx19]) + ⟨stR s₀, by simp [h.rd, h.wr, hp.wr], contains_offset (by omega) (by omega)⟩ fun s₁ u₁ => ?_ + refine wp_li (by omega) fun s₂ u₂ => wp_stwbrx (a := out s₀ + BitVec.ofNat 64 (4 * k)) (by decide) + (by rw [u₂.other .r28 (by decide), u₁.other .r28 (by decide), hx21, u₂.gpr]) + (by rw [u₂.wr, u₁.wr]; exact ⟨outR s₀, by simp [h.wr, hp.wr], contains_offset (by omega) (by omega)⟩) + fun s₃ g₃ => hnext s₃ ⟨by rw [g₃.rd, u₂.rd, u₁.rd, h.rd], by rw [g₃.wr, u₂.wr, u₁.wr, h.wr], + fun r hr => ?_, by rw [g₃.sp, u₂.sp, u₁.sp, h.sp], ?_⟩ + · have : r ≠ .r8 ∧ r ≠ .r11 := by revert r hr; decide + rw [g₃.gpr, u₂.other r this.2, u₁.other r this.1, h.keep r hr] + · have hread : s.mem.readW (st s₀ + BitVec.ofNat 64 (4 * k)) 32 = (stateAt sD.mem (st s₀))[k] := by + rw [h.mem, (out_frame s₀ sD.mem _ (by omega)).readW + (r := ⟨st s₀ + BitVec.ofNat 64 (4 * k), 4⟩) (Region.contains_self _ _) ?_ (by decide)] + · simp [stateAt] + · intro r' hr' + simp only [List.mem_cons, List.not_mem_nil, or_false] at hr' + subst hr' + exact hp.st_out.sub_left (sub_offset (by omega) (by omega)) + rw [g₃.mem, u₂.mem, u₁.mem, u₂.other _ (by decide), u₁.gpr, sw32, hread, h.mem, writeW_rev32, ← hP] + rw [writeBytes_append _ _ _ _ (by rw [hP]; simp [wordBytes]; omega), List.take_add_one, + List.getElem?_eq_getElem (by simp; omega), Option.toList_some, List.flatMap_append, + List.flatMap_singleton, Vector.getElem_toList] + +/-- The epilogue's postcondition. -/ +def Post (s₀ s' : State) : Prop := + (∀ p ∈ saved, s'.gpr p.1 = s₀.gpr p.1) ∧ s'.sp = s₀.sp ∧ Proof.Sha256.finalizePPC64LE.post s₀ s' + +theorem epilogue_ok {s₀ : State} (hp : Pre s₀) {sD : State} (hD : Done s₀ sD) {s : State} + (h : Out s₀ sD 8 s) : WP isa (.block restore) s (Post s₀) := by + have hC := hD.1 + have hfo := out_frame s₀ sD.mem (((stateAt sD.mem (st s₀)).toList.take 8).flatMap wordBytes) + (by rw [flat_length _ _ le_rfl]) + refine restore_ok (scr := scr s₀) (by rw [h.keep _ (by simp), hC.r27]) + (fun d hd₁ hd₂ => ⟨scR s₀, by simp [h.rd, h.wr, hp.wr], contains_offset hd₂ (by omega)⟩) s₀.gpr + (fun p hp' => ?_) fun s' hs _ hmem _ _ hsp => ⟨hs, by rw [hsp, h.sp, hC.sp], ?_⟩ + · rw [h.mem, ← hC.saved p hp'] + refine hfo.readW (r := ⟨scr s₀ + BitVec.ofNat 64 p.2, 8⟩) (Region.contains_self _ _) ?_ (by decide) + intro r' hr' + simp only [List.mem_cons, List.not_mem_nil, or_false] at hr' + subst hr' + exact hp.out_scr.symm.sub_left (saved_sub hp') + · intro iv m hr hc + have e := bytesAt_writeBytes sD.mem (out s₀) 0 (((stateAt sD.mem (st s₀)).toList.take 8).flatMap wordBytes) + (by rw [flat_length _ _ le_rfl]; omega) + have e' : bytesAt (writeBytes sD.mem (out s₀) (((stateAt sD.mem (st s₀)).toList.take 8).flatMap wordBytes)) + (out s₀) 32 = ((stateAt sD.mem (st s₀)).toList.take 8).flatMap wordBytes := by + rw [flat_length _ _ le_rfl, show out s₀ + BitVec.ofNat 64 0 = out s₀ by simp, + show bytesAt sD.mem (out s₀) 0 = [] from rfl, List.nil_append] at e + exact e + rw [← h.mem, ← hmem] at e' + rw [e', hD.2 iv m ⟨hr, hc⟩, List.take_of_length_le (by simp)] + +theorem out_all {s₀ : State} (hp : Pre s₀) {sD : State} (hD : Done s₀ sD) : + ∀ j ≤ 8, ∀ s, Out s₀ sD (8 - j) s → + WP isa (.block (((List.range 8).drop (8 - j)).flatMap outW ++ restore)) s (Post s₀) := by + intro j + induction j with + | zero => + intro _ s h + rw [show (List.range 8).drop (8 - 0) = [] from rfl, List.flatMap_nil, List.nil_append] + exact epilogue_ok hp hD h + | succ j ih => + intro hj s h + rw [List.drop_eq_getElem_cons (by simp; omega), List.flatMap_cons, List.append_assoc, + List.getElem_range] + refine out_step hp hD (by omega) h fun s' h' => ?_ + rw [show 8 - (j + 1) + 1 = 8 - j by omega] + exact ih (by omega) s' (by rwa [show 8 - (j + 1) + 1 = 8 - j by omega] at h') + +/-- No instruction of `finalizeMain` writes the callee-saved registers it does not save. -/ +theorem untouched_ok : ∀ r ∈ untouched, ∀ i ∈ instrs finalizeMain, dstOf i ≠ some r := by + have : ((instrs finalizeMain).all fun i => untouched.all fun r => dstOf i != some r) = true := by + rw [← Code.allInstrs_eq]; decide +kernel + intro r hr i hi + have := List.all_eq_true.mp (List.all_eq_true.mp this i hi) r hr + simpa using this + +/-- `finalize` without its frame: the callee-saved registers are kept. -/ +theorem correctMain {s₀ : State} (hp : Pre s₀) : + WP isa finalizeMain s₀ fun s' => (∀ r ∈ preserved, s'.gpr r = s₀.gpr r) ∧ + s'.sp = s₀.sp ∧ Proof.Sha256.finalizePPC64LE.post s₀ s' := by + refine WP.mono (WP.gprs (Q := fun (s' : State) => Post s₀ s' ∧ ∀ r ∈ nvRegs, s'.gpr r = s₀.gpr r) ?_ + untouched_ok) fun s' ⟨⟨⟨hsv, hsp, hpost⟩, hnv⟩, hu⟩ => ⟨fun r hr => ?_, hsp, hpost⟩ + · rw [finalize_eq] + refine WP.seq (WP.mono (WP.gprs (rs := nvRegs) (prologue_ok hp) (by + intro r hr i hi + have : ((instrs (.block (save .r6 ++ prologue) : Prog isa)).all fun i => + nvRegs.all fun r => dstOf i != some r) = true := by decide + simpa using List.all_eq_true.mp (List.all_eq_true.mp this i hi) r hr)) + fun s₁ ⟨⟨k, hL⟩, hnv₁⟩ => ?_) + refine WP.seq (WP.mono (Q := fun (s : State) => Done s₀ s ∧ ∀ r ∈ nvRegs, s.gpr r = s₀.gpr r) ?_ + fun sD ⟨hD, hnvD⟩ => ?_) + · refine WP.loop (M := isa) (fun i s => (∃ n, LInv s₀ i n s) ∧ ∀ r ∈ nvRegs, s.gpr r = s₀.gpr r) + ?_ k s₁ ⟨⟨_, hL⟩, hnv₁⟩ + rintro i s ⟨⟨n, hL⟩, hnv⟩ + refine WP.mono (body_ok hp hL) fun s' ⟨h, hnv'⟩ => ?_ + have hnv'' : ∀ r ∈ nvRegs, s'.gpr r = s₀.gpr r := fun r hr => (hnv' r hr).trans (hnv r hr) + rcases h with ⟨he, hD⟩ | ⟨he, rfl, hL'⟩ + · exact .inl ⟨he, hD, hnv''⟩ + · exact .inr ⟨he, 0, by omega, ⟨0, hL'⟩, hnv''⟩ + · have := out_all hp hD 8 le_rfl sD ⟨hD.1.rd, hD.1.wr, fun _ _ => rfl, rfl, by simp [writeBytes_nil]⟩ + rw [show 8 - 8 = 0 from rfl, List.drop_zero] at this + refine WP.mono (WP.gprs (rs := nvRegs) this (by + intro r hr i hi + have : ((instrs (.block ((List.range 8).flatMap outW ++ restore) : Prog isa)).all fun i => + nvRegs.all fun r => dstOf i != some r) = true := by decide + simpa using List.all_eq_true.mp (List.all_eq_true.mp this i hi) r hr)) + fun s' ⟨h, hnv'⟩ => ⟨h, fun r hr => (hnv' r hr).trans (hnvD r hr)⟩ + · have key : ∀ r ∈ preserved, r ∈ untouched ∨ r ∈ nvRegs ∨ r ∈ saved.map Prod.fst := by decide + rcases key r hr with hr' | hr' | hr' + · exact hu r hr' + · exact hnv r hr' + · obtain ⟨p, hp', rfl⟩ := List.mem_map.mp hr' + exact hsv p hp' + +/-- The state `finalizeMain` starts in: the link register moved to `r0`, +then pushed in a frame. -/ +abbrev inner (s₀ : State) : State := framed .r0 (s₀.write .r0 s₀.lr) + +theorem correct {s₀ : State} (hp : Pre s₀) (hs : Stack s₀) : + WP isa finalize s₀ fun s' => abiPreserved s₀ s' ∧ Proof.Sha256.finalizePPC64LE.post s₀ s' := by + have hpi : Pre (inner s₀) := ⟨hp.rd, hp.wr, hp.st_out, hp.st_scr, hp.out_scr⟩ + refine WP.seq (WP.cons exec_mflr (WP.block_nil (WP.seq ?_))) + refine WP.frameReg (by exact hs.sp48) (fun R hR => ?_) (WP.mono (correctMain hpi) + fun s' ⟨hk, hsp, hpost⟩ => ?_) + · rw [show (s₀.write .r0 s₀.lr).wr = s₀.wr from rfl, hp.wr] at hR + simp only [List.mem_cons, List.not_mem_nil, or_false] at hR + rcases hR with rfl | rfl | rfl + · exact hs.st.sub_left (frame_sub _) + · exact hs.out.sub_left (frame_sub _) + · exact hs.scr.sub_left (frame_sub _) + · refine WP.cons exec_mtlr (WP.block_nil ⟨⟨fun r hr => ?_, rfl, ?_⟩, fun iv m hm hc => ?_⟩) + · have h0 : r ≠ .r0 := by revert r hr; decide + simp only [State.write, h0, ite_false] + rw [hk r hr] + simp only [framed, State.write, h0, ite_false] + · simp [State.write] + · exact hpost iv m (reprFrom_congr (fun i hi => write_frame_bytes (R := stR s₀) hs.st + (by simp) hi) hm) hc + +/-- The initial taint: only the arguments are public. -/ +theorem agree₀ {s₁ s₂ : State} (hpub : Proof.Sha256.finalizePPC64LE.pub s₁ s₂) : + VG.PPC64LE.Taint.Agree (VG.PPC64LE.Taint.ofRegs [.r3, .r4, .r5, .r6]) s₁ s₂ := by + obtain ⟨p1, p2, p3, p4, hsp⟩ := hpub + refine ⟨hsp, fun r hr => ?_⟩ + simp only [VG.PPC64LE.Taint.mem_ofRegs, List.mem_cons, List.not_mem_nil, or_false] at hr + rcases hr with rfl | rfl | rfl | rfl <;> assumption + +/-- A state satisfying the precondition. -/ +def sat : State where + gpr r := match r with + | .r3 => 0x1000 | .r5 => 0x2000 | .r6 => 0x3000 | _ => 0 + lr := 0 + sp := 0x4000 + mem _ := 0 + rd := [] + wr := [⟨0x1000, 96⟩, ⟨0x2000, 32⟩, ⟨0x3000, 160⟩] + +theorem finalize_verified : Verified PPC64LE.target finalize Proof.Sha256.finalizePPC64LE := by + refine ⟨fun s hs => ?_, ?_, ?_⟩ + · obtain ⟨t, s', he, h⟩ := correct (pre_of hs).1 (pre_of hs).2 + exact ⟨t, s', he, h⟩ + · exact VG.Taint.constantTime (A := taint) (Taint.ofRegs [.r3, .r4, .r5, .r6]) (fun _ _ _ _ hp => agree₀ hp) + (by taint_decide) + · refine ⟨sat, rfl, rfl, ?_, ?_, ?_, by decide, ?_, ?_, ?_⟩ <;> + · intro a h₁ h₂ + simp only [Region.Contains, sat] at h₁ h₂ + bv_omega + +end VG.Proof.Sha256.PPC64LE.Stream.Finalize diff --git a/lean/VerifiedGarbage/Proof/Sha256/PPC64LE/Stream/Init.lean b/lean/VerifiedGarbage/Proof/Sha256/PPC64LE/Stream/Init.lean new file mode 100644 index 000000000..87cb690fa --- /dev/null +++ b/lean/VerifiedGarbage/Proof/Sha256/PPC64LE/Stream/Init.lean @@ -0,0 +1,101 @@ +import VerifiedGarbage.Proof.Sha256.PPC64LE.Stream.Common + +/-! +# Streaming SHA-256 on PPC64LE: `init` + +Untrusted: everything here is checked by Lean. +-/ + +namespace VG.Proof.Sha256.PPC64LE.Stream + +open VG VG.PPC64LE VG.Impl.Sha256.PPC64LE.Stream +open VG.Proof.Sha256.PPC64LE (writeState stateAt_writeState contains_offset) +open VG.Spec.Sha256 (stateAt H0) + +/-- The three instructions storing the 32-bit word `x` at `off(r3)`. -/ +def word (x : BitVec 32) (off : Nat) : List Instr := + [.lis .r8 (x.extractLsb' 16 16), .ori .r8 .r8 (x.extractLsb' 0 16), .store .w .r8 .r3 off] + +theorem init_eq : init = .block (word H0[0] 0 ++ word H0[1] 4 ++ word H0[2] 8 ++ word H0[3] 12 ++ + word H0[4] 16 ++ word H0[5] 20 ++ word H0[6] 24 ++ word H0[7] 28) := rfl + +theorem word_ok {x : BitVec 32} {off : Nat} (ho : off < 2 ^ 15) {rest : List Instr} + {s : State} {Q : State → Prop} (hout : InRegions s.wr (s.gpr .r3 + BitVec.ofNat 64 off) 4) + (k : ∀ s', (∀ r, r ≠ .r8 → s'.gpr r = s.gpr r) → s'.rd = s.rd → s'.wr = s.wr → s'.sp = s.sp → + s'.mem = s.mem.writeW (s.gpr .r3 + BitVec.ofNat 64 off) x → WP isa (.block rest) s' Q) : + WP isa (.block (word x off ++ rest)) s Q := by + simp only [word, List.cons_append, List.nil_append] + refine WP.cons exec_lis (WP.cons exec_ori (WP.cons (exec_store_w (by decide) ho ?_) + (k _ ?_ rfl rfl rfl ?_))) + · simpa [State.write] using hout + · intro r hr; simp [State.write, hr] + · simp only [State.write, ite_true, show Reg.r3 ≠ .r8 by decide, ite_false] + congr 1 + exact lis_ori x + +theorem init_correct {s₀ : State} (hp : Proof.Sha256.initPPC64LE.pre s₀) : + WP isa init s₀ fun s' => ((∀ r ∈ preserved, s'.gpr r = s₀.gpr r) ∧ s'.sp = s₀.sp) ∧ + Proof.Sha256.initPPC64LE.post s₀ s' := by + obtain ⟨-, hwr⟩ := hp + have o : ∀ k, k < 8 → InRegions s₀.wr (s₀.gpr .r3 + BitVec.ofNat 64 (4 * k)) 4 := + fun k hk => ⟨⟨s₀.gpr .r3, 96⟩, by simp [hwr], contains_offset (by omega) (by omega)⟩ + rw [init_eq, ← List.append_nil (_ ++ word H0[7] 28)] + simp only [List.append_assoc] + refine word_ok (by omega) (o 0 (by omega)) fun s1 g1 _ wr1 sp1 m1 => ?_ + refine word_ok (by omega) (by rw [wr1, g1 _ (by decide)]; exact o 1 (by omega)) + fun s2 g2 _ wr2 sp2 m2 => ?_ + refine word_ok (by omega) (by rw [wr2, wr1, g2 _ (by decide), g1 _ (by decide)]; exact o 2 (by omega)) + fun s3 g3 _ wr3 sp3 m3 => ?_ + have w3 : s3.wr = s₀.wr := by rw [wr3, wr2, wr1] + have k3 : s3.gpr .r3 = s₀.gpr .r3 := by rw [g3 _ (by decide), g2 _ (by decide), g1 _ (by decide)] + refine word_ok (by omega) (by rw [w3, k3]; exact o 3 (by omega)) fun s4 g4 _ wr4 sp4 m4 => ?_ + have k4 : ∀ r, r ≠ .r8 → s4.gpr r = s₀.gpr r := fun r h => by rw [g4 r h, g3 r h, g2 r h, g1 r h] + have w4 : s4.wr = s₀.wr := by rw [wr4, wr3, wr2, wr1] + refine word_ok (by omega) (by rw [w4, k4 _ (by decide)]; exact o 4 (by omega)) + fun s5 g5 _ wr5 sp5 m5 => ?_ + refine word_ok (by omega) (by rw [wr5, w4, g5 _ (by decide), k4 _ (by decide)]; exact o 5 (by omega)) + fun s6 g6 _ wr6 sp6 m6 => ?_ + have w6 : s6.wr = s₀.wr := by rw [wr6, wr5, w4] + have k6 : s6.gpr .r3 = s₀.gpr .r3 := by rw [g6 _ (by decide), g5 _ (by decide), k4 _ (by decide)] + refine word_ok (by omega) (by rw [w6, k6]; exact o 6 (by omega)) fun s7 g7 _ wr7 sp7 m7 => ?_ + have w7 : s7.wr = s₀.wr := by rw [wr7, w6] + have k7 : s7.gpr .r3 = s₀.gpr .r3 := by rw [g7 _ (by decide), k6] + refine word_ok (by omega) (by rw [w7, k7]; exact o 7 (by omega)) fun s8 g8 _ _ sp8 m8 => + WP.block_nil ?_ + have k8 : ∀ r, r ≠ .r8 → s8.gpr r = s₀.gpr r := fun r h => by + rw [g8 r h, g7 r h, g6 r h, g5 r h, k4 r h] + have hm : s8.mem = writeState s₀.mem (s₀.gpr .r3) H0 := by + rw [m8, m7, m6, m5, m4, m3, m2, m1] + simp only [g7 _ (show Reg.r3 ≠ .r8 by decide), g6 _ (show Reg.r3 ≠ .r8 by decide), + g5 _ (show Reg.r3 ≠ .r8 by decide), k4 _ (show Reg.r3 ≠ .r8 by decide), + g3 _ (show Reg.r3 ≠ .r8 by decide), g2 _ (show Reg.r3 ≠ .r8 by decide), + g1 _ (show Reg.r3 ≠ .r8 by decide)] + rfl + refine ⟨⟨fun r hr => k8 r ?_, by rw [sp8, sp7, sp6, sp5, sp4, sp3, sp2, sp1]⟩, ?_⟩ + · revert r; decide + · show Spec.Sha256.Repr s8.mem (s₀.gpr .r3) [] + rw [hm] + exact Proof.Sha256.Stream.repr_nil (stateAt_writeState _ _ _) + +/-- A state satisfying the precondition. -/ +def initSat : State where + gpr r := match r with + | .r3 => 0x1000 | _ => 0 + lr := 0 + sp := 0x4000 + mem _ := 0 + rd := [] + wr := [⟨0x1000, 96⟩] + +theorem init_verified : Verified PPC64LE.target init Proof.Sha256.initPPC64LE := by + refine ⟨fun s hs => ?_, ?_, ⟨initSat, rfl, rfl⟩⟩ + · obtain ⟨t, s', he, ⟨hk, hsp⟩, h⟩ := init_correct hs + exact ⟨t, s', he, ⟨hk, hsp, Exec.lr he (by decide +kernel) + (by rw [← Code.allInstrs_eq]; decide +kernel)⟩, h⟩ + · refine VG.Taint.constantTime (A := taint) (Taint.ofRegs [.r3]) ?_ (by taint_decide) + intro s₁ s₂ _ _ h + refine ⟨h.2, fun r hr => ?_⟩ + simp only [VG.PPC64LE.Taint.mem_ofRegs, List.mem_cons, List.not_mem_nil, or_false] at hr + subst hr; exact h.1 + +end VG.Proof.Sha256.PPC64LE.Stream diff --git a/lean/VerifiedGarbage/Proof/Sha256/PPC64LE/Stream/Update.lean b/lean/VerifiedGarbage/Proof/Sha256/PPC64LE/Stream/Update.lean new file mode 100644 index 000000000..72b537a1e --- /dev/null +++ b/lean/VerifiedGarbage/Proof/Sha256/PPC64LE/Stream/Update.lean @@ -0,0 +1,773 @@ +import VerifiedGarbage.Proof.Sha256.PPC64LE.Stream.Common + +/-! +# Streaming SHA-256 on PPC64LE: `update` + +Untrusted: everything here is checked by Lean. The same structure as the +x86-64 proof (`VG.Proof.Sha256.X86_64.Stream.Update`); the loop runs while +data is left, so every iteration consumes at least one byte. +-/ + +namespace VG.Proof.Sha256.PPC64LE.Stream.Update + +open VG VG.PPC64LE VG.Impl.Sha256.PPC64LE.Stream +open VG.Proof.Sha256.PPC64LE (contains_offset toNat_ofNat_lt sub_offset) +open VG.Proof.Sha256.PPC64LE.Stream +open VG.Proof.Sha256.Stream +open VG.Spec.Sha256 (HashValue stateAt blockAt compress parseBlock bytesAt) + +/-! ## The precondition -/ + +section +variable (s₀ : State) + +abbrev st : Addr := s₀.gpr .r3 +abbrev cnt : Nat := (s₀.gpr .r4).toNat +abbrev dp : Addr := s₀.gpr .r5 +abbrev len : Nat := (s₀.gpr .r6).toNat +abbrev scr : Addr := s₀.gpr .r7 +abbrev stR : Region := ⟨st s₀, 96⟩ +abbrev dR : Region := ⟨dp s₀, len s₀⟩ +abbrev scR : Region := ⟨scr s₀, 160⟩ +/-- The data. -/ +abbrev D : List Byte := bytesAt s₀.mem (dp s₀) (len s₀) + +/-- The messages the initial state represents. -/ +def R₀ (iv : HashValue) (m : List Byte) : Prop := + Spec.Sha256.ReprFrom iv s₀.mem (st s₀) m ∧ s₀.gpr .r4 = BitVec.ofNat 64 m.length + +/-- The caller's registers are saved in the scratch space. -/ +def Saved (m : Mem) : Prop := + ∀ p ∈ saved, m.readW (scr s₀ + BitVec.ofNat 64 p.2) 64 = s₀.gpr p.1 + +end + +structure Pre (s₀ : State) : Prop where + rd : s₀.rd = [dR s₀] + wr : s₀.wr = [stR s₀, scR s₀] + st_scr : (stR s₀).Disjoint (scR s₀) + d_st : (dR s₀).Disjoint (stR s₀) + d_scr : (dR s₀).Disjoint (scR s₀) + +/-- The frame saving the link register, below the stack pointer. -/ +abbrev stkR (s₀ : State) : Region := ⟨s₀.sp - 48, 48⟩ + +/-- The frame is below the stack pointer, and disjoint from the buffers. -/ +structure Stack (s₀ : State) : Prop where + sp48 : 48 ≤ s₀.sp.toNat + st : (stkR s₀).Disjoint (stR s₀) + d : (stkR s₀).Disjoint (dR s₀) + scr : (stkR s₀).Disjoint (scR s₀) + +theorem pre_of {s₀ : State} (h : Proof.Sha256.updatePPC64LE.pre s₀) : Pre s₀ ∧ Stack s₀ := by + obtain ⟨h1, h2, h3, h4, h5, h6, h7, h8, h9⟩ := h + exact ⟨⟨h1, h2, h3, h4, h5⟩, ⟨h6, h7, h8, h9⟩⟩ + +theorem R₀.length {s₀ : State} {iv : HashValue} {m : List Byte} (h : R₀ s₀ iv m) : cnt s₀ % 64 = m.length % 64 := by + rw [cnt, h.2, BitVec.toNat_ofNat] + omega + +theorem len_lt (s₀ : State) : len s₀ < 2 ^ 64 := (s₀.gpr .r6).isLt + +theorem D_length (s₀ : State) : (D s₀).length = len s₀ := by simp [bytesAt] + +/-! ## Invariants -/ + +/-- What holds throughout, after consuming `c` bytes of data. -/ +structure Common (s₀ : State) (c : Nat) (s : State) : Prop where + c_le : c ≤ len s₀ + rd : s.rd = s₀.rd + wr : s.wr = s₀.wr + r26 : s.gpr .r26 = st s₀ + r27 : s.gpr .r27 = scr s₀ + sp : s.sp = s₀.sp + r28 : s.gpr .r28 = dp s₀ + BitVec.ofNat 64 c + r29 : s.gpr .r29 = BitVec.ofNat 64 (len s₀ - c) + frame : Frame [stR s₀, scR s₀] s₀.mem s.mem + saved : Saved s₀ s.mem + +/-- The loop invariant: the state represents the message followed by the +first `c` bytes of data. -/ +structure Inv (s₀ : State) (c : Nat) (s : State) : Prop extends Common s₀ c s where + r30 : s.gpr .r30 = BitVec.ofNat 64 ((cnt s₀ + c) % 64) + repr : ∀ iv m, R₀ s₀ iv m → Spec.Sha256.ReprFrom iv s.mem (st s₀) (m ++ (D s₀).take c) + +/-- A whole block is ready at `r4`, and compressing it absorbs the first `c` +bytes of data. -/ +structure Pending (s₀ : State) (c : Nat) (s : State) : Prop extends Common s₀ c s where + r30 : s.gpr .r30 = 0 + r9 : s.gpr .r9 = 1 + mod : (cnt s₀ + c) % 64 = 0 + src : s.gpr .r4 = st s₀ + 32 ∨ ∃ c₀, s.gpr .r4 = dp s₀ + BitVec.ofNat 64 c₀ ∧ c₀ + 64 ≤ len s₀ + repr : ∀ iv m, R₀ s₀ iv m → ∀ mem', stateAt mem' (st s₀) = + compress (stateAt s.mem (st s₀)) (blockAt s.mem (s.gpr .r4)) → + Spec.Sha256.ReprFrom iv mem' (st s₀) (m ++ (D s₀).take c) + +/-- All the data is absorbed, and nothing is pending. -/ +def Done (s₀ : State) (s : State) : Prop := Inv s₀ (len s₀) s ∧ s.gpr .r9 = 0 + +theorem Common.of_gpr {s₀ : State} {c : Nat} {s s' : State} (h : Common s₀ c s) + (hg : ∀ r ∈ [Reg.r26, .r27, .r28, .r29], s'.gpr r = s.gpr r) + (hm : s'.mem = s.mem) (hrd : s'.rd = s.rd) (hwr : s'.wr = s.wr) (hsp : s'.sp = s.sp) : + Common s₀ c s' where + c_le := h.c_le + rd := hrd.trans h.rd + wr := hwr.trans h.wr + r26 := by rw [hg _ (by simp)]; exact h.r26 + r27 := by rw [hg _ (by simp)]; exact h.r27 + sp := hsp.trans h.sp + r28 := by rw [hg _ (by simp)]; exact h.r28 + r29 := by rw [hg _ (by simp)]; exact h.r29 + frame := by rw [hm]; exact h.frame + saved := by rw [hm]; exact h.saved + +theorem Inv.of_gpr {s₀ : State} {c : Nat} {s s' : State} (h : Inv s₀ c s) + (hg : ∀ r ∈ [Reg.r26, .r27, .r28, .r29, .r30], s'.gpr r = s.gpr r) + (hm : s'.mem = s.mem) (hrd : s'.rd = s.rd) (hwr : s'.wr = s.wr) (hsp : s'.sp = s.sp) : + Inv s₀ c s' := + { h.toCommon.of_gpr (fun r hr => hg r (by simp at hr ⊢; tauto)) hm hrd hwr hsp with + r30 := by rw [hg _ (by simp)]; exact h.r30 + repr := by rw [hm]; exact h.repr } + +/-- Where the caller's registers are saved. -/ +theorem saved_sub {s₀ : State} {p : Reg × Nat} (hp : p ∈ saved) : + Region.Sub ⟨scr s₀ + BitVec.ofNat 64 p.2, 8⟩ (scR s₀) := by + simp only [Impl.Sha256.PPC64LE.Stream.saved, List.mem_cons, List.not_mem_nil, or_false] at hp + rcases hp with rfl | rfl | rfl | rfl | rfl | rfl <;> exact sub_offset (by omega) (by omega) + +/-! ## Consuming data -/ + +theorem D_getD (s₀ : State) {i : Nat} (hi : i < len s₀) : + (D s₀).getD i 0 = s₀.mem (dp s₀ + BitVec.ofNat 64 i) := by + simp [bytesAt, List.getD_eq_getElem?_getD, hi] + +/-- The data is unchanged. -/ +theorem Common.data {s₀ : State} (hp : Pre s₀) {c : Nat} {s : State} (h : Common s₀ c s) {i : Nat} + (hi : i < len s₀) : s.mem (dp s₀ + BitVec.ofNat 64 i) = (D s₀).getD i 0 := by + rw [D_getD s₀ hi] + exact frame_bytes h.frame (R := dR s₀) (by simpa using ⟨hp.d_st, hp.d_scr⟩) (len_lt s₀).le hi + +theorem length_mid (s₀ : State) {iv : HashValue} {m : List Byte} (hm : R₀ s₀ iv m) {c : Nat} (hc : c ≤ len s₀) : + (m ++ (D s₀).take c).length % 64 = (cnt s₀ + c) % 64 := by + have := hm.length + simp only [List.length_append, List.length_take, D_length, Nat.min_eq_left hc] + omega + +theorem take_add_data (s₀ : State) (c t : Nat) (m : List Byte) : + m ++ (D s₀).take c ++ ((D s₀).drop c).take t = m ++ (D s₀).take (c + t) := by + rw [List.take_add, List.append_assoc] + +/-! ## Compressing a pending block -/ + +theorem Pending.compress_ok {s₀ : State} (hp : Pre s₀) {c : Nat} {s : State} (h : Pending s₀ c s) : + WP isa compressAt s fun s' => Inv s₀ c s' ∧ ∀ r ∈ preserved, s'.gpr r = s.gpr r := by + have e32 : Region.Sub ⟨st s₀, 32⟩ (stR s₀) := Region.sub_prefix (by omega) + have e112 : Region.Sub ⟨scr s₀, 112⟩ (scR s₀) := Region.sub_prefix (by omega) + have eSrc : Region.Sub ⟨s.gpr .r4, 64⟩ (stR s₀) ∨ Region.Sub ⟨s.gpr .r4, 64⟩ (dR s₀) := by + rcases h.src with h' | ⟨c₀, h', hc₀⟩ + · exact .inl (h' ▸ sub_offset (off := 32) (by omega) (by omega)) + · exact .inr (h' ▸ sub_offset (by omega) (by have := len_lt s₀; omega)) + refine compressAt_ok h.r26 h.r27 rfl ((hp.st_scr.sub_left e32).sub_right e112) ?_ ?_ ?_ ?_ ?_ + · rcases h.src with h' | ⟨c₀, h', hc₀⟩ + · rw [h']; intro a h₁ h₂; simp only [Region.Contains] at h₁ h₂; bv_omega + · exact (hp.d_st.sub_left (h' ▸ sub_offset (by omega) (by have := len_lt s₀; omega))).sub_right e32 + · rcases eSrc with e | e + · exact (hp.st_scr.sub_left e).sub_right e112 + · exact (hp.d_scr.sub_left e).sub_right e112 + · rw [h.rd, h.wr, hp.rd, hp.wr] + apply Covers.of_sub + intro r hr + simp only [List.mem_cons, List.not_mem_nil, or_false] at hr + rcases hr with rfl | rfl | rfl + · rcases h.src with h' | ⟨c₀, h', hc₀⟩ + · exact ⟨stR s₀, by simp, 32, by rw [h']; rfl, by simp⟩ + · exact ⟨dR s₀, by simp, c₀, h', hc₀⟩ + · exact ⟨stR s₀, by simp, 0, by simp, by simp⟩ + · exact ⟨scR s₀, by simp, 0, by simp, by simp⟩ + · rw [h.wr, hp.wr] + apply Covers.of_sub + intro r hr + simp only [List.mem_cons, List.not_mem_nil, or_false] at hr + rcases hr with rfl | rfl + · exact ⟨stR s₀, by simp, 0, by simp, by simp⟩ + · exact ⟨scR s₀, by simp, 0, by simp, by simp⟩ + · intro s' hrd hwr hcs hsp hf hstate + have cs : ∀ r, r ∈ preserved → s'.gpr r = s.gpr r := hcs + refine ⟨⟨⟨h.c_le, hrd.trans h.rd, hwr.trans h.wr, by rw [cs _ (by decide)]; exact h.r26, + by rw [cs _ (by decide)]; exact h.r27, hsp.trans h.sp, + by rw [cs _ (by decide)]; exact h.r28, + by rw [cs _ (by decide)]; exact h.r29, + h.frame.trans (hf.sub ?_), fun p hp' => ?_⟩, ?_, fun iv m hm => h.repr iv m hm _ hstate⟩, cs⟩ + · intro r hr + simp only [List.mem_cons, List.not_mem_nil, or_false] at hr + rcases hr with rfl | rfl + · exact ⟨stR s₀, by simp, e32⟩ + · exact ⟨scR s₀, by simp, e112⟩ + · rw [← h.saved p hp'] + refine hf.readW (r := ⟨scr s₀ + BitVec.ofNat 64 p.2, 8⟩) (Region.contains_self _ _) ?_ (by decide) + intro r' hr' + simp only [List.mem_cons, List.not_mem_nil, or_false] at hr' + rcases hr' with rfl | rfl + · exact (hp.st_scr.symm.sub_left (saved_sub hp')).sub_right e32 + · simp only [Impl.Sha256.PPC64LE.Stream.saved, List.mem_cons, List.not_mem_nil, or_false] at hp' + rcases hp' with rfl | rfl | rfl | rfl | rfl | rfl <;> + · intro a h₁ h₂; simp only [Region.Contains] at h₁ h₂; bv_omega + · rw [cs _ (by decide), h.r30, h.mod]; rfl + +/-! ## A whole block straight from the data -/ + +theorem direct_ok {s₀ : State} (hp : Pre s₀) {c : Nat} {s : State} (hI : Inv s₀ c s) + (hr : (cnt s₀ + c) % 64 = 0) (hl : 64 ≤ len s₀ - c) : + WP isa (.block direct) s (Pending s₀ (c + 64)) := by + have hlen := len_lt s₀ + unfold direct + refine wp_mov fun s₁ u₁ => wp_addi (by decide) (by decide) fun s₂ u₂ => wp_subi (by decide) (by decide) fun s₃ u₃ => + wp_li (by decide) fun s₄ u₄ => WP.block_nil ?_ + have g : ∀ r, r ≠ .r4 → r ≠ .r28 → r ≠ .r29 → r ≠ .r9 → s₄.gpr r = s.gpr r := fun r h1 h2 h3 h4 => by + rw [u₄.other r h4, u₃.other r h3, u₂.other r h2, u₁.other r h1] + have m₄ : s₄.mem = s.mem := by rw [u₄.mem, u₃.mem, u₂.mem, u₁.mem] + have h1 : s₄.gpr .r4 = dp s₀ + BitVec.ofNat 64 c := by + rw [u₄.other _ (by decide), u₃.other _ (by decide), u₂.other _ (by decide), u₁.gpr, hI.r28] + refine ⟨⟨by omega, by rw [u₄.rd, u₃.rd, u₂.rd, u₁.rd, hI.rd], by rw [u₄.wr, u₃.wr, u₂.wr, u₁.wr, hI.wr], + by rw [g _ (by decide) (by decide) (by decide) (by decide), hI.r26], + by rw [g _ (by decide) (by decide) (by decide) (by decide), hI.r27], + by rw [u₄.sp, u₃.sp, u₂.sp, u₁.sp, hI.sp], ?_, ?_, by rw [m₄]; exact hI.frame, + by rw [m₄]; exact hI.saved⟩, ?_, by rw [u₄.gpr]; rfl, by omega, .inr ⟨c, h1, by omega⟩, ?_⟩ + · rw [u₄.other _ (by decide), u₃.other _ (by decide), u₂.gpr, u₁.other _ (by decide), hI.r28, + BitVec.add_assoc, ← BitVec.ofNat_add] + · rw [u₄.other _ (by decide), u₃.gpr, u₂.other _ (by decide), u₁.other _ (by decide), hI.r29, + sub_ofNat (by omega), Nat.sub_sub] + · rw [g _ (by decide) (by decide) (by decide) (by decide), hI.r30, hr]; rfl + · intro iv m hm mem' hs + have hmod := length_mid s₀ hm (c := c) (by omega) + rw [← take_add_data] + refine reprFrom_append_block (hI.repr iv m hm) + (by rw [hmod, hr, List.length_take, List.length_drop, D_length]; omega) ?_ + rw [hs, m₄, h1] + congr 1 + rw [show (m ++ List.take c (D s₀)).drop (64 * ((m ++ List.take c (D s₀)).length / 64)) = [] by + rw [List.drop_eq_nil_iff]; omega, List.nil_append] + apply parseBlock_congr + intro k hk + rw [show dp s₀ + BitVec.ofNat 64 c + BitVec.ofNat 64 k = dp s₀ + BitVec.ofNat 64 (c + k) by + simp only [BitVec.ofNat_add]; rw [BitVec.add_assoc], hI.data hp (by omega)] + simp [List.getD_eq_getElem?_getD, List.getElem?_drop, hk] + +/-! ## Buffering data -/ + +section +variable (s₀ : State) (c : Nat) +/-- Bytes in the buffer before this iteration. -/ +abbrev rr : Nat := (cnt s₀ + c) % 64 +/-- Bytes copied into the buffer in this iteration. -/ +abbrev tt : Nat := min (64 - rr s₀ c) (len s₀ - c) +/-- Where they go. -/ +abbrev q : Addr := st s₀ + 32 + BitVec.ofNat 64 (rr s₀ c) +/-- The data copied. -/ +abbrev xs : List Byte := ((D s₀).drop c).take (tt s₀ c) +end + +theorem rr_lt (s₀ : State) (c : Nat) : rr s₀ c < 64 := Nat.mod_lt _ (by omega) +theorem tt_le (s₀ : State) (c : Nat) : tt s₀ c ≤ len s₀ - c := Nat.min_le_right _ _ +theorem tt_le' (s₀ : State) (c : Nat) : tt s₀ c ≤ 64 - rr s₀ c := Nat.min_le_left _ _ +theorem rr_eq (s₀ : State) (c : Nat) : rr s₀ c = (cnt s₀ + c) % 64 := rfl +theorem tt_eq (s₀ : State) (c : Nat) : tt s₀ c = min (64 - rr s₀ c) (len s₀ - c) := rfl + +theorem q_eq (s₀ : State) (c : Nat) : q s₀ c = st s₀ + BitVec.ofNat 64 (32 + rr s₀ c) := by + simp only [q, BitVec.ofNat_add]; rw [BitVec.add_assoc]; rfl + +theorem xs_length (s₀ : State) (c : Nat) : (xs s₀ c).length = tt s₀ c := by + have := tt_le s₀ c + simp only [xs, List.length_take, List.length_drop, D_length]; omega + +/-- The state while copying: `j` bytes copied, into memory otherwise as in `mI`. -/ +structure Copy (s₀ : State) (c : Nat) (mI : Mem) (j : Nat) (s : State) : Prop where + j_le : j ≤ tt s₀ c + rd : s.rd = s₀.rd + wr : s.wr = s₀.wr + r26 : s.gpr .r26 = st s₀ + r27 : s.gpr .r27 = scr s₀ + sp : s.sp = s₀.sp + r28 : s.gpr .r28 = dp s₀ + BitVec.ofNat 64 (c + j) + r29 : s.gpr .r29 = BitVec.ofNat 64 (len s₀ - c - tt s₀ c) + r30 : s.gpr .r30 = BitVec.ofNat 64 (rr s₀ c + j) + r10 : s.gpr .r10 = BitVec.ofNat 64 (tt s₀ c - j) + r9 : s.gpr .r9 = 0 + mem : s.mem = writeBytes mI (q s₀ c) ((xs s₀ c).take j) + +theorem write_frame (s₀ : State) (c : Nat) (mI : Mem) (j : Nat) (hj : j ≤ tt s₀ c) : + Frame [stR s₀] mI (writeBytes mI (q s₀ c) ((xs s₀ c).take j)) := by + have := tt_le' s₀ c; have := rr_lt s₀ c + refine writeBytes_frame _ _ _ ?_ + rw [q_eq] + exact contains_offset (by simp only [List.length_take]; omega) (by omega) + +/-- The copy loop's body. -/ +def copyBody : List Instr := + [.lbz .r8 .r28 0, .add .r11 .r26 .r30, .stb .r8 .r11 32, .addi .r28 .r28 1, + .addi .r30 .r30 1, .subi .r10 .r10 1] + +theorem copy_step {s₀ : State} (hp : Pre s₀) {c : Nat} {sI : State} (hI : Inv s₀ c sI) {j : Nat} + (hj : j < tt s₀ c) {s : State} (h : Copy s₀ c sI.mem j s) : + WP isa (.block copyBody) s fun s' => + Copy s₀ c sI.mem (j + 1) s' ∧ s'.gpr .r10 = BitVec.ofNat 64 (tt s₀ c - (j + 1)) := by + have hlen := len_lt s₀ + have hc := hI.c_le + have hr := rr_lt s₀ c + have ht := tt_le s₀ c; have ht' := tt_le' s₀ c + -- The byte read. + have hin : InRegions (s.rd ++ s.wr) (dp s₀ + BitVec.ofNat 64 (c + j)) 1 := + ⟨dR s₀, by simp [h.rd, hp.rd], contains_offset (by omega) (by omega)⟩ + have hbyte : s.mem (dp s₀ + BitVec.ofNat 64 (c + j)) = (D s₀).getD (c + j) 0 := by + rw [h.mem, ← hI.data hp (by omega)] + exact frame_bytes (write_frame s₀ c sI.mem j h.j_le) (R := dR s₀) (by simpa using hp.d_st) + (by show len s₀ ≤ 2 ^ 64; omega) (by show c + j < len s₀; omega) + -- The byte written. + have hout : InRegions s.wr (q s₀ c + BitVec.ofNat 64 j) 1 := + ⟨stR s₀, by simp [h.wr, hp.wr], by + rw [q_eq, BitVec.add_assoc, ← BitVec.ofNat_add]; exact contains_offset (by omega) (by omega)⟩ + have hxs := xs_length s₀ c + unfold copyBody + refine wp_lbz (a := dp s₀ + BitVec.ofNat 64 (c + j)) (by decide) (by omega) (by rw [h.r28]; simp) hin + fun s₁ u₁ => ?_ + refine wp_add fun s₂ u₂ => wp_stb (a := q s₀ c + BitVec.ofNat 64 j) (by decide) (by omega) ?_ + (by rw [u₂.wr, u₁.wr]; exact hout) fun s₃ g₃ => ?_ + · rw [u₂.gpr, u₁.other _ (by decide), u₁.other _ (by decide), h.r26, h.r30, q] + simp only [BitVec.ofNat_add, show BitVec.ofNat 64 32 = (32 : BitVec 64) from rfl] + ac_rfl + refine wp_addi (by decide) (by decide) fun s₄ u₄ => wp_addi (by decide) (by decide) fun s₅ u₅ => + wp_subi (by decide) (by decide) fun s₆ u₆ => WP.block_nil ?_ + have g : ∀ r, r ≠ .r8 → r ≠ .r11 → r ≠ .r28 → r ≠ .r30 → r ≠ .r10 → s₆.gpr r = s.gpr r := + fun r h1 h2 h3 h4 h5 => by + rw [u₆.other r h5, u₅.other r h4, u₄.other r h3, g₃.gpr, u₂.other r h2, u₁.other r h1] + have hx11 : s₆.gpr .r10 = BitVec.ofNat 64 (tt s₀ c - (j + 1)) := by + rw [u₆.gpr, u₅.other _ (by decide), u₄.other _ (by decide), g₃.gpr, u₂.other _ (by decide), + u₁.other _ (by decide), h.r10, sub_ofNat (by omega), Nat.sub_sub] + refine ⟨⟨by omega, ?_, ?_, ?_, ?_, ?_, ?_, ?_, ?_, hx11, ?_, ?_⟩, hx11⟩ + · rw [u₆.rd, u₅.rd, u₄.rd, g₃.rd, u₂.rd, u₁.rd, h.rd] + · rw [u₆.wr, u₅.wr, u₄.wr, g₃.wr, u₂.wr, u₁.wr, h.wr] + · rw [g .r26 (by decide) (by decide) (by decide) (by decide) (by decide), h.r26] + · rw [g .r27 (by decide) (by decide) (by decide) (by decide) (by decide), h.r27] + · rw [u₆.sp, u₅.sp, u₄.sp, g₃.sp, u₂.sp, u₁.sp, h.sp] + · rw [u₆.other _ (by decide), u₅.other _ (by decide), u₄.gpr, g₃.gpr, u₂.other _ (by decide), + u₁.other _ (by decide), h.r28, BitVec.add_assoc, ← BitVec.ofNat_add, Nat.add_assoc] + · rw [g .r29 (by decide) (by decide) (by decide) (by decide) (by decide), h.r29] + · rw [u₆.other _ (by decide), u₅.gpr, u₄.other _ (by decide), g₃.gpr, u₂.other _ (by decide), + u₁.other _ (by decide), h.r30, ← BitVec.ofNat_add, Nat.add_assoc] + · rw [g .r9 (by decide) (by decide) (by decide) (by decide) (by decide), h.r9] + · have hj' : j < (xs s₀ c).length := by omega + rw [u₆.mem, u₅.mem, u₄.mem, g₃.mem, u₂.mem, u₁.mem, u₂.other _ (by decide), u₁.gpr, hbyte, h.mem, + List.take_add_one, List.getElem?_eq_getElem hj', Option.toList_some, + writeBytes_snoc _ _ _ _ (by simp only [List.length_take]; omega)] + have hl : (List.take j (xs s₀ c)).length = j := by rw [List.length_take, Nat.min_eq_left hj'.le] + rw [hl] + have e : ((List.getD (D s₀) (c + j) 0).setWidth 64).setWidth 8 = List.getD (D s₀) (c + j) 0 := by + ext i hi; simp + rw [e] + congr 1 + simp only [xs, List.getElem_take, List.getElem_drop, List.getD_eq_getElem?_getD, + List.getElem?_eq_getElem (show c + j < (D s₀).length by rw [D_length]; omega), Option.getD_some] + +theorem copy_loop_ok {s₀ : State} (hp : Pre s₀) {c : Nat} {sI : State} (hI : Inv s₀ c sI) {s : State} + (h : Copy s₀ c sI.mem 0 s) (ht : 0 < tt s₀ c) : + WP isa (.loop (.block copyBody) (.nonzero .d .r10)) s (Copy s₀ c sI.mem (tt s₀ c)) := by + refine WP.loop (M := isa) (fun n s => ∃ j, n = tt s₀ c - j ∧ j < tt s₀ c ∧ Copy s₀ c sI.mem j s) + ?_ (tt s₀ c) s ⟨0, rfl, ht, h⟩ + rintro n s ⟨j, rfl, hj, hc⟩ + refine WP.mono (copy_step hp hI hj hc) fun s' ⟨hc', h11⟩ => ?_ + have hz : isa.eval (.nonzero .d .r10) s' = some (decide (tt s₀ c - (j + 1) ≠ 0)) := by + show VG.PPC64LE.eval (.nonzero .d .r10) s' = _ + rw [eval_nonzero, h11, bne, ofNat_beq_zero (by have := tt_le' s₀ c; omega)] + simp + by_cases hl : tt s₀ c - (j + 1) = 0 + · refine .inl ⟨by rw [hz]; simp [hl], ?_⟩ + rwa [show j + 1 = tt s₀ c by omega] at hc' + · exact .inr ⟨by rw [hz]; simp [hl], _, by omega, j + 1, rfl, by omega, hc'⟩ + +/-- The memory after copying `tt` bytes. -/ +theorem copied_facts {s₀ : State} (hp : Pre s₀) {c : Nat} {sI : State} (hI : Inv s₀ c sI) : + let mem := writeBytes sI.mem (q s₀ c) (xs s₀ c) + Frame [stR s₀, scR s₀] s₀.mem mem ∧ Saved s₀ mem ∧ stateAt mem (st s₀) = stateAt sI.mem (st s₀) ∧ + bytesAt mem (st s₀ + 32) (rr s₀ c + tt s₀ c) = bytesAt sI.mem (st s₀ + 32) (rr s₀ c) ++ xs s₀ c := by + intro mem + have hr := rr_lt s₀ c; have ht' := tt_le' s₀ c + have hxs := xs_length s₀ c + have hf : Frame [stR s₀] sI.mem mem := by + have := write_frame s₀ c sI.mem (tt s₀ c) le_rfl + rwa [List.take_of_length_le (by omega)] at this + refine ⟨hI.frame.trans (hf.mono (by simp)), fun p hp' => ?_, ?_, ?_⟩ + · rw [← hI.saved p hp'] + refine hf.readW (r := ⟨scr s₀ + BitVec.ofNat 64 p.2, 8⟩) (Region.contains_self _ _) ?_ (by decide) + intro r' hr' + simp only [List.mem_cons, List.not_mem_nil, or_false] at hr' + subst hr' + exact hp.st_scr.symm.sub_left (saved_sub hp') + · apply stateAt_congr + intro i hi + simp only [mem, q_eq] + exact writeBytes_before _ _ _ (by omega) (by omega) + · rw [← hxs] + exact bytesAt_writeBytes _ _ _ _ (by omega) + +/-- A full buffer: compress it. -/ +theorem fill_pending {s₀ : State} (hp : Pre s₀) {c : Nat} {sI : State} (hI : Inv s₀ c sI) {s : State} + (h : Copy s₀ c sI.mem (tt s₀ c) s) (hfull : rr s₀ c + tt s₀ c = 64) : + WP isa (.block [.addi .r4 .r26 32, .li .r30 0, .li .r9 1]) s + (Pending s₀ (c + tt s₀ c)) := by + have hr := rr_lt s₀ c; have ht := tt_le s₀ c; have ht' := tt_le' s₀ c + have hrr := rr_eq s₀ c; have htt := tt_eq s₀ c + have hxs := xs_length s₀ c + have hc := hI.c_le + obtain ⟨hfr, hsv, hst, hby⟩ := copied_facts hp hI + have hmem : s.mem = writeBytes sI.mem (q s₀ c) (xs s₀ c) := by + rw [h.mem, List.take_of_length_le (by omega)] + refine wp_addi (by decide) (by decide) fun s₁ u₁ => wp_li (by decide) fun s₂ u₂ => wp_li (by decide) fun s₃ u₃ => WP.block_nil ?_ + have g : ∀ r, r ≠ .r4 → r ≠ .r30 → r ≠ .r9 → s₃.gpr r = s.gpr r := fun r h1 h2 h3 => by + rw [u₃.other r h3, u₂.other r h2, u₁.other r h1] + have m₃ : s₃.mem = s.mem := by rw [u₃.mem, u₂.mem, u₁.mem] + have hx1 : s₃.gpr .r4 = st s₀ + 32 := by + rw [u₃.other _ (by decide), u₂.other _ (by decide), u₁.gpr, h.r26]; rfl + refine ⟨⟨by omega, ?_, ?_, ?_, ?_, ?_, ?_, ?_, by rw [m₃, hmem]; exact hfr, by rw [m₃, hmem]; exact hsv⟩, + by rw [u₃.other _ (by decide), u₂.gpr]; rfl, by rw [u₃.gpr]; rfl, by omega, .inl hx1, ?_⟩ + · rw [u₃.rd, u₂.rd, u₁.rd, h.rd] + · rw [u₃.wr, u₂.wr, u₁.wr, h.wr] + · rw [g .r26 (by decide) (by decide) (by decide), h.r26] + · rw [g .r27 (by decide) (by decide) (by decide), h.r27] + · rw [u₃.sp, u₂.sp, u₁.sp, h.sp] + · rw [g .r28 (by decide) (by decide) (by decide), h.r28] + · rw [g .r29 (by decide) (by decide) (by decide), h.r29, Nat.sub_sub] + · intro iv m hm mem' hs + rw [← take_add_data] + have hmod := length_mid s₀ hm hc + refine reprFrom_append_block (hI.repr iv m hm) (by rw [hmod, hxs]; exact hfull) ?_ + rw [hs, m₃, hmem, hst, hx1] + refine congrArg (compress _) (parseBlock_congr fun k hk => ?_) + have hb := (hI.repr iv m hm).2 + rw [hmod] at hb + rw [hb, show rr s₀ c + tt s₀ c = 64 from hfull] at hby + exact bytesAt_getD hby hk + +/-- All the data fits in the buffer. -/ +theorem fill_done {s₀ : State} (hp : Pre s₀) {c : Nat} {sI : State} (hI : Inv s₀ c sI) {s : State} + (h : Copy s₀ c sI.mem (tt s₀ c) s) (hnf : rr s₀ c + tt s₀ c ≠ 64) : Done s₀ s := by + have hr := rr_lt s₀ c; have ht := tt_le s₀ c; have ht' := tt_le' s₀ c + have hrr := rr_eq s₀ c; have htt := tt_eq s₀ c + have hxs := xs_length s₀ c + have hc := hI.c_le + have htl : tt s₀ c = len s₀ - c := by omega + obtain ⟨hfr, hsv, hst, hby⟩ := copied_facts hp hI + have hmem : s.mem = writeBytes sI.mem (q s₀ c) (xs s₀ c) := by + rw [h.mem, List.take_of_length_le (by omega)] + refine ⟨⟨⟨le_rfl, h.rd, h.wr, h.r26, h.r27, h.sp, ?_, ?_, by rw [hmem]; exact hfr, + by rw [hmem]; exact hsv⟩, ?_, fun iv m hm => ?_⟩, h.r9⟩ + · rw [h.r28]; congr 2; omega + · rw [h.r29]; congr 1; omega + · rw [h.r30]; congr 1; omega + · have hmod := length_mid s₀ hm hc + rw [show len s₀ = c + tt s₀ c by omega, ← take_add_data] + refine reprFrom_append_buf (hI.repr iv m hm) (by rw [hmod, hxs]; omega) (by rw [hmem, hst]) ?_ + rw [hmod, hxs, hmem, hby] + have hb := (hI.repr iv m hm).2 + rw [hmod] at hb + rw [hb] + +theorem fill_eq : fill = + .seq (.block [.li .r10 64, .sub .r10 .r10 .r30, .lsr .d .r8 .r29 6]) + (.seq (.ite (.zero .d .r8) + (.seq (.block [.add .r8 .r29 .r30, .lsr .d .r8 .r8 6]) + (.ite (.zero .d .r8) (.block [mov .r10 .r29]) (.block []))) + (.block [])) + (.seq (.block [.sub .r29 .r29 .r10]) + (.seq (.loop (.block copyBody) (.nonzero .d .r10)) + (.seq (.block [.subi .r8 .r30 64]) + (.ite (.zero .d .r8) (.block [.addi .r4 .r26 32, .li .r30 0, .li .r9 1]) + (.block [])))))) := rfl + +theorem fill_ok {s₀ : State} (hp : Pre s₀) {c : Nat} {s : State} (hI : Inv s₀ c s) (hcl : c < len s₀) + (h10 : s.gpr .r9 = 0) : + WP isa fill s fun s' => (∃ c', c < c' ∧ Pending s₀ c' s') ∨ Done s₀ s' := by + have hr := rr_lt s₀ c; have ht := tt_le s₀ c; have ht' := tt_le' s₀ c + have hrr := rr_eq s₀ c; have htt := tt_eq s₀ c + have ne : ∀ r ∈ [Reg.r26, .r27, .r28, .r29, .r30], r ≠ .r8 ∧ r ≠ .r10 := by decide + have hc := hI.c_le; have hlen := len_lt s₀ + rw [fill_eq] + -- `r10 := 64 - r; r8 := len >> 6` + refine WP.seq (wp_li (by decide) fun s₁ u₁ => wp_sub fun s₂ u₂ => wp_lsr (by decide) fun s₃ u₃ => WP.block_nil ?_) + have e₃ : ∀ r, r ≠ .r8 → r ≠ .r10 → s₃.gpr r = s.gpr r := fun r h h' => by + rw [u₃.other r h, u₂.other r h', u₁.other r h'] + have hI₃ : Inv s₀ c s₃ := hI.of_gpr (fun r hr => e₃ r (ne r hr).1 (ne r hr).2) + (by rw [u₃.mem, u₂.mem, u₁.mem]) (by rw [u₃.rd, u₂.rd, u₁.rd]) (by rw [u₃.wr, u₂.wr, u₁.wr]) + (by rw [u₃.sp, u₂.sp, u₁.sp]) + have h11₃ : s₃.gpr .r10 = BitVec.ofNat 64 (64 - rr s₀ c) := by + rw [u₃.other _ (by decide), u₂.gpr, u₁.gpr, u₁.other _ (by decide), hI.r30, sub_ofNat (by omega)] + have h9₃ : s₃.gpr .r8 = BitVec.ofNat 64 ((len s₀ - c) / 64) := by + rw [u₃.gpr, u₂.other _ (by decide), u₁.other _ (by decide), hI.r29, ofNat_shr6 (by omega)] + -- `r10 := min(r10, len)` + refine WP.seq (WP.mono (Q := fun (s₄ : State) => Inv s₀ c s₄ ∧ s₄.gpr .r10 = BitVec.ofNat 64 (tt s₀ c) ∧ + s₄.gpr .r9 = 0 ∧ s₄.mem = s.mem) ?_ fun s₄ ⟨hI₄, h11₄, h10₄, hm₄⟩ => ?_) + · have hm₃ : s₃.mem = s.mem := by rw [u₃.mem, u₂.mem, u₁.mem] + have h10₃ : s₃.gpr .r9 = 0 := by rw [e₃ _ (by decide) (by decide), h10] + refine WP.ite (decide ((len s₀ - c) / 64 = 0)) + (by show VG.PPC64LE.eval (.zero .d .r8) s₃ = _; rw [eval_zero, h9₃, ofNat_beq_zero (by omega)]) (fun hb => ?_) (fun hb => ?_) + · simp only [decide_eq_true_eq] at hb + refine WP.seq (wp_add fun s₅ u₅ => wp_lsr (by decide) fun s₆ u₆ => WP.block_nil ?_) + have e₆ : ∀ r, r ≠ .r8 → s₆.gpr r = s₃.gpr r := fun r h => by rw [u₆.other r h, u₅.other r h] + have hI₆ : Inv s₀ c s₆ := hI₃.of_gpr (fun r hr => e₆ r (ne r hr).1) (by rw [u₆.mem, u₅.mem]) (by rw [u₆.rd, u₅.rd]) (by rw [u₆.wr, u₅.wr]) + (by rw [u₆.sp, u₅.sp]) + have h9₆ : s₆.gpr .r8 = BitVec.ofNat 64 ((len s₀ - c + rr s₀ c) / 64) := by + rw [u₆.gpr, u₅.gpr, hI₃.r29, hI₃.r30, ← BitVec.ofNat_add, ofNat_shr6 (by omega)] + refine WP.ite (decide ((len s₀ - c + rr s₀ c) / 64 = 0)) + (by show VG.PPC64LE.eval (.zero .d .r8) s₆ = _; rw [eval_zero, h9₆, ofNat_beq_zero (by omega)]) (fun hb' => ?_) (fun hb' => ?_) + · simp only [decide_eq_true_eq] at hb' + refine wp_mov fun s₇ u₇ => WP.block_nil ⟨hI₆.of_gpr (fun r hr => u₇.other r (ne r hr).2) + u₇.mem u₇.rd u₇.wr u₇.sp, + ?_, by rw [u₇.other _ (by decide), e₆ _ (by decide), h10₃], by rw [u₇.mem, u₆.mem, u₅.mem, hm₃]⟩ + rw [u₇.gpr, hI₆.r29]; congr 1; omega + · simp only [decide_eq_false_iff_not] at hb' + refine WP.block_nil ⟨hI₆, ?_, by rw [e₆ _ (by decide), h10₃], by rw [u₆.mem, u₅.mem, hm₃]⟩ + rw [e₆ _ (by decide), h11₃]; congr 1; omega + · simp only [decide_eq_false_iff_not] at hb + refine WP.block_nil ⟨hI₃, ?_, h10₃, hm₃⟩ + rw [h11₃]; congr 1; omega + -- `r29 -= r10` + refine WP.seq (wp_sub fun s₅ u₅ => WP.block_nil ?_) + have hC₀ : Copy s₀ c s.mem 0 s₅ := by + have e : ∀ r, r ≠ .r29 → s₅.gpr r = s₄.gpr r := fun r h => u₅.other r h + refine ⟨Nat.zero_le _, by rw [u₅.rd, hI₄.rd], by rw [u₅.wr, hI₄.wr], + by rw [e _ (by decide), hI₄.r26], by rw [e _ (by decide), hI₄.r27], by rw [u₅.sp, hI₄.sp], + by rw [e _ (by decide), hI₄.r28, Nat.add_zero], ?_, by rw [e _ (by decide), hI₄.r30, Nat.add_zero], + by rw [e _ (by decide), h11₄, Nat.sub_zero], by rw [e _ (by decide), h10₄], ?_⟩ + · rw [u₅.gpr, hI₄.r29, h11₄, sub_ofNat (by omega), Nat.sub_sub] + · rw [u₅.mem, hm₄, List.take_zero, writeBytes_nil] + -- Copy the bytes. + refine WP.seq (WP.mono (copy_loop_ok hp hI hC₀ (by omega)) fun s₆ hC => ?_) + -- Is the buffer full? + refine WP.seq (wp_subi (by decide) (by decide) fun s₇ u₇ => WP.block_nil ?_) + have hC₇ : Copy s₀ c s.mem (tt s₀ c) s₇ := + ⟨hC.j_le, by rw [u₇.rd, hC.rd], by rw [u₇.wr, hC.wr], by rw [u₇.other _ (by decide), hC.r26], + by rw [u₇.other _ (by decide), hC.r27], by rw [u₇.sp, hC.sp], by rw [u₇.other _ (by decide), hC.r28], + by rw [u₇.other _ (by decide), hC.r29], by rw [u₇.other _ (by decide), hC.r30], + by rw [u₇.other _ (by decide), hC.r10], by rw [u₇.other _ (by decide), hC.r9], + by rw [u₇.mem, hC.mem]⟩ + have hz : eval (.zero .d .r8) s₇ = some (decide (rr s₀ c + tt s₀ c = 64)) := by + rw [eval_zero, u₇.gpr, hC.r30, sub_beq (by omega) (by omega)] + refine WP.ite (decide (rr s₀ c + tt s₀ c = 64)) hz (fun hb => ?_) (fun hb => ?_) + · simp only [decide_eq_true_eq] at hb + exact WP.mono (fill_pending hp hI hC₇ hb) fun s' h => .inl ⟨c + tt s₀ c, by omega, h⟩ + · simp only [decide_eq_false_iff_not] at hb + exact WP.block_nil (.inr (fill_done hp hI hC₇ hb)) + +/-! ## One iteration -/ + +theorem body_eq : updateBody = + .seq (.block [.li .r9 0]) + (.seq (.ite (.zero .d .r30) + (.seq (.block [.lsr .d .r8 .r29 6]) (.ite (.zero .d .r8) fill (.block direct))) + fill) + (.ite (.zero .d .r9) (.block []) compressAt)) := rfl + +theorem body_ok {s₀ : State} (hp : Pre s₀) {c : Nat} {s : State} (hI : Inv s₀ c s) (hcl : c < len s₀) : + WP isa updateBody s fun s' => (∃ c', c < c' ∧ Inv s₀ c' s') ∧ ∀ r ∈ nvRegs, s'.gpr r = s.gpr r := by + have hlen := len_lt s₀; have hc := hI.c_le; have hr := rr_lt s₀ c + have ne : ∀ r ∈ [Reg.r26, .r27, .r28, .r29, .r30], r ≠ .r9 ∧ r ≠ .r8 := by decide + rw [body_eq] + refine WP.seq (wp_li (by decide) fun s₁ u₁ => WP.block_nil ?_) + have hI₁ : Inv s₀ c s₁ := hI.of_gpr (fun r hr => u₁.other r (ne r hr).1) u₁.mem u₁.rd u₁.wr u₁.sp + have h10₁ : s₁.gpr .r9 = 0 := by rw [u₁.gpr]; rfl + have nv₁ : ∀ r ∈ nvRegs, s₁.gpr r = s.gpr r := fun r hr => u₁.other r (by revert r hr; decide) + refine WP.seq (WP.mono (WP.gprs (rs := nvRegs) (Q := fun s' => (∃ c', c < c' ∧ Pending s₀ c' s') ∨ Done s₀ s') + ?_ (by + intro r hr i hi + have : ((instrs (.ite (.zero .d .r30) + (.seq (.block [.lsr .d .r8 .r29 6]) (.ite (.zero .d .r8) fill (.block direct))) fill : + Prog isa)).all fun i => nvRegs.all fun r => dstOf i != some r) = true := by + rw [← Code.allInstrs_eq]; decide +kernel + simpa using List.all_eq_true.mp (List.all_eq_true.mp this i hi) r hr)) + fun s' ⟨h, hnv⟩ => ?_) + · refine WP.ite (decide (rr s₀ c = 0)) + (by show VG.PPC64LE.eval (.zero .d .r30) s₁ = _; rw [eval_zero, hI₁.r30, ofNat_beq_zero (by omega)]) + (fun hb => ?_) (fun _ => fill_ok hp hI₁ hcl h10₁) + simp only [decide_eq_true_eq] at hb + refine WP.seq (wp_lsr (by decide) fun s₂ u₂ => WP.block_nil ?_) + have hI₂ : Inv s₀ c s₂ := hI₁.of_gpr (fun r hr => u₂.other r (ne r hr).2) u₂.mem u₂.rd u₂.wr u₂.sp + have h10₂ : s₂.gpr .r9 = 0 := by rw [u₂.other _ (by decide), h10₁] + refine WP.ite (decide ((len s₀ - c) / 64 = 0)) + (by show VG.PPC64LE.eval (.zero .d .r8) s₂ = _ + rw [eval_zero, u₂.gpr, hI₁.r29, ofNat_shr6 (by omega), ofNat_beq_zero (by omega)]) + (fun _ => fill_ok hp hI₂ hcl h10₂) (fun hb' => ?_) + simp only [decide_eq_false_iff_not] at hb' + exact WP.mono (direct_ok hp hI₂ hb (by omega)) fun s' h => .inl ⟨c + 64, by omega, h⟩ + · have nv : ∀ r ∈ nvRegs, s'.gpr r = s.gpr r := fun r hr => (hnv r hr).trans (nv₁ r hr) + rcases h with ⟨c', hc', hP⟩ | ⟨hD, h10⟩ + · refine WP.ite false (by show VG.PPC64LE.eval (.zero .d .r9) s' = _; rw [eval_zero, hP.r9]; rfl) + (fun h => by cases h) fun _ => WP.mono (hP.compress_ok hp) fun s'' ⟨h, hpr⟩ => + ⟨⟨c', hc', h⟩, fun r hr => (hpr r (nv_pres r hr)).trans (nv r hr)⟩ + · refine WP.ite true (by show VG.PPC64LE.eval (.zero .d .r9) s' = _; rw [eval_zero, h10]; rfl) + (fun _ => WP.block_nil ⟨⟨len s₀, hcl, hD⟩, nv⟩) fun h => by cases h + +/-! ## Prologue and epilogue -/ + +/-- The prologue after saving. -/ +def prologue : List Instr := + [mov .r26 .r3, mov .r27 .r7, mov .r28 .r5, mov .r29 .r6, .li .r8 63, .logic .and .r30 .r4 .r8] + +theorem update_eq : updateMain = .seq (.block (save .r7 ++ prologue)) + (.seq (.ite (.zero .d .r29) (.block []) (.loop updateBody (.nonzero .d .r29))) (.block restore)) := rfl + +theorem prologue_ok {s₀ : State} (hp : Pre s₀) : + WP isa (.block (save .r7 ++ prologue)) s₀ (Inv s₀ 0) := by + refine save_ok (by decide) (fun d hd₁ hd₂ => ⟨scR s₀, by simp [hp.wr], contains_offset (by omega) (by omega)⟩) + fun s₁ g₁ rd₁ wr₁ sp₁ m₁ => ?_ + unfold prologue + refine wp_mov fun s₂ u₂ => wp_mov fun s₃ u₃ => wp_mov fun s₄ u₄ => wp_mov fun s₅ u₅ => + wp_li (by decide) fun s₆ u₆ => wp_and fun s₇ u₇ => WP.block_nil ?_ + have hm₇ : s₇.mem = saveMem s₀.mem (scr s₀) s₀.gpr := by + rw [u₇.mem, u₆.mem, u₅.mem, u₄.mem, u₃.mem, u₂.mem, m₁] + refine ⟨⟨Nat.zero_le _, ?_, ?_, ?_, ?_, ?_, ?_, ?_, ?_, ?_⟩, ?_, fun iv m hm => ?_⟩ + · rw [u₇.rd, u₆.rd, u₅.rd, u₄.rd, u₃.rd, u₂.rd, rd₁] + · rw [u₇.wr, u₆.wr, u₅.wr, u₄.wr, u₃.wr, u₂.wr, wr₁] + · rw [u₇.other _ (by decide), u₆.other _ (by decide), u₅.other _ (by decide), u₄.other _ (by decide), + u₃.other _ (by decide), u₂.gpr, g₁] + · rw [u₇.other _ (by decide), u₆.other _ (by decide), u₅.other _ (by decide), u₄.other _ (by decide), + u₃.gpr, u₂.other _ (by decide), g₁] + · rw [u₇.sp, u₆.sp, u₅.sp, u₄.sp, u₃.sp, u₂.sp, sp₁] + · rw [u₇.other _ (by decide), u₆.other _ (by decide), u₅.other _ (by decide), u₄.gpr, + u₃.other _ (by decide), u₂.other _ (by decide), g₁] + simp + · rw [u₇.other _ (by decide), u₆.other _ (by decide), u₅.gpr, u₄.other _ (by decide), + u₃.other _ (by decide), u₂.other _ (by decide), g₁] + simp + · rw [hm₇]; exact (saveMem_frame _ _ _).mono (by simp) + · rw [hm₇]; exact saveMem_saved _ _ _ + · rw [u₇.gpr, u₆.gpr, u₆.other .r4 (by decide), u₅.other .r4 (by decide), u₄.other .r4 (by decide), + u₃.other .r4 (by decide), u₂.other .r4 (by decide), g₁, and63, Nat.add_zero] + · rw [List.take_zero, List.append_nil, hm₇] + exact reprFrom_congr (fun i hi => frame_bytes (saveMem_frame s₀.mem (scr s₀) s₀.gpr) (R := stR s₀) + (by simpa using hp.st_scr) (by simp) hi) hm.1 + +/-- The epilogue's postcondition. -/ +def Post (s₀ s' : State) : Prop := + (∀ p ∈ saved, s'.gpr p.1 = s₀.gpr p.1) ∧ s'.sp = s₀.sp ∧ Proof.Sha256.updatePPC64LE.post s₀ s' + +theorem epilogue_ok {s₀ : State} (hp : Pre s₀) {s : State} (hI : Inv s₀ (len s₀) s) : + WP isa (.block restore) s (Post s₀) := by + refine restore_ok (scr := scr s₀) hI.r27 + (fun d hd₁ hd₂ => ⟨scR s₀, by simp [hI.rd, hI.wr, hp.wr], contains_offset hd₂ (by omega)⟩) s₀.gpr + hI.saved fun s' hs _ hmem _ _ hsp => ⟨hs, by rw [hsp, hI.sp], fun iv m hr hc => ?_⟩ + have := hI.repr iv m ⟨hr, hc⟩ + rwa [List.take_of_length_le (by rw [D_length]), ← hmem] at this + +/-- No instruction of `updateMain` writes the callee-saved registers it does not save. -/ +theorem untouched_ok : ∀ r ∈ untouched, ∀ i ∈ instrs updateMain, dstOf i ≠ some r := by + have : ((instrs updateMain).all fun i => untouched.all fun r => dstOf i != some r) = true := by + rw [← Code.allInstrs_eq]; decide +kernel + intro r hr i hi + have := List.all_eq_true.mp (List.all_eq_true.mp this i hi) r hr + simpa using this + +/-- `update` without its frame: the callee-saved registers are kept. -/ +theorem correctMain {s₀ : State} (hp : Pre s₀) : + WP isa updateMain s₀ fun s' => (∀ r ∈ preserved, s'.gpr r = s₀.gpr r) ∧ + s'.sp = s₀.sp ∧ Proof.Sha256.updatePPC64LE.post s₀ s' := by + have hlen := len_lt s₀ + refine WP.mono (WP.gprs (Q := fun (s' : State) => Post s₀ s' ∧ ∀ r ∈ nvRegs, s'.gpr r = s₀.gpr r) ?_ + untouched_ok) + fun s' ⟨⟨⟨hsv, hsp, hpost⟩, hnv⟩, hu⟩ => ⟨fun r hr => ?_, hsp, hpost⟩ + · rw [update_eq] + refine WP.seq (WP.mono (WP.gprs (rs := nvRegs) (prologue_ok hp) (by + intro r hr i hi + have : ((instrs (.block (save .r7 ++ prologue) : Prog isa)).all fun i => + nvRegs.all fun r => dstOf i != some r) = true := by decide + simpa using List.all_eq_true.mp (List.all_eq_true.mp this i hi) r hr)) + fun s₁ ⟨hI, hnv₁⟩ => ?_) + refine WP.seq (WP.mono (Q := fun (s : State) => Inv s₀ (len s₀) s ∧ ∀ r ∈ nvRegs, s.gpr r = s₀.gpr r) ?_ + fun s₂ ⟨hI₂, hnv₂⟩ => WP.mono (WP.gprs (rs := nvRegs) (epilogue_ok hp hI₂) (by decide)) + fun s₃ ⟨h, hnv₃⟩ => ⟨h, fun r hr => (hnv₃ r hr).trans (hnv₂ r hr)⟩) + refine WP.ite (decide (len s₀ = 0)) + (by show VG.PPC64LE.eval (.zero .d .r29) s₁ = _ + rw [eval_zero, hI.r29, Nat.sub_zero, ofNat_beq_zero (by omega)]) + (fun hb => ?_) (fun hb => ?_) + · simp only [decide_eq_true_eq] at hb + exact WP.block_nil ⟨hb ▸ hI, hnv₁⟩ + · simp only [decide_eq_false_iff_not] at hb + refine WP.loop (M := isa) (fun n s => ∃ c, n = len s₀ - c ∧ c < len s₀ ∧ Inv s₀ c s ∧ + ∀ r ∈ nvRegs, s.gpr r = s₀.gpr r) ?_ (len s₀) s₁ + ⟨0, rfl, by omega, hI, hnv₁⟩ + rintro n s ⟨c, rfl, hcl, hI, hnv⟩ + refine WP.mono (body_ok hp hI hcl) fun s' ⟨⟨c', hc, hI'⟩, hnv'⟩ => ?_ + have hnv'' : ∀ r ∈ nvRegs, s'.gpr r = s₀.gpr r := fun r hr => (hnv' r hr).trans (hnv r hr) + have hc' := hI'.c_le + have hz : isa.eval (.nonzero .d .r29) s' = some (decide (len s₀ - c' ≠ 0)) := by + show VG.PPC64LE.eval (.nonzero .d .r29) s' = _ + rw [eval_nonzero, hI'.r29, bne, ofNat_beq_zero (by omega)] + simp + by_cases hl : len s₀ - c' = 0 + · refine .inl ⟨by rw [hz]; simp [hl], ?_, hnv''⟩ + rwa [show c' = len s₀ by omega] at hI' + · exact .inr ⟨by rw [hz]; simp [hl], len s₀ - c', by omega, c', rfl, by omega, hI', hnv''⟩ + · have key : ∀ r ∈ preserved, r ∈ untouched ∨ r ∈ nvRegs ∨ r ∈ saved.map Prod.fst := by decide + rcases key r hr with hr' | hr' | hr' + · exact hu r hr' + · exact hnv r hr' + · obtain ⟨p, hp', rfl⟩ := List.mem_map.mp hr' + exact hsv p hp' + +/-- The state `updateMain` starts in: the link register moved to `r0`, then +pushed in a frame. -/ +abbrev inner (s₀ : State) : State := framed .r0 (s₀.write .r0 s₀.lr) + +theorem correct {s₀ : State} (hp : Pre s₀) (hs : Stack s₀) : + WP isa update s₀ fun s' => abiPreserved s₀ s' ∧ Proof.Sha256.updatePPC64LE.post s₀ s' := by + have hpi : Pre (inner s₀) := ⟨hp.rd, hp.wr, hp.st_scr, hp.d_st, hp.d_scr⟩ + refine WP.seq (WP.cons exec_mflr (WP.block_nil (WP.seq ?_))) + refine WP.frameReg (by exact hs.sp48) (fun R hR => ?_) (WP.mono (correctMain hpi) + fun s' ⟨hk, hsp, hpost⟩ => ?_) + · rw [show (s₀.write .r0 s₀.lr).wr = s₀.wr from rfl, hp.wr] at hR + simp only [List.mem_cons, List.not_mem_nil, or_false] at hR + rcases hR with rfl | rfl + · exact hs.st.sub_left (frame_sub _) + · exact hs.scr.sub_left (frame_sub _) + · refine WP.cons exec_mtlr (WP.block_nil ⟨⟨fun r hr => ?_, rfl, ?_⟩, fun iv m hm hc => ?_⟩) + · have h0 : r ≠ .r0 := by revert r hr; decide + simp only [State.write, h0, ite_false] + rw [hk r hr] + simp only [framed, State.write, h0, ite_false] + · simp [State.write] + · have e : bytesAt (inner s₀).mem (dp s₀) (len s₀) = bytesAt s₀.mem (dp s₀) (len s₀) := + bytesAt_congr fun i hi => write_frame_bytes hs.d (len_lt s₀) hi + have := hpost iv m (reprFrom_congr (fun i hi => write_frame_bytes (R := stR s₀) hs.st + (by simp) hi) hm) hc + change Spec.Sha256.ReprFrom iv s'.mem (s₀.gpr .r3) + (m ++ bytesAt (inner s₀).mem (s₀.gpr .r5) (s₀.gpr .r6).toNat) at this + rw [e] at this + exact this + +theorem agree₀ {s₁ s₂ : State} (hpub : Proof.Sha256.updatePPC64LE.pub s₁ s₂) : + VG.PPC64LE.Taint.Agree (VG.PPC64LE.Taint.ofRegs [.r3, .r4, .r5, .r6, .r7]) s₁ s₂ := by + obtain ⟨p1, p2, p3, p4, p5, hsp⟩ := hpub + refine ⟨hsp, fun r hr => ?_⟩ + simp only [VG.PPC64LE.Taint.mem_ofRegs, List.mem_cons, List.not_mem_nil, or_false] at hr + rcases hr with rfl | rfl | rfl | rfl | rfl <;> assumption + +/-- A state satisfying the precondition (with no data). -/ +def sat : State where + gpr r := match r with + | .r3 => 0x1000 | .r5 => 0x2000 | .r7 => 0x3000 | _ => 0 + lr := 0 + sp := 0x4000 + mem _ := 0 + rd := [⟨0x2000, 0⟩] + wr := [⟨0x1000, 96⟩, ⟨0x3000, 160⟩] + +theorem update_verified : Verified PPC64LE.target update Proof.Sha256.updatePPC64LE := by + refine ⟨fun s hs => ?_, ?_, ?_⟩ + · obtain ⟨t, s', he, h⟩ := correct (pre_of hs).1 (pre_of hs).2 + exact ⟨t, s', he, h⟩ + · exact VG.Taint.constantTime (A := taint) (Taint.ofRegs [.r3, .r4, .r5, .r6, .r7]) (fun _ _ _ _ hp => agree₀ hp) + (by taint_decide) + · refine ⟨sat, rfl, rfl, ?_, ?_, ?_, by decide, ?_, ?_, ?_⟩ <;> + · intro a h₁ h₂ + simp only [Region.Contains, sat] at h₁ h₂ + bv_omega + +end VG.Proof.Sha256.PPC64LE.Stream.Update diff --git a/lean/VerifiedGarbage/Proof/Sha256/Stream.lean b/lean/VerifiedGarbage/Proof/Sha256/Stream.lean index 80cad6d78..21ab5b179 100644 --- a/lean/VerifiedGarbage/Proof/Sha256/Stream.lean +++ b/lean/VerifiedGarbage/Proof/Sha256/Stream.lean @@ -79,10 +79,10 @@ theorem bytesAt_congr {mem mem' : Mem} {p : Addr} {n : Nat} intro i hi exact h i (List.mem_range.mp hi) -/-- `Repr` only depends on the 96 bytes of the state. -/ -theorem repr_congr {mem mem' : Mem} {p : Addr} {m : List Byte} +/-- `ReprFrom` only depends on the 96 bytes of the state. -/ +theorem reprFrom_congr {iv : HashValue} {mem mem' : Mem} {p : Addr} {m : List Byte} (h : ∀ i < 96, mem' (p + BitVec.ofNat 64 i) = mem (p + BitVec.ofNat 64 i)) - (hr : Spec.Sha256.Repr mem p m) : Spec.Sha256.Repr mem' p m := by + (hr : Spec.Sha256.ReprFrom iv mem p m) : Spec.Sha256.ReprFrom iv mem' p m := by refine ⟨by rw [stateAt_congr fun i hi => h i (by omega)]; exact hr.1, ?_⟩ rw [← hr.2] apply bytesAt_congr @@ -91,6 +91,12 @@ theorem repr_congr {mem mem' : Mem} {p : Addr} {m : List Byte} rwa [show p + 32 + BitVec.ofNat 64 i = p + BitVec.ofNat 64 (32 + i) by simp only [BitVec.ofNat_add]; rw [BitVec.add_assoc]; rfl] +/-- `Repr` only depends on the 96 bytes of the state. -/ +theorem repr_congr {mem mem' : Mem} {p : Addr} {m : List Byte} + (h : ∀ i < 96, mem' (p + BitVec.ofNat 64 i) = mem (p + BitVec.ofNat 64 i)) + (hr : Spec.Sha256.Repr mem p m) : Spec.Sha256.Repr mem' p m := + reprFrom_congr h hr + export VG.WriteBytes (writeBytes writeBytes_nil writeW8_apply writeBytes_snoc writeBytes_before writeBytes_frame write_eq_writeBytes writeBytes_append) /-- Bytes `[0, r)` from `p` stay, and the bytes `xs` follow them. -/ @@ -120,10 +126,10 @@ theorem repr_nil {mem : Mem} {p : Addr} (h : stateAt mem p = H0) : Spec.Sha256.R reprFrom_nil h /-- Appending bytes that stay within the buffer. -/ -theorem repr_append_buf {mem mem' : Mem} {p : Addr} {m xs : List Byte} (hr : Spec.Sha256.Repr mem p m) +theorem reprFrom_append_buf {iv : HashValue} {mem mem' : Mem} {p : Addr} {m xs : List Byte} (hr : Spec.Sha256.ReprFrom iv mem p m) (hlen : m.length % 64 + xs.length < 64) (hs : stateAt mem' p = stateAt mem p) (hb : bytesAt mem' (p + 32) (m.length % 64 + xs.length) = m.drop (64 * (m.length / 64)) ++ xs) : - Spec.Sha256.Repr mem' p (m ++ xs) := by + Spec.Sha256.ReprFrom iv mem' p (m ++ xs) := by have hdiv : (m ++ xs).length / 64 = m.length / 64 := by simp only [List.length_append]; omega have hmod : (m ++ xs).length % 64 = m.length % 64 + xs.length := by simp only [List.length_append]; omega @@ -133,11 +139,11 @@ theorem repr_append_buf {mem mem' : Mem} {p : Addr} {m xs : List Byte} (hr : Spe /-- Appending bytes that complete a block `B` (whose bytes are the buffered ones followed by `xs`), which is compressed. -/ -theorem repr_append_block {mem mem' : Mem} {p : Addr} {m xs : List Byte} (hr : Spec.Sha256.Repr mem p m) +theorem reprFrom_append_block {iv : HashValue} {mem mem' : Mem} {p : Addr} {m xs : List Byte} (hr : Spec.Sha256.ReprFrom iv mem p m) (hlen : m.length % 64 + xs.length = 64) (hs : stateAt mem' p = compress (stateAt mem p) (parseBlock fun k => (m.drop (64 * (m.length / 64)) ++ xs).getD k 0)) : - Spec.Sha256.Repr mem' p (m ++ xs) := by + Spec.Sha256.ReprFrom iv mem' p (m ++ xs) := by have hdiv : (m ++ xs).length / 64 = m.length / 64 + 1 := by simp only [List.length_append]; omega have hmod : (m ++ xs).length % 64 = 0 := by simp only [List.length_append]; omega refine ⟨?_, ?_⟩ @@ -150,6 +156,22 @@ theorem repr_append_block {mem mem' : Mem} {p : Addr} {m xs : List Byte} (hr : S simp only [bytesAt, List.range_zero, List.map_nil] symm; rw [List.drop_eq_nil_iff]; simp only [List.length_append]; omega +/-- Appending bytes that stay within the buffer. -/ +theorem repr_append_buf {mem mem' : Mem} {p : Addr} {m xs : List Byte} (hr : Spec.Sha256.Repr mem p m) + (hlen : m.length % 64 + xs.length < 64) (hs : stateAt mem' p = stateAt mem p) + (hb : bytesAt mem' (p + 32) (m.length % 64 + xs.length) = m.drop (64 * (m.length / 64)) ++ xs) : + Spec.Sha256.Repr mem' p (m ++ xs) := + reprFrom_append_buf hr hlen hs hb + +/-- Appending bytes that complete a block `B` (whose bytes are the buffered +ones followed by `xs`), which is compressed. -/ +theorem repr_append_block {mem mem' : Mem} {p : Addr} {m xs : List Byte} (hr : Spec.Sha256.Repr mem p m) + (hlen : m.length % 64 + xs.length = 64) + (hs : stateAt mem' p = + compress (stateAt mem p) (parseBlock fun k => (m.drop (64 * (m.length / 64)) ++ xs).getD k 0)) : + Spec.Sha256.Repr mem' p (m ++ xs) := + reprFrom_append_block hr hlen hs + /-! ## Padding -/ /-- The message length in bits, as 8 big-endian bytes. -/ @@ -212,9 +234,9 @@ theorem compressList_one (H : HashValue) (p : List Byte) : compressList H p 1 = compress H (parseBlock fun t => p.getD t 0) := by rw [compressList_succ, compressList_zero]; simp [blockOf] -theorem hash_eq (m : List Byte) (nt : Nat) +theorem finalHash_eq {iv : HashValue} (m : List Byte) (nt : Nat) (hn : (m.length % 64 + 1 + (119 - m.length % 64) % 64 + 8) = 64 * nt) : - Spec.Sha256.hash m = (compressList (compressList H0 m (m.length / 64)) + Spec.Sha256.finalHash iv m = (compressList (compressList iv m (m.length / 64)) (rest m ++ [0x80] ++ List.replicate ((119 - m.length % 64) % 64) 0 ++ lenBytes m) nt).toList.flatMap wordBytes := by have hp : pad m = m ++ ([0x80] ++ List.replicate ((119 - m.length % 64) % 64) 0 ++ lenBytes m) := by @@ -222,7 +244,7 @@ theorem hash_eq (m : List Byte) (nt : Nat) have hlen : (pad m).length / 64 = m.length / 64 + nt := by rw [hp]; simp only [List.length_append, List.length_replicate, lenBytes_length, List.length_singleton] omega - simp only [Spec.Sha256.hash, Spec.Sha256.finalHash] + simp only [Spec.Sha256.finalHash] rw [hlen, compressList_add, hp, compressList_append (by omega), List.drop_append_of_le_length (by omega)] simp only [List.append_assoc] @@ -234,11 +256,11 @@ theorem parseBlock_congr {f g : Nat → Byte} (h : ∀ k < 64, f k = g k) : pars rw [h _ (by omega), h _ (by omega), h _ (by omega), h _ (by omega)] /-- A message whose padding takes one more block. -/ -theorem hash_one {m : List Byte} (hr : m.length % 64 < 56) : - Spec.Sha256.hash m = (compress (compressList H0 m (m.length / 64)) +theorem finalHash_one {iv : HashValue} {m : List Byte} (hr : m.length % 64 < 56) : + Spec.Sha256.finalHash iv m = (compress (compressList iv m (m.length / 64)) (parseBlock fun t => (rest m ++ [0x80] ++ List.replicate (55 - m.length % 64) 0 ++ lenBytes m).getD t 0)).toList.flatMap wordBytes := by - rw [hash_eq m 1 (by omega), compressList_one, + rw [finalHash_eq m 1 (by omega), compressList_one, show (119 - m.length % 64) % 64 = 55 - m.length % 64 by omega] theorem getD_append_right {p q : List Byte} {j : Nat} : @@ -246,11 +268,11 @@ theorem getD_append_right {p q : List Byte} {j : Nat} : simp [List.getD_eq_getElem?_getD, List.getElem?_append_right] /-- A message whose padding takes two more blocks. -/ -theorem hash_two {m : List Byte} (hr : 56 ≤ m.length % 64) : - Spec.Sha256.hash m = (compress (compress (compressList H0 m (m.length / 64)) +theorem finalHash_two {iv : HashValue} {m : List Byte} (hr : 56 ≤ m.length % 64) : + Spec.Sha256.finalHash iv m = (compress (compress (compressList iv m (m.length / 64)) (parseBlock fun t => (rest m ++ [0x80] ++ List.replicate (63 - m.length % 64) 0).getD t 0)) (parseBlock fun t => (List.replicate 56 0 ++ lenBytes m).getD t 0)).toList.flatMap wordBytes := by - rw [hash_eq m 2 (by omega), compressList_succ, compressList_one] + rw [finalHash_eq m 2 (by omega), compressList_succ, compressList_one] have e : rest m ++ [0x80] ++ List.replicate ((119 - m.length % 64) % 64) 0 ++ lenBytes m = (rest m ++ [0x80] ++ List.replicate (63 - m.length % 64) 0) ++ (List.replicate 56 0 ++ lenBytes m) := by @@ -273,4 +295,25 @@ theorem hash_two {m : List Byte} (hr : 56 ≤ m.length % 64) : simpa using this rw [h1, h2] + +theorem hash_eq (m : List Byte) (nt : Nat) + (hn : (m.length % 64 + 1 + (119 - m.length % 64) % 64 + 8) = 64 * nt) : + Spec.Sha256.hash m = (compressList (compressList H0 m (m.length / 64)) + (rest m ++ [0x80] ++ List.replicate ((119 - m.length % 64) % 64) 0 ++ lenBytes m) nt).toList.flatMap + wordBytes := + finalHash_eq m nt hn + +/-- A message whose padding takes one more block. -/ +theorem hash_one {m : List Byte} (hr : m.length % 64 < 56) : + Spec.Sha256.hash m = (compress (compressList H0 m (m.length / 64)) + (parseBlock fun t => (rest m ++ [0x80] ++ List.replicate (55 - m.length % 64) 0 ++ + lenBytes m).getD t 0)).toList.flatMap wordBytes := + finalHash_one hr + +/-- A message whose padding takes two more blocks. -/ +theorem hash_two {m : List Byte} (hr : 56 ≤ m.length % 64) : + Spec.Sha256.hash m = (compress (compress (compressList H0 m (m.length / 64)) + (parseBlock fun t => (rest m ++ [0x80] ++ List.replicate (63 - m.length % 64) 0).getD t 0)) + (parseBlock fun t => (List.replicate 56 0 ++ lenBytes m).getD t 0)).toList.flatMap wordBytes := + finalHash_two hr end VG.Proof.Sha256.Stream diff --git a/src/asm/powerpc64le/mod.rs b/src/asm/powerpc64le/mod.rs index 5be504a68..f3bdc1079 100644 --- a/src/asm/powerpc64le/mod.rs +++ b/src/asm/powerpc64le/mod.rs @@ -4,5 +4,8 @@ #[rustfmt::skip] pub(crate) mod chacha20; +#[rustfmt::skip] +pub(crate) mod sha256; + #[rustfmt::skip] pub(crate) mod zeroize; diff --git a/src/asm/powerpc64le/sha256.rs b/src/asm/powerpc64le/sha256.rs new file mode 100644 index 000000000..7b45355ca --- /dev/null +++ b/src/asm/powerpc64le/sha256.rs @@ -0,0 +1,2954 @@ +// @generated by lean/Emit.lean. DO NOT EDIT. +//! Verified `sha256` functions for `powerpc64le`. +#![allow(dead_code)] + +/// The SHA-256 compression function (FIPS 180-4 §6.2.2): updates the hash value `*state` with the `n` 64-byte blocks starting at `blocks`, in order. +/// +/// Contract: `VG.Spec.Sha256.compressContract`. Constant time: only the pointers and `n` may affect timing, not the hash value or the blocks. +/// +/// # Safety +/// +/// * `state` must be valid for reads and writes of 32 bytes. +/// * `blocks` must be valid for reads of `64 * n` bytes. +/// * `scratch` must be valid for reads and writes of 560 bytes. +/// * The contents of `scratch` on return are unspecified. +/// * `state` and `scratch` must not overlap each other or `blocks` (distinct Rust objects never do). +/// * None of `state`, `blocks` and `scratch` may wrap around the end of the address space (no Rust object does). +#[unsafe(naked)] +pub(crate) unsafe extern "C" fn vg_sha256_compress(state: *mut [u32; 8], blocks: *const [u8; 64], n: usize, scratch: *mut [u64; 70]) { + core::arch::naked_asm!( + "std %r14, 64(%r6)", + "std %r15, 72(%r6)", + "std %r16, 80(%r6)", + "std %r17, 88(%r6)", + "std %r18, 96(%r6)", + "std %r19, 104(%r6)", + "cmpldi %cr0, %r5, 0", + "beq %cr0, 20f", + "22:", + "lwz %r7, 0(%r3)", + "lwz %r8, 4(%r3)", + "lwz %r9, 8(%r3)", + "lwz %r10, 12(%r3)", + "lwz %r11, 16(%r3)", + "lwz %r12, 20(%r3)", + "lwz %r14, 24(%r3)", + "lwz %r15, 28(%r3)", + "li %r0, 0", + "lwbrx %r16, %r4, %r0", + "stw %r16, 0(%r6)", + "rlwinm %r17, %r11, 26, 0, 31", + "rlwinm %r18, %r11, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r11, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r15, %r15, %r17", + "xor %r17, %r12, %r14", + "and %r17, %r17, %r11", + "xor %r17, %r17, %r14", + "add %r15, %r15, %r17", + "lis %r17, 17034", + "ori %r17, %r17, 12184", + "add %r15, %r15, %r17", + "add %r15, %r15, %r16", + "add %r10, %r10, %r15", + "rlwinm %r17, %r7, 30, 0, 31", + "rlwinm %r18, %r7, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r7, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r15, %r15, %r17", + "or %r17, %r7, %r8", + "and %r17, %r17, %r9", + "and %r18, %r7, %r8", + "or %r17, %r17, %r18", + "add %r15, %r15, %r17", + "li %r0, 4", + "lwbrx %r16, %r4, %r0", + "stw %r16, 4(%r6)", + "rlwinm %r17, %r10, 26, 0, 31", + "rlwinm %r18, %r10, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r10, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r14, %r14, %r17", + "xor %r17, %r11, %r12", + "and %r17, %r17, %r10", + "xor %r17, %r17, %r12", + "add %r14, %r14, %r17", + "lis %r17, 28983", + "ori %r17, %r17, 17553", + "add %r14, %r14, %r17", + "add %r14, %r14, %r16", + "add %r9, %r9, %r14", + "rlwinm %r17, %r15, 30, 0, 31", + "rlwinm %r18, %r15, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r15, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r14, %r14, %r17", + "or %r17, %r15, %r7", + "and %r17, %r17, %r8", + "and %r18, %r15, %r7", + "or %r17, %r17, %r18", + "add %r14, %r14, %r17", + "li %r0, 8", + "lwbrx %r16, %r4, %r0", + "stw %r16, 8(%r6)", + "rlwinm %r17, %r9, 26, 0, 31", + "rlwinm %r18, %r9, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r9, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r12, %r12, %r17", + "xor %r17, %r10, %r11", + "and %r17, %r17, %r9", + "xor %r17, %r17, %r11", + "add %r12, %r12, %r17", + "lis %r17, -19008", + "ori %r17, %r17, 64463", + "add %r12, %r12, %r17", + "add %r12, %r12, %r16", + "add %r8, %r8, %r12", + "rlwinm %r17, %r14, 30, 0, 31", + "rlwinm %r18, %r14, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r14, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r12, %r12, %r17", + "or %r17, %r14, %r15", + "and %r17, %r17, %r7", + "and %r18, %r14, %r15", + "or %r17, %r17, %r18", + "add %r12, %r12, %r17", + "li %r0, 12", + "lwbrx %r16, %r4, %r0", + "stw %r16, 12(%r6)", + "rlwinm %r17, %r8, 26, 0, 31", + "rlwinm %r18, %r8, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r8, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r11, %r11, %r17", + "xor %r17, %r9, %r10", + "and %r17, %r17, %r8", + "xor %r17, %r17, %r10", + "add %r11, %r11, %r17", + "lis %r17, -5707", + "ori %r17, %r17, 56229", + "add %r11, %r11, %r17", + "add %r11, %r11, %r16", + "add %r7, %r7, %r11", + "rlwinm %r17, %r12, 30, 0, 31", + "rlwinm %r18, %r12, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r12, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r11, %r11, %r17", + "or %r17, %r12, %r14", + "and %r17, %r17, %r15", + "and %r18, %r12, %r14", + "or %r17, %r17, %r18", + "add %r11, %r11, %r17", + "li %r0, 16", + "lwbrx %r16, %r4, %r0", + "stw %r16, 16(%r6)", + "rlwinm %r17, %r7, 26, 0, 31", + "rlwinm %r18, %r7, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r7, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r10, %r10, %r17", + "xor %r17, %r8, %r9", + "and %r17, %r17, %r7", + "xor %r17, %r17, %r9", + "add %r10, %r10, %r17", + "lis %r17, 14678", + "ori %r17, %r17, 49755", + "add %r10, %r10, %r17", + "add %r10, %r10, %r16", + "add %r15, %r15, %r10", + "rlwinm %r17, %r11, 30, 0, 31", + "rlwinm %r18, %r11, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r11, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r10, %r10, %r17", + "or %r17, %r11, %r12", + "and %r17, %r17, %r14", + "and %r18, %r11, %r12", + "or %r17, %r17, %r18", + "add %r10, %r10, %r17", + "li %r0, 20", + "lwbrx %r16, %r4, %r0", + "stw %r16, 20(%r6)", + "rlwinm %r17, %r15, 26, 0, 31", + "rlwinm %r18, %r15, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r15, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r9, %r9, %r17", + "xor %r17, %r7, %r8", + "and %r17, %r17, %r15", + "xor %r17, %r17, %r8", + "add %r9, %r9, %r17", + "lis %r17, 23025", + "ori %r17, %r17, 4593", + "add %r9, %r9, %r17", + "add %r9, %r9, %r16", + "add %r14, %r14, %r9", + "rlwinm %r17, %r10, 30, 0, 31", + "rlwinm %r18, %r10, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r10, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r9, %r9, %r17", + "or %r17, %r10, %r11", + "and %r17, %r17, %r12", + "and %r18, %r10, %r11", + "or %r17, %r17, %r18", + "add %r9, %r9, %r17", + "li %r0, 24", + "lwbrx %r16, %r4, %r0", + "stw %r16, 24(%r6)", + "rlwinm %r17, %r14, 26, 0, 31", + "rlwinm %r18, %r14, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r14, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r8, %r8, %r17", + "xor %r17, %r15, %r7", + "and %r17, %r17, %r14", + "xor %r17, %r17, %r7", + "add %r8, %r8, %r17", + "lis %r17, -28097", + "ori %r17, %r17, 33444", + "add %r8, %r8, %r17", + "add %r8, %r8, %r16", + "add %r12, %r12, %r8", + "rlwinm %r17, %r9, 30, 0, 31", + "rlwinm %r18, %r9, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r9, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r8, %r8, %r17", + "or %r17, %r9, %r10", + "and %r17, %r17, %r11", + "and %r18, %r9, %r10", + "or %r17, %r17, %r18", + "add %r8, %r8, %r17", + "li %r0, 28", + "lwbrx %r16, %r4, %r0", + "stw %r16, 28(%r6)", + "rlwinm %r17, %r12, 26, 0, 31", + "rlwinm %r18, %r12, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r12, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r7, %r7, %r17", + "xor %r17, %r14, %r15", + "and %r17, %r17, %r12", + "xor %r17, %r17, %r15", + "add %r7, %r7, %r17", + "lis %r17, -21732", + "ori %r17, %r17, 24277", + "add %r7, %r7, %r17", + "add %r7, %r7, %r16", + "add %r11, %r11, %r7", + "rlwinm %r17, %r8, 30, 0, 31", + "rlwinm %r18, %r8, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r8, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r7, %r7, %r17", + "or %r17, %r8, %r9", + "and %r17, %r17, %r10", + "and %r18, %r8, %r9", + "or %r17, %r17, %r18", + "add %r7, %r7, %r17", + "li %r0, 32", + "lwbrx %r16, %r4, %r0", + "stw %r16, 32(%r6)", + "rlwinm %r17, %r11, 26, 0, 31", + "rlwinm %r18, %r11, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r11, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r15, %r15, %r17", + "xor %r17, %r12, %r14", + "and %r17, %r17, %r11", + "xor %r17, %r17, %r14", + "add %r15, %r15, %r17", + "lis %r17, -10233", + "ori %r17, %r17, 43672", + "add %r15, %r15, %r17", + "add %r15, %r15, %r16", + "add %r10, %r10, %r15", + "rlwinm %r17, %r7, 30, 0, 31", + "rlwinm %r18, %r7, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r7, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r15, %r15, %r17", + "or %r17, %r7, %r8", + "and %r17, %r17, %r9", + "and %r18, %r7, %r8", + "or %r17, %r17, %r18", + "add %r15, %r15, %r17", + "li %r0, 36", + "lwbrx %r16, %r4, %r0", + "stw %r16, 36(%r6)", + "rlwinm %r17, %r10, 26, 0, 31", + "rlwinm %r18, %r10, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r10, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r14, %r14, %r17", + "xor %r17, %r11, %r12", + "and %r17, %r17, %r10", + "xor %r17, %r17, %r12", + "add %r14, %r14, %r17", + "lis %r17, 4739", + "ori %r17, %r17, 23297", + "add %r14, %r14, %r17", + "add %r14, %r14, %r16", + "add %r9, %r9, %r14", + "rlwinm %r17, %r15, 30, 0, 31", + "rlwinm %r18, %r15, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r15, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r14, %r14, %r17", + "or %r17, %r15, %r7", + "and %r17, %r17, %r8", + "and %r18, %r15, %r7", + "or %r17, %r17, %r18", + "add %r14, %r14, %r17", + "li %r0, 40", + "lwbrx %r16, %r4, %r0", + "stw %r16, 40(%r6)", + "rlwinm %r17, %r9, 26, 0, 31", + "rlwinm %r18, %r9, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r9, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r12, %r12, %r17", + "xor %r17, %r10, %r11", + "and %r17, %r17, %r9", + "xor %r17, %r17, %r11", + "add %r12, %r12, %r17", + "lis %r17, 9265", + "ori %r17, %r17, 34238", + "add %r12, %r12, %r17", + "add %r12, %r12, %r16", + "add %r8, %r8, %r12", + "rlwinm %r17, %r14, 30, 0, 31", + "rlwinm %r18, %r14, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r14, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r12, %r12, %r17", + "or %r17, %r14, %r15", + "and %r17, %r17, %r7", + "and %r18, %r14, %r15", + "or %r17, %r17, %r18", + "add %r12, %r12, %r17", + "li %r0, 44", + "lwbrx %r16, %r4, %r0", + "stw %r16, 44(%r6)", + "rlwinm %r17, %r8, 26, 0, 31", + "rlwinm %r18, %r8, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r8, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r11, %r11, %r17", + "xor %r17, %r9, %r10", + "and %r17, %r17, %r8", + "xor %r17, %r17, %r10", + "add %r11, %r11, %r17", + "lis %r17, 21772", + "ori %r17, %r17, 32195", + "add %r11, %r11, %r17", + "add %r11, %r11, %r16", + "add %r7, %r7, %r11", + "rlwinm %r17, %r12, 30, 0, 31", + "rlwinm %r18, %r12, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r12, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r11, %r11, %r17", + "or %r17, %r12, %r14", + "and %r17, %r17, %r15", + "and %r18, %r12, %r14", + "or %r17, %r17, %r18", + "add %r11, %r11, %r17", + "li %r0, 48", + "lwbrx %r16, %r4, %r0", + "stw %r16, 48(%r6)", + "rlwinm %r17, %r7, 26, 0, 31", + "rlwinm %r18, %r7, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r7, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r10, %r10, %r17", + "xor %r17, %r8, %r9", + "and %r17, %r17, %r7", + "xor %r17, %r17, %r9", + "add %r10, %r10, %r17", + "lis %r17, 29374", + "ori %r17, %r17, 23924", + "add %r10, %r10, %r17", + "add %r10, %r10, %r16", + "add %r15, %r15, %r10", + "rlwinm %r17, %r11, 30, 0, 31", + "rlwinm %r18, %r11, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r11, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r10, %r10, %r17", + "or %r17, %r11, %r12", + "and %r17, %r17, %r14", + "and %r18, %r11, %r12", + "or %r17, %r17, %r18", + "add %r10, %r10, %r17", + "li %r0, 52", + "lwbrx %r16, %r4, %r0", + "stw %r16, 52(%r6)", + "rlwinm %r17, %r15, 26, 0, 31", + "rlwinm %r18, %r15, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r15, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r9, %r9, %r17", + "xor %r17, %r7, %r8", + "and %r17, %r17, %r15", + "xor %r17, %r17, %r8", + "add %r9, %r9, %r17", + "lis %r17, -32546", + "ori %r17, %r17, 45566", + "add %r9, %r9, %r17", + "add %r9, %r9, %r16", + "add %r14, %r14, %r9", + "rlwinm %r17, %r10, 30, 0, 31", + "rlwinm %r18, %r10, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r10, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r9, %r9, %r17", + "or %r17, %r10, %r11", + "and %r17, %r17, %r12", + "and %r18, %r10, %r11", + "or %r17, %r17, %r18", + "add %r9, %r9, %r17", + "li %r0, 56", + "lwbrx %r16, %r4, %r0", + "stw %r16, 56(%r6)", + "rlwinm %r17, %r14, 26, 0, 31", + "rlwinm %r18, %r14, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r14, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r8, %r8, %r17", + "xor %r17, %r15, %r7", + "and %r17, %r17, %r14", + "xor %r17, %r17, %r7", + "add %r8, %r8, %r17", + "lis %r17, -25636", + "ori %r17, %r17, 1703", + "add %r8, %r8, %r17", + "add %r8, %r8, %r16", + "add %r12, %r12, %r8", + "rlwinm %r17, %r9, 30, 0, 31", + "rlwinm %r18, %r9, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r9, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r8, %r8, %r17", + "or %r17, %r9, %r10", + "and %r17, %r17, %r11", + "and %r18, %r9, %r10", + "or %r17, %r17, %r18", + "add %r8, %r8, %r17", + "li %r0, 60", + "lwbrx %r16, %r4, %r0", + "stw %r16, 60(%r6)", + "rlwinm %r17, %r12, 26, 0, 31", + "rlwinm %r18, %r12, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r12, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r7, %r7, %r17", + "xor %r17, %r14, %r15", + "and %r17, %r17, %r12", + "xor %r17, %r17, %r15", + "add %r7, %r7, %r17", + "lis %r17, -15973", + "ori %r17, %r17, 61812", + "add %r7, %r7, %r17", + "add %r7, %r7, %r16", + "add %r11, %r11, %r7", + "rlwinm %r17, %r8, 30, 0, 31", + "rlwinm %r18, %r8, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r8, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r7, %r7, %r17", + "or %r17, %r8, %r9", + "and %r17, %r17, %r10", + "and %r18, %r8, %r9", + "or %r17, %r17, %r18", + "add %r7, %r7, %r17", + "lwz %r17, 56(%r6)", + "rlwinm %r16, %r17, 15, 0, 31", + "rlwinm %r18, %r17, 13, 0, 31", + "xor %r16, %r16, %r18", + "rlwinm %r18, %r17, 22, 10, 31", + "xor %r16, %r16, %r18", + "lwz %r18, 36(%r6)", + "add %r16, %r16, %r18", + "lwz %r17, 4(%r6)", + "rlwinm %r18, %r17, 25, 0, 31", + "rlwinm %r19, %r17, 14, 0, 31", + "xor %r18, %r18, %r19", + "rlwinm %r19, %r17, 29, 3, 31", + "xor %r18, %r18, %r19", + "add %r16, %r16, %r18", + "lwz %r18, 0(%r6)", + "add %r16, %r16, %r18", + "stw %r16, 0(%r6)", + "rlwinm %r17, %r11, 26, 0, 31", + "rlwinm %r18, %r11, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r11, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r15, %r15, %r17", + "xor %r17, %r12, %r14", + "and %r17, %r17, %r11", + "xor %r17, %r17, %r14", + "add %r15, %r15, %r17", + "lis %r17, -7013", + "ori %r17, %r17, 27073", + "add %r15, %r15, %r17", + "add %r15, %r15, %r16", + "add %r10, %r10, %r15", + "rlwinm %r17, %r7, 30, 0, 31", + "rlwinm %r18, %r7, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r7, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r15, %r15, %r17", + "or %r17, %r7, %r8", + "and %r17, %r17, %r9", + "and %r18, %r7, %r8", + "or %r17, %r17, %r18", + "add %r15, %r15, %r17", + "lwz %r17, 60(%r6)", + "rlwinm %r16, %r17, 15, 0, 31", + "rlwinm %r18, %r17, 13, 0, 31", + "xor %r16, %r16, %r18", + "rlwinm %r18, %r17, 22, 10, 31", + "xor %r16, %r16, %r18", + "lwz %r18, 40(%r6)", + "add %r16, %r16, %r18", + "lwz %r17, 8(%r6)", + "rlwinm %r18, %r17, 25, 0, 31", + "rlwinm %r19, %r17, 14, 0, 31", + "xor %r18, %r18, %r19", + "rlwinm %r19, %r17, 29, 3, 31", + "xor %r18, %r18, %r19", + "add %r16, %r16, %r18", + "lwz %r18, 4(%r6)", + "add %r16, %r16, %r18", + "stw %r16, 4(%r6)", + "rlwinm %r17, %r10, 26, 0, 31", + "rlwinm %r18, %r10, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r10, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r14, %r14, %r17", + "xor %r17, %r11, %r12", + "and %r17, %r17, %r10", + "xor %r17, %r17, %r12", + "add %r14, %r14, %r17", + "lis %r17, -4162", + "ori %r17, %r17, 18310", + "add %r14, %r14, %r17", + "add %r14, %r14, %r16", + "add %r9, %r9, %r14", + "rlwinm %r17, %r15, 30, 0, 31", + "rlwinm %r18, %r15, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r15, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r14, %r14, %r17", + "or %r17, %r15, %r7", + "and %r17, %r17, %r8", + "and %r18, %r15, %r7", + "or %r17, %r17, %r18", + "add %r14, %r14, %r17", + "lwz %r17, 0(%r6)", + "rlwinm %r16, %r17, 15, 0, 31", + "rlwinm %r18, %r17, 13, 0, 31", + "xor %r16, %r16, %r18", + "rlwinm %r18, %r17, 22, 10, 31", + "xor %r16, %r16, %r18", + "lwz %r18, 44(%r6)", + "add %r16, %r16, %r18", + "lwz %r17, 12(%r6)", + "rlwinm %r18, %r17, 25, 0, 31", + "rlwinm %r19, %r17, 14, 0, 31", + "xor %r18, %r18, %r19", + "rlwinm %r19, %r17, 29, 3, 31", + "xor %r18, %r18, %r19", + "add %r16, %r16, %r18", + "lwz %r18, 8(%r6)", + "add %r16, %r16, %r18", + "stw %r16, 8(%r6)", + "rlwinm %r17, %r9, 26, 0, 31", + "rlwinm %r18, %r9, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r9, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r12, %r12, %r17", + "xor %r17, %r10, %r11", + "and %r17, %r17, %r9", + "xor %r17, %r17, %r11", + "add %r12, %r12, %r17", + "lis %r17, 4033", + "ori %r17, %r17, 40390", + "add %r12, %r12, %r17", + "add %r12, %r12, %r16", + "add %r8, %r8, %r12", + "rlwinm %r17, %r14, 30, 0, 31", + "rlwinm %r18, %r14, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r14, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r12, %r12, %r17", + "or %r17, %r14, %r15", + "and %r17, %r17, %r7", + "and %r18, %r14, %r15", + "or %r17, %r17, %r18", + "add %r12, %r12, %r17", + "lwz %r17, 4(%r6)", + "rlwinm %r16, %r17, 15, 0, 31", + "rlwinm %r18, %r17, 13, 0, 31", + "xor %r16, %r16, %r18", + "rlwinm %r18, %r17, 22, 10, 31", + "xor %r16, %r16, %r18", + "lwz %r18, 48(%r6)", + "add %r16, %r16, %r18", + "lwz %r17, 16(%r6)", + "rlwinm %r18, %r17, 25, 0, 31", + "rlwinm %r19, %r17, 14, 0, 31", + "xor %r18, %r18, %r19", + "rlwinm %r19, %r17, 29, 3, 31", + "xor %r18, %r18, %r19", + "add %r16, %r16, %r18", + "lwz %r18, 12(%r6)", + "add %r16, %r16, %r18", + "stw %r16, 12(%r6)", + "rlwinm %r17, %r8, 26, 0, 31", + "rlwinm %r18, %r8, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r8, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r11, %r11, %r17", + "xor %r17, %r9, %r10", + "and %r17, %r17, %r8", + "xor %r17, %r17, %r10", + "add %r11, %r11, %r17", + "lis %r17, 9228", + "ori %r17, %r17, 41420", + "add %r11, %r11, %r17", + "add %r11, %r11, %r16", + "add %r7, %r7, %r11", + "rlwinm %r17, %r12, 30, 0, 31", + "rlwinm %r18, %r12, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r12, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r11, %r11, %r17", + "or %r17, %r12, %r14", + "and %r17, %r17, %r15", + "and %r18, %r12, %r14", + "or %r17, %r17, %r18", + "add %r11, %r11, %r17", + "lwz %r17, 8(%r6)", + "rlwinm %r16, %r17, 15, 0, 31", + "rlwinm %r18, %r17, 13, 0, 31", + "xor %r16, %r16, %r18", + "rlwinm %r18, %r17, 22, 10, 31", + "xor %r16, %r16, %r18", + "lwz %r18, 52(%r6)", + "add %r16, %r16, %r18", + "lwz %r17, 20(%r6)", + "rlwinm %r18, %r17, 25, 0, 31", + "rlwinm %r19, %r17, 14, 0, 31", + "xor %r18, %r18, %r19", + "rlwinm %r19, %r17, 29, 3, 31", + "xor %r18, %r18, %r19", + "add %r16, %r16, %r18", + "lwz %r18, 16(%r6)", + "add %r16, %r16, %r18", + "stw %r16, 16(%r6)", + "rlwinm %r17, %r7, 26, 0, 31", + "rlwinm %r18, %r7, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r7, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r10, %r10, %r17", + "xor %r17, %r8, %r9", + "and %r17, %r17, %r7", + "xor %r17, %r17, %r9", + "add %r10, %r10, %r17", + "lis %r17, 11753", + "ori %r17, %r17, 11375", + "add %r10, %r10, %r17", + "add %r10, %r10, %r16", + "add %r15, %r15, %r10", + "rlwinm %r17, %r11, 30, 0, 31", + "rlwinm %r18, %r11, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r11, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r10, %r10, %r17", + "or %r17, %r11, %r12", + "and %r17, %r17, %r14", + "and %r18, %r11, %r12", + "or %r17, %r17, %r18", + "add %r10, %r10, %r17", + "lwz %r17, 12(%r6)", + "rlwinm %r16, %r17, 15, 0, 31", + "rlwinm %r18, %r17, 13, 0, 31", + "xor %r16, %r16, %r18", + "rlwinm %r18, %r17, 22, 10, 31", + "xor %r16, %r16, %r18", + "lwz %r18, 56(%r6)", + "add %r16, %r16, %r18", + "lwz %r17, 24(%r6)", + "rlwinm %r18, %r17, 25, 0, 31", + "rlwinm %r19, %r17, 14, 0, 31", + "xor %r18, %r18, %r19", + "rlwinm %r19, %r17, 29, 3, 31", + "xor %r18, %r18, %r19", + "add %r16, %r16, %r18", + "lwz %r18, 20(%r6)", + "add %r16, %r16, %r18", + "stw %r16, 20(%r6)", + "rlwinm %r17, %r15, 26, 0, 31", + "rlwinm %r18, %r15, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r15, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r9, %r9, %r17", + "xor %r17, %r7, %r8", + "and %r17, %r17, %r15", + "xor %r17, %r17, %r8", + "add %r9, %r9, %r17", + "lis %r17, 19060", + "ori %r17, %r17, 33962", + "add %r9, %r9, %r17", + "add %r9, %r9, %r16", + "add %r14, %r14, %r9", + "rlwinm %r17, %r10, 30, 0, 31", + "rlwinm %r18, %r10, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r10, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r9, %r9, %r17", + "or %r17, %r10, %r11", + "and %r17, %r17, %r12", + "and %r18, %r10, %r11", + "or %r17, %r17, %r18", + "add %r9, %r9, %r17", + "lwz %r17, 16(%r6)", + "rlwinm %r16, %r17, 15, 0, 31", + "rlwinm %r18, %r17, 13, 0, 31", + "xor %r16, %r16, %r18", + "rlwinm %r18, %r17, 22, 10, 31", + "xor %r16, %r16, %r18", + "lwz %r18, 60(%r6)", + "add %r16, %r16, %r18", + "lwz %r17, 28(%r6)", + "rlwinm %r18, %r17, 25, 0, 31", + "rlwinm %r19, %r17, 14, 0, 31", + "xor %r18, %r18, %r19", + "rlwinm %r19, %r17, 29, 3, 31", + "xor %r18, %r18, %r19", + "add %r16, %r16, %r18", + "lwz %r18, 24(%r6)", + "add %r16, %r16, %r18", + "stw %r16, 24(%r6)", + "rlwinm %r17, %r14, 26, 0, 31", + "rlwinm %r18, %r14, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r14, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r8, %r8, %r17", + "xor %r17, %r15, %r7", + "and %r17, %r17, %r14", + "xor %r17, %r17, %r7", + "add %r8, %r8, %r17", + "lis %r17, 23728", + "ori %r17, %r17, 43484", + "add %r8, %r8, %r17", + "add %r8, %r8, %r16", + "add %r12, %r12, %r8", + "rlwinm %r17, %r9, 30, 0, 31", + "rlwinm %r18, %r9, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r9, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r8, %r8, %r17", + "or %r17, %r9, %r10", + "and %r17, %r17, %r11", + "and %r18, %r9, %r10", + "or %r17, %r17, %r18", + "add %r8, %r8, %r17", + "lwz %r17, 20(%r6)", + "rlwinm %r16, %r17, 15, 0, 31", + "rlwinm %r18, %r17, 13, 0, 31", + "xor %r16, %r16, %r18", + "rlwinm %r18, %r17, 22, 10, 31", + "xor %r16, %r16, %r18", + "lwz %r18, 0(%r6)", + "add %r16, %r16, %r18", + "lwz %r17, 32(%r6)", + "rlwinm %r18, %r17, 25, 0, 31", + "rlwinm %r19, %r17, 14, 0, 31", + "xor %r18, %r18, %r19", + "rlwinm %r19, %r17, 29, 3, 31", + "xor %r18, %r18, %r19", + "add %r16, %r16, %r18", + "lwz %r18, 28(%r6)", + "add %r16, %r16, %r18", + "stw %r16, 28(%r6)", + "rlwinm %r17, %r12, 26, 0, 31", + "rlwinm %r18, %r12, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r12, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r7, %r7, %r17", + "xor %r17, %r14, %r15", + "and %r17, %r17, %r12", + "xor %r17, %r17, %r15", + "add %r7, %r7, %r17", + "lis %r17, 30457", + "ori %r17, %r17, 35034", + "add %r7, %r7, %r17", + "add %r7, %r7, %r16", + "add %r11, %r11, %r7", + "rlwinm %r17, %r8, 30, 0, 31", + "rlwinm %r18, %r8, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r8, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r7, %r7, %r17", + "or %r17, %r8, %r9", + "and %r17, %r17, %r10", + "and %r18, %r8, %r9", + "or %r17, %r17, %r18", + "add %r7, %r7, %r17", + "lwz %r17, 24(%r6)", + "rlwinm %r16, %r17, 15, 0, 31", + "rlwinm %r18, %r17, 13, 0, 31", + "xor %r16, %r16, %r18", + "rlwinm %r18, %r17, 22, 10, 31", + "xor %r16, %r16, %r18", + "lwz %r18, 4(%r6)", + "add %r16, %r16, %r18", + "lwz %r17, 36(%r6)", + "rlwinm %r18, %r17, 25, 0, 31", + "rlwinm %r19, %r17, 14, 0, 31", + "xor %r18, %r18, %r19", + "rlwinm %r19, %r17, 29, 3, 31", + "xor %r18, %r18, %r19", + "add %r16, %r16, %r18", + "lwz %r18, 32(%r6)", + "add %r16, %r16, %r18", + "stw %r16, 32(%r6)", + "rlwinm %r17, %r11, 26, 0, 31", + "rlwinm %r18, %r11, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r11, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r15, %r15, %r17", + "xor %r17, %r12, %r14", + "and %r17, %r17, %r11", + "xor %r17, %r17, %r14", + "add %r15, %r15, %r17", + "lis %r17, -26562", + "ori %r17, %r17, 20818", + "add %r15, %r15, %r17", + "add %r15, %r15, %r16", + "add %r10, %r10, %r15", + "rlwinm %r17, %r7, 30, 0, 31", + "rlwinm %r18, %r7, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r7, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r15, %r15, %r17", + "or %r17, %r7, %r8", + "and %r17, %r17, %r9", + "and %r18, %r7, %r8", + "or %r17, %r17, %r18", + "add %r15, %r15, %r17", + "lwz %r17, 28(%r6)", + "rlwinm %r16, %r17, 15, 0, 31", + "rlwinm %r18, %r17, 13, 0, 31", + "xor %r16, %r16, %r18", + "rlwinm %r18, %r17, 22, 10, 31", + "xor %r16, %r16, %r18", + "lwz %r18, 8(%r6)", + "add %r16, %r16, %r18", + "lwz %r17, 40(%r6)", + "rlwinm %r18, %r17, 25, 0, 31", + "rlwinm %r19, %r17, 14, 0, 31", + "xor %r18, %r18, %r19", + "rlwinm %r19, %r17, 29, 3, 31", + "xor %r18, %r18, %r19", + "add %r16, %r16, %r18", + "lwz %r18, 36(%r6)", + "add %r16, %r16, %r18", + "stw %r16, 36(%r6)", + "rlwinm %r17, %r10, 26, 0, 31", + "rlwinm %r18, %r10, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r10, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r14, %r14, %r17", + "xor %r17, %r11, %r12", + "and %r17, %r17, %r10", + "xor %r17, %r17, %r12", + "add %r14, %r14, %r17", + "lis %r17, -22479", + "ori %r17, %r17, 50797", + "add %r14, %r14, %r17", + "add %r14, %r14, %r16", + "add %r9, %r9, %r14", + "rlwinm %r17, %r15, 30, 0, 31", + "rlwinm %r18, %r15, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r15, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r14, %r14, %r17", + "or %r17, %r15, %r7", + "and %r17, %r17, %r8", + "and %r18, %r15, %r7", + "or %r17, %r17, %r18", + "add %r14, %r14, %r17", + "lwz %r17, 32(%r6)", + "rlwinm %r16, %r17, 15, 0, 31", + "rlwinm %r18, %r17, 13, 0, 31", + "xor %r16, %r16, %r18", + "rlwinm %r18, %r17, 22, 10, 31", + "xor %r16, %r16, %r18", + "lwz %r18, 12(%r6)", + "add %r16, %r16, %r18", + "lwz %r17, 44(%r6)", + "rlwinm %r18, %r17, 25, 0, 31", + "rlwinm %r19, %r17, 14, 0, 31", + "xor %r18, %r18, %r19", + "rlwinm %r19, %r17, 29, 3, 31", + "xor %r18, %r18, %r19", + "add %r16, %r16, %r18", + "lwz %r18, 40(%r6)", + "add %r16, %r16, %r18", + "stw %r16, 40(%r6)", + "rlwinm %r17, %r9, 26, 0, 31", + "rlwinm %r18, %r9, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r9, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r12, %r12, %r17", + "xor %r17, %r10, %r11", + "and %r17, %r17, %r9", + "xor %r17, %r17, %r11", + "add %r12, %r12, %r17", + "lis %r17, -20477", + "ori %r17, %r17, 10184", + "add %r12, %r12, %r17", + "add %r12, %r12, %r16", + "add %r8, %r8, %r12", + "rlwinm %r17, %r14, 30, 0, 31", + "rlwinm %r18, %r14, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r14, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r12, %r12, %r17", + "or %r17, %r14, %r15", + "and %r17, %r17, %r7", + "and %r18, %r14, %r15", + "or %r17, %r17, %r18", + "add %r12, %r12, %r17", + "lwz %r17, 36(%r6)", + "rlwinm %r16, %r17, 15, 0, 31", + "rlwinm %r18, %r17, 13, 0, 31", + "xor %r16, %r16, %r18", + "rlwinm %r18, %r17, 22, 10, 31", + "xor %r16, %r16, %r18", + "lwz %r18, 16(%r6)", + "add %r16, %r16, %r18", + "lwz %r17, 48(%r6)", + "rlwinm %r18, %r17, 25, 0, 31", + "rlwinm %r19, %r17, 14, 0, 31", + "xor %r18, %r18, %r19", + "rlwinm %r19, %r17, 29, 3, 31", + "xor %r18, %r18, %r19", + "add %r16, %r16, %r18", + "lwz %r18, 44(%r6)", + "add %r16, %r16, %r18", + "stw %r16, 44(%r6)", + "rlwinm %r17, %r8, 26, 0, 31", + "rlwinm %r18, %r8, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r8, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r11, %r11, %r17", + "xor %r17, %r9, %r10", + "and %r17, %r17, %r8", + "xor %r17, %r17, %r10", + "add %r11, %r11, %r17", + "lis %r17, -16551", + "ori %r17, %r17, 32711", + "add %r11, %r11, %r17", + "add %r11, %r11, %r16", + "add %r7, %r7, %r11", + "rlwinm %r17, %r12, 30, 0, 31", + "rlwinm %r18, %r12, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r12, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r11, %r11, %r17", + "or %r17, %r12, %r14", + "and %r17, %r17, %r15", + "and %r18, %r12, %r14", + "or %r17, %r17, %r18", + "add %r11, %r11, %r17", + "lwz %r17, 40(%r6)", + "rlwinm %r16, %r17, 15, 0, 31", + "rlwinm %r18, %r17, 13, 0, 31", + "xor %r16, %r16, %r18", + "rlwinm %r18, %r17, 22, 10, 31", + "xor %r16, %r16, %r18", + "lwz %r18, 20(%r6)", + "add %r16, %r16, %r18", + "lwz %r17, 52(%r6)", + "rlwinm %r18, %r17, 25, 0, 31", + "rlwinm %r19, %r17, 14, 0, 31", + "xor %r18, %r18, %r19", + "rlwinm %r19, %r17, 29, 3, 31", + "xor %r18, %r18, %r19", + "add %r16, %r16, %r18", + "lwz %r18, 48(%r6)", + "add %r16, %r16, %r18", + "stw %r16, 48(%r6)", + "rlwinm %r17, %r7, 26, 0, 31", + "rlwinm %r18, %r7, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r7, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r10, %r10, %r17", + "xor %r17, %r8, %r9", + "and %r17, %r17, %r7", + "xor %r17, %r17, %r9", + "add %r10, %r10, %r17", + "lis %r17, -14624", + "ori %r17, %r17, 3059", + "add %r10, %r10, %r17", + "add %r10, %r10, %r16", + "add %r15, %r15, %r10", + "rlwinm %r17, %r11, 30, 0, 31", + "rlwinm %r18, %r11, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r11, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r10, %r10, %r17", + "or %r17, %r11, %r12", + "and %r17, %r17, %r14", + "and %r18, %r11, %r12", + "or %r17, %r17, %r18", + "add %r10, %r10, %r17", + "lwz %r17, 44(%r6)", + "rlwinm %r16, %r17, 15, 0, 31", + "rlwinm %r18, %r17, 13, 0, 31", + "xor %r16, %r16, %r18", + "rlwinm %r18, %r17, 22, 10, 31", + "xor %r16, %r16, %r18", + "lwz %r18, 24(%r6)", + "add %r16, %r16, %r18", + "lwz %r17, 56(%r6)", + "rlwinm %r18, %r17, 25, 0, 31", + "rlwinm %r19, %r17, 14, 0, 31", + "xor %r18, %r18, %r19", + "rlwinm %r19, %r17, 29, 3, 31", + "xor %r18, %r18, %r19", + "add %r16, %r16, %r18", + "lwz %r18, 52(%r6)", + "add %r16, %r16, %r18", + "stw %r16, 52(%r6)", + "rlwinm %r17, %r15, 26, 0, 31", + "rlwinm %r18, %r15, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r15, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r9, %r9, %r17", + "xor %r17, %r7, %r8", + "and %r17, %r17, %r15", + "xor %r17, %r17, %r8", + "add %r9, %r9, %r17", + "lis %r17, -10841", + "ori %r17, %r17, 37191", + "add %r9, %r9, %r17", + "add %r9, %r9, %r16", + "add %r14, %r14, %r9", + "rlwinm %r17, %r10, 30, 0, 31", + "rlwinm %r18, %r10, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r10, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r9, %r9, %r17", + "or %r17, %r10, %r11", + "and %r17, %r17, %r12", + "and %r18, %r10, %r11", + "or %r17, %r17, %r18", + "add %r9, %r9, %r17", + "lwz %r17, 48(%r6)", + "rlwinm %r16, %r17, 15, 0, 31", + "rlwinm %r18, %r17, 13, 0, 31", + "xor %r16, %r16, %r18", + "rlwinm %r18, %r17, 22, 10, 31", + "xor %r16, %r16, %r18", + "lwz %r18, 28(%r6)", + "add %r16, %r16, %r18", + "lwz %r17, 60(%r6)", + "rlwinm %r18, %r17, 25, 0, 31", + "rlwinm %r19, %r17, 14, 0, 31", + "xor %r18, %r18, %r19", + "rlwinm %r19, %r17, 29, 3, 31", + "xor %r18, %r18, %r19", + "add %r16, %r16, %r18", + "lwz %r18, 56(%r6)", + "add %r16, %r16, %r18", + "stw %r16, 56(%r6)", + "rlwinm %r17, %r14, 26, 0, 31", + "rlwinm %r18, %r14, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r14, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r8, %r8, %r17", + "xor %r17, %r15, %r7", + "and %r17, %r17, %r14", + "xor %r17, %r17, %r7", + "add %r8, %r8, %r17", + "lis %r17, 1738", + "ori %r17, %r17, 25425", + "add %r8, %r8, %r17", + "add %r8, %r8, %r16", + "add %r12, %r12, %r8", + "rlwinm %r17, %r9, 30, 0, 31", + "rlwinm %r18, %r9, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r9, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r8, %r8, %r17", + "or %r17, %r9, %r10", + "and %r17, %r17, %r11", + "and %r18, %r9, %r10", + "or %r17, %r17, %r18", + "add %r8, %r8, %r17", + "lwz %r17, 52(%r6)", + "rlwinm %r16, %r17, 15, 0, 31", + "rlwinm %r18, %r17, 13, 0, 31", + "xor %r16, %r16, %r18", + "rlwinm %r18, %r17, 22, 10, 31", + "xor %r16, %r16, %r18", + "lwz %r18, 32(%r6)", + "add %r16, %r16, %r18", + "lwz %r17, 0(%r6)", + "rlwinm %r18, %r17, 25, 0, 31", + "rlwinm %r19, %r17, 14, 0, 31", + "xor %r18, %r18, %r19", + "rlwinm %r19, %r17, 29, 3, 31", + "xor %r18, %r18, %r19", + "add %r16, %r16, %r18", + "lwz %r18, 60(%r6)", + "add %r16, %r16, %r18", + "stw %r16, 60(%r6)", + "rlwinm %r17, %r12, 26, 0, 31", + "rlwinm %r18, %r12, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r12, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r7, %r7, %r17", + "xor %r17, %r14, %r15", + "and %r17, %r17, %r12", + "xor %r17, %r17, %r15", + "add %r7, %r7, %r17", + "lis %r17, 5161", + "ori %r17, %r17, 10599", + "add %r7, %r7, %r17", + "add %r7, %r7, %r16", + "add %r11, %r11, %r7", + "rlwinm %r17, %r8, 30, 0, 31", + "rlwinm %r18, %r8, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r8, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r7, %r7, %r17", + "or %r17, %r8, %r9", + "and %r17, %r17, %r10", + "and %r18, %r8, %r9", + "or %r17, %r17, %r18", + "add %r7, %r7, %r17", + "lwz %r17, 56(%r6)", + "rlwinm %r16, %r17, 15, 0, 31", + "rlwinm %r18, %r17, 13, 0, 31", + "xor %r16, %r16, %r18", + "rlwinm %r18, %r17, 22, 10, 31", + "xor %r16, %r16, %r18", + "lwz %r18, 36(%r6)", + "add %r16, %r16, %r18", + "lwz %r17, 4(%r6)", + "rlwinm %r18, %r17, 25, 0, 31", + "rlwinm %r19, %r17, 14, 0, 31", + "xor %r18, %r18, %r19", + "rlwinm %r19, %r17, 29, 3, 31", + "xor %r18, %r18, %r19", + "add %r16, %r16, %r18", + "lwz %r18, 0(%r6)", + "add %r16, %r16, %r18", + "stw %r16, 0(%r6)", + "rlwinm %r17, %r11, 26, 0, 31", + "rlwinm %r18, %r11, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r11, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r15, %r15, %r17", + "xor %r17, %r12, %r14", + "and %r17, %r17, %r11", + "xor %r17, %r17, %r14", + "add %r15, %r15, %r17", + "lis %r17, 10167", + "ori %r17, %r17, 2693", + "add %r15, %r15, %r17", + "add %r15, %r15, %r16", + "add %r10, %r10, %r15", + "rlwinm %r17, %r7, 30, 0, 31", + "rlwinm %r18, %r7, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r7, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r15, %r15, %r17", + "or %r17, %r7, %r8", + "and %r17, %r17, %r9", + "and %r18, %r7, %r8", + "or %r17, %r17, %r18", + "add %r15, %r15, %r17", + "lwz %r17, 60(%r6)", + "rlwinm %r16, %r17, 15, 0, 31", + "rlwinm %r18, %r17, 13, 0, 31", + "xor %r16, %r16, %r18", + "rlwinm %r18, %r17, 22, 10, 31", + "xor %r16, %r16, %r18", + "lwz %r18, 40(%r6)", + "add %r16, %r16, %r18", + "lwz %r17, 8(%r6)", + "rlwinm %r18, %r17, 25, 0, 31", + "rlwinm %r19, %r17, 14, 0, 31", + "xor %r18, %r18, %r19", + "rlwinm %r19, %r17, 29, 3, 31", + "xor %r18, %r18, %r19", + "add %r16, %r16, %r18", + "lwz %r18, 4(%r6)", + "add %r16, %r16, %r18", + "stw %r16, 4(%r6)", + "rlwinm %r17, %r10, 26, 0, 31", + "rlwinm %r18, %r10, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r10, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r14, %r14, %r17", + "xor %r17, %r11, %r12", + "and %r17, %r17, %r10", + "xor %r17, %r17, %r12", + "add %r14, %r14, %r17", + "lis %r17, 11803", + "ori %r17, %r17, 8504", + "add %r14, %r14, %r17", + "add %r14, %r14, %r16", + "add %r9, %r9, %r14", + "rlwinm %r17, %r15, 30, 0, 31", + "rlwinm %r18, %r15, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r15, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r14, %r14, %r17", + "or %r17, %r15, %r7", + "and %r17, %r17, %r8", + "and %r18, %r15, %r7", + "or %r17, %r17, %r18", + "add %r14, %r14, %r17", + "lwz %r17, 0(%r6)", + "rlwinm %r16, %r17, 15, 0, 31", + "rlwinm %r18, %r17, 13, 0, 31", + "xor %r16, %r16, %r18", + "rlwinm %r18, %r17, 22, 10, 31", + "xor %r16, %r16, %r18", + "lwz %r18, 44(%r6)", + "add %r16, %r16, %r18", + "lwz %r17, 12(%r6)", + "rlwinm %r18, %r17, 25, 0, 31", + "rlwinm %r19, %r17, 14, 0, 31", + "xor %r18, %r18, %r19", + "rlwinm %r19, %r17, 29, 3, 31", + "xor %r18, %r18, %r19", + "add %r16, %r16, %r18", + "lwz %r18, 8(%r6)", + "add %r16, %r16, %r18", + "stw %r16, 8(%r6)", + "rlwinm %r17, %r9, 26, 0, 31", + "rlwinm %r18, %r9, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r9, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r12, %r12, %r17", + "xor %r17, %r10, %r11", + "and %r17, %r17, %r9", + "xor %r17, %r17, %r11", + "add %r12, %r12, %r17", + "lis %r17, 19756", + "ori %r17, %r17, 28156", + "add %r12, %r12, %r17", + "add %r12, %r12, %r16", + "add %r8, %r8, %r12", + "rlwinm %r17, %r14, 30, 0, 31", + "rlwinm %r18, %r14, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r14, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r12, %r12, %r17", + "or %r17, %r14, %r15", + "and %r17, %r17, %r7", + "and %r18, %r14, %r15", + "or %r17, %r17, %r18", + "add %r12, %r12, %r17", + "lwz %r17, 4(%r6)", + "rlwinm %r16, %r17, 15, 0, 31", + "rlwinm %r18, %r17, 13, 0, 31", + "xor %r16, %r16, %r18", + "rlwinm %r18, %r17, 22, 10, 31", + "xor %r16, %r16, %r18", + "lwz %r18, 48(%r6)", + "add %r16, %r16, %r18", + "lwz %r17, 16(%r6)", + "rlwinm %r18, %r17, 25, 0, 31", + "rlwinm %r19, %r17, 14, 0, 31", + "xor %r18, %r18, %r19", + "rlwinm %r19, %r17, 29, 3, 31", + "xor %r18, %r18, %r19", + "add %r16, %r16, %r18", + "lwz %r18, 12(%r6)", + "add %r16, %r16, %r18", + "stw %r16, 12(%r6)", + "rlwinm %r17, %r8, 26, 0, 31", + "rlwinm %r18, %r8, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r8, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r11, %r11, %r17", + "xor %r17, %r9, %r10", + "and %r17, %r17, %r8", + "xor %r17, %r17, %r10", + "add %r11, %r11, %r17", + "lis %r17, 21304", + "ori %r17, %r17, 3347", + "add %r11, %r11, %r17", + "add %r11, %r11, %r16", + "add %r7, %r7, %r11", + "rlwinm %r17, %r12, 30, 0, 31", + "rlwinm %r18, %r12, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r12, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r11, %r11, %r17", + "or %r17, %r12, %r14", + "and %r17, %r17, %r15", + "and %r18, %r12, %r14", + "or %r17, %r17, %r18", + "add %r11, %r11, %r17", + "lwz %r17, 8(%r6)", + "rlwinm %r16, %r17, 15, 0, 31", + "rlwinm %r18, %r17, 13, 0, 31", + "xor %r16, %r16, %r18", + "rlwinm %r18, %r17, 22, 10, 31", + "xor %r16, %r16, %r18", + "lwz %r18, 52(%r6)", + "add %r16, %r16, %r18", + "lwz %r17, 20(%r6)", + "rlwinm %r18, %r17, 25, 0, 31", + "rlwinm %r19, %r17, 14, 0, 31", + "xor %r18, %r18, %r19", + "rlwinm %r19, %r17, 29, 3, 31", + "xor %r18, %r18, %r19", + "add %r16, %r16, %r18", + "lwz %r18, 16(%r6)", + "add %r16, %r16, %r18", + "stw %r16, 16(%r6)", + "rlwinm %r17, %r7, 26, 0, 31", + "rlwinm %r18, %r7, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r7, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r10, %r10, %r17", + "xor %r17, %r8, %r9", + "and %r17, %r17, %r7", + "xor %r17, %r17, %r9", + "add %r10, %r10, %r17", + "lis %r17, 25866", + "ori %r17, %r17, 29524", + "add %r10, %r10, %r17", + "add %r10, %r10, %r16", + "add %r15, %r15, %r10", + "rlwinm %r17, %r11, 30, 0, 31", + "rlwinm %r18, %r11, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r11, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r10, %r10, %r17", + "or %r17, %r11, %r12", + "and %r17, %r17, %r14", + "and %r18, %r11, %r12", + "or %r17, %r17, %r18", + "add %r10, %r10, %r17", + "lwz %r17, 12(%r6)", + "rlwinm %r16, %r17, 15, 0, 31", + "rlwinm %r18, %r17, 13, 0, 31", + "xor %r16, %r16, %r18", + "rlwinm %r18, %r17, 22, 10, 31", + "xor %r16, %r16, %r18", + "lwz %r18, 56(%r6)", + "add %r16, %r16, %r18", + "lwz %r17, 24(%r6)", + "rlwinm %r18, %r17, 25, 0, 31", + "rlwinm %r19, %r17, 14, 0, 31", + "xor %r18, %r18, %r19", + "rlwinm %r19, %r17, 29, 3, 31", + "xor %r18, %r18, %r19", + "add %r16, %r16, %r18", + "lwz %r18, 20(%r6)", + "add %r16, %r16, %r18", + "stw %r16, 20(%r6)", + "rlwinm %r17, %r15, 26, 0, 31", + "rlwinm %r18, %r15, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r15, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r9, %r9, %r17", + "xor %r17, %r7, %r8", + "and %r17, %r17, %r15", + "xor %r17, %r17, %r8", + "add %r9, %r9, %r17", + "lis %r17, 30314", + "ori %r17, %r17, 2747", + "add %r9, %r9, %r17", + "add %r9, %r9, %r16", + "add %r14, %r14, %r9", + "rlwinm %r17, %r10, 30, 0, 31", + "rlwinm %r18, %r10, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r10, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r9, %r9, %r17", + "or %r17, %r10, %r11", + "and %r17, %r17, %r12", + "and %r18, %r10, %r11", + "or %r17, %r17, %r18", + "add %r9, %r9, %r17", + "lwz %r17, 16(%r6)", + "rlwinm %r16, %r17, 15, 0, 31", + "rlwinm %r18, %r17, 13, 0, 31", + "xor %r16, %r16, %r18", + "rlwinm %r18, %r17, 22, 10, 31", + "xor %r16, %r16, %r18", + "lwz %r18, 60(%r6)", + "add %r16, %r16, %r18", + "lwz %r17, 28(%r6)", + "rlwinm %r18, %r17, 25, 0, 31", + "rlwinm %r19, %r17, 14, 0, 31", + "xor %r18, %r18, %r19", + "rlwinm %r19, %r17, 29, 3, 31", + "xor %r18, %r18, %r19", + "add %r16, %r16, %r18", + "lwz %r18, 24(%r6)", + "add %r16, %r16, %r18", + "stw %r16, 24(%r6)", + "rlwinm %r17, %r14, 26, 0, 31", + "rlwinm %r18, %r14, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r14, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r8, %r8, %r17", + "xor %r17, %r15, %r7", + "and %r17, %r17, %r14", + "xor %r17, %r17, %r7", + "add %r8, %r8, %r17", + "lis %r17, -32318", + "ori %r17, %r17, 51502", + "add %r8, %r8, %r17", + "add %r8, %r8, %r16", + "add %r12, %r12, %r8", + "rlwinm %r17, %r9, 30, 0, 31", + "rlwinm %r18, %r9, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r9, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r8, %r8, %r17", + "or %r17, %r9, %r10", + "and %r17, %r17, %r11", + "and %r18, %r9, %r10", + "or %r17, %r17, %r18", + "add %r8, %r8, %r17", + "lwz %r17, 20(%r6)", + "rlwinm %r16, %r17, 15, 0, 31", + "rlwinm %r18, %r17, 13, 0, 31", + "xor %r16, %r16, %r18", + "rlwinm %r18, %r17, 22, 10, 31", + "xor %r16, %r16, %r18", + "lwz %r18, 0(%r6)", + "add %r16, %r16, %r18", + "lwz %r17, 32(%r6)", + "rlwinm %r18, %r17, 25, 0, 31", + "rlwinm %r19, %r17, 14, 0, 31", + "xor %r18, %r18, %r19", + "rlwinm %r19, %r17, 29, 3, 31", + "xor %r18, %r18, %r19", + "add %r16, %r16, %r18", + "lwz %r18, 28(%r6)", + "add %r16, %r16, %r18", + "stw %r16, 28(%r6)", + "rlwinm %r17, %r12, 26, 0, 31", + "rlwinm %r18, %r12, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r12, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r7, %r7, %r17", + "xor %r17, %r14, %r15", + "and %r17, %r17, %r12", + "xor %r17, %r17, %r15", + "add %r7, %r7, %r17", + "lis %r17, -28046", + "ori %r17, %r17, 11397", + "add %r7, %r7, %r17", + "add %r7, %r7, %r16", + "add %r11, %r11, %r7", + "rlwinm %r17, %r8, 30, 0, 31", + "rlwinm %r18, %r8, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r8, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r7, %r7, %r17", + "or %r17, %r8, %r9", + "and %r17, %r17, %r10", + "and %r18, %r8, %r9", + "or %r17, %r17, %r18", + "add %r7, %r7, %r17", + "lwz %r17, 24(%r6)", + "rlwinm %r16, %r17, 15, 0, 31", + "rlwinm %r18, %r17, 13, 0, 31", + "xor %r16, %r16, %r18", + "rlwinm %r18, %r17, 22, 10, 31", + "xor %r16, %r16, %r18", + "lwz %r18, 4(%r6)", + "add %r16, %r16, %r18", + "lwz %r17, 36(%r6)", + "rlwinm %r18, %r17, 25, 0, 31", + "rlwinm %r19, %r17, 14, 0, 31", + "xor %r18, %r18, %r19", + "rlwinm %r19, %r17, 29, 3, 31", + "xor %r18, %r18, %r19", + "add %r16, %r16, %r18", + "lwz %r18, 32(%r6)", + "add %r16, %r16, %r18", + "stw %r16, 32(%r6)", + "rlwinm %r17, %r11, 26, 0, 31", + "rlwinm %r18, %r11, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r11, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r15, %r15, %r17", + "xor %r17, %r12, %r14", + "and %r17, %r17, %r11", + "xor %r17, %r17, %r14", + "add %r15, %r15, %r17", + "lis %r17, -23873", + "ori %r17, %r17, 59553", + "add %r15, %r15, %r17", + "add %r15, %r15, %r16", + "add %r10, %r10, %r15", + "rlwinm %r17, %r7, 30, 0, 31", + "rlwinm %r18, %r7, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r7, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r15, %r15, %r17", + "or %r17, %r7, %r8", + "and %r17, %r17, %r9", + "and %r18, %r7, %r8", + "or %r17, %r17, %r18", + "add %r15, %r15, %r17", + "lwz %r17, 28(%r6)", + "rlwinm %r16, %r17, 15, 0, 31", + "rlwinm %r18, %r17, 13, 0, 31", + "xor %r16, %r16, %r18", + "rlwinm %r18, %r17, 22, 10, 31", + "xor %r16, %r16, %r18", + "lwz %r18, 8(%r6)", + "add %r16, %r16, %r18", + "lwz %r17, 40(%r6)", + "rlwinm %r18, %r17, 25, 0, 31", + "rlwinm %r19, %r17, 14, 0, 31", + "xor %r18, %r18, %r19", + "rlwinm %r19, %r17, 29, 3, 31", + "xor %r18, %r18, %r19", + "add %r16, %r16, %r18", + "lwz %r18, 36(%r6)", + "add %r16, %r16, %r18", + "stw %r16, 36(%r6)", + "rlwinm %r17, %r10, 26, 0, 31", + "rlwinm %r18, %r10, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r10, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r14, %r14, %r17", + "xor %r17, %r11, %r12", + "and %r17, %r17, %r10", + "xor %r17, %r17, %r12", + "add %r14, %r14, %r17", + "lis %r17, -22502", + "ori %r17, %r17, 26187", + "add %r14, %r14, %r17", + "add %r14, %r14, %r16", + "add %r9, %r9, %r14", + "rlwinm %r17, %r15, 30, 0, 31", + "rlwinm %r18, %r15, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r15, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r14, %r14, %r17", + "or %r17, %r15, %r7", + "and %r17, %r17, %r8", + "and %r18, %r15, %r7", + "or %r17, %r17, %r18", + "add %r14, %r14, %r17", + "lwz %r17, 32(%r6)", + "rlwinm %r16, %r17, 15, 0, 31", + "rlwinm %r18, %r17, 13, 0, 31", + "xor %r16, %r16, %r18", + "rlwinm %r18, %r17, 22, 10, 31", + "xor %r16, %r16, %r18", + "lwz %r18, 12(%r6)", + "add %r16, %r16, %r18", + "lwz %r17, 44(%r6)", + "rlwinm %r18, %r17, 25, 0, 31", + "rlwinm %r19, %r17, 14, 0, 31", + "xor %r18, %r18, %r19", + "rlwinm %r19, %r17, 29, 3, 31", + "xor %r18, %r18, %r19", + "add %r16, %r16, %r18", + "lwz %r18, 40(%r6)", + "add %r16, %r16, %r18", + "stw %r16, 40(%r6)", + "rlwinm %r17, %r9, 26, 0, 31", + "rlwinm %r18, %r9, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r9, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r12, %r12, %r17", + "xor %r17, %r10, %r11", + "and %r17, %r17, %r9", + "xor %r17, %r17, %r11", + "add %r12, %r12, %r17", + "lis %r17, -15797", + "ori %r17, %r17, 35696", + "add %r12, %r12, %r17", + "add %r12, %r12, %r16", + "add %r8, %r8, %r12", + "rlwinm %r17, %r14, 30, 0, 31", + "rlwinm %r18, %r14, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r14, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r12, %r12, %r17", + "or %r17, %r14, %r15", + "and %r17, %r17, %r7", + "and %r18, %r14, %r15", + "or %r17, %r17, %r18", + "add %r12, %r12, %r17", + "lwz %r17, 36(%r6)", + "rlwinm %r16, %r17, 15, 0, 31", + "rlwinm %r18, %r17, 13, 0, 31", + "xor %r16, %r16, %r18", + "rlwinm %r18, %r17, 22, 10, 31", + "xor %r16, %r16, %r18", + "lwz %r18, 16(%r6)", + "add %r16, %r16, %r18", + "lwz %r17, 48(%r6)", + "rlwinm %r18, %r17, 25, 0, 31", + "rlwinm %r19, %r17, 14, 0, 31", + "xor %r18, %r18, %r19", + "rlwinm %r19, %r17, 29, 3, 31", + "xor %r18, %r18, %r19", + "add %r16, %r16, %r18", + "lwz %r18, 44(%r6)", + "add %r16, %r16, %r18", + "stw %r16, 44(%r6)", + "rlwinm %r17, %r8, 26, 0, 31", + "rlwinm %r18, %r8, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r8, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r11, %r11, %r17", + "xor %r17, %r9, %r10", + "and %r17, %r17, %r8", + "xor %r17, %r17, %r10", + "add %r11, %r11, %r17", + "lis %r17, -14484", + "ori %r17, %r17, 20899", + "add %r11, %r11, %r17", + "add %r11, %r11, %r16", + "add %r7, %r7, %r11", + "rlwinm %r17, %r12, 30, 0, 31", + "rlwinm %r18, %r12, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r12, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r11, %r11, %r17", + "or %r17, %r12, %r14", + "and %r17, %r17, %r15", + "and %r18, %r12, %r14", + "or %r17, %r17, %r18", + "add %r11, %r11, %r17", + "lwz %r17, 40(%r6)", + "rlwinm %r16, %r17, 15, 0, 31", + "rlwinm %r18, %r17, 13, 0, 31", + "xor %r16, %r16, %r18", + "rlwinm %r18, %r17, 22, 10, 31", + "xor %r16, %r16, %r18", + "lwz %r18, 20(%r6)", + "add %r16, %r16, %r18", + "lwz %r17, 52(%r6)", + "rlwinm %r18, %r17, 25, 0, 31", + "rlwinm %r19, %r17, 14, 0, 31", + "xor %r18, %r18, %r19", + "rlwinm %r19, %r17, 29, 3, 31", + "xor %r18, %r18, %r19", + "add %r16, %r16, %r18", + "lwz %r18, 48(%r6)", + "add %r16, %r16, %r18", + "stw %r16, 48(%r6)", + "rlwinm %r17, %r7, 26, 0, 31", + "rlwinm %r18, %r7, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r7, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r10, %r10, %r17", + "xor %r17, %r8, %r9", + "and %r17, %r17, %r7", + "xor %r17, %r17, %r9", + "add %r10, %r10, %r17", + "lis %r17, -11886", + "ori %r17, %r17, 59417", + "add %r10, %r10, %r17", + "add %r10, %r10, %r16", + "add %r15, %r15, %r10", + "rlwinm %r17, %r11, 30, 0, 31", + "rlwinm %r18, %r11, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r11, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r10, %r10, %r17", + "or %r17, %r11, %r12", + "and %r17, %r17, %r14", + "and %r18, %r11, %r12", + "or %r17, %r17, %r18", + "add %r10, %r10, %r17", + "lwz %r17, 44(%r6)", + "rlwinm %r16, %r17, 15, 0, 31", + "rlwinm %r18, %r17, 13, 0, 31", + "xor %r16, %r16, %r18", + "rlwinm %r18, %r17, 22, 10, 31", + "xor %r16, %r16, %r18", + "lwz %r18, 24(%r6)", + "add %r16, %r16, %r18", + "lwz %r17, 56(%r6)", + "rlwinm %r18, %r17, 25, 0, 31", + "rlwinm %r19, %r17, 14, 0, 31", + "xor %r18, %r18, %r19", + "rlwinm %r19, %r17, 29, 3, 31", + "xor %r18, %r18, %r19", + "add %r16, %r16, %r18", + "lwz %r18, 52(%r6)", + "add %r16, %r16, %r18", + "stw %r16, 52(%r6)", + "rlwinm %r17, %r15, 26, 0, 31", + "rlwinm %r18, %r15, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r15, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r9, %r9, %r17", + "xor %r17, %r7, %r8", + "and %r17, %r17, %r15", + "xor %r17, %r17, %r8", + "add %r9, %r9, %r17", + "lis %r17, -10599", + "ori %r17, %r17, 1572", + "add %r9, %r9, %r17", + "add %r9, %r9, %r16", + "add %r14, %r14, %r9", + "rlwinm %r17, %r10, 30, 0, 31", + "rlwinm %r18, %r10, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r10, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r9, %r9, %r17", + "or %r17, %r10, %r11", + "and %r17, %r17, %r12", + "and %r18, %r10, %r11", + "or %r17, %r17, %r18", + "add %r9, %r9, %r17", + "lwz %r17, 48(%r6)", + "rlwinm %r16, %r17, 15, 0, 31", + "rlwinm %r18, %r17, 13, 0, 31", + "xor %r16, %r16, %r18", + "rlwinm %r18, %r17, 22, 10, 31", + "xor %r16, %r16, %r18", + "lwz %r18, 28(%r6)", + "add %r16, %r16, %r18", + "lwz %r17, 60(%r6)", + "rlwinm %r18, %r17, 25, 0, 31", + "rlwinm %r19, %r17, 14, 0, 31", + "xor %r18, %r18, %r19", + "rlwinm %r19, %r17, 29, 3, 31", + "xor %r18, %r18, %r19", + "add %r16, %r16, %r18", + "lwz %r18, 56(%r6)", + "add %r16, %r16, %r18", + "stw %r16, 56(%r6)", + "rlwinm %r17, %r14, 26, 0, 31", + "rlwinm %r18, %r14, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r14, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r8, %r8, %r17", + "xor %r17, %r15, %r7", + "and %r17, %r17, %r14", + "xor %r17, %r17, %r7", + "add %r8, %r8, %r17", + "lis %r17, -3058", + "ori %r17, %r17, 13701", + "add %r8, %r8, %r17", + "add %r8, %r8, %r16", + "add %r12, %r12, %r8", + "rlwinm %r17, %r9, 30, 0, 31", + "rlwinm %r18, %r9, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r9, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r8, %r8, %r17", + "or %r17, %r9, %r10", + "and %r17, %r17, %r11", + "and %r18, %r9, %r10", + "or %r17, %r17, %r18", + "add %r8, %r8, %r17", + "lwz %r17, 52(%r6)", + "rlwinm %r16, %r17, 15, 0, 31", + "rlwinm %r18, %r17, 13, 0, 31", + "xor %r16, %r16, %r18", + "rlwinm %r18, %r17, 22, 10, 31", + "xor %r16, %r16, %r18", + "lwz %r18, 32(%r6)", + "add %r16, %r16, %r18", + "lwz %r17, 0(%r6)", + "rlwinm %r18, %r17, 25, 0, 31", + "rlwinm %r19, %r17, 14, 0, 31", + "xor %r18, %r18, %r19", + "rlwinm %r19, %r17, 29, 3, 31", + "xor %r18, %r18, %r19", + "add %r16, %r16, %r18", + "lwz %r18, 60(%r6)", + "add %r16, %r16, %r18", + "stw %r16, 60(%r6)", + "rlwinm %r17, %r12, 26, 0, 31", + "rlwinm %r18, %r12, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r12, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r7, %r7, %r17", + "xor %r17, %r14, %r15", + "and %r17, %r17, %r12", + "xor %r17, %r17, %r15", + "add %r7, %r7, %r17", + "lis %r17, 4202", + "ori %r17, %r17, 41072", + "add %r7, %r7, %r17", + "add %r7, %r7, %r16", + "add %r11, %r11, %r7", + "rlwinm %r17, %r8, 30, 0, 31", + "rlwinm %r18, %r8, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r8, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r7, %r7, %r17", + "or %r17, %r8, %r9", + "and %r17, %r17, %r10", + "and %r18, %r8, %r9", + "or %r17, %r17, %r18", + "add %r7, %r7, %r17", + "lwz %r17, 56(%r6)", + "rlwinm %r16, %r17, 15, 0, 31", + "rlwinm %r18, %r17, 13, 0, 31", + "xor %r16, %r16, %r18", + "rlwinm %r18, %r17, 22, 10, 31", + "xor %r16, %r16, %r18", + "lwz %r18, 36(%r6)", + "add %r16, %r16, %r18", + "lwz %r17, 4(%r6)", + "rlwinm %r18, %r17, 25, 0, 31", + "rlwinm %r19, %r17, 14, 0, 31", + "xor %r18, %r18, %r19", + "rlwinm %r19, %r17, 29, 3, 31", + "xor %r18, %r18, %r19", + "add %r16, %r16, %r18", + "lwz %r18, 0(%r6)", + "add %r16, %r16, %r18", + "stw %r16, 0(%r6)", + "rlwinm %r17, %r11, 26, 0, 31", + "rlwinm %r18, %r11, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r11, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r15, %r15, %r17", + "xor %r17, %r12, %r14", + "and %r17, %r17, %r11", + "xor %r17, %r17, %r14", + "add %r15, %r15, %r17", + "lis %r17, 6564", + "ori %r17, %r17, 49430", + "add %r15, %r15, %r17", + "add %r15, %r15, %r16", + "add %r10, %r10, %r15", + "rlwinm %r17, %r7, 30, 0, 31", + "rlwinm %r18, %r7, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r7, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r15, %r15, %r17", + "or %r17, %r7, %r8", + "and %r17, %r17, %r9", + "and %r18, %r7, %r8", + "or %r17, %r17, %r18", + "add %r15, %r15, %r17", + "lwz %r17, 60(%r6)", + "rlwinm %r16, %r17, 15, 0, 31", + "rlwinm %r18, %r17, 13, 0, 31", + "xor %r16, %r16, %r18", + "rlwinm %r18, %r17, 22, 10, 31", + "xor %r16, %r16, %r18", + "lwz %r18, 40(%r6)", + "add %r16, %r16, %r18", + "lwz %r17, 8(%r6)", + "rlwinm %r18, %r17, 25, 0, 31", + "rlwinm %r19, %r17, 14, 0, 31", + "xor %r18, %r18, %r19", + "rlwinm %r19, %r17, 29, 3, 31", + "xor %r18, %r18, %r19", + "add %r16, %r16, %r18", + "lwz %r18, 4(%r6)", + "add %r16, %r16, %r18", + "stw %r16, 4(%r6)", + "rlwinm %r17, %r10, 26, 0, 31", + "rlwinm %r18, %r10, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r10, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r14, %r14, %r17", + "xor %r17, %r11, %r12", + "and %r17, %r17, %r10", + "xor %r17, %r17, %r12", + "add %r14, %r14, %r17", + "lis %r17, 7735", + "ori %r17, %r17, 27656", + "add %r14, %r14, %r17", + "add %r14, %r14, %r16", + "add %r9, %r9, %r14", + "rlwinm %r17, %r15, 30, 0, 31", + "rlwinm %r18, %r15, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r15, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r14, %r14, %r17", + "or %r17, %r15, %r7", + "and %r17, %r17, %r8", + "and %r18, %r15, %r7", + "or %r17, %r17, %r18", + "add %r14, %r14, %r17", + "lwz %r17, 0(%r6)", + "rlwinm %r16, %r17, 15, 0, 31", + "rlwinm %r18, %r17, 13, 0, 31", + "xor %r16, %r16, %r18", + "rlwinm %r18, %r17, 22, 10, 31", + "xor %r16, %r16, %r18", + "lwz %r18, 44(%r6)", + "add %r16, %r16, %r18", + "lwz %r17, 12(%r6)", + "rlwinm %r18, %r17, 25, 0, 31", + "rlwinm %r19, %r17, 14, 0, 31", + "xor %r18, %r18, %r19", + "rlwinm %r19, %r17, 29, 3, 31", + "xor %r18, %r18, %r19", + "add %r16, %r16, %r18", + "lwz %r18, 8(%r6)", + "add %r16, %r16, %r18", + "stw %r16, 8(%r6)", + "rlwinm %r17, %r9, 26, 0, 31", + "rlwinm %r18, %r9, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r9, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r12, %r12, %r17", + "xor %r17, %r10, %r11", + "and %r17, %r17, %r9", + "xor %r17, %r17, %r11", + "add %r12, %r12, %r17", + "lis %r17, 10056", + "ori %r17, %r17, 30540", + "add %r12, %r12, %r17", + "add %r12, %r12, %r16", + "add %r8, %r8, %r12", + "rlwinm %r17, %r14, 30, 0, 31", + "rlwinm %r18, %r14, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r14, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r12, %r12, %r17", + "or %r17, %r14, %r15", + "and %r17, %r17, %r7", + "and %r18, %r14, %r15", + "or %r17, %r17, %r18", + "add %r12, %r12, %r17", + "lwz %r17, 4(%r6)", + "rlwinm %r16, %r17, 15, 0, 31", + "rlwinm %r18, %r17, 13, 0, 31", + "xor %r16, %r16, %r18", + "rlwinm %r18, %r17, 22, 10, 31", + "xor %r16, %r16, %r18", + "lwz %r18, 48(%r6)", + "add %r16, %r16, %r18", + "lwz %r17, 16(%r6)", + "rlwinm %r18, %r17, 25, 0, 31", + "rlwinm %r19, %r17, 14, 0, 31", + "xor %r18, %r18, %r19", + "rlwinm %r19, %r17, 29, 3, 31", + "xor %r18, %r18, %r19", + "add %r16, %r16, %r18", + "lwz %r18, 12(%r6)", + "add %r16, %r16, %r18", + "stw %r16, 12(%r6)", + "rlwinm %r17, %r8, 26, 0, 31", + "rlwinm %r18, %r8, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r8, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r11, %r11, %r17", + "xor %r17, %r9, %r10", + "and %r17, %r17, %r8", + "xor %r17, %r17, %r10", + "add %r11, %r11, %r17", + "lis %r17, 13488", + "ori %r17, %r17, 48309", + "add %r11, %r11, %r17", + "add %r11, %r11, %r16", + "add %r7, %r7, %r11", + "rlwinm %r17, %r12, 30, 0, 31", + "rlwinm %r18, %r12, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r12, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r11, %r11, %r17", + "or %r17, %r12, %r14", + "and %r17, %r17, %r15", + "and %r18, %r12, %r14", + "or %r17, %r17, %r18", + "add %r11, %r11, %r17", + "lwz %r17, 8(%r6)", + "rlwinm %r16, %r17, 15, 0, 31", + "rlwinm %r18, %r17, 13, 0, 31", + "xor %r16, %r16, %r18", + "rlwinm %r18, %r17, 22, 10, 31", + "xor %r16, %r16, %r18", + "lwz %r18, 52(%r6)", + "add %r16, %r16, %r18", + "lwz %r17, 20(%r6)", + "rlwinm %r18, %r17, 25, 0, 31", + "rlwinm %r19, %r17, 14, 0, 31", + "xor %r18, %r18, %r19", + "rlwinm %r19, %r17, 29, 3, 31", + "xor %r18, %r18, %r19", + "add %r16, %r16, %r18", + "lwz %r18, 16(%r6)", + "add %r16, %r16, %r18", + "stw %r16, 16(%r6)", + "rlwinm %r17, %r7, 26, 0, 31", + "rlwinm %r18, %r7, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r7, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r10, %r10, %r17", + "xor %r17, %r8, %r9", + "and %r17, %r17, %r7", + "xor %r17, %r17, %r9", + "add %r10, %r10, %r17", + "lis %r17, 14620", + "ori %r17, %r17, 3251", + "add %r10, %r10, %r17", + "add %r10, %r10, %r16", + "add %r15, %r15, %r10", + "rlwinm %r17, %r11, 30, 0, 31", + "rlwinm %r18, %r11, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r11, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r10, %r10, %r17", + "or %r17, %r11, %r12", + "and %r17, %r17, %r14", + "and %r18, %r11, %r12", + "or %r17, %r17, %r18", + "add %r10, %r10, %r17", + "lwz %r17, 12(%r6)", + "rlwinm %r16, %r17, 15, 0, 31", + "rlwinm %r18, %r17, 13, 0, 31", + "xor %r16, %r16, %r18", + "rlwinm %r18, %r17, 22, 10, 31", + "xor %r16, %r16, %r18", + "lwz %r18, 56(%r6)", + "add %r16, %r16, %r18", + "lwz %r17, 24(%r6)", + "rlwinm %r18, %r17, 25, 0, 31", + "rlwinm %r19, %r17, 14, 0, 31", + "xor %r18, %r18, %r19", + "rlwinm %r19, %r17, 29, 3, 31", + "xor %r18, %r18, %r19", + "add %r16, %r16, %r18", + "lwz %r18, 20(%r6)", + "add %r16, %r16, %r18", + "stw %r16, 20(%r6)", + "rlwinm %r17, %r15, 26, 0, 31", + "rlwinm %r18, %r15, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r15, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r9, %r9, %r17", + "xor %r17, %r7, %r8", + "and %r17, %r17, %r15", + "xor %r17, %r17, %r8", + "add %r9, %r9, %r17", + "lis %r17, 20184", + "ori %r17, %r17, 43594", + "add %r9, %r9, %r17", + "add %r9, %r9, %r16", + "add %r14, %r14, %r9", + "rlwinm %r17, %r10, 30, 0, 31", + "rlwinm %r18, %r10, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r10, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r9, %r9, %r17", + "or %r17, %r10, %r11", + "and %r17, %r17, %r12", + "and %r18, %r10, %r11", + "or %r17, %r17, %r18", + "add %r9, %r9, %r17", + "lwz %r17, 16(%r6)", + "rlwinm %r16, %r17, 15, 0, 31", + "rlwinm %r18, %r17, 13, 0, 31", + "xor %r16, %r16, %r18", + "rlwinm %r18, %r17, 22, 10, 31", + "xor %r16, %r16, %r18", + "lwz %r18, 60(%r6)", + "add %r16, %r16, %r18", + "lwz %r17, 28(%r6)", + "rlwinm %r18, %r17, 25, 0, 31", + "rlwinm %r19, %r17, 14, 0, 31", + "xor %r18, %r18, %r19", + "rlwinm %r19, %r17, 29, 3, 31", + "xor %r18, %r18, %r19", + "add %r16, %r16, %r18", + "lwz %r18, 24(%r6)", + "add %r16, %r16, %r18", + "stw %r16, 24(%r6)", + "rlwinm %r17, %r14, 26, 0, 31", + "rlwinm %r18, %r14, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r14, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r8, %r8, %r17", + "xor %r17, %r15, %r7", + "and %r17, %r17, %r14", + "xor %r17, %r17, %r7", + "add %r8, %r8, %r17", + "lis %r17, 23452", + "ori %r17, %r17, 51791", + "add %r8, %r8, %r17", + "add %r8, %r8, %r16", + "add %r12, %r12, %r8", + "rlwinm %r17, %r9, 30, 0, 31", + "rlwinm %r18, %r9, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r9, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r8, %r8, %r17", + "or %r17, %r9, %r10", + "and %r17, %r17, %r11", + "and %r18, %r9, %r10", + "or %r17, %r17, %r18", + "add %r8, %r8, %r17", + "lwz %r17, 20(%r6)", + "rlwinm %r16, %r17, 15, 0, 31", + "rlwinm %r18, %r17, 13, 0, 31", + "xor %r16, %r16, %r18", + "rlwinm %r18, %r17, 22, 10, 31", + "xor %r16, %r16, %r18", + "lwz %r18, 0(%r6)", + "add %r16, %r16, %r18", + "lwz %r17, 32(%r6)", + "rlwinm %r18, %r17, 25, 0, 31", + "rlwinm %r19, %r17, 14, 0, 31", + "xor %r18, %r18, %r19", + "rlwinm %r19, %r17, 29, 3, 31", + "xor %r18, %r18, %r19", + "add %r16, %r16, %r18", + "lwz %r18, 28(%r6)", + "add %r16, %r16, %r18", + "stw %r16, 28(%r6)", + "rlwinm %r17, %r12, 26, 0, 31", + "rlwinm %r18, %r12, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r12, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r7, %r7, %r17", + "xor %r17, %r14, %r15", + "and %r17, %r17, %r12", + "xor %r17, %r17, %r15", + "add %r7, %r7, %r17", + "lis %r17, 26670", + "ori %r17, %r17, 28659", + "add %r7, %r7, %r17", + "add %r7, %r7, %r16", + "add %r11, %r11, %r7", + "rlwinm %r17, %r8, 30, 0, 31", + "rlwinm %r18, %r8, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r8, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r7, %r7, %r17", + "or %r17, %r8, %r9", + "and %r17, %r17, %r10", + "and %r18, %r8, %r9", + "or %r17, %r17, %r18", + "add %r7, %r7, %r17", + "lwz %r17, 24(%r6)", + "rlwinm %r16, %r17, 15, 0, 31", + "rlwinm %r18, %r17, 13, 0, 31", + "xor %r16, %r16, %r18", + "rlwinm %r18, %r17, 22, 10, 31", + "xor %r16, %r16, %r18", + "lwz %r18, 4(%r6)", + "add %r16, %r16, %r18", + "lwz %r17, 36(%r6)", + "rlwinm %r18, %r17, 25, 0, 31", + "rlwinm %r19, %r17, 14, 0, 31", + "xor %r18, %r18, %r19", + "rlwinm %r19, %r17, 29, 3, 31", + "xor %r18, %r18, %r19", + "add %r16, %r16, %r18", + "lwz %r18, 32(%r6)", + "add %r16, %r16, %r18", + "stw %r16, 32(%r6)", + "rlwinm %r17, %r11, 26, 0, 31", + "rlwinm %r18, %r11, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r11, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r15, %r15, %r17", + "xor %r17, %r12, %r14", + "and %r17, %r17, %r11", + "xor %r17, %r17, %r14", + "add %r15, %r15, %r17", + "lis %r17, 29839", + "ori %r17, %r17, 33518", + "add %r15, %r15, %r17", + "add %r15, %r15, %r16", + "add %r10, %r10, %r15", + "rlwinm %r17, %r7, 30, 0, 31", + "rlwinm %r18, %r7, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r7, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r15, %r15, %r17", + "or %r17, %r7, %r8", + "and %r17, %r17, %r9", + "and %r18, %r7, %r8", + "or %r17, %r17, %r18", + "add %r15, %r15, %r17", + "lwz %r17, 28(%r6)", + "rlwinm %r16, %r17, 15, 0, 31", + "rlwinm %r18, %r17, 13, 0, 31", + "xor %r16, %r16, %r18", + "rlwinm %r18, %r17, 22, 10, 31", + "xor %r16, %r16, %r18", + "lwz %r18, 8(%r6)", + "add %r16, %r16, %r18", + "lwz %r17, 40(%r6)", + "rlwinm %r18, %r17, 25, 0, 31", + "rlwinm %r19, %r17, 14, 0, 31", + "xor %r18, %r18, %r19", + "rlwinm %r19, %r17, 29, 3, 31", + "xor %r18, %r18, %r19", + "add %r16, %r16, %r18", + "lwz %r18, 36(%r6)", + "add %r16, %r16, %r18", + "stw %r16, 36(%r6)", + "rlwinm %r17, %r10, 26, 0, 31", + "rlwinm %r18, %r10, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r10, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r14, %r14, %r17", + "xor %r17, %r11, %r12", + "and %r17, %r17, %r10", + "xor %r17, %r17, %r12", + "add %r14, %r14, %r17", + "lis %r17, 30885", + "ori %r17, %r17, 25455", + "add %r14, %r14, %r17", + "add %r14, %r14, %r16", + "add %r9, %r9, %r14", + "rlwinm %r17, %r15, 30, 0, 31", + "rlwinm %r18, %r15, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r15, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r14, %r14, %r17", + "or %r17, %r15, %r7", + "and %r17, %r17, %r8", + "and %r18, %r15, %r7", + "or %r17, %r17, %r18", + "add %r14, %r14, %r17", + "lwz %r17, 32(%r6)", + "rlwinm %r16, %r17, 15, 0, 31", + "rlwinm %r18, %r17, 13, 0, 31", + "xor %r16, %r16, %r18", + "rlwinm %r18, %r17, 22, 10, 31", + "xor %r16, %r16, %r18", + "lwz %r18, 12(%r6)", + "add %r16, %r16, %r18", + "lwz %r17, 44(%r6)", + "rlwinm %r18, %r17, 25, 0, 31", + "rlwinm %r19, %r17, 14, 0, 31", + "xor %r18, %r18, %r19", + "rlwinm %r19, %r17, 29, 3, 31", + "xor %r18, %r18, %r19", + "add %r16, %r16, %r18", + "lwz %r18, 40(%r6)", + "add %r16, %r16, %r18", + "stw %r16, 40(%r6)", + "rlwinm %r17, %r9, 26, 0, 31", + "rlwinm %r18, %r9, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r9, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r12, %r12, %r17", + "xor %r17, %r10, %r11", + "and %r17, %r17, %r9", + "xor %r17, %r17, %r11", + "add %r12, %r12, %r17", + "lis %r17, -31544", + "ori %r17, %r17, 30740", + "add %r12, %r12, %r17", + "add %r12, %r12, %r16", + "add %r8, %r8, %r12", + "rlwinm %r17, %r14, 30, 0, 31", + "rlwinm %r18, %r14, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r14, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r12, %r12, %r17", + "or %r17, %r14, %r15", + "and %r17, %r17, %r7", + "and %r18, %r14, %r15", + "or %r17, %r17, %r18", + "add %r12, %r12, %r17", + "lwz %r17, 36(%r6)", + "rlwinm %r16, %r17, 15, 0, 31", + "rlwinm %r18, %r17, 13, 0, 31", + "xor %r16, %r16, %r18", + "rlwinm %r18, %r17, 22, 10, 31", + "xor %r16, %r16, %r18", + "lwz %r18, 16(%r6)", + "add %r16, %r16, %r18", + "lwz %r17, 48(%r6)", + "rlwinm %r18, %r17, 25, 0, 31", + "rlwinm %r19, %r17, 14, 0, 31", + "xor %r18, %r18, %r19", + "rlwinm %r19, %r17, 29, 3, 31", + "xor %r18, %r18, %r19", + "add %r16, %r16, %r18", + "lwz %r18, 44(%r6)", + "add %r16, %r16, %r18", + "stw %r16, 44(%r6)", + "rlwinm %r17, %r8, 26, 0, 31", + "rlwinm %r18, %r8, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r8, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r11, %r11, %r17", + "xor %r17, %r9, %r10", + "and %r17, %r17, %r8", + "xor %r17, %r17, %r10", + "add %r11, %r11, %r17", + "lis %r17, -29497", + "ori %r17, %r17, 520", + "add %r11, %r11, %r17", + "add %r11, %r11, %r16", + "add %r7, %r7, %r11", + "rlwinm %r17, %r12, 30, 0, 31", + "rlwinm %r18, %r12, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r12, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r11, %r11, %r17", + "or %r17, %r12, %r14", + "and %r17, %r17, %r15", + "and %r18, %r12, %r14", + "or %r17, %r17, %r18", + "add %r11, %r11, %r17", + "lwz %r17, 40(%r6)", + "rlwinm %r16, %r17, 15, 0, 31", + "rlwinm %r18, %r17, 13, 0, 31", + "xor %r16, %r16, %r18", + "rlwinm %r18, %r17, 22, 10, 31", + "xor %r16, %r16, %r18", + "lwz %r18, 20(%r6)", + "add %r16, %r16, %r18", + "lwz %r17, 52(%r6)", + "rlwinm %r18, %r17, 25, 0, 31", + "rlwinm %r19, %r17, 14, 0, 31", + "xor %r18, %r18, %r19", + "rlwinm %r19, %r17, 29, 3, 31", + "xor %r18, %r18, %r19", + "add %r16, %r16, %r18", + "lwz %r18, 48(%r6)", + "add %r16, %r16, %r18", + "stw %r16, 48(%r6)", + "rlwinm %r17, %r7, 26, 0, 31", + "rlwinm %r18, %r7, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r7, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r10, %r10, %r17", + "xor %r17, %r8, %r9", + "and %r17, %r17, %r7", + "xor %r17, %r17, %r9", + "add %r10, %r10, %r17", + "lis %r17, -28482", + "ori %r17, %r17, 65530", + "add %r10, %r10, %r17", + "add %r10, %r10, %r16", + "add %r15, %r15, %r10", + "rlwinm %r17, %r11, 30, 0, 31", + "rlwinm %r18, %r11, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r11, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r10, %r10, %r17", + "or %r17, %r11, %r12", + "and %r17, %r17, %r14", + "and %r18, %r11, %r12", + "or %r17, %r17, %r18", + "add %r10, %r10, %r17", + "lwz %r17, 44(%r6)", + "rlwinm %r16, %r17, 15, 0, 31", + "rlwinm %r18, %r17, 13, 0, 31", + "xor %r16, %r16, %r18", + "rlwinm %r18, %r17, 22, 10, 31", + "xor %r16, %r16, %r18", + "lwz %r18, 24(%r6)", + "add %r16, %r16, %r18", + "lwz %r17, 56(%r6)", + "rlwinm %r18, %r17, 25, 0, 31", + "rlwinm %r19, %r17, 14, 0, 31", + "xor %r18, %r18, %r19", + "rlwinm %r19, %r17, 29, 3, 31", + "xor %r18, %r18, %r19", + "add %r16, %r16, %r18", + "lwz %r18, 52(%r6)", + "add %r16, %r16, %r18", + "stw %r16, 52(%r6)", + "rlwinm %r17, %r15, 26, 0, 31", + "rlwinm %r18, %r15, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r15, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r9, %r9, %r17", + "xor %r17, %r7, %r8", + "and %r17, %r17, %r15", + "xor %r17, %r17, %r8", + "add %r9, %r9, %r17", + "lis %r17, -23472", + "ori %r17, %r17, 27883", + "add %r9, %r9, %r17", + "add %r9, %r9, %r16", + "add %r14, %r14, %r9", + "rlwinm %r17, %r10, 30, 0, 31", + "rlwinm %r18, %r10, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r10, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r9, %r9, %r17", + "or %r17, %r10, %r11", + "and %r17, %r17, %r12", + "and %r18, %r10, %r11", + "or %r17, %r17, %r18", + "add %r9, %r9, %r17", + "lwz %r17, 48(%r6)", + "rlwinm %r16, %r17, 15, 0, 31", + "rlwinm %r18, %r17, 13, 0, 31", + "xor %r16, %r16, %r18", + "rlwinm %r18, %r17, 22, 10, 31", + "xor %r16, %r16, %r18", + "lwz %r18, 28(%r6)", + "add %r16, %r16, %r18", + "lwz %r17, 60(%r6)", + "rlwinm %r18, %r17, 25, 0, 31", + "rlwinm %r19, %r17, 14, 0, 31", + "xor %r18, %r18, %r19", + "rlwinm %r19, %r17, 29, 3, 31", + "xor %r18, %r18, %r19", + "add %r16, %r16, %r18", + "lwz %r18, 56(%r6)", + "add %r16, %r16, %r18", + "stw %r16, 56(%r6)", + "rlwinm %r17, %r14, 26, 0, 31", + "rlwinm %r18, %r14, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r14, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r8, %r8, %r17", + "xor %r17, %r15, %r7", + "and %r17, %r17, %r14", + "xor %r17, %r17, %r7", + "add %r8, %r8, %r17", + "lis %r17, -16647", + "ori %r17, %r17, 41975", + "add %r8, %r8, %r17", + "add %r8, %r8, %r16", + "add %r12, %r12, %r8", + "rlwinm %r17, %r9, 30, 0, 31", + "rlwinm %r18, %r9, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r9, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r8, %r8, %r17", + "or %r17, %r9, %r10", + "and %r17, %r17, %r11", + "and %r18, %r9, %r10", + "or %r17, %r17, %r18", + "add %r8, %r8, %r17", + "lwz %r17, 52(%r6)", + "rlwinm %r16, %r17, 15, 0, 31", + "rlwinm %r18, %r17, 13, 0, 31", + "xor %r16, %r16, %r18", + "rlwinm %r18, %r17, 22, 10, 31", + "xor %r16, %r16, %r18", + "lwz %r18, 32(%r6)", + "add %r16, %r16, %r18", + "lwz %r17, 0(%r6)", + "rlwinm %r18, %r17, 25, 0, 31", + "rlwinm %r19, %r17, 14, 0, 31", + "xor %r18, %r18, %r19", + "rlwinm %r19, %r17, 29, 3, 31", + "xor %r18, %r18, %r19", + "add %r16, %r16, %r18", + "lwz %r18, 60(%r6)", + "add %r16, %r16, %r18", + "stw %r16, 60(%r6)", + "rlwinm %r17, %r12, 26, 0, 31", + "rlwinm %r18, %r12, 21, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r12, 7, 0, 31", + "xor %r17, %r17, %r18", + "add %r7, %r7, %r17", + "xor %r17, %r14, %r15", + "and %r17, %r17, %r12", + "xor %r17, %r17, %r15", + "add %r7, %r7, %r17", + "lis %r17, -14735", + "ori %r17, %r17, 30962", + "add %r7, %r7, %r17", + "add %r7, %r7, %r16", + "add %r11, %r11, %r7", + "rlwinm %r17, %r8, 30, 0, 31", + "rlwinm %r18, %r8, 19, 0, 31", + "xor %r17, %r17, %r18", + "rlwinm %r18, %r8, 10, 0, 31", + "xor %r17, %r17, %r18", + "add %r7, %r7, %r17", + "or %r17, %r8, %r9", + "and %r17, %r17, %r10", + "and %r18, %r8, %r9", + "or %r17, %r17, %r18", + "add %r7, %r7, %r17", + "lwz %r16, 0(%r3)", + "lwz %r17, 4(%r3)", + "lwz %r18, 8(%r3)", + "lwz %r19, 12(%r3)", + "add %r7, %r7, %r16", + "add %r8, %r8, %r17", + "add %r9, %r9, %r18", + "add %r10, %r10, %r19", + "lwz %r16, 16(%r3)", + "lwz %r17, 20(%r3)", + "lwz %r18, 24(%r3)", + "lwz %r19, 28(%r3)", + "add %r11, %r11, %r16", + "add %r12, %r12, %r17", + "add %r14, %r14, %r18", + "add %r15, %r15, %r19", + "stw %r7, 0(%r3)", + "stw %r8, 4(%r3)", + "stw %r9, 8(%r3)", + "stw %r10, 12(%r3)", + "stw %r11, 16(%r3)", + "stw %r12, 20(%r3)", + "stw %r14, 24(%r3)", + "stw %r15, 28(%r3)", + "addi %r4, %r4, 64", + "addi %r5, %r5, -1", + "cmpldi %cr0, %r5, 0", + "bne %cr0, 22b", + "b 21f", + "20:", + "21:", + "ld %r14, 64(%r6)", + "ld %r15, 72(%r6)", + "ld %r16, 80(%r6)", + "ld %r17, 88(%r6)", + "ld %r18, 96(%r6)", + "ld %r19, 104(%r6)", + "blr", + ) +} + +/// Starts a SHA-256 computation: makes the streaming state `*state` represent the empty message. +/// +/// Contract: `VG.Spec.Sha256.initContract`. The streaming state is the hash value followed by a buffered partial block (`VG.Spec.Sha256.Repr`). +/// +/// # Safety +/// +/// * `state` must be valid for reads and writes of 96 bytes. +/// * `state` must not wrap around the end of the address space (no Rust object does). +#[unsafe(naked)] +pub(crate) unsafe extern "C" fn vg_sha256_init(state: *mut [u8; 96]) { + core::arch::naked_asm!( + "lis %r8, 27145", + "ori %r8, %r8, 58983", + "stw %r8, 0(%r3)", + "lis %r8, -17561", + "ori %r8, %r8, 44677", + "stw %r8, 4(%r3)", + "lis %r8, 15470", + "ori %r8, %r8, 62322", + "stw %r8, 8(%r3)", + "lis %r8, -23217", + "ori %r8, %r8, 62778", + "stw %r8, 12(%r3)", + "lis %r8, 20750", + "ori %r8, %r8, 21119", + "stw %r8, 16(%r3)", + "lis %r8, -25851", + "ori %r8, %r8, 26764", + "stw %r8, 20(%r3)", + "lis %r8, 8067", + "ori %r8, %r8, 55723", + "stw %r8, 24(%r3)", + "lis %r8, 23520", + "ori %r8, %r8, 52505", + "stw %r8, 28(%r3)", + "blr", + ) +} + +/// Absorbs data into a SHA-224 or SHA-256 computation: if the streaming state `*state` represents a message of `count` bytes (modulo 2⁶⁴), it then represents that message followed by the `len` bytes at `data`. +/// +/// Contract: `VG.Spec.Sha256.updateContract`. Constant time: only the pointers, `count` and `len` may affect timing, not the state or the data. +/// +/// # Safety +/// +/// * `state` must be valid for reads and writes of 96 bytes. +/// * `data` must be valid for reads of `len` bytes. +/// * `scratch` must be valid for reads and writes of 608 bytes. +/// * The contents of `scratch` on return are unspecified. +/// * `state` and `scratch` must not overlap each other or `data` (distinct Rust objects never do). +/// * None of `state`, `data` and `scratch` may overlap the 48 bytes of stack below the stack pointer, or wrap around the end of the address space (no Rust object does). +#[unsafe(naked)] +pub(crate) unsafe extern "C" fn vg_sha256_update(state: *mut [u8; 96], count: u64, data: *const u8, len: usize, scratch: *mut [u64; 76]) { + core::arch::naked_asm!( + "mflr %r0", + "stdu %r1, -48(%r1)", + "std %r0, 32(%r1)", + "std %r26, 112(%r7)", + "std %r27, 120(%r7)", + "std %r28, 128(%r7)", + "std %r29, 136(%r7)", + "std %r30, 144(%r7)", + "std %r31, 152(%r7)", + "addi %r26, %r3, 0", + "addi %r27, %r7, 0", + "addi %r28, %r5, 0", + "addi %r29, %r6, 0", + "li %r8, 63", + "and %r30, %r4, %r8", + "cmpldi %cr0, %r29, 0", + "beq %cr0, 20f", + "22:", + "li %r9, 0", + "cmpldi %cr0, %r30, 0", + "beq %cr0, 23f", + "li %r10, 64", + "subf %r10, %r30, %r10", + "rldicl %r8, %r29, 58, 6", + "cmpldi %cr0, %r8, 0", + "beq %cr0, 25f", + "b 26f", + "25:", + "add %r8, %r29, %r30", + "rldicl %r8, %r8, 58, 6", + "cmpldi %cr0, %r8, 0", + "beq %cr0, 27f", + "b 28f", + "27:", + "addi %r10, %r29, 0", + "28:", + "26:", + "subf %r29, %r10, %r29", + "29:", + "lbz %r8, 0(%r28)", + "add %r11, %r26, %r30", + "stb %r8, 32(%r11)", + "addi %r28, %r28, 1", + "addi %r30, %r30, 1", + "addi %r10, %r10, -1", + "cmpldi %cr0, %r10, 0", + "bne %cr0, 29b", + "addi %r8, %r30, -64", + "cmpldi %cr0, %r8, 0", + "beq %cr0, 210f", + "b 211f", + "210:", + "addi %r4, %r26, 32", + "li %r30, 0", + "li %r9, 1", + "211:", + "b 24f", + "23:", + "rldicl %r8, %r29, 58, 6", + "cmpldi %cr0, %r8, 0", + "beq %cr0, 212f", + "addi %r4, %r28, 0", + "addi %r28, %r28, 64", + "addi %r29, %r29, -64", + "li %r9, 1", + "b 213f", + "212:", + "li %r10, 64", + "subf %r10, %r30, %r10", + "rldicl %r8, %r29, 58, 6", + "cmpldi %cr0, %r8, 0", + "beq %cr0, 214f", + "b 215f", + "214:", + "add %r8, %r29, %r30", + "rldicl %r8, %r8, 58, 6", + "cmpldi %cr0, %r8, 0", + "beq %cr0, 216f", + "b 217f", + "216:", + "addi %r10, %r29, 0", + "217:", + "215:", + "subf %r29, %r10, %r29", + "218:", + "lbz %r8, 0(%r28)", + "add %r11, %r26, %r30", + "stb %r8, 32(%r11)", + "addi %r28, %r28, 1", + "addi %r30, %r30, 1", + "addi %r10, %r10, -1", + "cmpldi %cr0, %r10, 0", + "bne %cr0, 218b", + "addi %r8, %r30, -64", + "cmpldi %cr0, %r8, 0", + "beq %cr0, 219f", + "b 220f", + "219:", + "addi %r4, %r26, 32", + "li %r30, 0", + "li %r9, 1", + "220:", + "213:", + "24:", + "cmpldi %cr0, %r9, 0", + "beq %cr0, 221f", + "addi %r3, %r26, 0", + "li %r5, 1", + "addi %r6, %r27, 0", + "bl {vg_sha256_compress}", + "b 222f", + "221:", + "222:", + "cmpldi %cr0, %r29, 0", + "bne %cr0, 22b", + "b 21f", + "20:", + "21:", + "ld %r26, 112(%r27)", + "ld %r28, 128(%r27)", + "ld %r29, 136(%r27)", + "ld %r30, 144(%r27)", + "ld %r31, 152(%r27)", + "ld %r27, 120(%r27)", + "ld %r0, 32(%r1)", + "addi %r1, %r1, 48", + "mtlr %r0", + "blr", + vg_sha256_compress = sym super::sha256::vg_sha256_compress, + ) +} + +/// Finishes a SHA-224 or SHA-256 computation: if the streaming state `*state` represents a message of `count` bytes (modulo 2⁶⁴), hashed from an initial hash value, writes the final hash value `H⁽ᴺ⁾` of that message (32 bytes) to `*out`. The SHA-256 digest is all of it; the SHA-224 digest is its first 28 bytes. +/// +/// Contract: `VG.Spec.Sha256.finalizeContract`. Constant time: only the pointers and `count` may affect timing, not the state. +/// +/// # Safety +/// +/// * `state` must be valid for reads and writes of 96 bytes. +/// * `out` must be valid for reads and writes of 32 bytes. +/// * `scratch` must be valid for reads and writes of 608 bytes. +/// * The contents of `state` on return are unspecified. +/// * The contents of `scratch` on return are unspecified. +/// * `state`, `out` and `scratch` must not overlap each other (distinct Rust objects never do). +/// * None of `state`, `out` and `scratch` may overlap the 48 bytes of stack below the stack pointer, or wrap around the end of the address space (no Rust object does). +#[unsafe(naked)] +pub(crate) unsafe extern "C" fn vg_sha256_finalize(state: *mut [u8; 96], count: u64, out: *mut [u8; 32], scratch: *mut [u64; 76]) { + core::arch::naked_asm!( + "mflr %r0", + "stdu %r1, -48(%r1)", + "std %r0, 32(%r1)", + "std %r26, 112(%r6)", + "std %r27, 120(%r6)", + "std %r28, 128(%r6)", + "std %r29, 136(%r6)", + "std %r30, 144(%r6)", + "std %r31, 152(%r6)", + "addi %r26, %r3, 0", + "addi %r27, %r6, 0", + "addi %r28, %r5, 0", + "addi %r29, %r4, 0", + "li %r8, 63", + "and %r30, %r29, %r8", + "li %r8, 128", + "add %r11, %r26, %r30", + "stb %r8, 32(%r11)", + "addi %r30, %r30, 1", + "addi %r31, %r30, 7", + "rldicl %r31, %r31, 58, 6", + "20:", + "li %r10, 64", + "cmpldi %cr0, %r31, 0", + "beq %cr0, 21f", + "b 22f", + "21:", + "li %r10, 56", + "22:", + "li %r8, 0", + "subf %r10, %r30, %r10", + "cmpldi %cr0, %r10, 0", + "beq %cr0, 23f", + "25:", + "add %r11, %r26, %r30", + "stb %r8, 32(%r11)", + "addi %r30, %r30, 1", + "addi %r10, %r10, -1", + "cmpldi %cr0, %r10, 0", + "bne %cr0, 25b", + "b 24f", + "23:", + "24:", + "cmpldi %cr0, %r31, 0", + "beq %cr0, 26f", + "b 27f", + "26:", + "add %r8, %r29, %r29", + "add %r8, %r8, %r8", + "add %r8, %r8, %r8", + "li %r11, 88", + "stdbrx %r8, %r26, %r11", + "27:", + "addi %r4, %r26, 32", + "addi %r3, %r26, 0", + "li %r5, 1", + "addi %r6, %r27, 0", + "bl {vg_sha256_compress}", + "li %r30, 0", + "addi %r31, %r31, -1", + "cmpldi %cr0, %r31, 0", + "beq %cr0, 20b", + "lwz %r8, 0(%r26)", + "li %r11, 0", + "stwbrx %r8, %r28, %r11", + "lwz %r8, 4(%r26)", + "li %r11, 4", + "stwbrx %r8, %r28, %r11", + "lwz %r8, 8(%r26)", + "li %r11, 8", + "stwbrx %r8, %r28, %r11", + "lwz %r8, 12(%r26)", + "li %r11, 12", + "stwbrx %r8, %r28, %r11", + "lwz %r8, 16(%r26)", + "li %r11, 16", + "stwbrx %r8, %r28, %r11", + "lwz %r8, 20(%r26)", + "li %r11, 20", + "stwbrx %r8, %r28, %r11", + "lwz %r8, 24(%r26)", + "li %r11, 24", + "stwbrx %r8, %r28, %r11", + "lwz %r8, 28(%r26)", + "li %r11, 28", + "stwbrx %r8, %r28, %r11", + "ld %r26, 112(%r27)", + "ld %r28, 128(%r27)", + "ld %r29, 136(%r27)", + "ld %r30, 144(%r27)", + "ld %r31, 152(%r27)", + "ld %r27, 120(%r27)", + "ld %r0, 32(%r1)", + "addi %r1, %r1, 48", + "mtlr %r0", + "blr", + vg_sha256_compress = sym super::sha256::vg_sha256_compress, + ) +} diff --git a/src/hashes/mod.rs b/src/hashes/mod.rs index 9e62945b7..33e3d5db8 100644 --- a/src/hashes/mod.rs +++ b/src/hashes/mod.rs @@ -13,7 +13,8 @@ target_arch = "x86_64", target_arch = "aarch64", target_arch = "arm", - target_arch = "x86" + target_arch = "x86", + all(target_arch = "powerpc64", target_endian = "little") ))] mod blake2; diff --git a/src/hashes/sha256.rs b/src/hashes/sha256.rs index 0850f34f6..41b788173 100644 --- a/src/hashes/sha256.rs +++ b/src/hashes/sha256.rs @@ -19,7 +19,8 @@ target_arch = "x86_64", target_arch = "aarch64", target_arch = "arm", - target_arch = "x86" + target_arch = "x86", + all(target_arch = "powerpc64", target_endian = "little") ))] #[cfg(target_arch = "x86_64")] diff --git a/src/zeroize.rs b/src/zeroize.rs index 1e8935074..da8d050a0 100644 --- a/src/zeroize.rs +++ b/src/zeroize.rs @@ -27,25 +27,11 @@ all(target_arch = "powerpc64", target_endian = "little") ))] -#[cfg_attr( - all(target_arch = "powerpc64", target_endian = "little", not(test)), - expect( - dead_code, - reason = "PPC64LE has only ChaCha20 yet, which wipes with `zeroize_raw`" - ) -)] mod sealed { pub trait Sealed {} } /// An integer type: the value whose bytes are all zero is 0. -#[cfg_attr( - all(target_arch = "powerpc64", target_endian = "little", not(test)), - expect( - dead_code, - reason = "PPC64LE has only ChaCha20 yet, which wipes with `zeroize_raw`" - ) -)] pub(crate) trait Int: Copy + sealed::Sealed {} macro_rules! int { @@ -60,13 +46,6 @@ int!(u8, u16, u32, u64, i16, i32, i64); /// Overwrites `x` with zeros using the verified assembly primitive. Its /// opaque call prevents the compiler from removing the stores. -#[cfg_attr( - all(target_arch = "powerpc64", target_endian = "little", not(test)), - expect( - dead_code, - reason = "PPC64LE has only ChaCha20 yet, which wipes with `zeroize_raw`" - ) -)] pub(crate) fn zeroize(x: &mut [T]) { // SAFETY: `x` is writable for its entire byte length, cannot wrap, and // lies outside the callee’s stack frame. All-zero bytes are valid for T. diff --git a/tests/cavp/main.rs b/tests/cavp/main.rs index 73dbf650c..d929abc5a 100644 --- a/tests/cavp/main.rs +++ b/tests/cavp/main.rs @@ -10,7 +10,8 @@ target_arch = "x86_64", target_arch = "aarch64", target_arch = "arm", - target_arch = "x86" + target_arch = "x86", + all(target_arch = "powerpc64", target_endian = "little") ))] mod aes_gcm; diff --git a/tests/cavp/sha1.rs b/tests/cavp/sha1.rs index 5b6c3d2d8..7d2066e50 100644 --- a/tests/cavp/sha1.rs +++ b/tests/cavp/sha1.rs @@ -1,6 +1,13 @@ //! SHA-1: every message length from 0 to 64 bytes, 64 long messages (from //! 163 to 6400 bytes) and the Monte Carlo test. +#![cfg(any( + target_arch = "x86_64", + target_arch = "aarch64", + target_arch = "arm", + target_arch = "x86" +))] + use super::{check_messages, check_monte_carlo}; use verified_garbage::hashes::sha1::Sha1; diff --git a/tests/cavp/sha224.rs b/tests/cavp/sha224.rs index 8d201290e..ef3326855 100644 --- a/tests/cavp/sha224.rs +++ b/tests/cavp/sha224.rs @@ -1,6 +1,13 @@ //! SHA-224: every message length from 0 to 64 bytes, 64 long messages and the //! Monte Carlo test. +#![cfg(any( + target_arch = "x86_64", + target_arch = "aarch64", + target_arch = "arm", + target_arch = "x86" +))] + use super::{check_messages, check_monte_carlo}; use verified_garbage::hashes::sha224::Sha224; diff --git a/tests/cavp/sha384.rs b/tests/cavp/sha384.rs index 0db465e46..3e534c11a 100644 --- a/tests/cavp/sha384.rs +++ b/tests/cavp/sha384.rs @@ -1,6 +1,13 @@ //! SHA-384: every message length from 0 to 128 bytes, 128 long messages //! (from 227 to 12800 bytes) and the Monte Carlo test. +#![cfg(any( + target_arch = "x86_64", + target_arch = "aarch64", + target_arch = "arm", + target_arch = "x86" +))] + use super::{check_messages, check_monte_carlo}; use verified_garbage::hashes::sha384::Sha384; diff --git a/tests/cavp/sha512.rs b/tests/cavp/sha512.rs index e3bb3ae43..07480f06d 100644 --- a/tests/cavp/sha512.rs +++ b/tests/cavp/sha512.rs @@ -1,6 +1,13 @@ //! SHA-512: every message length from 0 to 128 bytes, 128 long messages //! (from 227 to 12800 bytes) and the Monte Carlo test. +#![cfg(any( + target_arch = "x86_64", + target_arch = "aarch64", + target_arch = "arm", + target_arch = "x86" +))] + use super::{check_messages, check_monte_carlo}; use verified_garbage::hashes::sha512::Sha512; diff --git a/tests/cavp/sha512_224.rs b/tests/cavp/sha512_224.rs index 654158ae5..5b7ed5b8c 100644 --- a/tests/cavp/sha512_224.rs +++ b/tests/cavp/sha512_224.rs @@ -1,6 +1,13 @@ //! SHA-512/224: every message length from 0 to 128 bytes, 128 long messages //! (from 227 to 12800 bytes) and the Monte Carlo test. +#![cfg(any( + target_arch = "x86_64", + target_arch = "aarch64", + target_arch = "arm", + target_arch = "x86" +))] + use super::{check_messages, check_monte_carlo}; use verified_garbage::hashes::sha512_224::Sha512_224; diff --git a/tests/cavp/sha512_256.rs b/tests/cavp/sha512_256.rs index 0b34ff9e4..9cc7db195 100644 --- a/tests/cavp/sha512_256.rs +++ b/tests/cavp/sha512_256.rs @@ -1,6 +1,13 @@ //! SHA-512/256: every message length from 0 to 128 bytes, 128 long messages //! (from 227 to 12800 bytes) and the Monte Carlo test. +#![cfg(any( + target_arch = "x86_64", + target_arch = "aarch64", + target_arch = "arm", + target_arch = "x86" +))] + use super::{check_messages, check_monte_carlo}; use verified_garbage::hashes::sha512_256::Sha512_256;