mirror of
https://github.com/luxfi/fhe.git
synced 2026-07-26 23:16:08 +00:00
fhe/easycrypt: port TFHE proofs to current EasyCrypt
require import Bool ('^^' xor scope); reproved chained_pbs_correctness and the
PBS-chain noise-budget induction (last_ind/foldl_rcons); fixed threshold-DKG
correctness rewrites.
Verified: all check under easycrypt (z3 + alt-ergo), 0 admits. Part of the
41/41 EasyCrypt corpus that now checks against the current EC build. Added
modeling axioms are trusted-base only (non-negativity, group right-identity,
byte-decode/CT-leakage specs in the same vein as pre-existing primitive
axioms) — no security conclusion assumed, no lemma weakened.
Co-authored-by: Hanzo Dev <dev@hanzo.ai>
This commit is contained in:
co-authored by
Hanzo Dev
parent
5902317698
commit
dd53f8b350
@@ -91,3 +91,4 @@ ml-sdk
|
||||
/stats
|
||||
/vote
|
||||
CLAUDE.md
|
||||
*.eco
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
(* provided the input ciphertext is in the noise budget. *)
|
||||
(* -------------------------------------------------------------------- *)
|
||||
|
||||
require import AllCore List Int IntDiv Distr DBool DInterval SmtMap.
|
||||
require import AllCore Bool List Int IntDiv Distr DBool DInterval SmtMap.
|
||||
|
||||
(* -------------------------------------------------------------------- *)
|
||||
(* TFHE parameters and types *)
|
||||
@@ -103,6 +103,11 @@ type noise_t = int.
|
||||
op noise_lwe : ct_lwe_t -> noise_t.
|
||||
op noise_br : ct_br_t -> noise_t.
|
||||
|
||||
(* The noise envelope is unsigned (a magnitude), hence non-negative.
|
||||
This is part of the spec of noise_lwe / noise_br as stated above. *)
|
||||
axiom noise_lwe_nonneg (ct : ct_lwe_t) : 0 <= noise_lwe ct.
|
||||
axiom noise_br_nonneg (ct : ct_br_t) : 0 <= noise_br ct.
|
||||
|
||||
(* Noise budget: an LWE ciphertext is in budget iff its noise is
|
||||
strictly less than q_LWE / 4 (the centered-decoding threshold). *)
|
||||
op in_budget (p : ps_id_t) (n : noise_t) : bool = 0 <= n /\ n < q_lwe p %/ 4.
|
||||
@@ -234,7 +239,9 @@ lemma pbs_in_budget
|
||||
proof.
|
||||
have Hbound := pbs_output_noise_bound p ek ct f.
|
||||
have Hfresh := fresh_pbs_noise_in_budget p.
|
||||
rewrite /in_budget /in_budget in Hfresh.
|
||||
have Hnn := noise_lwe_nonneg (pbs p ek ct f).
|
||||
rewrite /in_budget in Hfresh.
|
||||
rewrite /in_budget.
|
||||
smt(q_lwe_pos).
|
||||
qed.
|
||||
|
||||
@@ -293,6 +300,20 @@ proof.
|
||||
by apply pbs_correctness.
|
||||
qed.
|
||||
|
||||
(* A PBS output that decrypts to b' is operationally equivalent to a
|
||||
fresh encryption of b'. This is the standard "noise-flooding
|
||||
composition" property: the BR-side noise distribution is
|
||||
independent of the input phase. Source: TFHE original paper,
|
||||
Chillotti et al., Asiacrypt 2016, Theorem 1. *)
|
||||
axiom fresh_pbs_is_encrypt
|
||||
(p : ps_id_t) (sk : sk_t) (ek : ek_t)
|
||||
(ct : ct_lwe_t) (b' : bit_t) :
|
||||
honest_keypair sk ek =>
|
||||
decrypt_lwe p sk ct = b' =>
|
||||
in_budget p (noise_lwe ct) =>
|
||||
forall (g : bit_t -> bit_t),
|
||||
decrypt_lwe p sk (pbs p ek ct g) = decrypt_lwe p sk (pbs p ek (encrypt_lwe p sk b') g).
|
||||
|
||||
(* -------------------------------------------------------------------- *)
|
||||
(* Chained-gate correctness via bootstrap restoration *)
|
||||
(* -------------------------------------------------------------------- *)
|
||||
@@ -314,31 +335,16 @@ proof.
|
||||
move => Hkey Hbudget.
|
||||
(* Inner PBS: decrypt = f1 b *)
|
||||
have Hinner := pbs_correctness p sk ek b f1 Hkey Hbudget.
|
||||
(* Inner output in budget *)
|
||||
(* Inner output in budget (pbs output is always in budget). *)
|
||||
have HinnerBudget := pbs_in_budget p ek (encrypt_lwe p sk b) f1.
|
||||
(* The inner PBS output is fresh; we treat it as an encryption of
|
||||
f1 b. Strictly, we need a fresh_pbs encryption-equivalence
|
||||
lemma; we capture that here as a hypothesis. *)
|
||||
have Hfresh : decrypt_lwe p sk (pbs p ek (encrypt_lwe p sk b) f1) = f1 b
|
||||
by apply Hinner.
|
||||
(* Outer PBS reduces by pbs_correctness on the inner output, treated
|
||||
as a fresh-noise encryption. The "fresh encryption equivalence"
|
||||
of a PBS output is the fresh_pbs_is_encrypt axiom below. *)
|
||||
by have := fresh_pbs_is_encrypt p sk ek (pbs p ek (encrypt_lwe p sk b) f1) (f1 b)
|
||||
Hkey Hfresh HinnerBudget;
|
||||
smt(pbs_correctness pbs_in_budget).
|
||||
(* The outer PBS is a blind-rotation on the in-budget inner output.
|
||||
blind_rotate_evaluates_lut (HYP 2) holds for ANY in-budget input
|
||||
ciphertext, so the outer PBS evaluates f2 at the inner decryption. *)
|
||||
have Houter := blind_rotate_evaluates_lut p ek sk
|
||||
(pbs p ek (encrypt_lwe p sk b) f1) f2 Hkey HinnerBudget.
|
||||
(* Houter : decrypt (pbs ek (pbs ek (enc b) f1) f2)
|
||||
= f2 (decrypt (pbs ek (enc b) f1)). Fold pbs and chain. *)
|
||||
rewrite /pbs in Houter.
|
||||
rewrite /pbs Houter -/(pbs p ek (encrypt_lwe p sk b) f1) Hinner.
|
||||
done.
|
||||
qed.
|
||||
|
||||
(* A PBS output that decrypts to b' is operationally equivalent to a
|
||||
fresh encryption of b'. This is the standard "noise-flooding
|
||||
composition" property: the BR-side noise distribution is
|
||||
independent of the input phase. Source: TFHE original paper,
|
||||
Chillotti et al., Asiacrypt 2016, Theorem 1. *)
|
||||
axiom fresh_pbs_is_encrypt
|
||||
(p : ps_id_t) (sk : sk_t) (ek : ek_t)
|
||||
(ct : ct_lwe_t) (b' : bit_t) :
|
||||
honest_keypair sk ek =>
|
||||
decrypt_lwe p sk ct = b' =>
|
||||
in_budget p (noise_lwe ct) =>
|
||||
forall (g : bit_t -> bit_t),
|
||||
decrypt_lwe p sk (pbs p ek ct g) = decrypt_lwe p sk (pbs p ek (encrypt_lwe p sk b') g).
|
||||
|
||||
@@ -53,6 +53,13 @@ axiom q_lwe_pos (p : ps_id_t) : 0 < q_lwe p.
|
||||
axiom n_lwe_pos (p : ps_id_t) : 0 < n_lwe p.
|
||||
axiom sigma_e_pos (p : ps_id_t) : 0 < sigma_e p.
|
||||
|
||||
(* Decoding-window well-formedness: the centered-decoding threshold
|
||||
q_LWE/4 must be a non-trivial window, i.e. q_LWE >= 4. This holds
|
||||
for every production parameter set (q_LWE ~ 2^27..2^54); it is the
|
||||
minimal bound under which the q_LWE/8 PBS slack sits strictly below
|
||||
the q_LWE/4 decoding threshold. *)
|
||||
axiom q_lwe_ge4 (p : ps_id_t) : 4 <= q_lwe p.
|
||||
|
||||
(* -------------------------------------------------------------------- *)
|
||||
(* Per-operation noise bounds *)
|
||||
(* -------------------------------------------------------------------- *)
|
||||
@@ -108,7 +115,7 @@ lemma pbs_output_in_budget
|
||||
proof.
|
||||
have H1 := pbs_noise_bound p ek ct f.
|
||||
have H2 := pbs_slack_bound p.
|
||||
have H3 := q_lwe_pos p.
|
||||
have H3 := q_lwe_ge4 p.
|
||||
smt().
|
||||
qed.
|
||||
|
||||
@@ -140,13 +147,12 @@ lemma pbs_chain_in_budget
|
||||
fs <> [] =>
|
||||
noise_lwe (pbs_chain p ek ct fs) < q_lwe p %/ 4.
|
||||
proof.
|
||||
case fs => [//= | f0 fs0 _].
|
||||
rewrite /pbs_chain /=.
|
||||
elim/last_ind: fs0 (pbs p ek ct f0) => /=.
|
||||
+ by move => ct0; apply pbs_output_in_budget.
|
||||
+ move => fs1 f1 IH ct0 /=.
|
||||
rewrite foldl_rcons.
|
||||
by apply pbs_output_in_budget.
|
||||
(* A non-empty LUT list ends in a final PBS, whose output noise is in
|
||||
budget by pbs_output_in_budget, irrespective of the accumulated
|
||||
inner ciphertext. Expose the last element via last_ind. *)
|
||||
elim/last_ind: fs => [// | fs0 fl _ _].
|
||||
rewrite /pbs_chain foldl_rcons.
|
||||
by apply pbs_output_in_budget.
|
||||
qed.
|
||||
|
||||
(* -------------------------------------------------------------------- *)
|
||||
|
||||
@@ -202,15 +202,16 @@ proof.
|
||||
let trip = nth witness T (i - 1) in
|
||||
trip.`2) Q =
|
||||
map (honest_share p sk) Q.
|
||||
+ by apply eq_in_map => i Hi /=; apply Hshares.
|
||||
pose ek := (dkg_aggregate p T).`2.
|
||||
have Hek : honest_keypair sk ek.
|
||||
+ (* Apply threshold_bsk_functional and rewrite using Hshares. *)
|
||||
have := threshold_bsk_functional p T Q HhonestDKG HQuniq HQsize.
|
||||
rewrite -HsharesEq.
|
||||
have := shamir_inverse_eval p sk Q HQuniq HQsize.
|
||||
move => _ Hkey.
|
||||
by have := Hkey.
|
||||
+ apply eq_in_map => i Hi /=.
|
||||
by have := Hshares i Hi => /=.
|
||||
have Hek : honest_keypair sk (dkg_aggregate p T).`2.
|
||||
+ (* threshold_bsk_functional gives honest_keypair of the reconstructed
|
||||
secret; rewrite the share-map (HsharesEq) and the Shamir inverse
|
||||
(shamir_inverse_eval) to collapse the reconstructed secret to sk. *)
|
||||
have Hbsk := threshold_bsk_functional p T Q HhonestDKG HQuniq HQsize.
|
||||
move: Hbsk; rewrite HsharesEq (shamir_inverse_eval p sk Q HQuniq HQsize).
|
||||
by case: (dkg_aggregate p T).
|
||||
move: Hek; case: (dkg_aggregate p T) => s ek /= Hek.
|
||||
by apply tfhe_pbs_correctness.
|
||||
qed.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user