fips205-slhdsa-verified/verification/gen/SlhVerify/FunsExternal.lean
mrwulf 2267e04d10 phase 2: FOURTH CERTIFICATE — hypertree layer walk (Algorithm 12) + de-plumbing
fips205.ht_loop_eq (Proofs/HtSpec.lean): the extracted ht_verify_free_loop
equals the explicit d-layer fold — at layer j: idx_leaf = idx_tree masked
to h' bits (mask+cast), idx_tree >>= h', layer address j, tree address to
the shifted index, node recomputed through xmss_pk_from_sig on the j-th
XMSS signature. Pins the hypertree layer schedule; the final node ==
pk_root comparison sits one bind above in ht_verify_free (apex material).
Exact cone: [propext, Classical.choice, Quot.sound, verify_mono.oracle.f,
verify_mono.oracle.h, verify_mono.oracle.t_l] — kernel-3 plus exactly the
three hash primitives the referenced WOTS+/XMSS machinery touches.

THE LAYER'S OBSTRUCTION (one per layer, on pattern) was not the proof but
the CONE: the first extraction of this loop carried Result-conversion
plumbing (try_from/is_err/unwrap; transitively a Take iterator and the
&u32 Sub instance) — all axioms, rightly rejected by the Phase-3 audit.
Fixed at SOURCE level (fips205-source 6f6a9d6, 8 sites, semantics
identical for every FIPS 205 parameter set, differential test re-run
green), then re-extracted: the loop body is now straight-line and the
proof is the plain chain/wots recipe (no branches; base case via
loop.eq_1; step lemma closes by rfl; induction = bind_congr ×12).

Also in this commit:
- gen/ regenerated from the patched snapshot (loop bodies of the three
  prior certificates byte-identical modulo source line comments; all
  three proofs recompiled unchanged and re-audited green).
- Dead-stub deletion (axiom-shadowing hygiene rule): the five obsoleted
  plumbing axioms + vestigial take.default removed from FunsExternal, the
  orphaned TryFromIntError type axiom removed from TypesExternal. The
  model's external surface is now: 5 SHA-2 oracles (the boundary), the
  Take iterator machinery used only by helpers::to_int (apex round's
  de-plumbing item), 3 zeroize blanket impls (never on the verify path),
  and the discharged-real u32 Step defs.
- check.sh: PROOFS += HtSpec, CERTS += fips205.ht_loop_eq, audit import
  (self-test structure anchors untouched). README: four certificates +
  the de-plumbing record.

Fidelity review at authorship (three-way): extracted body == Rust
ht_verify_free (verbatim from upstream hypertree.rs, calls -> *_free) ==
FIPS 205 Algorithm 12, incl. mask-then-shift order and layer-then-tree
address order.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 17:14:21 +02:00

165 lines
8.5 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/- ──────────────────────────────────────────────────────────────────────────────
gen/SlhVerify/FunsExternal.lean — hand-maintained external functions.
TWO CLASSES of external, per honesty invariants H4/H5:
(1) THE CRYPTOGRAPHIC BOUNDARY — the deliberate opaque axioms.
The five SLH-DSA-SHA2-128s hash primitives, reached by name from the
monomorphic verify path (verify_mono::oracle):
· verify_mono.oracle.f — F (chain / FORS leaf)
· verify_mono.oracle.h — H (Merkle node)
· verify_mono.oracle.t_l — T_len (WOTS+ pk compression)
· verify_mono.oracle.t_len — T_k (FORS root compression)
· verify_mono.oracle.h_msg — H_msg (message digest)
These are SHA-256-based; their correctness against FIPS 180-4 is the
standing hash-oracle boundary (see TRUSTED-BASE.md). The apex
certificate will carry EXACTLY these five beyond Lean's three kernel
axioms — nothing else.
(2) TRANSPILER PLUMBING — core-library externals Aeneas emits for this
extraction config. These carry NO cryptographic content. The u32
range Step machinery is DISCHARGED below with real definitions
(2026-07-22). The try_from / is_err / &u32-Sub / wots-Take /
Debug-fmt axioms were ELIMINATED at source level by the
fips205-source de-plumbing patch (8 sites, semantics identical,
differential-test-validated) and their declarations deleted here
(dead-stub rule, 2026-07-23). Remaining as axioms: the Take
iterator machinery used by helpers::to_int (slh_verify_internal's
digest split — the apex round's de-plumbing item) and the zeroize
blanket impls (never on the verify path). The #print axioms audit
confirms only class (1) survives in any certificate cone.
────────────────────────────────────────────────────────────────────────────── -/
-- This is a template file: rename it to "FunsExternal.lean" and fill the holes.
import Aeneas
import SlhVerify.Types
open Aeneas Aeneas.Std Result ControlFlow Error
set_option linter.dupNamespace false
set_option linter.hashCommand false
set_option linter.unusedVariables false
/- You can set the `maxHeartbeats` value with the `-max-heartbeats` CLI option -/
set_option maxHeartbeats 1000000
/- You can set the `maxRecDepth` value with the `-max-recdepth` CLI option -/
set_option maxRecDepth 2048
open fips205
/-- [core::iter::adapters::take::{impl core::iter::traits::iterator::Iterator<Clause0_Item> for core::iter::adapters::take::Take<I>}::next]:
Source: '/rustc/library/core/src/iter/adapters/take.rs', lines 36:4-36:55
Name pattern: [core::iter::adapters::take::{core::iter::traits::iterator::Iterator<core::iter::adapters::take::Take<@I>, @Clause0_Item>}::next]
Visibility: public -/
@[rust_fun
"core::iter::adapters::take::{core::iter::traits::iterator::Iterator<core::iter::adapters::take::Take<@I>, @Clause0_Item>}::next"]
axiom core.iter.adapters.take.Take.Insts.CoreIterTraitsIteratorIterator.next
{I : Type} {Clause0_Item : Type} (traitsiteratorIteratorInst :
core.iter.traits.iterator.Iterator I Clause0_Item) :
core.iter.adapters.take.Take I → Result ((Option Clause0_Item) ×
(core.iter.adapters.take.Take I))
/-- [core::iter::range::{impl core::iter::range::Step for u32}::backward_checked]:
Source: '/rustc/library/core/src/iter/range.rs', lines 290:16-290:74
Name pattern: [core::iter::range::{core::iter::range::Step<u32>}::backward_checked]
Visibility: public -/
-- DISCHARGED (2026-07-22, proof phase): Aeneas.Std ships a real `Step`
-- instance only for `usize` (StepUsize); u32 ranges therefore extracted as
-- opaque axioms. These are the FAITHFUL models of Rust's `impl Step for u32`
-- (core/src/iter/range.rs), mirroring StepUsize: forward/backward via
-- u32::try_from(n)-then-checked_{add,sub}; steps_between = saturating
-- difference. Real defs, axiom-clean — so the range-loop cones (chain, and
-- every layer above) carry no plumbing axiom, only the kernel three + the
-- five hash oracles. NOT the deployed hash boundary; ordinary loop control.
@[rust_fun
"core::iter::range::{core::iter::range::Step<u32>}::backward_checked"]
def U32.Insts.CoreIterRangeStep.backward_checked
: Std.U32 → Std.Usize → Result (Option Std.U32) :=
fun start n =>
if h : n.val < 2 ^ 32 then
ok (Std.U32.checked_sub start (Std.U32.ofNatCore n.val (by omega)))
else ok none
/-- [core::iter::range::{impl core::iter::range::Step for u32}::forward_checked]:
Source: '/rustc/library/core/src/iter/range.rs', lines 282:16-282:73
Name pattern: [core::iter::range::{core::iter::range::Step<u32>}::forward_checked]
Visibility: public -/
@[rust_fun
"core::iter::range::{core::iter::range::Step<u32>}::forward_checked"]
def U32.Insts.CoreIterRangeStep.forward_checked
: Std.U32 → Std.Usize → Result (Option Std.U32) :=
fun start n =>
if h : n.val < 2 ^ 32 then
ok (Std.U32.checked_add start (Std.U32.ofNatCore n.val (by omega)))
else ok none
/-- [core::iter::range::{impl core::iter::range::Step for u32}::steps_between]:
Source: '/rustc/library/core/src/iter/range.rs', lines 271:16-271:84
Name pattern: [core::iter::range::{core::iter::range::Step<u32>}::steps_between]
Visibility: public -/
@[rust_fun "core::iter::range::{core::iter::range::Step<u32>}::steps_between"]
def U32.Insts.CoreIterRangeStep.steps_between
: Std.U32 → Std.U32 → Result (Std.Usize × (Option Std.Usize)) :=
fun start end_ =>
if h : start.val > end_.val then ok (0#usize, none)
else
let steps := Std.Usize.ofNatCore (end_.val - start.val) (by scalar_tac)
ok (steps, some steps)
/-- [zeroize::{impl zeroize::Zeroize for Z}::zeroize]:
Source: '/cargo/registry/src/index.crates.io-1949cf8c6b5b557f/zeroize-1.9.0/src/lib.rs', lines 274:4-274:25
Name pattern: [zeroize::{zeroize::Zeroize<@Z>}::zeroize]
Visibility: public -/
@[rust_fun "zeroize::{zeroize::Zeroize<@Z>}::zeroize"]
axiom zeroize.Zeroize.Blanket.zeroize
{Z : Type} (DefaultIsZeroesInst : zeroize.DefaultIsZeroes Z) : Z → Result Z
/-- [zeroize::{impl zeroize::Zeroize for [Z; N]}::zeroize]:
Source: '/cargo/registry/src/index.crates.io-1949cf8c6b5b557f/zeroize-1.9.0/src/lib.rs', lines 346:4-346:25
Name pattern: [zeroize::{zeroize::Zeroize<[@Z; @N]>}::zeroize]
Visibility: public -/
@[rust_fun "zeroize::{zeroize::Zeroize<[@Z; @N]>}::zeroize"]
axiom Array.Insts.ZeroizeZeroize.zeroize
{Z : Type} {N : Std.Usize} (ZeroizeInst : zeroize.Zeroize Z) :
Array Z N → Result (Array Z N)
/-- [zeroize::__internal::{impl zeroize::__internal::AssertZeroize for T}::zeroize_or_on_drop]:
Source: '/cargo/registry/src/index.crates.io-1949cf8c6b5b557f/zeroize-1.9.0/src/lib.rs', lines 846:8-846:40
Name pattern: [zeroize::__internal::{zeroize::__internal::AssertZeroize<@T>}::zeroize_or_on_drop]
Visibility: public -/
@[rust_fun
"zeroize::__internal::{zeroize::__internal::AssertZeroize<@T>}::zeroize_or_on_drop"]
axiom zeroize.__internal.AssertZeroize.Blanket.zeroize_or_on_drop
{T : Type} (ZeroizeInst : zeroize.Zeroize T) : T → Result T
/-- [fips205::verify_mono::oracle::f]:
Source: 'src/verify_mono.rs', lines 49:4-51:5 -/
axiom verify_mono.oracle.f
(N : Std.Usize) :
Slice Std.U8 → types.Adrs → Slice Std.U8 → Result (Array Std.U8 N)
/-- [fips205::verify_mono::oracle::h]:
Source: 'src/verify_mono.rs', lines 54:4-56:5 -/
axiom verify_mono.oracle.h
(N : Std.Usize) :
Slice Std.U8 → types.Adrs → Slice Std.U8 → Slice Std.U8 → Result
(Array Std.U8 N)
/-- [fips205::verify_mono::oracle::t_l]:
Source: 'src/verify_mono.rs', lines 60:4-64:5 -/
axiom verify_mono.oracle.t_l
{X : Std.Usize} {N : Std.Usize} :
Slice Std.U8 → types.Adrs → Array (Array Std.U8 N) X → Result (Array
Std.U8 N)
/-- [fips205::verify_mono::oracle::t_len]:
Source: 'src/verify_mono.rs', lines 69:4-73:5 -/
axiom verify_mono.oracle.t_len
{X : Std.Usize} {N : Std.Usize} :
Slice Std.U8 → types.Adrs → Array (Array Std.U8 N) X → Result (Array
Std.U8 N)
/-- [fips205::verify_mono::oracle::h_msg]:
Source: 'src/verify_mono.rs', lines 81:4-85:5 -/
axiom verify_mono.oracle.h_msg
(M : Std.Usize) :
Slice Std.U8 → Slice Std.U8 → Slice Std.U8 → Slice Std.U8 → Result
(Array Std.U8 M)