Conversation
|
This PR still uses the old layout that the conflict restructure (#144, #147, #148, #150) replaced on What to move:
This PR is stacked on another branch, so apply the same moves on that base first. See the "Keeping parallel PRs from conflicting" section of Generated by Claude Code |
ec8a97f to
02073e3
Compare
109b8e5 to
93ee3bf
Compare
|
Done: the whole stack (#97 → #108 → #109 → #110 → #111 / #117) is rebuilt on current In this PR (93ee3bf):
Generated by Claude Code |
02073e3 to
6625c2d
Compare
93ee3bf to
c28f602
Compare
c28f602 to
fb99738
Compare
649e7eb to
5197baf
Compare
fb99738 to
c8470e8
Compare
The rewrite lemmas for running PPC64LE blocks symbolically (Exec.lean, including that the stack pointer, and in code without calls the link register, are unchanged), and the taint analysis that proves constant time (Taint.lean). 32-bit values are tracked by the low word of a register, since add, subf and the logical instructions act on all 64 bits; lo32_add and friends push the low word through them. Running verified code from a state that permits more memory, the registers code never writes, calls of verified functions (WP.call, WP.callF) and the 48-byte ELFv2 frames that save the link register (WP.frameReg), ported from the AArch64 framework (Inline.lean, Call.lean). Refs #55 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Fw6RULWHCeVgMDGc3wRrwE
vg_chacha20_block keeps the 16 words in the low words of r5-r12 and r14-r21, saving the nonvolatile r14-r21 in the working space of buf (bytes 64-127) and restoring them at the end; r0 is the temporary for adding the input state. The proof carries the words as the low 32 bits of the registers, since the 64-bit adds leave carries in the high words. vg_chacha20_xor follows the AArch64 implementation: it calls the block function for each 64 bytes, keeping state and buf in r3 and r4 (which the block function never writes) and the data pointer and remaining length in the nonvolatile r22 and r23. Our caller's r22 and r23 and our return address (moved from the link register to r0) are saved in buf[256..280), so no stack is used. The ChaCha20 API and its tests (Wycheproof) now build on little-endian powerpc64, and pass under qemu-ppc64le; its benchmark is no longer gated off there. ChaCha20 chooses its implementation with the CPU detection in cpu.rs, so its allowance for going unused on PPC64LE is dropped. The algorithm table gets a PPC64LE column. Refs #55 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Fw6RULWHCeVgMDGc3wRrwE
ChaCha20's key objects wipe themselves with vg_zeroize (crate::zeroize), which needs an implementation on every architecture that uses it: a verified PPC64LE one, the same algorithm as AArch64's (words, then bytes). Also a shared crun tactic for short PPC64LE blocks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Fw6RULWHCeVgMDGc3wRrwE
5197baf to
9c74d3f
Compare
c8470e8 to
2f7ff6a
Compare
Part of #55. Stacked on #108 (the PPC64LE TCB), which is stacked on #97 (CI). There are no TCB or spec changes. This PR adds implementations proven against the existing
Spec.ChaCha20.blockContract,Spec.ChaCha20.xorContractandSpec.Zeroize.zeroizeContract, plus the proof framework they need.Commits
Proof: PPC64LE framework (symbolic execution, taint tracking, calls):
Proof/Framework/PPC64LE/{Exec,Taint,Inline,Call}.lean, ported from the AArch64 framework:runBlock_cons/runStep_some/runBlock_nilstepping lemmas.spis unchanged, andLRtoo in code without calls.VG.Taint.constantTime … (by taint_decide).Exec.widen), registers that code never writes (Exec.gpr), calls of verified functions (WP.call) and the ELFv2 frames that saveLR(WP.frameReg).32-bit values are tracked as the low word of a register, since
add/subf/logical instructions act on all 64 bits;lo32_addand friends push the low word through them. The byte-reversed loads use the target-independentProof/Framework/Bswap.leanlemmas, so no PPC64LE module imports another target's (ci/check_lean_imports.py).ChaCha20 on PPC64LE:
vg_chacha20_blockkeeps the 16 state words in the low words ofr5–r12andr14–r21. It saves the nonvolatiler14–r21in the working half ofbuf(bytes 64–127) and restores them at the end;r0is the temporary for adding the input state. Rotations arerotrwi(rlwinm), which read the low word and ignore the carries the 64-bit adds leave in the high word.vg_chacha20_xorfollows the AArch64 implementation. It callsvg_chacha20_blockonce per 64 bytes of data and XORsmin(64, remaining)bytes of the output into the data, a byte at a time. It then increments the counter word.stateandbufstay inr3/r4, which the block function never writes. The data pointer and remaining length are kept in the nonvolatiler22/r23. Our caller'sr22/r23, and the return address (mflr r0), are saved inbuf[256..280), so no stack is used (stack := 0, as on the other targets). The proof tracksr14–r21across the calls through the block function's ABI guarantee.Proof/ChaCha20/PPC64LE/. Both artifacts are registered (inApiform) inArtifacts/ChaCha20/PPC64LE.lean, andsrc/asm/powerpc64le/is regenerated.Zeroization on PPC64LE: since
mainaddedvg_zeroize(crate::zeroize, used by ChaCha20'sDrop), every architecture that builds ChaCha20 needs it. It is the AArch64 algorithm, inImpl/Zeroize/PPC64LE.lean:stdof zero overlen / 8words, thenstboverlen % 8bytes. The proof inProof/Zeroize/PPC64LE.leanfollowsProof/Zeroize/AArch64.leanand its sharedProof/Zeroize/Common.lean. The artifact is registered inArtifacts/Zeroize/PPC64LE.lean. A smallcruntactic (Proof/Framework/PPC64LE/Run.lean) steps short blocks, as the AArch64 proofs' does.Rust
src/lib.rsaliasescrate::archtoasm::powerpc64leon little-endian powerpc64.src/chacha20.rs,src/zeroize.rsandtests/wycheproof/chacha20.rsname PPC64LE (all(target_arch = "powerpc64", target_endian = "little")) in their inner#[cfg(...)].bench_arches.pydoes not benchmark PPC64LE.cpu::detected()on every architecture, so theallow(dead_code)that CI: test on ppc64le, on a ppc64le runner as pyca/cryptography does #97 added tosrc/cpu.rsfor PPC64LE is dropped.README
The table is generated.
ci/algorithms_table.pynow knows PPC64LE (ARCHESgets"powerpc64", andASM_DIRSmaps it tosrc/asm/powerpc64le/), and the ✅ definition includes it. ChaCha20 is ✅ on PPC64LE; every other algorithm is ❌ there for now.Testing
On #97's head (
mainat 48dfb92), these all pass:lake buildandEmit.lean --checkci/check_lean_imports.py,check_lean_speed.py,check_vectors.py,check_arch_gates.py,check_variants.py,algorithms_table.py --checkcargo fmt, andcargo clippy -D warningson the host and for ppc64lecargo teston x86-64, and cross-built forpowerpc64le-unknown-linux-gnuunderqemu-ppc64le(the unit tests, includingzeroize's, and the Wycheproof ChaCha20 vectors)🤖 Generated with Claude Code
https://claude.ai/code/session_01Fw6RULWHCeVgMDGc3wRrwE