Commit graph

9 commits

Author SHA1 Message Date
e2c5cf1d4b P2-c: classify and pin the extraction boundary
Aeneas emits a *_Template.lean naming everything the extracted code needs
from outside itself — the extraction's own statement of its boundary.
extract.sh has always said, in prose, "after regenerating, diff the template
against the hand-written file". Prose is not a gate, and the diff cannot be
one: the two files legitimately differ in almost every line, holes and
Aeneas comments against real definitions and modeling policy.

MEASURING FIRST CHANGED WHAT THIS ITEM SHOULD BE. The TODO offered two
options — enforce the diff, or pin both files — and the answer turned out to
be neither. Both files were ALREADY byte-pinned by Phase 0b. And two further
things stand here: the generated Funs.lean imports the model and CALLS these
externals, so the Lean compiler enforces their TYPES wherever the extracted
code uses them; and the per-certificate exact cones catch any external that
becomes, or stops being, an assumption anything depends on.

What none of those three sees is the CLASSIFICATION: for each name the
extraction asks for, whether this repository answers with an ASSUMPTION or
with a PROOF. That is the tier-A/B claim the documents make in prose — the
curve calls and the three curve types resolve to proven definitions rather
than axioms, because gen/CurveField/Funs.lean opens `namespace
curve25519_dalek` and so defines the very names Aeneas asks for. Nothing
checked it. A regeneration that renamed one, or a model that quietly
answered one with an axiom instead, would have left the documents claiming a
proof where the repository had an assumption.

Phase 0d recomputes the classification with model-correspondence.py
(namespace-aware, so a definition inside a namespace counts under its full
name) and requires equality with the committed MODEL-CORRESPONDENCE.txt.
UNRESOLVED — the extraction asking for something nothing here provides — is
a hard failure.

  dalek     43 MODEL   8 PROVEN   3 EXTRA
  anza      38 MODEL   0 PROVEN   4 EXTRA   (no CurveSig crate)
  risc0     36 MODEL   8 PROVEN   4 EXTRA
  betrusted 35 MODEL   8 PROVEN   4 EXTRA

selftest-correspondence.sh, five cases, negative-tested by disabling the
comparison. The case that matters is 2: a PROVEN external answered by an
axiom instead. No name changes anywhere, every byte pin still matches, and
it compiles, because the signature is unchanged — before Phase 0d nothing in
the button could tell.

Trap recorded for whoever extends it: case 3 first deleted the PROVEN rows,
which was VACUOUS on anza, since anza has none — it removed nothing, the
table still matched, and the case passed while testing nothing. It now
deletes the first row whatever its verdict AND asserts the file changed.

extract.sh now points at the gate instead of asking a human to look.

Certified by a full sweep: both buttons, all four forks, purged trees,
machine otherwise idle. 8/8 green.
2026-07-31 17:53:31 +02:00
33fb8bb231 Coherence pass 4 (the closing pass): 4-tier apex documentation + hygiene
- README: pyramid-diagram apex row upgraded to the proven full lift
  (accepted <=> decompress(R) = [k](-A)+[s]B), status table names all
  four button-enforced tiers, apex section gains the phase-2 tier table
  (half-lift / point equation / full lift) + the decompress-chain
  summary; source pin updated to the pushed patch commit.
- TRUSTED-BASE item 5: rewritten from the single byte-apex certificate
  to the FOUR enforced tiers (decompress_of_canonical noted as
  standard-three-only).
- gen/CurveField/FunsExternal.lean: stale root-namespace
  edwards.decompress.step_1/step_2 axioms removed (dead weight left
  behind by un-opaquing; outside every cone, but they forced
  fully-qualified unfolds - see control FAILURES.md).
- check.sh Phase 3b success echo aligned to "apex + full-lift" (echo
  only; the enforcing greps covered all four tiers already).

Validated by the pass-4 sweep: 9/9 buttons green (this repo's check.sh
+ check-scalar.sh among them), logs retained in the pass workspace.
Full record: formal-verification-control/COHERENCE-PASS-4.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 04:01:15 +02:00
a2803fe34e Phase 2, brick 3 opened: decompress extracted for real (gen green)
extract.sh drops --opaque crate::edwards::decompress: step_1/step_2,
sqrt_ratio_i, pow_p58, and FieldElement51::from_bytes now extract as real
code (source aa0f6ab patches step_2's conditional_negate to the documented
negate-then-conditional-assign - the ConditionallyNegatable blanket impl
is the one thing the toolchain cannot translate). No new axioms: the
slice-level ct_eq the sqrt check needs was already a real def. Full
button green on the regenerated universe.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 18:04:04 +02:00
d6a60b2135 extract.sh: reproducible end-to-end (CurveField merged gen + CurveSig glue)
The verify-glue extraction (charon on the vendored ed25519-dalek with the
SHA-512/wire-format opaque boundary) is now stanza [3/4]-[4/4] of the one
extraction script, not an ad-hoc step. Regenerated artifacts identical.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 19:50:37 +02:00
c85704c0c4 THE SIGNATURE APEX: the EdDSA verification equation, proven and audited
`Proofs/SigApexSpec.lean`:
- `verify_loop_full` — the extracted 32-byte comparison loop returns exactly
  the byte-equality of the two arrays (induction; axiom cone = exactly
  [propext, Classical.choice, Quot.sound]).
- `verify_accepts_iff` — THE APEX: for a signature that parses, the
  extracted RustCrypto verifier accepts IFF the recomputed compressed point
      compress( [s]·B − [k]·A )
  equals the signature's R byte-for-byte. The recomputation is grounded in
  the PROVEN curve model (every curve and scalar call is a certified
  definition); k is whatever scalar the SHA-512 oracle produces — the
  honest EdDSA acceptance criterion with the hash opaque.

Boundary hygiene forced by the audit itself:
- The public vartime_double_scalar_mul_basepoint dispatch pulled the AVX2
  vector-backend axiom into the apex cone. Fixed at the build level:
  extract.sh pins RUSTFLAGS --cfg curve25519_dalek_backend="serial", so the
  SIMD arm compiles out; BackendKind has only Serial and
  get_selected_backend becomes a real definition (ok Serial).
- subtle.Choice.unwrap_u8 upgraded from axiom to the documented model
  definition (Choice := U8; unwrap_u8 = self.0) — it sits on the verify
  path via compress → is_negative.
- CurveSig modules added to GEN_MODULES (stale-olean incoherence otherwise).

check.sh grows Phase 3b: the apex certificate's axiom cone must equal
EXACTLY
  [propext, Classical.choice, Quot.sound,
   ed25519.Signature, sha2.Sha512,
   sha512_new, sha512_update, sha512_finalize_bytes,
   ed25519.Signature.to_bytes, signature.error.Error, Error.new]
— the SHA-512 hash oracle plus the opaque wire-format types. NO curve
axioms, NO scalar axioms, NO backend axioms, enforced on every button press.

Full check.sh green: 16 standard certificates + the apex audit.

Phase 2 (the point-level equation [s]B − [k]A = decompress R, needing
to_bytes canonicity and decompress) remains deferred and documented.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 19:45:55 +02:00
5bf9ed5176 Merge scalar into CurveField; integrate the verify glue against the model
Gen merge: extract.sh now co-extracts the Scalar52 backend and the public
scalar::from_bytes_mod_order[_wide] conversions into the SAME CurveField
model, so the whole library — field, curve_models, edwards, scalar — shares
one type universe (Scalar is a single structure, not two). The scalar proof
chain repoints by one import line (ScalarDenote: CurveScalar.Funs ->
CurveField.Funs); check-scalar.sh's gen list follows. Both buttons — the
scalar certificates and the field/group/dsm certificates — pass fresh over
the merged gen, so the merge is proven-safe, not merely hoped-safe.

Verify glue (gen/CurveSig): the extracted ed25519-dalek verify_sha512 path,
integrated against the proven model:
- TypesExternal.lean imports CurveField.Types, so CompressedEdwardsY /
  EdwardsPoint / Scalar in the glue ARE the proven model's types. Only the
  genuinely foreign types stay opaque: sha2.Sha512, ed25519.Signature,
  signature.error.Error.
- FunsExternal.lean imports CurveField.Funs, so every curve/scalar call
  (compress, vartime_double_scalar_mul_basepoint, as_bytes, neg,
  from_bytes_mod_order[_wide]) resolves to a proven definition — no axioms.
  The `?`-operator plumbing (Try::branch, FromResidual::from_residual) and
  compressed_from_bytes get real definitions. Only the SHA-512 hasher
  (sha512_new/update/finalize_bytes) and two opaque wire accessors
  (Signature.to_bytes, Error.new) remain axiomatized — the deliberate,
  documented hash-oracle boundary.

Audited: `verify_sha512`'s entire axiom cone is
  [propext, Classical.choice, Quot.sound,
   sha2.Sha512, sha512_new, sha512_update, sha512_finalize_bytes,
   ed25519.Signature.to_bytes, signature.error.Error.new]
— zero curve axioms, zero scalar axioms. The verify path is definitionally
grounded in the certified model; the only trust boundary is SHA-512.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 18:13:58 +02:00
8e52a449dc Double-scalar-mul enters the verified model: vartime_double_base extracted transparently
extract.sh now opens crate::backend::serial::scalar_mul::vartime_double_base
(the other scalar_mul strategies stay opaque): non_adjacent_form (with its
loops), NafLookupTable5 (from/select), the curve-model helpers and
vartime_double_base::mul itself land in gen/CurveField - the same
namespace as the proven edwards operations, so the coming double-and-add
induction can consume EdDouble/EdAddProjNiels/EdConvert directly.
Zero sorries, zero external axioms (the pinned sources carry documented
compat refactors: single-assignment loop helpers, param-rooted while,
always-256-iterations, index-based LE load).

Full check.sh pressed fresh over the regenerated model: every existing
field and group-law certificate still green and axiom-clean - the scope
extension is purely additive.
2026-07-04 11:48:51 +02:00
8ce599c4aa group-law layer: complete twisted Edwards addition law proven
Extraction widened to backend::serial::curve_models + edwards (own gen/,
209 defs). Adapted the reference Ed* proof suite: namespace rename +
Curve25519TraitsIdentity -> Curve25519_dalekTraitsIdentity. New opaque
externals (scalar_mul backends, get_selected_backend, decompress, sum,
from_slice) are axioms outside both certificate cones — verified by the
Phase-3 audit. All 21 proofs compile; field certificates unchanged.

Not claimed (matching the reference solution's honest scope): edAdd
associativity, scalar multiplication, decompress/compress, AVX2 backend.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 14:50:42 +02:00
b79375600f field layer: 14 proofs pass, fieldImplementation axiom-clean
Ported from the locally verified Hermes working copy; FeQ and Square2Spec
(dead files in the published replica) now compile and are in the check
manifest. check.sh gates: source integrity, stub audit, zero axiom
declarations under Proofs/, per-certificate axiom audit.

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