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;