https://github.com/EasyCrypt/easycrypt
Tip revision: 723d459c8d5a51439d1d36e0352311b6d127f017 authored by Pierre-Yves Strub on 17 March 2020, 21:17:33 UTC
def. of ring quotients
def. of ring quotients
Tip revision: 723d459
cramer_shoup.ec
require import AllCore List Distr Dexcepted PKE.
require import StdOrder StdBigop.
import RealOrder Bigreal.
require TCR RndExcept.
(** DiffieHellman *)
require import DiffieHellman.
import DDH.
axiom gt1_q : 1 < q.
theory Ad1.
clone import RndExcept as RndE with
type input <- unit,
type t <- F.t,
op d <- fun _ => FDistr.dt,
type out <- bool
proof *.
realize d_ll. move=> _;apply FDistr.dt_ll. qed.
clone include Adversary1_1 with
op n <- q
proof *.
realize gt1_n by apply gt1_q.
realize d_uni by move=> _ x; rewrite FDistr.dt1E.
end Ad1.
theory DDH_ex.
module DDH0_ex (A:Adversary) = {
proc main() : bool = {
var b, x, y;
x = $FDistr.dt \ (pred1 F.zero);
y = $FDistr.dt;
b = A.guess(g ^ x, g ^ y, g ^ (x*y));
return b;
}
}.
module DDH1_ex (A:Adversary) = {
proc main() : bool = {
var b, x, y, z;
x = $FDistr.dt \ (pred1 F.zero);
y = $FDistr.dt;
z = $FDistr.dt;
b = A.guess(g ^ x, g ^ y, g ^ z);
return b;
}
}.
section PROOFS.
declare module A:Adversary.
axiom A_ll : islossless A.guess.
local module Addh0 : Ad1.ADV = {
proc a1 () = { return ((), F.zero); }
proc a2 (x:t) = {
var b, y;
y = $FDistr.dt;
b = A.guess(g ^ x, g ^ y, g ^ (x*y));
return b;
}
}.
local module Addh1 = {
proc a1 = Addh0.a1
proc a2 (x:t) = {
var b, y, z;
y = $FDistr.dt;
z = $FDistr.dt;
b = A.guess(g ^ x, g ^ y, g ^ z);
return b;
}
}.
local lemma a1_ll : islossless Addh0.a1.
proof. proc;auto. qed.
lemma adv_DDH_DDH_ex &m :
`| Pr[DDH0_ex(A).main()@ &m : res] - Pr[DDH1_ex(A).main()@ &m : res] | <=
`| Pr[DDH0(A).main()@ &m : res] - Pr[DDH1(A).main()@ &m : res] | + 2%r / q%r.
proof.
have /= H0 := Ad1.pr_abs Addh0 a1_ll _ &m (fun b _ => b).
+ by proc;call A_ll;rnd;skip;rewrite /= FDistr.dt_ll.
have /= H1 := Ad1.pr_abs Addh1 a1_ll _ &m (fun b _ => b).
+ by proc;call A_ll;do !rnd;skip;rewrite /= FDistr.dt_ll.
have -> : 2%r / q%r = inv q%r + inv q%r.
+ field;smt (q_pos lt_fromint).
have <- : Pr[Ad1.MainE(Addh0).main() @ &m : res] = Pr[DDH0_ex(A).main() @ &m : res].
+ by byequiv => //;proc;inline *;sim;auto.
have <- : Pr[Ad1.MainE(Addh1).main() @ &m : res] = Pr[DDH1_ex(A).main() @ &m : res].
+ by byequiv => //;proc;inline *;sim;auto.
have <- : Pr[Ad1.Main(Addh0).main() @ &m : res] = Pr[DDH0(A).main() @ &m : res].
+ by byequiv => //;proc;inline *;sim;auto.
have <- /# : Pr[Ad1.Main(Addh1).main() @ &m : res] = Pr[DDH1(A).main() @ &m : res].
by byequiv => //;proc;inline *;sim;auto.
qed.
end section PROOFS.
end DDH_ex.
import DDH_ex.
(** Target Collision Resistant *)
clone import TCR as TCR_H with
type t_from <- group * group * group,
type t_to <- F.t.
axiom dk_ll : is_lossless dk.
hint exact random : dk_ll.
(** Cramer Shoup Encryption *)
clone import PKE as PKE_ with
type pkey = K * group * group * group * group * group,
type skey = K * group * group * F.t * F.t * F.t * F.t * F.t * F.t,
type plaintext = group,
type ciphertext = group * group * group * group.
module CramerShoup : Scheme = {
proc kg() : pkey * skey = {
var x1, x2, y1, y2, z1, z2, k, w, g_, pk, sk;
x1 <$ FDistr.dt;
x2 <$ FDistr.dt;
y1 <$ FDistr.dt;
y2 <$ FDistr.dt;
z1 <$ FDistr.dt;
z2 <$ FDistr.dt;
w <$ FDistr.dt \ (pred1 F.zero);
k <$ dk;
g_ <- g ^ w;
pk <- (k, g, g_, g^x1 * g_^x2, g^y1 * g_^y2, g^z1 * g_^z2);
sk <- (k, g, g_, x1, x2, y1, y2, z1, z2);
return (pk, sk);
}
proc enc(pk:pkey, m:plaintext) : ciphertext = {
var k,g,g_,e,f,h,u,a,a_,c,v,d;
(k,g,g_,e,f,h) = pk;
u <$ FDistr.dt;
a <- g^u; a_ <- g_^u;
c <- h^u * m;
v <- H k (a, a_, c);
d <- e^u * f^(u*v);
return (a,a_,c,d);
}
proc dec(sk:skey, ci:ciphertext) = {
var k,g,g_,x1,x2,y1,y2,z1,z2,a,a_,c,d,v;
(k,g,g_,x1,x2,y1,y2,z1,z2) <- sk;
(a,a_,c,d) <- ci;
v <- H k (a, a_, c);
return (if d = a ^ (x1 + v * y1) * a_^(x2 + v * y2) then Some (c / (a^z1 * a_^z2))
else None);
}
}.
(** Correctness of the scheme *)
hoare CramerShoup_correct : Correctness(CramerShoup).main : true ==> res.
proof.
proc;inline *;auto => /> &m1 x1 _ x2 _ y1 _ y2 _ z1 _ z2 _ w Hw k _ u _.
have -> /=: (g ^ x1 * g ^ w ^ x2) ^ u *
(g ^ y1 * g ^ w ^ y2) ^
(u * H k (g ^ u, g ^ w ^ u, (g ^ z1 * g ^ w ^ z2) ^ u * m{m1})) =
g ^ u ^
(x1 + H k (g ^ u, g ^ w ^ u, (g ^ z1 * g ^ w ^ z2) ^ u * m{m1}) * y1) *
g ^ w ^ u ^
(x2 + H k (g ^ u, g ^ w ^ u, (g ^ z1 * g ^ w ^ z2) ^ u * m{m1}) * y2).
+ by rewrite log_bij !(log_g, log_pow, log_mul);ring.
by rewrite log_bij -div_def !(log_g, log_pow, log_mul);ring.
qed.
(** IND-CCA Security of the scheme *)
module B_DDH (A:CCA_ADV) = {
module CCA = CCA(CramerShoup, A)
proc guess(gx gy gz:group): bool = {
var g_, a, a_, x1,x2,y1,y2,z1,z2,k,e,f,h,m0,m1,b,b',c,v,d,c',pk;
x1 <$ FDistr.dt;
x2 <$ FDistr.dt;
y1 <$ FDistr.dt;
y2 <$ FDistr.dt;
z1 <$ FDistr.dt;
z2 <$ FDistr.dt;
g_ <- gx;
a <- gy;
a_ <- gz;
k <$ dk;
e <- g^x1 * g_^x2;
f <- g^y1 * g_^y2;
h <- g^z1 * g_^z2;
CCA.log <- [];
CCA.cstar <- None;
pk <- (k, g, g_, g^x1 * g_^x2, g^y1 * g_^y2, g^z1 * g_^z2);
CCA.sk <- (k, g, g_, x1, x2, y1, y2, z1, z2);
(m0,m1) <- CCA.A.choose(pk);
b <$ {0,1};
c <- a^z1 * a_^z2 * (b ? m1 : m0);
v <- H k (a,a_,c);
d <- a^(x1 + v*y1) * a_^(x2+v*y2);
c' <- (a,a_,c,d);
CCA.cstar <- Some c';
b' <- CCA.A.guess(c');
return (b = b');
}
}.
module B_TCR (A:CCA_ADV) = {
var log : ciphertext list
var cstar : ciphertext option
var g3 : ( group * group * group) option
var g_, a, a_, c, d : group
var w, u , u', x, y, z, alpha, v' : t
var k : K
module O = {
proc dec(ci:ciphertext) = {
var m, a,a_,c,d,v;
m <- None;
if (size log < PKE_.qD && Some ci <> cstar) {
log <- ci :: log;
(a,a_,c,d) <- ci;
v <- H k (a, a_, c);
if (a_ <> a^w /\ v = v' /\ (a,a_,c) <> (B_TCR.a, B_TCR.a_,B_TCR.c)) g3 <- Some (a,a_,c);
m = if (a_ = a^w /\ d = a ^ (x + v*y)) then Some (c / a ^ z)
else None;
}
return m;
}
}
module A = A (O)
proc c1() = {
var r';
log <- [];
g3 <- None;
cstar <- None;
w <$ FDistr.dt \ (pred1 F.zero);
u <$ FDistr.dt;
u' <$ FDistr.dt \ (pred1 u);
g_ <- g ^ w;
a <- g^u; a_ <- g_^u';
r' <$ FDistr.dt; c <- g^r';
return (a, a_, c);
}
proc c2 (k:K) = {
var m0, m1, b0, e, f, h, r;
B_TCR.k <- k;
y <$ FDistr.dt; f <- g^y;
z <$ FDistr.dt; h <- g^z;
v' <- H k (a, a_, c);
x <$ FDistr.dt; r <$ FDistr.dt; e <- g^x;
alpha <- (r - u*(x + v'*y))/ (w*(u'-u));
d <- g ^ r;
(m0,m1) <@ A.choose(k, g, g_, e, f, h);
cstar <- Some (a,a_,c,d);
b0 <@ A.guess(a,a_,c,d);
return (oget g3);
}
}.
lemma CCA_dec_ll (A<:CCA_ADV) : islossless CCA(CramerShoup, A).O.dec.
proof. islossless. qed.
section Security_Aux.
declare module A : CCA_ADV {CCA, B_TCR}.
axiom guess_ll : forall (O <: CCA_ORC{A}), islossless O.dec => islossless A(O).guess.
axiom choose_ll : forall (O <: CCA_ORC{A}), islossless O.dec => islossless A(O).choose.
equiv CCA_DDH0 : CCA(CramerShoup, A).main ~ DDH0_ex(B_DDH(A)).main : ={glob A} ==> ={res}.
proof.
proc;inline *;wp.
call (_: ={glob CCA}); 1: sim.
swap{1} 9 -8; swap{1} 20 -18; auto.
call (_: ={glob CCA}); 1: sim.
auto => &m1 &m2 /> w _ u _ x1 _ x2 _ y1 _ y2 _ z1 _ z2 _ k _ r b _.
have -> :
H k
(g ^ u, g ^ w ^ u,
(g ^ z1 * g ^ w ^ z2) ^ u * if b then r.`2 else r.`1) =
H k
(g ^ u, g ^ (w * u),
g ^ u ^ z1 * g ^ (w * u) ^ z2 * if b then r.`2 else r.`1).
+ by congr;congr;rewrite log_bij !(log_g, log_pow, log_mul); ring.
progress;
try by (rewrite log_bij !(log_g, log_pow, log_mul);ring).
smt ().
qed.
lemma pr_CCA_DDH0 &m :
Pr[CCA(CramerShoup, A).main() @ &m : res] =
Pr[DDH0_ex(B_DDH(A)).main() @ &m : res].
proof. by byequiv CCA_DDH0. qed.
local module G1 = {
var log : ciphertext list
var cstar : ciphertext option
var bad : bool
var u,u',w : t
var x,x1,x2 : t
var y,y1,y2 : t
var z,z1,z2 : t
var g_: group
var k : K
module O = {
proc dec(ci:ciphertext) = {
var m, a,a_,c,d,v;
m <- None;
if (size log < PKE_.qD && Some ci <> G1.cstar) {
log <- ci :: log;
(a,a_,c,d) <- ci;
v <- H k (a, a_, c);
bad <- bad \/ (a_ <> a^w /\ d = a ^ (x1 + v*y1) * a_ ^ (x2 + v * y2));
m = if (a_ = a^w /\ d = a ^ (x + v*y)) then Some (c / a ^ z)
else None;
}
return m;
}
}
module A = A(O)
proc a1 () = {
log <- [];
cstar <- None;
bad <- false;
w <$ FDistr.dt \ (pred1 F.zero);
u <$ FDistr.dt;
return ((),u);
}
proc a2 (u0' : t) = {
var m0, m1, b, b0, a, a_, c, d, v, e, f, h;
u' <- u0';
g_ <- g ^ w; k <$ dk;
a <- g^u; a_ <- g_^u';
x <$ FDistr.dt; x2 <$ FDistr.dt; x1 <- x - w * x2; e <- g^x;
y <$ FDistr.dt; y2 <$ FDistr.dt; y1 <- y - w * y2; f <- g^y;
z <$ FDistr.dt; z2 <$ FDistr.dt; z1 <- z - w * z2; h <- g^z;
(m0,m1) <@ A.choose(k, g, g_, e, f, h);
b <$ {0,1};
c <- a^z1 * a_^z2 * (b ? m1 : m0);
v <- H k (a, a_, c);
d <- a^(x1 + v*y1) * a_^(x2+v*y2);
cstar <- Some (a,a_,c,d);
b0 <@ A.guess(a,a_,c,d);
return (b = b0);
}
}.
local equiv DDH1_G1_dec :
CCA(CramerShoup, A).O.dec ~ G1.O.dec :
( !G1.bad{2} /\ c{1} = ci{2} /\
(G1.x{2} = G1.x1{2} + G1.w{2} * G1.x2{2} /\
G1.y{2} = G1.y1{2} + G1.w{2} * G1.y2{2} /\
G1.z{2} = G1.z1{2} + G1.w{2} * G1.z2{2}) /\
CCA.log{1} = G1.log{2} /\ CCA.cstar{1} = G1.cstar{2} /\
CCA.sk{1} = (G1.k{2}, g, G1.g_{2}, G1.x1{2}, G1.x2{2}, G1.y1{2}, G1.y2{2}, G1.z1{2}, G1.z2{2})) ==>
(!G1.bad{2} =>
={res} /\
(G1.x{2} = G1.x1{2} + G1.w{2} * G1.x2{2} /\
G1.y{2} = G1.y1{2} + G1.w{2} * G1.y2{2} /\
G1.z{2} = G1.z1{2} + G1.w{2} * G1.z2{2}) /\
CCA.log{1} = G1.log{2} /\ CCA.cstar{1} = G1.cstar{2} /\
CCA.sk{1} = (G1.k{2}, g, G1.g_{2}, G1.x1{2}, G1.x2{2}, G1.y1{2}, G1.y2{2}, G1.z1{2}, G1.z2{2})).
proof.
proc;sp 0 1;inline *;if => //;auto.
move=> &m1 &m2 /> _ /=;rewrite negb_and /=.
case: (ci{m2}) => a a_ c d => /=.
case: (a_ = a ^ G1.w{m2}) => [ -> _ _ | _ _ _ -> ] //=.
have -> :
a ^ (G1.x1{m2} + H G1.k{m2} (a, a ^ G1.w{m2}, c) * G1.y1{m2}) *
a ^ G1.w{m2} ^ (G1.x2{m2} + H G1.k{m2} (a, a ^ G1.w{m2}, c) * G1.y2{m2}) =
a ^ (G1.x1{m2} + G1.w{m2} * G1.x2{m2} +
H G1.k{m2} (a, a ^ G1.w{m2}, c) * (G1.y1{m2} + G1.w{m2} * G1.y2{m2})).
+ by rewrite log_bij !(log_g, log_pow, log_mul);ring.
have -> // : a ^ G1.z1{m2} * a ^ G1.w{m2} ^ G1.z2{m2} =
a ^ (G1.z1{m2} + G1.w{m2} * G1.z2{m2}).
by rewrite log_bij !(log_g, log_pow, log_mul);ring.
qed.
local lemma G1_dec_ll : islossless G1.O.dec.
proof. by proc;inline *;auto. qed.
local lemma G1_dec_bad : phoare[ G1.O.dec : G1.bad ==> G1.bad ] = 1%r.
proof. by proc; auto => ? ->. qed.
local equiv DDH1_G1 : DDH1_ex(B_DDH(A)).main ~ Ad1.Main(G1).main :
={glob A} ==> !G1.bad{2} => ={res}.
proof.
proc;inline *;wp.
call (_: G1.bad,
(
(G1.x = G1.x1 + G1.w * G1.x2 /\
G1.y = G1.y1 + G1.w * G1.y2 /\
G1.z = G1.z1 + G1.w * G1.z2){2} /\
CCA.log{1} = G1.log{2} /\ CCA.cstar{1} = G1.cstar{2} /\
CCA.sk{1} = (G1.k, g, G1.g_, G1.x1, G1.x2, G1.y1, G1.y2, G1.z1, G1.z2){2})).
+ by apply guess_ll.
+ by apply DDH1_G1_dec.
+ by move=> _ _; apply (CCA_dec_ll A).
+ by move=> _;apply G1_dec_bad.
wp;rnd.
call (_: G1.bad,
(
(G1.x = G1.x1 + G1.w * G1.x2 /\
G1.y = G1.y1 + G1.w * G1.y2 /\
G1.z = G1.z1 + G1.w * G1.z2){2} /\
CCA.log{1} = G1.log{2} /\ CCA.cstar{1} = G1.cstar{2} /\
CCA.sk{1} = (G1.k, g, G1.g_, G1.x1, G1.x2, G1.y1, G1.y2, G1.z1, G1.z2){2})).
+ by apply choose_ll.
+ by apply DDH1_G1_dec.
+ by move=> _ _; apply (CCA_dec_ll A).
+ by move=> _;apply G1_dec_bad.
swap{1} 16 -9;wp.
swap -1;rnd (fun z => z + G1.w{2} * G1.z2{2}) (fun z => z - G1.w{2} * G1.z2{2}).
rnd;wp.
swap -1;rnd (fun z => z + G1.w{2} * G1.y2{2}) (fun z => z - G1.w{2} * G1.y2{2}).
rnd;wp.
swap -1;rnd (fun z => z + G1.w{2} * G1.x2{2}) (fun z => z - G1.w{2} * G1.x2{2}).
rnd;wp;rnd;wp.
rnd (fun z => z / x{1}) (fun z => z * x{1}) => /=.
auto => &m1 &m2 /= -> xL H;rewrite H /=;move: H => /supp_dexcepted.
rewrite /pred1 -ofint0 => -[] InxL HxL yL _.
split => [ ? _ | eqxL]; 1:by field.
move=> zL InzL_; split => [ | _]; 1:by field.
move=> kL -> /= x2L _.
split => [ ? _ | Eqx2L]; 1: by ring.
move=> x1L Inx1L;split; 1: by ring.
move=> _ y2L _ /=;split => [ ? _ | Eqy2L]; 1: by ring.
move=> y1L Iny1L; split => [ | H{H}]; 1: by ring.
move=> z2L _ /=;split => [ ? _ | Eqz2L]; 1: by ring.
move=> z1L Inz1L.
have <- /= : z1L = z1L + xL * z2L - xL * z2L by ring.
have H1 : forall x1L x2L, g ^ x1L * g ^ xL ^ x2L = g ^ (x1L + xL * x2L).
+ by move=> ??;rewrite log_bij !(log_g, log_pow, log_mul);ring.
rewrite !H1 /=.
have H2 : forall x1L x2L, x1L + xL * x2L = x1L + xL * x2L - xL * x2L + xL * x2L.
+ by move=> ??;ring.
rewrite -!H2 /=;split=> [ | _].
+ by split ;ring.
move=> ??????? Hbad ? ? /=.
have <- /= : g ^ zL = g ^ xL ^ (zL / xL).
+ by rewrite log_bij !(log_g, log_pow, log_mul);field.
split.
+ move=> /Hbad [#] !->> /= <- <-.
by split; rewrite log_bij !(log_g, log_pow, log_mul) /=.
by move=> _ {H Hbad} ??????? Hbad /Hbad.
qed.
lemma dt_r_ll x : is_lossless (FDistr.dt \ pred1 x).
proof.
by rewrite dexcepted_ll ?FDistr.dt_ll // FDistr.dt1E ltr_pdivr_mulr /= lt_fromint; smt (gt1_q).
qed.
local lemma aux1 &m :
Pr[CCA(CramerShoup, A).main() @ &m : res] <=
`| Pr[DDH0(B_DDH(A)).main() @ &m : res] - Pr[DDH1(B_DDH(A)).main() @ &m : res] |
+ Pr[Ad1.MainE(G1).main() @ &m : res \/ G1.bad] + 3%r/q%r.
proof.
have -> :
Pr[CCA(CramerShoup, A).main() @ &m : res] = Pr[DDH0_ex(B_DDH(A)).main() @ &m : res].
+ byequiv CCA_DDH0 => //.
have := adv_DDH_DDH_ex (B_DDH(A)) _ &m.
+ proc;call (guess_ll (<:CCA(CramerShoup,A).O) (CCA_dec_ll A));auto.
call (choose_ll (<:CCA(CramerShoup,A).O) (CCA_dec_ll A));auto => /=.
by rewrite FDistr.dt_ll DBool.dbool_ll dk_ll.
have : Pr[DDH1_ex(B_DDH(A)).main() @ &m : res] <=
Pr[Ad1.Main(G1).main() @ &m : res \/ G1.bad].
+ byequiv DDH1_G1 => //;1: smt ().
(* print glob G1. *)
have /= := Ad1.pr_abs G1 _ _ &m (fun (b:bool) (x : glob G1) => b \/ x.`14).
+ proc;auto => />; by rewrite dt_r_ll ?FDistr.dt_ll.
+ proc;auto;call (guess_ll (<:G1.O) G1_dec_ll);auto.
by call (choose_ll (<:G1.O) G1_dec_ll);auto; rewrite dk_ll FDistr.dt_ll DBool.dbool_ll.
smt (mu_bounded).
qed.
local module G2 = {
module O = G1.O
module A = G1.A
var alpha, v: t
proc main1 () = {
var m0, m1, b, b0, v, e, f, h, r', a, a_, c, d;
G1.log <- [];
G1.cstar <- None;
G1.bad <- false;
G1.w <$ FDistr.dt \ (pred1 F.zero);
G1.u <$ FDistr.dt;
G1.u' <$ FDistr.dt \ (pred1 G1.u);
G1.g_ <- g ^ G1.w; G1.k <$ dk;
a <- g^G1.u; a_ <- G1.g_^G1.u';
G1.x <$ FDistr.dt; G1.x2 <$ FDistr.dt; G1.x1 <- G1.x - G1.w * G1.x2; e <- g^G1.x;
G1.y <$ FDistr.dt; G1.y2 <$ FDistr.dt; G1.y1 <- G1.y - G1.w * G1.y2; f <- g^G1.y;
G1.z <$ FDistr.dt; h <- g^G1.z;
(m0,m1) <@ A.choose(G1.k, g, G1.g_, e, f, h);
b <$ {0,1};
r' <$ FDistr.dt;
c <- g^r';
v <- H G1.k (a, a_, c);
d <- a^(G1.x1 + v*G1.y1) * a_^(G1.x2+v*G1.y2);
G1.cstar <- Some (a,a_,c,d);
b0 <@ A.guess(a,a_,c,d);
return (b = b0);
}
proc main () = {
var m0, m1, b, b0, e, f, h, r, r', a, a_, c, d;
G1.log <- [];
G1.cstar <- None;
G1.bad <- false;
G1.w <$ FDistr.dt \ (pred1 F.zero);
G1.u <$ FDistr.dt;
G1.u' <$ FDistr.dt \ (pred1 G1.u);
G1.g_ <- g ^ G1.w; G1.k <$ dk;
a <- g^G1.u; a_ <- G1.g_^G1.u';
G1.y <$ FDistr.dt; G1.y2 <$ FDistr.dt; G1.y1 <- G1.y - G1.w * G1.y2; f <- g^G1.y;
G1.z <$ FDistr.dt; r' <$ FDistr.dt; h <- g^G1.z;
c <- g^r';
v <- H G1.k (a, a_, c);
G1.x <$ FDistr.dt; r <$ FDistr.dt;
alpha <- (r - G1.u*(G1.x + v*G1.y))/ (G1.w*(G1.u'-G1.u));
G1.x2 <- alpha - v*G1.y2;
G1.x1 <- G1.x - G1.w * G1.x2; e <- g^G1.x;
d <- g ^ r;
(m0,m1) <@ A.choose(G1.k, g, G1.g_, e, f, h);
G1.cstar <- Some (a,a_,c,d);
b0 <@ A.guess(a,a_,c,d);
b <$ {0,1};
return (b = b0);
}
}.
local equiv G1_G21 : Ad1.MainE(G1).main ~ G2.main1 : ={glob A} ==> ={res, G1.bad}.
proof.
proc;inline *;wp.
call (_: ={G1.bad, G1.cstar, G1.log, G1.x, G1.x1, G1.x2, G1.y,
G1.y1, G1.y2, G1.z, G1.w, G1.k}).
+ by sim => />.
swap{1} [23..24] 3;wp => /=.
rnd (fun z2 => G1.u*G1.z - G1.u*G1.w*z2 + G1.w*G1.u'* z2 + log (b ? m1 : m0)){1}
(fun r' => (r' - G1.u*G1.z - log (b ? m1 : m0)) / (G1.w * (G1.u' - G1.u))){1}.
rnd.
call (_: ={G1.bad, G1.cstar, G1.log, G1.x, G1.x1, G1.x2, G1.y,
G1.y1, G1.y2, G1.z, G1.w, G1.k}).
+ by sim => />.
auto => &m1 &m2 />;rewrite /pred1 -ofint0.
move=> wL /supp_dexcepted [] _ /= HwL uL _ u'L /supp_dexcepted [] _ /= Hu'L .
move=> kL _ xL _ x2L _ yL _ y2L _ zL _ resu bL _.
have H1 : (-uL) * wL + u'L * wL = wL * (u'L - uL) by ring.
have H2 : (-uL) * wL + u'L * wL <> ofint 0.
+ rewrite H1 ofint0 mulf_eq0 negb_or -{1}ofint0 HwL /=.
by move: Hu'L;apply: contra => H;ring H.
split => [? _ | _ ]; 1: by field.
move=> z2L _; split => [ | _]; 1: by field.
pose HH1 := H _ _; pose HH2 := H _ _.
have -> : HH1 = HH2.
+ rewrite /HH1 /HH2;do 2!congr.
by rewrite log_bij !(log_g, log_pow, log_mul);ring.
progress; rewrite log_bij !(log_g, log_pow, log_mul);field => //.
qed.
local equiv G21_G2 : G2.main1 ~ G2.main : ={glob A} ==> ={res, G1.bad}.
proof.
proc;inline *;wp. swap{2} -2.
call (_: ={G1.bad, G1.cstar, G1.log, G1.x, G1.x1, G1.x2, G1.y,
G1.y1, G1.y2, G1.z, G1.w, G1.k}).
+ by sim => />.
wp;swap {1} [11..14] 6;swap{1} -7;rnd.
call (_: ={G1.bad, G1.cstar, G1.log, G1.x, G1.x1, G1.x2, G1.y,
G1.y1, G1.y2, G1.z, G1.w, G1.k}).
+ by sim => />.
wp.
rnd (fun x2 => (x2 + G2.v*G1.y2) * (G1.w*(G1.u'-G1.u)) + G1.u*(G1.x + G2.v*G1.y)){2}
(fun r => (r - G1.u*(G1.x + G2.v*G1.y))/ (G1.w*(G1.u'-G1.u)) - G2.v*G1.y2){2}.
auto => &m1 &m2 />;rewrite /pred1 -ofint0.
move=> wL /supp_dexcepted [] _ /= HwL uL _ u'L /supp_dexcepted [] _ /= Hu'L .
move=> kL _ yL _ y2L _ zL _ r'L _ xL _.
have H1 : (-uL) * wL + u'L * wL = wL * (u'L - uL) by ring.
have H2 : (-uL) * wL + u'L * wL <> ofint 0.
+ rewrite H1 ofint0 mulf_eq0 negb_or -{1}ofint0 HwL /=.
by move: Hu'L;apply: contra => H;ring H.
split => [? _ | _ ]; 1: by field.
move=> z2L _; split => [ | _]; 1: by field.
by progress;2..3:rewrite log_bij !(log_g, log_pow, log_mul);field.
qed.
local lemma pr_G2_res &m: Pr[G2.main() @ &m : res] <= 1%r/2%r.
proof.
byphoare=> //;proc;rnd;conseq (_: _ ==> true) => //=.
by move=> ?;rewrite DBool.dbool1E.
qed.
local module G3 = {
var g3 : ( group * group * group) option
var y2log : t list
var cilog : ciphertext list
var a, a_, c, d: group
module O = {
proc dec(ci:ciphertext) = {
var m, a,a_,c,d,v, y2';
m <- None;
if (size G1.log < PKE_.qD && Some ci <> G1.cstar) {
cilog <- (G1.cstar = None) ? ci :: cilog : cilog;
G1.log <- ci :: G1.log;
(a,a_,c,d) <- ci;
v <- H G1.k (a, a_, c);
if (a_ <> a^G1.w) {
if (v = G2.v /\ (a,a_,c) <> (G3.a,G3.a_,G3.c)) g3 <- Some (a,a_,c);
else {
y2' <- ((log d - log a*(G1.x + v*G1.y))/(log a_ - log a*G1.w) - G2.alpha) / (v -G2.v);
y2log <- y2' :: y2log;
}
}
m = if (a_ = a^G1.w /\ d = a ^ (G1.x + v*G1.y)) then Some (c / a ^ G1.z)
else None;
}
return m;
}
}
module A = A (O)
proc main () = {
var m0, m1, b0, e, f, h, r, r';
G1.log <- [];
G3.y2log <- [];
G3.cilog <- [];
G3.g3 <- None;
G1.cstar <- None;
G1.w <$ FDistr.dt \ (pred1 F.zero);
G1.u <$ FDistr.dt;
G1.u' <$ FDistr.dt \ (pred1 G1.u);
G1.g_ <- g ^ G1.w; G1.k <$ dk;
a <- g^G1.u; a_ <- G1.g_^G1.u';
G1.y <$ FDistr.dt; f <- g^G1.y;
G1.z <$ FDistr.dt; r' <$ FDistr.dt; h <- g^G1.z;
c <- g^r';
G2.v <- H G1.k (a, a_, c);
G1.x <$ FDistr.dt; r <$ FDistr.dt; e <- g^G1.x;
G2.alpha <- (r - G1.u*(G1.x + G2.v*G1.y))/ (G1.w*(G1.u'-G1.u));
d <- g ^ r;
(m0,m1) <@ A.choose(G1.k, g, G1.g_, e, f, h);
G1.cstar <- Some (a,a_,c,d);
b0 <@ A.guess(a,a_,c,d);
G1.y2 <$ FDistr.dt;
G1.y1 <- G1.y - G1.w * G1.y2;
G1.x2 <- G2.alpha - G2.v*G1.y2;
G1.x1 <- G1.x - G1.w * G1.x2;
}
}.
local equiv G2_G3_dec : G1.O.dec ~ G3.O.dec :
! (G3.g3 <> None \/ (G3.a, G3.a_,G3.c, G3.d) \in G3.cilog){2} /\
={ci} /\ ={G1.x, G1.y, G1.z, G1.x1, G1.x2, G1.y1, G1.y2, G1.log, G1.cstar, G1.w,
G1.u, G1.u', G1.k} /\
(G1.cstar <> None => G1.cstar = Some (G3.a,G3.a_,G3.c,G3.d)){2} /\
(G3.d = G3.a^(G1.x1 + G2.v*G1.y1) * G3.a_^(G1.x2+G2.v*G1.y2) /\
G1.y1 = G1.y - G1.w * G1.y2 /\
G1.x1 = G1.x - G1.w * G1.x2 /\
G1.x2 = G2.alpha - G2.v * G1.y2){2} /\
(G1.bad{1} => G1.y2{2} \in G3.y2log{2}) ==>
!(G3.g3 <> None \/ (G3.a, G3.a_,G3.c, G3.d) \in G3.cilog){2} =>
(={res} /\ ={G1.x, G1.y, G1.z, G1.x1, G1.x2, G1.y1, G1.y2, G1.log, G1.cstar, G1.w,
G1.u, G1.u', G1.k} /\
(G1.cstar <> None => G1.cstar = Some (G3.a,G3.a_,G3.c,G3.d)){2} /\
(G3.d = G3.a^(G1.x1 + G2.v*G1.y1) * G3.a_^(G1.x2+G2.v*G1.y2) /\
G1.y1 = G1.y - G1.w * G1.y2 /\
G1.x1 = G1.x - G1.w * G1.x2 /\
G1.x2 = G2.alpha - G2.v * G1.y2){2} /\
(G1.bad{1} => G1.y2{2} \in G3.y2log{2})).
proof.
proc;auto => &m1 &m2 />.
case: (ci{m2}) => a a_ c d /=.
pose v := H _ _. rewrite !negb_or => [[]] Hg3 Hcilog Hstareq.
rewrite Hg3 /=.
case: (G1.bad{m1}) => [_ -> | ] //=.
move=> Hbad Hsize Hstar;rewrite !negb_and /= 2!negb_or /= -!andaE.
case (v = G2.v{m2}) => [->> /= ? [#]!->> Hstar1 ->>| /=].
+ by case: (G1.cstar{m2}) Hstareq Hstar Hstar1.
move=> Hv Ha _ ->>;left.
rewrite !(log_g, log_pow, log_mul);field => //.
+ by move: Hv;apply: contra;rewrite ofint0 => H;ring H.
by move: Ha;apply: contra; rewrite log_bij log_pow ofint0 => H;ring H.
qed.
local equiv G2_G3 : G2.main ~ G3.main :
={glob A} ==>
!(G3.g3 <> None \/ (G3.a, G3.a_,G3.c, G3.d) \in G3.cilog){2} =>
(G1.bad{1} => (G1.y2 \in G3.y2log){2}).
proof.
proc.
swap{2} [28..29] -14. swap{2} [30..31] -4. rnd{1}.
call (_ : (G3.g3 <> None \/ (G3.a, G3.a_,G3.c, G3.d) \in G3.cilog),
(={G1.x, G1.y, G1.z, G1.x1, G1.x2, G1.y1, G1.y2, G1.log, G1.cstar, G1.w,
G1.u, G1.u', G1.k} /\
(G1.cstar <> None => G1.cstar = Some (G3.a,G3.a_,G3.c,G3.d)){2} /\
(G3.d = G3.a^(G1.x1 + G2.v*G1.y1) * G3.a_^(G1.x2+G2.v*G1.y2) /\
G1.y1 = G1.y - G1.w * G1.y2 /\
G1.x1 = G1.x - G1.w * G1.x2 /\
G1.x2 = G2.alpha - G2.v * G1.y2){2} /\
(G1.bad{1} => G1.y2{2} \in G3.y2log{2}))).
+ by apply guess_ll.
+ by apply G2_G3_dec.
+ by move=> &m2 _;apply G1_dec_ll.
+ by move=> /=;proc;auto => /#.
wp;call (_ : (G3.g3 <> None \/ (G3.a, G3.a_,G3.c, G3.d) \in G3.cilog),
(={G1.x, G1.y, G1.z, G1.x1, G1.x2, G1.y1, G1.y2, G1.log, G1.cstar, G1.w,
G1.u, G1.u', G1.k} /\
(G1.cstar <> None => G1.cstar = Some (G3.a,G3.a_,G3.c,G3.d)){2} /\
(G3.d = G3.a^(G1.x1 + G2.v*G1.y1) * G3.a_^(G1.x2+G2.v*G1.y2) /\
G1.y1 = G1.y - G1.w * G1.y2 /\
G1.x1 = G1.x - G1.w * G1.x2 /\
G1.x2 = G2.alpha - G2.v * G1.y2){2} /\
(G1.bad{1} => G1.y2{2} \in G3.y2log{2}))).
+ by apply choose_ll.
+ by apply G2_G3_dec.
+ by move=> &m2 _;apply G1_dec_ll.
+ by move=> /=;proc;auto => /#.
auto => &m1 &m2 />.
move=> wL /supp_dexcepted [] _;rewrite /pred1 -F.ofint0 => HwL0.
move=> uL _ u'L /supp_dexcepted [] _ /= HuL kL _.
move=> yL _ y2L _ zL _ r'L _ xL _ rL _.
have H1 : (-uL) * wL + u'L * wL = wL * (u'L - uL) by ring.
have H2 : (-uL) * wL + u'L * wL <> ofint 0.
+ rewrite H1 ofint0 mulf_eq0 negb_or -{1}ofint0 HwL0 /=.
by move: HuL;apply: contra => H;ring H.
split => [ | _].
+ by rewrite log_bij !(log_g, log_pow, log_mul);field.
smt().
qed.
local lemma pr_G3_y2log &m :
Pr[G3.main() @ &m : G1.y2 \in G3.y2log] <= PKE_.qD%r / q%r.
proof.
byphoare => //;proc;wp;rnd.
conseq (_: _ ==> size G3.y2log <= PKE_.qD) => /=.
+ move=> y2log Hsize;apply (ler_trans ((size y2log)%r/q%r)).
+ by apply (mu_mem_le_mu1 FDistr.dt y2log (inv q%r)) => x;rewrite FDistr.dt1E.
apply ler_wpmul2r => //;2: by apply le_fromint.
apply invr_ge0;smt (le_fromint gt1_q).
call (_: size G3.y2log <= size G1.log /\ size G3.y2log <= PKE_.qD).
+ proc;auto => /#.
auto;call (_: size G3.y2log <= size G1.log /\ size G3.y2log <= PKE_.qD).
+ proc;auto => /#.
auto => />;smt (qD_pos).
qed.
local equiv G3_TCR : G3.main ~ TCR(B_TCR(A)).main : ={glob A} ==> G3.g3{1} <> None => res{2}.
proof.
proc;inline *;wp;rnd{1}.
call (_ : B_TCR.log{2} = G1.log{1} /\
B_TCR.cstar{2} = G1.cstar{1} /\
B_TCR.k{2} = G1.k{1} /\
B_TCR.x{2} = G1.x{1} /\ B_TCR.y{2} = G1.y{1} /\ B_TCR.z{2} = G1.z{1} /\
B_TCR.a{2} = G3.a{1} /\ B_TCR.a_{2} = G3.a_{1} /\ B_TCR.c{2} = G3.c{1} /\
B_TCR.v'{2} = G2.v{1} /\
B_TCR.w{2} = G1.w{1} /\
B_TCR.g3{2} = G3.g3{1} /\
(G3.g3{1} <> None =>
(H B_TCR.k (oget B_TCR.g3) = B_TCR.v' /\ (oget B_TCR.g3) <>
(B_TCR.a,B_TCR.a_,B_TCR.c)){2})).
+ by proc;auto=> /#.
wp; call (_ : B_TCR.log{2} = G1.log{1} /\
B_TCR.cstar{2} = G1.cstar{1} /\
B_TCR.k{2} = G1.k{1} /\
B_TCR.x{2} = G1.x{1} /\ B_TCR.y{2} = G1.y{1} /\ B_TCR.z{2} = G1.z{1} /\
B_TCR.a{2} = G3.a{1} /\ B_TCR.a_{2} = G3.a_{1} /\ B_TCR.c{2} = G3.c{1} /\
B_TCR.v'{2} = G2.v{1} /\
B_TCR.w{2} = G1.w{1} /\
B_TCR.g3{2} = G3.g3{1} /\
(G3.g3{1} <> None =>
(H B_TCR.k (oget B_TCR.g3) = B_TCR.v' /\ (oget B_TCR.g3) <>
(B_TCR.a,B_TCR.a_,B_TCR.c)){2})).
+ by proc;auto=> /#.
swap{1} 16 -7;auto; smt (FDistr.dt_ll).
qed.
local module G4 = {
module O = {
proc dec(ci:ciphertext) = {
var m, a,a_,c,d,v;
m <- None;
if (size G1.log < PKE_.qD && Some ci <> G1.cstar) {
G3.cilog <- (G1.cstar = None) ? ci :: G3.cilog : G3.cilog;
G1.log <- ci :: G1.log;
(a,a_,c,d) <- ci;
v <- H G1.k (a, a_, c);
m = if (a_ = a^G1.w /\ d = a ^ (G1.x + v*G1.y)) then Some (c / a ^ G1.z)
else None;
}
return m;
}
}
module A = A (O)
proc main () = {
var m0, m1, b0, e, f, h, r, r';
G1.log <- [];
G3.cilog <- [];
G1.cstar <- None;
G1.w <$ FDistr.dt \ (pred1 F.zero);
G1.g_ <- g ^ G1.w;
G1.k <$ dk;
G1.y <$ FDistr.dt; f <- g^G1.y;
G1.z <$ FDistr.dt; h <- g^G1.z;
G1.x <$ FDistr.dt; e <- g^G1.x;
(m0,m1) <@ A.choose(G1.k, g, G1.g_, e, f, h);
G1.u <$ FDistr.dt;
G1.u' <$ FDistr.dt \ (pred1 G1.u);
r' <$ FDistr.dt;
r <$ FDistr.dt;
G3.a <- g^G1.u; G3.a_ <- G1.g_^G1.u';G3.c <- g^r'; G3.d <- g ^ r;
G2.v <- H G1.k (G3.a, G3.a_, G3.c);
G2.alpha <- (r - G1.u*(G1.x + G2.v*G1.y))/ (G1.w*(G1.u'-G1.u));
G1.cstar <- Some (G3.a,G3.a_,G3.c,G3.d);
b0 <@ A.guess(G3.a,G3.a_,G3.c,G3.d);
}
}.
local equiv G3_G4 : G3.main ~ G4.main : ={glob A} ==> ={G3.a, G3.a_,G3.c, G3.d, G3.cilog}.
proof.
proc;wp;rnd{1}.
call (_ : ={G1.log, G1.cstar, G1.k, G1.w, G1.x, G1.y, G1.z, G3.cilog}).
+ by proc;auto => />.
wp. swap{2} [14..17] -1.
call (_ : ={G1.log, G1.cstar, G1.k, G1.w, G1.x, G1.y, G1.z, G3.cilog}).
+ by proc;auto => />.
swap{2} [13..14]-8. swap{2} [13..14]1.
by auto => />;rewrite FDistr.dt_ll.
qed.
(* TODO: move this ?*)
lemma mu_mem_le_mu1_size (dt : 'a distr) (l : 'a list) (r : real) n:
size l <= n =>
(forall (x : 'a), mu1 dt x <= r) => mu dt (mem l) <= n%r * r.
proof.
move=> Hsize Hmu1;apply (ler_trans ((size l)%r * r)).
+ by apply mu_mem_le_mu1.
apply ler_wpmul2r; 1: smt (mu_bounded).
by apply le_fromint.
qed.
import StdRing.RField.
local lemma pr_G4 &m:
Pr[G4.main() @ &m : (G3.a, G3.a_,G3.c, G3.d) \in G3.cilog] <=
(PKE_.qD%r/q%r)^3 * (PKE_.qD%r/(q-1)%r).
proof.
byphoare=> //;proc.
seq 23 : ((G3.a, G3.a_, G3.c, G3.d) \in G3.cilog)
((PKE_.qD%r / q%r)^3 * (PKE_.qD%r / (q - 1)%r)) 1%r _ 0%r => //;last first.
+ hoare; call (_ : G1.cstar <> None /\ !(G3.a, G3.a_, G3.c, G3.d) \in G3.cilog).
+ by proc;auto => /#.
by auto.
seq 13 : true 1%r ((PKE_.qD%r / q%r) ^ 3 * (PKE_.qD%r / (q - 1)%r))
0%r _ (size G3.cilog <= PKE_.qD /\ G1.w <> F.zero /\ G1.g_ = g ^ G1.w) => //.
+ call (_ : size G3.cilog <= size G1.log /\ size G1.log <= PKE_.qD).
+ proc;auto => /#.
auto => /= w /supp_dexcepted;smt (qD_pos).
wp;conseq (_ : _ ==> G1.u \in map (fun (g4:ciphertext) => log g4.`1) G3.cilog /\
G1.u' \in map (fun (g4:ciphertext) => log g4.`2 / G1.w) G3.cilog /\
r' \in map (fun (g4:ciphertext) => log g4.`3) G3.cilog /\
r \in map (fun (g4:ciphertext) => log g4.`4) G3.cilog).
+ move=> &hr />;rewrite -ofint0 => _ Hw u u' r r' Hlog.
do !split;apply mapP;
exists (G.g ^ u, g ^ G1.w{hr} ^ u', G.g ^ r', G.g ^ r);
rewrite Hlog /= !log_pow ?log_g;1,3,4: by ring.
by field.
seq 1 : (G1.u \in map (fun (g4 : ciphertext) => log g4.`1) G3.cilog)
(PKE_.qD%r / q%r) ((PKE_.qD%r / q%r)^2 * (PKE_.qD%r / (q - 1)%r))
_ 0%r (size G3.cilog <= PKE_.qD) => //;
last 2 first.
+ hoare;conseq (_ : _ ==> true) => // /#.
+ move=> &hr _;apply lerr_eq;ring.
+ by auto.
+ rnd;skip => /> &hr Hsize _;pose m' := map _ _.
apply (mu_mem_le_mu1_size FDistr.dt m') => //.
+ by rewrite /m' size_map.
by move=> ?;rewrite FDistr.dt1E.
seq 1 : (G1.u' \in map (fun (g4 : ciphertext) => log g4.`2 / G1.w) G3.cilog)
(PKE_.qD%r / (q-1)%r) ((PKE_.qD%r / q%r)^2) _ 0%r
(size G3.cilog <= PKE_.qD) => //;last 2 first.
+ hoare;conseq (_ : _ ==> true) => // /#.
+ move=> &hr _;apply lerr_eq;ring.
+ by auto.
+ rnd;skip => /> &hr Hsize _;pose m' := map _ _.
apply (mu_mem_le_mu1_size (FDistr.dt \ pred1 G1.u{hr}) m') => //.
+ by rewrite /m' size_map.
move=> x;rewrite dexcepted1E {1}/pred1.
case: (x = G1.u{hr}) => _.
+ apply invr_ge0;smt (le_fromint gt1_q).
rewrite FDistr.dt_ll !FDistr.dt1E;apply lerr_eq.
field;smt (gt1_q le_fromint).
seq 1 : (r' \in map (fun (g4 : ciphertext) => log g4.`3) G3.cilog)
(PKE_.qD%r / q%r) (PKE_.qD%r / q%r) _ 0%r
(size G3.cilog <= PKE_.qD) => //;last 2 first.
+ hoare;conseq (_ : _ ==> true) => // /#.
+ move=> &hr _;apply lerr_eq;field.
+ rewrite (_: 2 = (0 + 1) + 1) // !powrS // powr0;smt (le_fromint gt1_q).
smt (le_fromint gt1_q).
+ by auto.
+ rnd;skip => /> &hr Hsize _;pose m' := map _ _.
apply (mu_mem_le_mu1_size FDistr.dt m') => //.
+ by rewrite /m' size_map.
by move=> ?;rewrite FDistr.dt1E.
conseq (_ : _ ==> (r \in map (fun (g4 : ciphertext) => log g4.`4) G3.cilog)) => //.
rnd;skip => /> &hr Hsize _;pose m' := map _ _.
apply (mu_mem_le_mu1_size FDistr.dt m') => //.
+ by rewrite /m' size_map.
by move=> ?;rewrite FDistr.dt1E.
qed.
lemma aux2 &m :
Pr[CCA(CramerShoup, A).main() @ &m : res] <=
`|Pr[DDH0(B_DDH(A)).main() @ &m : res] -
Pr[DDH1(B_DDH(A)).main() @ &m : res]| +
Pr[TCR(B_TCR(A)).main() @ &m : res] +
1%r/2%r + (PKE_.qD + 3)%r / q%r + (PKE_.qD%r/q%r)^3 * (PKE_.qD%r/(q-1)%r).
proof.
have := aux1 &m.
have -> : Pr[Ad1.MainE(G1).main() @ &m : res \/ G1.bad] =
Pr[G2.main1() @ &m : res \/ G1.bad].
+ by byequiv G1_G21.
have -> : Pr[G2.main1() @ &m : res \/ G1.bad] = Pr[G2.main() @ &m : res \/ G1.bad].
+ by byequiv G21_G2.
have : Pr[G2.main() @ &m : res \/ G1.bad] <= 1%r/2%r + Pr[G2.main() @ &m : G1.bad].
+ by rewrite Pr [mu_or];have := (pr_G2_res &m);smt (mu_bounded).
have : Pr[G2.main() @ &m : G1.bad] <=
Pr[G3.main() @ &m : G3.g3 <> None \/ (G3.a, G3.a_,G3.c, G3.d) \in G3.cilog \/
G1.y2 \in G3.y2log].
+ byequiv G2_G3 => // /#.
rewrite Pr [mu_or];rewrite Pr [mu_or].
have : Pr[G3.main() @ &m : G3.g3 <> None] <= Pr[TCR(B_TCR(A)).main() @ &m : res].
+ byequiv G3_TCR => //.
have : Pr[G3.main() @ &m : (G3.a, G3.a_,G3.c, G3.d) \in G3.cilog] =
Pr[G4.main() @ &m : (G3.a, G3.a_,G3.c, G3.d) \in G3.cilog].
+ byequiv G3_G4=> //.
have := pr_G4 &m.
have := pr_G3_y2log &m.
have -> : (PKE_.qD + 3)%r / q%r = PKE_.qD%r/q%r + 3%r/q%r.
+ by rewrite fromintD;ring.
smt (mu_bounded).
qed.
end section Security_Aux.
section Security.
declare module A : CCA_ADV {CCA, B_TCR}.
axiom guess_ll : forall (O <: CCA_ORC{A}), islossless O.dec => islossless A(O).guess.
axiom choose_ll : forall (O <: CCA_ORC{A}), islossless O.dec => islossless A(O).choose.
local module NA (O:CCA_ORC) = {
module A = A(O)
proc choose = A.choose
proc guess(c:ciphertext) = {
var b;
b <@ A.guess(c);
return !b;
}
}.
local lemma CCA_NA &m :
Pr[CCA(CramerShoup, A).main() @ &m : res] =
1%r - Pr[CCA(CramerShoup, NA).main() @ &m : res].
proof.
have -> : Pr[CCA(CramerShoup, NA).main() @ &m : res] =
Pr[CCA(CramerShoup, A).main() @ &m : !res].
+ byequiv=> //;proc;inline *;wp.
by conseq (_ : _ ==> ={b} /\ b'{2} = b0{1});[ smt() | sim].
rewrite Pr [mu_not].
have -> : Pr[CCA(CramerShoup, A).main() @ &m : true] = 1%r;last by ring.
byphoare=> //;proc; islossless.
+ by apply (guess_ll (<:CCA(CramerShoup, A).O) (CCA_dec_ll A)).
+ by apply (choose_ll (<:CCA(CramerShoup, A).O) (CCA_dec_ll A)).
apply dexcepted_ll; 1: by apply FDistr.dt_ll.
rewrite FDistr.dt1E;smt (le_fromint gt1_q).
qed.
local lemma DDH0_NA &m : Pr[DDH0(B_DDH(NA)).main() @ &m : res] =
1%r - Pr[DDH0(B_DDH(A)).main() @ &m : res].
proof.
have -> : Pr[DDH0(B_DDH(NA)).main() @ &m : res] =
Pr[DDH0(B_DDH(A)).main() @ &m : !res].
+ byequiv=> //;proc;inline *;wp.
by conseq (_ : _ ==> ={b0} /\ b'{2} = b1{1});[ smt() | sim].
rewrite Pr [mu_not];congr.
byphoare=> //;proc;inline *;auto.
islossless.
+ by apply (guess_ll (<:CCA(CramerShoup, A).O) (CCA_dec_ll A)).
by apply (choose_ll (<:CCA(CramerShoup, A).O) (CCA_dec_ll A)).
qed.
local lemma DDH1_NA &m : Pr[DDH1(B_DDH(NA)).main() @ &m : res] =
1%r - Pr[DDH1(B_DDH(A)).main() @ &m : res].
proof.
have -> : Pr[DDH1(B_DDH(NA)).main() @ &m : res] =
Pr[DDH1(B_DDH(A)).main() @ &m : !res].
+ byequiv=> //;proc;inline *;wp.
by conseq (_ : _ ==> ={b0} /\ b'{2} = b1{1});[ smt() | sim].
rewrite Pr [mu_not];congr.
byphoare=> //; islossless.
+ by apply (guess_ll (<:CCA(CramerShoup, A).O) (CCA_dec_ll A)).
by apply (choose_ll (<:CCA(CramerShoup, A).O) (CCA_dec_ll A)).
qed.
local lemma TCR_NA &m : Pr[TCR(B_TCR(NA)).main() @ &m : res] =
Pr[TCR(B_TCR(A)).main() @ &m : res].
proof.
byequiv=> //;proc;inline *;sim.
call (_: ={ B_TCR.v', B_TCR.k, B_TCR.cstar, B_TCR.a, B_TCR.a_, B_TCR.c,
B_TCR.log, B_TCR.g3, B_TCR.w, B_TCR.x, B_TCR.y, B_TCR.z}).
+ by sim.
auto;call (_: ={ B_TCR.v', B_TCR.k, B_TCR.cstar, B_TCR.a, B_TCR.a_, B_TCR.c,
B_TCR.log, B_TCR.g3, B_TCR.w, B_TCR.x, B_TCR.y, B_TCR.z});2: by auto.
by sim.
qed.
lemma conclusion &m :
`|Pr[CCA(CramerShoup, A).main() @ &m : res] - 1%r/2%r | <=
`|Pr[DDH0(B_DDH(A)).main() @ &m : res] - Pr[DDH1(B_DDH(A)).main() @ &m : res]| +
Pr[TCR(B_TCR(A)).main() @ &m : res] +
(PKE_.qD + 3)%r / q%r + (PKE_.qD%r/q%r)^3 * (PKE_.qD%r/(q-1)%r).
proof.
case (Pr[CCA(CramerShoup, A).main() @ &m : res] <= 1%r/2%r);last first.
+ have /# := aux2 A guess_ll choose_ll &m.
have := aux2 NA _ choose_ll &m.
+ by move=> O O_ll;proc;inline *;call (_ : true) => //; apply guess_ll.
rewrite (CCA_NA &m) (DDH0_NA &m) (DDH1_NA &m) (TCR_NA &m).
smt (mu_bounded).
qed.
end section Security.