-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathSymEnc.ec
175 lines (131 loc) · 4.77 KB
/
SymEnc.ec
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
(* SymEnc.ec *)
(* Symmetric Encryption *)
(* definitions, including games for judging correctness and IND-CPA
(indistinguishability under chosen plaintext attack) security *)
prover [""]. (* no SMT solvers *)
require import AllCore Distr DBool.
(* theory parameters *)
type key. (* encryption keys *)
type text. (* plaintexts *)
type cipher. (* ciphertexts *)
op ciph_def : cipher. (* default ciphertext *)
(* encryption oracle limit before game's encryption
this says limit_pre has type int and the axiom ge0_limit_pre says
limit_pre is non-negative *)
op limit_pre : {int | 0 <= limit_pre} as ge0_limit_pre.
(* encryption oracle limit after game's encryption *)
op limit_post : {int | 0 <= limit_post} as ge0_limit_post.
(* end theory parameters *)
(* module type of encryption schemes
an encryption scheme Enc should be stateless, meaning that
forall (g1 g2 : glob Enc), g1 = g2 *)
module type ENC = {
(* key generation *)
proc key_gen() : key
(* encryption *)
proc enc(k : key, x : text) : cipher
(* decryption *)
proc dec(k : key, c : cipher) : text
}.
(* module for checking correctness of encryption, parameterized
by encryption scheme
correctness means main returns true with probability 1, without any
assumptions about value of x *)
module Cor (Enc : ENC) = {
proc main(x : text) : bool = {
var k : key; var c : cipher; var y : text;
k <@ Enc.key_gen();
c <@ Enc.enc(k, x);
y <@ Enc.dec(k, c);
return x = y;
}
}.
(* module type of encryption oracles *)
module type EO = {
(* initialization *)
proc init() : unit
(* encryption of text by adversary before game's encryption *)
proc enc_pre(x : text) : cipher
(* one-time encryption of text by game *)
proc genc(x : text) : cipher
(* encryption of text by adversary after game's encryption *)
proc enc_post(x : text) : cipher
}.
(* standard encryption oracle, constructed from an encryption
scheme *)
module EncO (Enc : ENC) : EO = {
var key : key
var ctr_pre : int
var ctr_post : int
proc init() : unit = {
key <@ Enc.key_gen();
ctr_pre <- 0; ctr_post <- 0;
}
proc enc_pre(x : text) : cipher = {
var c : cipher;
if (ctr_pre < limit_pre) {
ctr_pre <- ctr_pre + 1;
c <@ Enc.enc(key, x);
}
else {
c <- ciph_def; (* default result *)
}
return c;
}
proc genc(x : text) : cipher = {
var c : cipher;
c <@ Enc.enc(key, x);
return c;
}
proc enc_post(x : text) : cipher = {
var c : cipher;
if (ctr_post < limit_post) {
ctr_post <- ctr_post + 1;
c <@ Enc.enc(key, x);
}
else {
c <- ciph_def; (* default result *)
}
return c;
}
}.
(* encryption adversary, parameterized by encryption oracle, EO
choose may only call EO.enc_pre; guess may only call EO.enc_post *)
module type ADV (EO : EO) = {
(* choose a pair of plaintexts, x1/x2 *)
proc choose() : text * text {EO.enc_pre}
(* given ciphertext c based on a random boolean b (the encryption
using EO.genc of x1 if b = true, the encryption of x2 if b =
false), try to guess b *)
proc guess(c : cipher) : bool {EO.enc_post}
}.
(* IND-CPA security game, parameterized by an encryption scheme Enc
and adversary Adv
an encryption scheme is secure iff the probability of main
returning true (Adv winning the game) is close to 1/2, i.e., Adv
isn't doing much better than always guessing the ciphertext comes
from the first plaintext, or of making a random guess
formally, we want that the absolute value of the difference between
the probability that main returns true and 1/2 to be small; this
says that Adv can neither win nor lose with probability much
different than 1/2 (if it could reliably lose, the addition of
a negation would result in an adversary that could reliably win)
because Adv can use EO to encrypt the plaintexts it chooses,
the encryption procedure of a secure encryption scheme is
necessarily probabilistic
Adv may directly use Enc (which is stateless) as much as it wants
(and in any case could simulate it), but the security theorem must
say it can't read/write the global variables of EncO *)
module INDCPA (Enc : ENC, Adv : ADV) = {
module EO = EncO(Enc) (* make EO from Enc *)
module A = Adv(EO) (* connect Adv to EO *)
proc main() : bool = {
var b, b' : bool; var x1, x2 : text; var c : cipher;
EO.init(); (* initialize EO *)
(x1, x2) <@ A.choose(); (* let A choose plaintexts x1/x2 *)
b <$ {0,1}; (* choose boolean b *)
c <@ EO.genc(b ? x1 : x2); (* encrypt x1 if b = true, x2 if b = false *)
b' <@ A.guess(c); (* give ciphertext to A, which returns guess *)
return b = b'; (* see if A guessed correctly, winning game *)
}
}.