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
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
use crate::expressions::Expression;
use crate::identifier::Identifier;
use crate::package::{Composition, OracleDef, OracleSig, Package, PackageInstance};
use crate::statement::{CodeBlock, Statement};
use crate::types::Type;
use std::collections::HashMap;

use crate::block;
use crate::fncall;

pub fn mapping_game(params: &HashMap<String, String>) -> Composition {
    let key_pkg_top_map = PackageInstance {
        name: "key_pkg_top_map".to_string(),
        params: params.clone(),
        pkg: Package {
            params: vec![("n".to_string(), Type::Integer)], /* key length*/
            state: vec![(
                "T".to_string(),
                Type::Table(Box::new(Type::Integer), Box::new(Type::new_bits("n"))),
            )],
            oracles: vec![
                OracleDef {
                    sig: OracleSig {
                        name: "Set".to_string(),
                        args: vec![
                            ("h".to_string(), Type::Integer), /* handle h */
                            ("k".to_string(), Type::new_bits("n")),
                        ], /* key k  */
                        tipe: Type::Integer,
                    },
                    code: block! { /* if T[h] = bot, T[h]<--k, return h */
                                                       /* if T[h] = bot, T[h]<--k, return h, else return h */
                                            Statement::IfThenElse(
                                                    Expression::new_equals(vec![
                                                        &Expression::TableAccess(Box::new(Identifier::new_scalar("T")),
                                                                                 Box::new(Identifier::new_scalar("h").to_expression())),
                                                        &Expression::None(Type::new_bits("n")),
                                                    ]),
                                             block! {
                                                    Statement::TableAssign(Identifier::new_scalar("T"),
                                                                           Identifier::new_scalar("h").to_expression(),
                                                                           Identifier::new_scalar("k").to_expression()),
                                                    Statement::Return(Some(Identifier::new_scalar("h").to_expression()))
                                                     },
                    /*                         block! {Statement::Abort},*/
                                            block! {
                                                    Statement::Return(Some(Identifier::new_scalar("h").to_expression()))
                                                   }
                                                )
                                        },
                },
                OracleDef {
                    sig: OracleSig {
                        name: "Get".to_string(),
                        args: vec![("h".to_string(), Type::Integer)],
                        tipe: Type::new_bits("n"),
                    },
                    code: block! {
                    Statement::IfThenElse(
                        Expression::new_equals(vec![
                                &Expression::TableAccess(Box::new(Identifier::new_scalar("T")),
                                                         Box::new(Identifier::new_scalar("h").to_expression())),
                                &Expression::None(Type::new_bits("n")),
                        ]),
                        block! {Statement::Abort},
                        block! {Statement::Return(
                            Some(Expression::Unwrap(Box::new( Expression::TableAccess(Box::new(Identifier::new_scalar("T")),
                                                               Box::new(Identifier::new_scalar("h").to_expression()))))))
                                }
                                        )
                    },
                },
            ],
        },
    };

    let mod_prf = PackageInstance {
        name: "prf".to_string(),
        params: params.clone(),
        pkg: Package {
            params: vec![
                ("n".to_string(), Type::new_scalar("int")),
                (
                    "f".to_string(),
                    Type::new_fn(
                        vec![Type::new_bits("n"), Type::new_bits("*")],
                        Type::new_bits("n"),
                    ),
                ),
            ],
            state: vec![],
            oracles: vec![OracleDef {
                sig: OracleSig {
                    name: "Eval".to_string(),
                    args: vec![
                        ("h".to_string(), Type::Integer),
                        ("msg".to_string(), Type::new_bits("*")),
                    ],
                    tipe: Type::Tuple(vec![Type::Integer, Type::new_bits("*")]),
                },
                code: block! {
                    Statement::Assign(Identifier::new_scalar("k"), Expression::OracleInvoc("Get".to_string(), vec![Identifier::new_scalar("h").to_expression()])),
                    Statement::Assign(Identifier::new_scalar("y"),fncall! { "f",
                                                      Identifier::new_scalar("k").to_expression(),
                                                      Identifier::new_scalar("msg").to_expression()}),
                    Statement::Assign(Identifier::new_scalar("z"), Expression::OracleInvoc(
                        "Set".to_string(),
                        vec![
                            Expression::Tuple(vec![
                                Identifier::new_scalar("h").to_expression(),
                                Identifier::new_scalar("msg").to_expression()
                            ]),
                            Identifier::new_scalar("y").to_expression()
                        ]
                    )),
                    Statement::Return(Some(
                        Expression::Tuple(vec![
                            Identifier::new_scalar("h").to_expression(),
                            Identifier::new_scalar("msg").to_expression()
                        ])
                    ))
                },
            }],
        },
    };

    let key_pkg_bottom = PackageInstance {
        name: "key_pkg_bottom".to_string(),
        params: params.clone(),
        pkg: Package {
            params: vec![("n".to_string(), Type::Integer)], /* key length*/
            state: vec![(
                "T".to_string(),
                Type::Table(
                    Box::new(Type::Tuple(vec![Type::Integer, Type::new_bits("*")])),
                    Box::new(Type::new_bits("n")),
                ),
            )],
            oracles: vec![
                OracleDef {
                    sig: OracleSig {
                        name: "Set".to_string(),
                        args: vec![
                            (
                                "h".to_string(),
                                Type::Tuple(vec![Type::Integer, Type::new_bits("*")]),
                            ),
                            ("k".to_string(), Type::new_bits("n")),
                        ], /* handle (int,msg) */
                        tipe: Type::Tuple(vec![Type::Integer, Type::new_bits("*")]),
                    },
                    code: block! { /* assert T[h] = bot, T[h]<--k, return h  */
                        Statement::IfThenElse(
                               Expression::new_equals(vec![
                                    &Expression::TableAccess(Box::new(Identifier::new_scalar("T")),
                                                            Box::new(Identifier::new_scalar("h").to_expression())),
                                    &Expression::None(Type::new_bits("n")),
                               ]),
                            block! {
                                Statement::TableAssign(Identifier::new_scalar("T"),
                                Identifier::new_scalar("h").to_expression(),
                                Identifier::new_scalar("k").to_expression()),
                                Statement::Return(Some(Identifier::new_scalar("h").to_expression()))
                                   },
                            block! {Statement::Return(Some(Identifier::new_scalar("h").to_expression()))}
                         /* block! {Statement::Abort} */
                        )
                    },
                },
                OracleDef {
                    sig: OracleSig {
                        name: "Get".to_string(),
                        args: vec![(
                            "h".to_string(),
                            Type::Tuple(vec![Type::Integer, Type::new_bits("*")]),
                        )],
                        tipe: Type::new_bits("n"),
                    },
                    code: block! { /*assert T[h]!=bot, return T[h] */
                        Statement::IfThenElse(
                            Expression::new_equals(vec![
                                    &Expression::TableAccess(Box::new(Identifier::new_scalar("T")),
                                                             Box::new(Identifier::new_scalar("h").to_expression())),
                                                             &Expression::None(Type::new_bits("n")),
                            ]),
                            block! {Statement::Abort},
                            block! {Statement::Return(Some(Expression::Unwrap(Box::new( Expression::TableAccess(Box::new(Identifier::new_scalar("T")),
                            Box::new(Identifier::new_scalar("h").to_expression()))))))}
                        )
                    },
                },
            ],
        },
    };

    let map_pkg = PackageInstance {
        name: "map_pkg".to_string(),
        params: params.clone(),
        pkg: Package {
            params: vec![("n".to_string(), Type::Integer)], /* key length*/
            state: vec![
                (
                    "Input_Map".to_string(),
                    Type::Table(Box::new(Type::Integer), Box::new(Type::Integer)),
                ),
                (
                    "Output_Map".to_string(),
                    Type::Table(
                        Box::new(Type::Tuple(vec![Type::Integer, Type::new_bits("*")])),
                        Box::new(Type::Tuple(vec![Type::Integer, Type::new_bits("*")])),
                    ),
                ),
            ],
            oracles: vec![
                OracleDef {
                    sig: OracleSig {
                        name: "Set".to_string(),
                        args: vec![
                            ("h".to_string(), Type::Integer),
                            ("k".to_string(), Type::new_bits("n")),
                        ], /* handle (int,msg) */
                        tipe: Type::Integer,
                    },
                    code: block! { /* if Input_Map[h] = bot, Input_Map[h] <-- Set(h,k), return h. Else return h.  */
                    Statement::IfThenElse(
                        Expression::new_equals(vec![
                            &Expression::TableAccess(Box::new(Identifier::new_scalar("Input_Map")),
                                                     Box::new(Identifier::new_scalar("h").to_expression())),
                            &Expression::None(Type::Integer),
                        ]),
                        block! {
                    Statement::Assign(Identifier::new_scalar("hh"), Expression::OracleInvoc(
                        "Set".to_string(),
                        vec![
                            Identifier::new_scalar("h").to_expression(),
                            Identifier::new_scalar("k").to_expression()
                        ])),
                    Statement::TableAssign(Identifier::new_scalar("Input_Map"),
                        Identifier::new_scalar("h").to_expression(),
                        Identifier::new_scalar("hh").to_expression()),
                    Statement::Return(Some(Identifier::new_scalar("h").to_expression()))
                            },
                        block! {Statement::Return(Some(Identifier::new_scalar("h").to_expression()))}
                    /* block! {Statement::Abort} */
                    )
                    },
                },
                OracleDef {
                    sig: OracleSig {
                        name: "Eval".to_string(),
                        args: vec![
                            ("h".to_string(), Type::Integer),
                            ("msg".to_string(), Type::new_bits("*")),
                        ],
                        tipe: Type::Tuple(vec![Type::Integer, Type::new_bits("*")]),
                    },
                    code: block! { /* if Input_Map[h] = bot, Output_Map[h,msg] <-- Eval(h,msg), return h. Else return h.  */
                        Statement::IfThenElse(
                            Expression::new_equals(vec![
                                &Expression::TableAccess(Box::new(Identifier::new_scalar("Input_Map")),
                                                         Box::new(Identifier::new_scalar("h").to_expression())),
                                                         &Expression::None(Type::Integer),
                            ]),
                            block! {
                                Statement::Return(
                                    Some(
                                        Expression::Tuple(
                                            vec![
                                                Identifier::new_scalar("h").to_expression(),
                                                Identifier::new_scalar("msg").to_expression()
                                            ]
                                        )
                                    )
                                )},
                            /* block! {Statement::Abort} */
                            block! {
                                Statement::Assign(Identifier::new_scalar("hh"), Expression::TableAccess(Box::new(Identifier::new_scalar("Input_Map")),
                                Box::new(Identifier::new_scalar("h").to_expression()))),
                                Statement::Assign(Identifier::new_scalar("hhh"), Expression::OracleInvoc(
                                    "Eval".to_string(),
                            vec![
                                    Expression::Unwrap(Box::new( Identifier::new_scalar("hh").to_expression())),
                                    Identifier::new_scalar("msg").to_expression()
                                ])),
                                Statement::TableAssign(Identifier::new_scalar("Output_Map"),
                                Expression::Tuple(vec![ Expression::Unwrap(Box::new(Identifier::new_scalar("hh").to_expression())), Identifier::new_scalar("msg").to_expression()]),
                                Identifier::new_scalar("hhh").to_expression()),
                        Statement::Return(Some(Expression::Tuple(vec![
                            Identifier::new_scalar("h").to_expression(),
                            Identifier::new_scalar("msg").to_expression()
                        ])))
                        }
                        )
                    },
                },
                OracleDef {
                    sig: OracleSig {
                        name: "Get".to_string(),
                        args: vec![(
                            "h".to_string(),
                            Type::Tuple(vec![Type::Integer, Type::new_bits("*")]),
                        )],
                        tipe: Type::new_bits("n"),
                    },
                    /*
                    if Output_Map[h] = bot
                        abort
                    else hh <-- Output_Map[h]
                        k <-- Get(hh)
                        return k
                    */
                    code: block! {
                        Statement::IfThenElse(
                            Expression::new_equals(vec![
                                    &Expression::TableAccess(Box::new(Identifier::new_scalar("Output_Map")),
                                                             Box::new(Identifier::new_scalar("h").to_expression())),
                                    &Expression::None(Type::Tuple(vec![Type::Integer, Type::new_bits("*")])),
                            ]),
                            block! {Statement::Abort},
                            block! {
                                Statement::Assign(Identifier::new_scalar("hh"),
                                Expression::TableAccess(Box::new(Identifier::new_scalar("Output_Map")),
                                                        Box::new(Identifier::new_scalar("h").to_expression()))),
                                Statement::Assign(Identifier::new_scalar("k"), Expression::OracleInvoc("Get".to_string(), vec![Expression::Unwrap(Box::new( Identifier::new_scalar("hh").to_expression()))])),
                                Statement::Return(Some(Identifier::new_scalar("k").to_expression()))
                            }
                        )
                    },
                },
            ],
        },
    };

    const PKGIDX_KEY_TOP_MAP: usize = 0;
    const PKGIDX_MOD_PRF: usize = 1;
    const PKGIDX_KEY_PKG_BOTTOM: usize = 2;
    const PKGIDX_MAP_PKG: usize = 3;

    Composition {
        pkgs: vec![
            key_pkg_top_map.clone(),
            mod_prf.clone(),
            key_pkg_bottom.clone(),
            map_pkg.clone(),
        ],
        edges: vec![
            (
                PKGIDX_MOD_PRF,
                PKGIDX_KEY_TOP_MAP,
                key_pkg_top_map.pkg.clone().oracles[1].sig.clone(), //Get
            ),
            (
                PKGIDX_MOD_PRF,
                PKGIDX_KEY_PKG_BOTTOM,
                key_pkg_bottom.pkg.clone().oracles[0].sig.clone(), //Set
            ),
            (
                PKGIDX_MAP_PKG,
                PKGIDX_KEY_TOP_MAP,
                key_pkg_top_map.pkg.clone().oracles[0].sig.clone(), // Set
            ),
            (
                PKGIDX_MAP_PKG,
                PKGIDX_MOD_PRF,
                mod_prf.pkg.clone().oracles[0].sig.clone(), //Eval
            ),
            (
                PKGIDX_MAP_PKG,
                PKGIDX_KEY_PKG_BOTTOM,
                key_pkg_bottom.pkg.clone().oracles[1].sig.clone(), // Get
            ),
        ],
        exports: vec![
            (PKGIDX_MAP_PKG, map_pkg.pkg.clone().oracles[0].sig.clone()),
            (PKGIDX_MAP_PKG, map_pkg.pkg.clone().oracles[1].sig.clone()),
            (PKGIDX_MAP_PKG, map_pkg.pkg.clone().oracles[2].sig.clone()),
        ],
        name: "no_mapping_game".to_string(),
    }
}