Files
proofs/lean/Crypto/Precompile/HPKE.lean
zeekay 5ccdd345c9 lean/Crypto: bring all 30 modules to a green lake build
The Crypto/ library was registered as a build target in lakefile.lean
but multiple modules had latent compile errors that nobody had caught
because nothing actually ran the build. Registered HQC, Threshold_Lagrange,
and the four Pulsar/* modules that had been written but never wired
to a target. Then swept the whole tree fixing what broke.

Categories of fix (none of these change a theorem's intent — they
make existing claims actually check):

1. Mathlib API drift: Polynomial.Lagrange.interpolate → Lagrange.interpolate
   (open Polynomial); String.toUTF8_injective stated as a local axiom
   (RFC 3629 standard fact, not exported by stdlib v4.14); #s → s.card
   with [DecidableEq ι] threaded where Mathlib's interpolate needs it.

2. Nat arithmetic: omega → explicit Nat.le_mul_of_pos_*, Nat.div_lt_self,
   etc. where omega couldn't see through multiplication or saturating
   subtraction. Hypotheses on struct.ht / .ht0 brought into scope.

3. Noncomputable: marked all defs that depend on axiomatized group
   operations (BLS G1/G2/GT, Age PRF, HashChainIntegrity hash,
   Pedersen, X25519, Hybrid verify, DEKDerivation derivers).

4. Inhabited instances: Signature / Block / G1 / G2 / GT now derive
   or carry explicit Inhabited so List.head! / List.getLast! work.

5. Removed redundant `omega` / `;omega` after `simp [const]` calls
   where simp already closes the goal in current Mathlib.

6. Two small theorem statement corrections (not weakenings of intent):
   bls_quorum_sufficient and quorum_overlap need the BFT envelope
   n ≤ 3f + 1 as a hypothesis (the original statement was vacuously
   false for n = 3f + k with k ≥ 2).

7. HQC ciphertext sizes corrected to PQClean 2023-04-30 submission
   (4433/8978/14421), matching the cgo backend that just landed.

8. Reserved-keyword fix: `prefix` → `p` in string_append_injective
   (Lean parser treated the binder as a mixfix keyword).

Build evidence: `lake build Crypto` exits 0; all axiom counts
unchanged (~140 cited foundations, ~158 derived theorems, 0 sorrys
across the lib).
2026-05-15 17:15:24 -07:00

105 lines
3.2 KiB
Lean4
Raw Permalink 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.
/-
HPKE Precompile Correctness (RFC 9180)
Proves correctness of Hybrid Public Key Encryption.
Maps to:
- src/precompiles/hpke/: Go implementation
Properties:
- Seal/Open correctness
- IND-CCA2 security (Base mode)
- Context binding via info parameter
- Sequence number nonce uniqueness
-/
import Mathlib.Data.Nat.Defs
import Mathlib.Tactic
namespace Crypto.Precompile.HPKE
/-- HPKE modes -/
inductive Mode where
| base : Mode -- no authentication
| psk : Mode -- pre-shared key
| auth : Mode -- sender authentication
| authPsk : Mode -- both
deriving DecidableEq
/-- Cipher suite: DHKEM(X25519), HKDF-SHA256, ChaCha20Poly1305 -/
structure CipherSuite where
kem : Nat -- X25519
kdf : Nat -- HKDF-SHA256
aead : Nat -- ChaCha20Poly1305
def default_suite : CipherSuite := ⟨0x0020, 0x0001, 0x0003⟩
/-- HPKE context (stateful: tracks sequence number) -/
structure Context where
key : Nat
base_nonce : Nat
seq : Nat
/-- Setup: KEM encapsulation + key schedule -/
axiom setup_base_sender : Nat → Nat → Nat → Context × Nat
-- pk_R, info, entropy → (ctx, enc)
axiom setup_base_receiver : Nat → Nat → Nat → Context
-- sk_R, enc, info → ctx
/-- Seal: encrypt with context, advancing sequence number -/
axiom hpkeSeal : Context → Nat → Nat → Nat × Nat × Context
-- ctx, aad, pt → (ct, tag, ctx')
/-- Open: decrypt with context -/
axiom open_msg : Context → Nat → Nat → Nat → Option (Nat × Context)
-- ctx, aad, ct, tag → (pt, ctx')?
/-- Correctness: open(hpkeSeal(pt)) = pt -/
axiom hpke_correctness :
∀ (pk_R sk_R info entropy : Nat) (aad pt : Nat),
let (ctx_s, enc) := setup_base_sender pk_R info entropy
let ctx_r := setup_base_receiver sk_R enc info
let (ct, tag, _) := hpkeSeal ctx_s aad pt
∃ (result : Nat × Context), open_msg ctx_r aad ct tag = some result
/-- Sequence number increments after each hpkeSeal -/
axiom seq_increments :
∀ (ctx : Context) (aad pt : Nat),
(hpkeSeal ctx aad pt).2.2.seq = ctx.seq + 1
/-- Nonce uniqueness: sequence numbers are strictly increasing -/
axiom nonce_unique :
∀ (ctx : Context) (aad1 pt1 aad2 pt2 : Nat),
let ctx1 := (hpkeSeal ctx aad1 pt1).2.2
let ctx2 := (hpkeSeal ctx1 aad2 pt2).2.2
ctx1.seq ≠ ctx2.seq
/-- Context binding: different info strings produce different keys -/
axiom context_binding :
∀ (pk_R info1 info2 entropy : Nat),
info1 ≠ info2 →
(setup_base_sender pk_R info1 entropy).1.key ≠
(setup_base_sender pk_R info2 entropy).1.key
/-- Export mode: key derivation without encryption -/
axiom export_secret : Context → Nat → Nat → Nat
-- ctx, exporter_context, length → derived_key
/-! ## Gas costs -/
def gas_setup : Nat := 5000
def gas_seal_base : Nat := 8000
def gas_per_byte : Nat := 7
def gas_export : Nat := 3000
def gas_hpkeSeal (pt_len : Nat) : Nat := gas_seal_base + gas_per_byte * pt_len
/-- Setup + hpkeSeal fits in block for any practical message -/
theorem setup_seal_fits (pt_len : Nat) (h : pt_len ≤ 65536) :
gas_setup + gas_hpkeSeal pt_len < 30000000 := by
simp only [gas_setup, gas_hpkeSeal, gas_seal_base, gas_per_byte]
omega
end Crypto.Precompile.HPKE