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;