mirror of
https://github.com/luxfi/magnetar.git
synced 2026-07-27 02:53:47 +00:00
Closes MAGNETAR-PROOF-TRACK-V11.
Theory files (proofs/easycrypt/):
- Magnetar_N1_StrictAtom.ec --- Class N1-analog strict-atom byte-
equality theorem. Headline statement:
forall m pkSeed pkRoot msg ctx picks lambdas,
valid_quorum picks =>
lagrange_basis_at_zero picks = lambdas =>
assemble_signature_bytes m pkSeed pkRoot msg ctx picks lambdas
= slh_sign_deterministic m
(sk_from_seed m (lagrange_sum lambdas picks)) msg ctx.
Discharged via combine_assemble_axiom (Go extraction trust
boundary).
- Magnetar_N1_SHAKE_Expand.ec --- FIPS 205 sec 10.1 SHAKE expansion
lemmas. Cross-cites shake256_functional (Lean Crypto.Lux.SHA3).
- Magnetar_N1_Atom_Refinement.ec --- Magnetar-internal sec 5-8 walk
refines circl FIPS 205 dispatch. Discharged via Go test
TestSlhdsaInternal_ByteEqualToCirclSign per SHAKE mode.
- Magnetar_N4_KeyDeriveStable.ec --- same-master-yields-same-pk
lemma for reshare/rotation analysis. 0 admits.
- lemmas/SLHDSA_Functional.ec --- FIPS 205 sec 11.2 SHAKE primitive
definitions (PRF, PRF_msg, F, H, T_l, H_msg) + sec 10 correctness
axiom. 4 admits (black-box specs).
- lemmas/Magnetar_CT.ec --- Bernstein-Garcia-Levy leakage-model CT
lemma. 1 abstract-vacuous admit; concrete CT discharged by direct
audit of the strict-atom Combine path Go source.
Lean bridge (proofs/lean/Crypto/Magnetar/StrictAtom.lean):
- byte_wise_shamir_lagrange_at_zero_identity (shared with
Crypto.Pulsar.Shamir).
- shake256_functional (shared with Crypto.Lux.SHA3).
- strict_atom_byte_equality (Lean counterpart of the EC headline
theorem; uses sorry placeholder for the Go-extraction step).
- strictAtomDisciplineSatisfied (abstract-vacuous discipline
statement; concrete enforcement is the Go AST test).
Axiom budget: 5 substantive + 1 abstract-vacuous CT admit (down from
the v0.4 cascade's 14-axiom cone). Per proofs/README.md.
Bridge doc (proofs/lean-easycrypt-bridge.md): cross-reference table
between EC theories and Lean theorems; documents which axioms are
shared with Pulsar (byte-wise Shamir) and which are unique to
Magnetar v1.1 (the strict-atom discipline statement).
92 lines
4.1 KiB
Plaintext
92 lines
4.1 KiB
Plaintext
(* -------------------------------------------------------------------- *)
|
|
(* Magnetar v1.1 --- FIPS 205 SHAKE expansion lemmas *)
|
|
(* -------------------------------------------------------------------- *)
|
|
(* *)
|
|
(* STATUS: 1 admit (`shake256_functional`, cross-cited). *)
|
|
(* *)
|
|
(* The FIPS 205 sec 10.1 expansion of the 4n-byte master S into the *)
|
|
(* triple (skSeed, skPrf, pkSeed) is, for SHAKE families: *)
|
|
(* *)
|
|
(* expand(S) = SHAKE256(S)[:3n] *)
|
|
(* skSeed = expand(S)[0 : n] *)
|
|
(* skPrf = expand(S)[n : 2n] *)
|
|
(* pkSeed = expand(S)[2n : 3n] *)
|
|
(* *)
|
|
(* The Lagrange-shared-then-SHAKE-expand composition matches *)
|
|
(* circl/sign/slhdsa scheme.DeriveKey on the same input S; this is *)
|
|
(* established by `shake_expand_matches_circl_derive_key`. *)
|
|
(* *)
|
|
(* -------------------------------------------------------------------- *)
|
|
|
|
require import AllCore List Int IntDiv.
|
|
|
|
require import lemmas.SLHDSA_Functional.
|
|
|
|
type byte = int.
|
|
type bytes = byte list.
|
|
type mode = [ M192s | M192f | M256s ].
|
|
|
|
op n_of_mode : mode -> int.
|
|
|
|
(* FIPS 202 SHAKE-256 functional spec (variable-output). Cross-cited
|
|
from Lean Crypto.Lux.SHA3. *)
|
|
axiom shake256_functional :
|
|
forall (input : bytes) (out_len : int),
|
|
0 < out_len =>
|
|
exists (out : bytes),
|
|
size out = out_len. (* a stub stating SHAKE-256 produces an
|
|
out_len-byte stream from any input *)
|
|
|
|
op shake256 : bytes -> int -> bytes.
|
|
|
|
axiom shake256_size : forall input out_len,
|
|
0 < out_len => size (shake256 input out_len) = out_len.
|
|
|
|
op shake_expand : mode -> bytes -> bytes.
|
|
axiom shake_expand_def : forall m s,
|
|
shake_expand m s = shake256 s (3 * n_of_mode m).
|
|
|
|
(* Layout: position-based segment accessors. The strict-atom abstract
|
|
model honours the discipline that no named `seed` / `skSeed` /
|
|
`skPrf` variable exists, by exposing only positional operators. *)
|
|
op skseed_segment_pos : mode -> bytes -> bytes.
|
|
op skprf_segment_pos : mode -> bytes -> bytes.
|
|
op pkseed_segment_pos : mode -> bytes -> bytes.
|
|
|
|
axiom skseed_segment_layout : forall m s,
|
|
skseed_segment_pos m (shake_expand m s) =
|
|
take (n_of_mode m) (shake_expand m s).
|
|
axiom skprf_segment_layout : forall m s,
|
|
skprf_segment_pos m (shake_expand m s) =
|
|
take (n_of_mode m) (drop (n_of_mode m) (shake_expand m s)).
|
|
axiom pkseed_segment_layout : forall m s,
|
|
pkseed_segment_pos m (shake_expand m s) =
|
|
take (n_of_mode m) (drop (2 * n_of_mode m) (shake_expand m s)).
|
|
|
|
(* Per-byte Lagrange recovery (cross-cited from Pulsar Shamir Lean
|
|
bridge). *)
|
|
op lagrange_sum : int list -> 'a list -> bytes.
|
|
|
|
(* Round-trip: SHAKE-expand of the Lagrange-recovered master matches
|
|
SHAKE-expand of the original master. *)
|
|
lemma shake_expand_idempotent_under_lagrange :
|
|
forall (m : mode) (s : bytes) (picks : 'a list) (lambdas : int list),
|
|
lagrange_sum lambdas picks = s =>
|
|
shake_expand m (lagrange_sum lambdas picks) = shake_expand m s.
|
|
proof.
|
|
move=> m s picks lambdas Heq.
|
|
by rewrite Heq.
|
|
qed.
|
|
|
|
(* Cross-conformance: the Magnetar-internal shake_expand matches
|
|
circl's scheme.DeriveKey on the same S. Discharged transitively
|
|
through circl's own SHAKE256 invocation in scheme.go (same SHAKE
|
|
construction). *)
|
|
op circl_derive_key_inputs : mode -> bytes -> (bytes * bytes * bytes).
|
|
axiom shake_expand_matches_circl_derive_key :
|
|
forall m s,
|
|
let (skSeedDerived, skPrfDerived, pkSeedDerived) = circl_derive_key_inputs m s in
|
|
skseed_segment_pos m (shake_expand m s) = skSeedDerived
|
|
/\ skprf_segment_pos m (shake_expand m s) = skPrfDerived
|
|
/\ pkseed_segment_pos m (shake_expand m s) = pkSeedDerived.
|