dalek-ed25519-verified/verification/extract.sh
mrwulf 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

67 lines
3.4 KiB
Bash
Executable file

#!/usr/bin/env bash
# Regenerate the Lean model in gen/ from the Rust sources.
#
# SCOPE: field arithmetic + Edwards point arithmetic
# roots: crate::field, crate::backend::serial::u64::field,
# crate::backend::serial::curve_models, crate::edwards
# (same widening the reference solution used for its Tier-1 addition-law
# theorem; scalar-mul backends and decompress internals stay opaque —
# upstream Aeneas cannot translate them; they are modeled/axiomatized in
# gen/CurveField/FunsExternal.lean OUTSIDE every certificate's cone).
#
# Rust --charon--> CurveField.llbc --aeneas--> gen/CurveField/*.lean
#
# The hand-written gen/CurveField/{TypesExternal,FunsExternal}.lean are NOT
# touched by regeneration (Aeneas only rewrites the *_Template variants).
# After regenerating, diff the templates against the hand-written files:
# diff gen/CurveField/FunsExternal_Template.lean gen/CurveField/FunsExternal.lean
#
# Usage: ./extract.sh
set -euo pipefail
source ~/aeneas-toolchain/env.sh
HERE="$(cd "$(dirname "$0")" && pwd)"
CRATE=~/GitClone/FormalVerification/sources/curve25519-dalek-source/curve25519-dalek
echo "[1/2] charon: Rust -> LLBC (field + curve_models + edwards + scalar [MERGED GEN])"
cd "$CRATE"
# Force the portable SERIAL backend (the one we verify): the SIMD dispatch
# arm is `#[cfg(curve25519_dalek_backend = "simd")]`, so pinning the cfg to
# "serial" removes it from the extraction — no vector-backend axiom leaks in.
export RUSTFLAGS='--cfg curve25519_dalek_backend="serial"'
charon cargo --preset=aeneas \
--start-from crate::field \
--start-from crate::backend::serial::u64::field \
--start-from crate::backend::serial::curve_models \
--start-from crate::edwards \
--start-from 'crate::backend::serial::u64::scalar::_::add' \
--start-from 'crate::backend::serial::u64::scalar::_::sub' \
--start-from 'crate::backend::serial::u64::scalar::_::mul' \
--start-from 'crate::backend::serial::u64::scalar::_::square' \
--start-from 'crate::backend::serial::u64::scalar::_::montgomery_mul' \
--start-from 'crate::backend::serial::u64::scalar::_::montgomery_square' \
--start-from 'crate::backend::serial::u64::scalar::_::montgomery_reduce' \
--start-from 'crate::backend::serial::u64::scalar::_::montgomery_invert' \
--start-from 'crate::backend::serial::u64::scalar::_::as_montgomery' \
--start-from 'crate::backend::serial::u64::scalar::_::from_montgomery' \
--start-from 'crate::backend::serial::u64::scalar::_::from_bytes_wide' \
--start-from 'crate::scalar::_::from_bytes_mod_order' \
--start-from 'crate::scalar::_::from_bytes_mod_order_wide' \
--opaque 'crate::field::_::internal_invert_batch' \
--opaque 'crate::backend::serial::scalar_mul::variable_base' \
--opaque 'crate::backend::serial::scalar_mul::straus' \
--opaque 'crate::backend::serial::scalar_mul::precomputed_straus' \
--opaque 'crate::backend::serial::scalar_mul::pippenger' \
--opaque 'crate::backend::vector' \
--opaque 'crate::backend::get_selected_backend' \
--opaque 'crate::edwards::decompress' \
--opaque 'crate::edwards::_::sum' \
--opaque 'crate::edwards::_::from_slice' \
--dest-file "$HERE/CurveField.llbc" \
-- --no-default-features
echo "[2/2] aeneas: LLBC -> Lean (split files, CurveField.* modules)"
cd "$HERE"
aeneas -backend lean -split-files -subdir CurveField -dest gen CurveField.llbc
echo "Done. Now run ./check.sh to type-check the regenerated model."