-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathUltimateSLH_optimized.v
More file actions
1637 lines (1519 loc) · 82.3 KB
/
UltimateSLH_optimized.v
File metadata and controls
1637 lines (1519 loc) · 82.3 KB
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
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
(** * UltimateSLH: Relative Security Against Speculation Attacks*)
(* TERSE: HIDEFROMHTML *)
Set Warnings "-notation-overridden,-parsing,-deprecated-hint-without-locality".
From Coq Require Import Strings.String.
From SECF Require Import Maps.
From SECF Require Import SpecCT.
From Coq Require Import Bool.Bool.
From Coq Require Import Arith.Arith.
From Coq Require Import Arith.EqNat.
From Coq Require Import Arith.PeanoNat. Import Nat.
From Coq Require Import Lia.
From Coq Require Import List. Import ListNotations.
Set Default Goal Selector "!".
(* TERSE: /HIDEFROMHTML *)
(** * Relative security *)
(** We would like to also enforce security for arbitrary programs that do
not follow the cryptographic constant time programming discipline
(i.e. which do not satisfy [ct_well_typed]). The goal is to achieve a
relative notion of security which intuitively ensures that the protected
program does not leak more information speculatively than the original
program leaks sequentially via the CT observations. One way to achieve this
protection is by transforming the program using Ultimate Speculative Load
Hardening (USLH), instead of the selective variant from the previous chapter. *)
(** We formalize this as a relative security property that doesn't label data at
all as public or secret. *)
(** We need to define [seq_same_obs] below wrt a small-step semantics, so that
this hypothesis also gives us something for sequentially infinite
executions, and also for executions that sequentially get stuck because of
out of bound accesses. *)
(** Sequential small-step semantics *)
Ltac invert H := inversion H; subst; clear H.
Reserved Notation
"'<((' c , st , ast '))>' '-->^' os '<((' ct , stt , astt '))>'"
(at level 40, c custom com at level 99, ct custom com at level 99,
st constr, ast constr, stt constr, astt constr at next level).
Inductive seq_eval_small_step :
com -> state -> astate ->
com -> state -> astate -> obs -> Prop :=
| SSM_Asgn : forall st ast e n x,
aeval st e = n ->
<((x := e, st, ast))> -->^[] <((skip, x !-> n; st, ast))>
| SSM_Seq : forall c1 st ast os c1t stt astt c2,
<((c1, st, ast))> -->^os <((c1t, stt, astt))> ->
<(((c1;c2), st, ast))> -->^os <(((c1t;c2), stt, astt))>
| SSM_Seq_Skip : forall st ast c2,
<(((skip;c2), st, ast))> -->^[] <((c2, st, ast))>
| SSM_If : forall be ct cf st ast,
<((if be then ct else cf end, st, ast))> -->^[OBranch (beval st be)]
<((match beval st be with
| true => ct
| false => cf end, st, ast))>
| SSM_While : forall be c st ast,
<((while be do c end, st, ast))> -->^[]
<((if be then c; while be do c end else skip end, st, ast))>
| SSM_ARead : forall x a ie st ast i,
aeval st ie = i ->
i < length (ast a) ->
<((x <- a[[ie]], st, ast))> -->^[OARead a i]
<((skip, x !-> nth i (ast a) 0; st, ast))>
| SSM_Write : forall a ie e st ast i n,
aeval st e = n ->
aeval st ie = i ->
i < length (ast a) ->
<((a[ie] <- e, st, ast))> -->^[OAWrite a i]
<((skip, st, a !-> upd i (ast a) n; ast))>
where "<(( c , st , ast ))> -->^ os <(( ct , stt , astt ))>" :=
(seq_eval_small_step c st ast ct stt astt os).
Reserved Notation
"'<((' c , st , ast '))>' '-->*^' os '<((' ct , stt , astt '))>'"
(at level 40, c custom com at level 99, ct custom com at level 99,
st constr, ast constr, stt constr, astt constr at next level).
Inductive multi_seq (c:com) (st:state) (ast:astate) :
com -> state -> astate -> obs -> Prop :=
| multi_seq_refl : <((c, st, ast))> -->*^[] <((c, st, ast))>
| multi_seq_trans (c':com) (st':state) (ast':astate)
(c'':com) (st'':state) (ast'':astate)
(os1 os2 : obs) :
<((c, st, ast))> -->^os1 <((c', st', ast'))> ->
<((c', st', ast'))> -->*^os2 <((c'', st'', ast''))> ->
<((c, st, ast))> -->*^(os1++os2) <((c'', st'', ast''))>
where "<(( c , st , ast ))> -->*^ os <(( ct , stt , astt ))>" :=
(multi_seq c st ast ct stt astt os).
Lemma multi_seq_combined_executions : forall c st ast cm stm astm osm ct stt astt ost,
<((c, st, ast))> -->*^osm <((cm, stm, astm))> ->
<((cm, stm, astm))> -->*^ost <((ct, stt, astt))> ->
<((c, st, ast))> -->*^(osm++ost) <((ct, stt, astt))>.
Proof.
intros c st ast cm stm astm osm ct stt astt ost Hev1 Hev2.
induction Hev1.
- rewrite app_nil_l. apply Hev2.
- rewrite <- app_assoc. eapply multi_seq_trans.
+ eapply H.
+ apply IHHev1. apply Hev2.
Qed.
Lemma seq_small_step_obs_type : forall c st1 ast1 stt1 astt1 ct1 os1 ct2 st2 ast2 stt2 astt2 os2,
<((c, st1, ast1))> -->^os1 <((ct1, stt1, astt1))> ->
<((c, st2, ast2))> -->^os2 <((ct2, stt2, astt2))> ->
match os2 with
| [] => os1 = []
| OBranch _ :: os => exists b, os1 = OBranch b :: os
| OARead _ _ :: os => exists a i, os1 = OARead a i :: os
| OAWrite _ _ :: os => exists a i, os1 = OAWrite a i :: os
end.
Proof.
induction c; intros st1 ast1 stt1 astt1 ct1 os1 ct2 st2 ast2 stt2 astt2 os2 H1 H2;
inversion H1; inversion H2; subst; try eauto.
+ eapply IHc1; eauto.
+ inversion H9.
+ inversion H17.
Qed.
Corollary seq_small_step_obs_length : forall c st1 ast1 stt1 astt1 ct1 os1 ct2 st2 ast2 stt2 astt2 os2,
<((c, st1, ast1))> -->^os1 <((ct1, stt1, astt1))> ->
<((c, st2, ast2))> -->^os2 <((ct2, stt2, astt2))> ->
length os1 = length os2.
Proof.
intros. eapply seq_small_step_obs_type in H; [|now apply H0].
destruct os1; subst; [now auto|].
destruct o.
2, 3 : now (do 2 destruct H); subst.
now destruct H; subst.
Qed.
(** Small-step speculative semantics *)
Reserved Notation
"'<((' c , st , ast , b '))>' '-->_' ds '^^' os '<((' ct , stt , astt , bt '))>'"
(at level 40, c custom com at level 99, ct custom com at level 99,
st constr, ast constr, stt constr, astt constr at next level).
Inductive spec_eval_small_step :
com -> state -> astate -> bool ->
com -> state -> astate -> bool -> dirs -> obs -> Prop :=
| SpecSM_Asgn : forall st ast b e n x,
aeval st e = n ->
<((x := e, st, ast, b))> -->_[]^^[] <((skip, x !-> n; st, ast, b))>
| SpecSM_Seq : forall c1 st ast b ds os c1t stt astt bt c2,
<((c1, st, ast, b))> -->_ds^^os <((c1t, stt, astt, bt))> ->
<(((c1;c2), st, ast, b))> -->_ds^^os <(((c1t;c2), stt, astt, bt))>
| SpecSM_Seq_Skip : forall st ast b c2,
<(((skip;c2), st, ast, b))> -->_[]^^[] <((c2, st, ast, b))>
| SpecSM_If : forall be ct cf st ast b c' b',
b' = beval st be ->
c' = (if b' then ct else cf) ->
<((if be then ct else cf end, st, ast, b))> -->_[DStep]^^[OBranch b'] <((c', st, ast, b))>
| SpecSM_If_F : forall be ct cf st ast b c' b',
b' = beval st be ->
c' = (if b' then cf else ct) ->
<((if be then ct else cf end, st, ast, b))> -->_[DForce]^^[OBranch b'] <((c', st, ast, true))>
| SpecSM_While : forall be c st ast b,
<((while be do c end, st, ast, b))> -->_[]^^[]
<((if be then c; while be do c end else skip end, st, ast, b))>
| SpecSM_ARead : forall x a ie st ast b i,
aeval st ie = i ->
i < length (ast a) ->
<((x <- a[[ie]], st, ast, b))> -->_[DStep]^^[OARead a i]
<((skip, x !-> nth i (ast a) 0; st, ast, b))>
| SpecSM_ARead_U : forall x a ie st ast i a' i',
aeval st ie = i ->
i >= length (ast a) ->
i' < length (ast a') ->
<((x <- a[[ie]], st, ast, true))> -->_[DLoad a' i']^^[OARead a i]
<((skip, x !-> nth i' (ast a') 0; st, ast, true))>
| SpecSM_Write : forall a ie e st ast b i n,
aeval st e = n ->
aeval st ie = i ->
i < length (ast a) ->
<((a[ie] <- e, st, ast, b))> -->_[DStep]^^[OAWrite a i]
<((skip, st, a !-> upd i (ast a) n; ast, b))>
| SpecSM_Write_U : forall a ie e st ast i n a' i',
aeval st e = n ->
aeval st ie = i ->
i >= length (ast a) ->
i' < length (ast a') ->
<((a[ie] <- e, st, ast, true))> -->_[DStore a' i']^^[OAWrite a i]
<((skip, st, a' !-> upd i' (ast a') n; ast, true))>
where "<(( c , st , ast , b ))> -->_ ds ^^ os <(( ct , stt , astt , bt ))>" :=
(spec_eval_small_step c st ast b ct stt astt bt ds os).
Reserved Notation
"'<((' c , st , ast , b '))>' '-->*_' ds '^^' os '<((' ct , stt , astt , bt '))>'"
(at level 40, c custom com at level 99, ct custom com at level 99,
st constr, ast constr, stt constr, astt constr at next level).
Inductive multi_spec (c:com) (st:state) (ast:astate) (b:bool) :
com -> state -> astate -> bool -> dirs -> obs -> Prop :=
| multi_spec_refl : <((c, st, ast, b))> -->*_[]^^[] <((c, st, ast, b))>
| multi_spec_trans (c':com) (st':state) (ast':astate) (b':bool)
(c'':com) (st'':state) (ast'':astate) (b'':bool)
(ds1 ds2 : dirs) (os1 os2 : obs) :
<((c, st, ast, b))> -->_ds1^^os1 <((c', st', ast', b'))> ->
<((c', st', ast', b'))> -->*_ds2^^os2 <((c'', st'', ast'', b''))> ->
<((c, st, ast, b))> -->*_(ds1++ds2)^^(os1++os2) <((c'', st'', ast'', b''))>
where "<(( c , st , ast , b ))> -->*_ ds ^^ os <(( ct , stt , astt , bt ))>" :=
(multi_spec c st ast b ct stt astt bt ds os).
Lemma multi_spec_trans_nil_l c st ast b c' st' ast' b' ct stt astt bt ds os :
<((c, st, ast, b))> -->_[]^^[] <((c', st', ast', b'))> ->
<((c', st', ast', b'))> -->*_ds^^os <((ct, stt, astt, bt))> ->
<((c, st, ast, b))> -->*_ds^^os <((ct, stt, astt, bt))>.
Proof.
intros. rewrite <- app_nil_l. rewrite <- app_nil_l with (l:=ds). eapply multi_spec_trans; eassumption.
Qed.
Lemma multi_spec_trans_nil_r c st ast b c' st' ast' b' ct stt astt bt ds os :
<((c, st, ast, b))> -->_ds^^os <((c', st', ast', b'))> ->
<((c', st', ast', b'))> -->*_[]^^[] <((ct, stt, astt, bt))> ->
<((c, st, ast, b))> -->*_ds^^os <((ct, stt, astt, bt))>.
Proof.
intros. rewrite <- app_nil_r. rewrite <- app_nil_r with (l:=ds). eapply multi_spec_trans; eassumption.
Qed.
Lemma multi_spec_combined_executions : forall c st ast cm stm astm osm ct stt astt ost ds ds' b b' b'',
<((c, st, ast, b))> -->*_ds^^osm <((cm, stm, astm, b'))> ->
<((cm, stm, astm, b'))> -->*_ds'^^ost <((ct, stt, astt, b''))> ->
<((c, st, ast, b))> -->*_(ds++ds')^^(osm++ost) <((ct, stt, astt, b''))>.
Proof.
intros.
induction H.
- rewrite app_nil_l. apply H0.
- rewrite <- !app_assoc. eapply multi_spec_trans.
+ eapply H.
+ apply IHmulti_spec. apply H0.
Qed.
Lemma multi_spec_add_snd_com : forall c st ast ct stt astt ds os c2 b bt,
<((c, st, ast, b))> -->*_ds^^os <((ct, stt, astt, bt))> ->
<((c;c2, st, ast, b))> -->*_ds^^os <((ct;c2, stt, astt, bt))>.
Proof.
intros. induction H; repeat econstructor; eauto.
Qed.
Lemma multi_spec_seq : forall c1 c2 cm st ast b stm astm bm ds os,
<((c1; c2, st, ast, b))> -->*_ds^^os <((cm, stm, astm, bm))> ->
(exists st' ast' b' ds1 ds2 os1 os2,
os = os1 ++ os2 /\ ds = ds1 ++ ds2 /\
<((c1, st, ast, b))> -->*_ds1^^os1 <((skip, st', ast', b'))> /\
<((c2, st', ast', b'))> -->*_ds2^^os2 <((cm, stm, astm, bm))>) \/
(exists c', cm = <{{ c'; c2 }}> /\
<((c1, st, ast, b))> -->*_ds^^os <((c', stm, astm, bm))>).
Proof.
intros. remember <{{ c1; c2 }}> as c. revert c1 c2 Heqc.
induction H; intros; subst.
{ right. repeat eexists. constructor. }
invert H.
+ edestruct IHmulti_spec; [reflexivity|..].
- do 8 destruct H. destruct H1, H2. subst. clear IHmulti_spec.
left. rewrite !app_assoc. repeat eexists; [econstructor|]; eassumption.
- do 2 destruct H. subst. clear IHmulti_spec.
right. repeat eexists. econstructor; eassumption.
+ left. repeat eexists; [constructor|eassumption].
Qed.
Lemma multi_seq_seq : forall c1 c2 cm st ast stm astm os,
<((c1; c2, st, ast))> -->*^os <((cm, stm, astm))> ->
(exists st' ast' os1 os2,
os = os1 ++ os2 /\
<((c1, st, ast))> -->*^os1 <((skip, st', ast'))> /\
<((c2, st', ast'))> -->*^os2 <((cm, stm, astm))>) \/
(exists c', cm = <{{ c'; c2 }}> /\
<((c1, st, ast))> -->*^os <((c', stm, astm))>).
Proof.
intros. remember <{{ c1; c2 }}> as c. revert c1 c2 Heqc.
induction H; intros; subst.
{ right. repeat eexists. constructor. }
invert H.
+ edestruct IHmulti_seq; [reflexivity|..].
- do 5 destruct H. destruct H1. subst. clear IHmulti_seq.
left. rewrite !app_assoc. repeat eexists; [econstructor|]; eassumption.
- do 2 destruct H. subst. clear IHmulti_seq.
right. repeat eexists. econstructor; eassumption.
+ left. repeat eexists; [constructor|eassumption].
Qed.
Lemma multi_spec_seq_assoc c1 c2 c3 st ast b c' st' ast' b' ds os :
<(((c1; c2); c3, st, ast, b))> -->*_ds^^os <((c', st', ast', b'))> ->
exists c'',
<((c1; c2; c3, st, ast, b))> -->*_ds^^os <((c'', st', ast', b'))> /\ (c' = <{{ skip }}> -> c'' = <{{ skip }}>).
Proof.
intros. apply multi_spec_seq in H. destruct H.
+ do 8 destruct H. destruct H0, H1. subst. apply multi_spec_seq in H1. destruct H1.
- do 8 destruct H. destruct H0, H1. subst. exists c'. split; [|tauto].
rewrite <- !app_assoc. eapply multi_spec_combined_executions; [apply multi_spec_add_snd_com, H1|].
eapply multi_spec_trans_nil_l; [apply SpecSM_Seq_Skip|]. eapply multi_spec_combined_executions; [apply multi_spec_add_snd_com, H3|].
eapply multi_spec_trans_nil_l; [apply SpecSM_Seq_Skip|apply H2].
- destruct H as (c''&abs&_). discriminate abs.
+ destruct H as (c''&->&H). apply multi_spec_seq in H. destruct H.
- do 8 destruct H. destruct H0, H1. subst. exists <{{ c''; c3 }}>.
split; [|discriminate]. eapply multi_spec_combined_executions; [apply multi_spec_add_snd_com, H1|].
eapply multi_spec_trans_nil_l; [apply SpecSM_Seq_Skip|]. apply multi_spec_add_snd_com, H2.
- destruct H as (c'&->&H). exists <{{ c'; c2; c3 }}>. split; [|discriminate].
apply multi_spec_add_snd_com, H.
Qed.
(** * Definition of Relative Secure *)
Definition seq_same_obs c st1 st2 ast1 ast2 : Prop :=
forall stt1 stt2 astt1 astt2 os1 os2 c1 c2,
<((c, st1, ast1))> -->*^os1 <((c1, stt1, astt1))> ->
<((c, st2, ast2))> -->*^os2 <((c2, stt2, astt2))> ->
(prefix os1 os2) \/ (prefix os2 os1).
Definition spec_same_obs c st1 st2 ast1 ast2 : Prop :=
forall ds stt1 stt2 astt1 astt2 bt1 bt2 os1 os2 c1 c2,
<((c, st1, ast1, false))> -->*_ds^^os1 <((c1, stt1, astt1, bt1))> ->
<((c, st2, ast2, false))> -->*_ds^^os2 <((c2, stt2, astt2, bt2))> ->
os1 = os2.
Definition relative_secure (trans : com -> com)
(c:com) (st1 st2 : state) (ast1 ast2 : astate): Prop :=
seq_same_obs c st1 st2 ast1 ast2 ->
spec_same_obs (trans c) st1 st2 ast1 ast2.
(** * Ultimate Speculative Load Hardening *)
Definition is_empty {A} (l:list A) := match l with [] => true | _ => false end.
Lemma is_empty_app {A} : forall (l l' : list A),
is_empty (l ++ l') = is_empty l && is_empty l'.
Proof.
now destruct l.
Qed.
Fixpoint vars_aexp (a:aexp) : list string :=
match a with
| ANum n => []
| AId x => [x]
| <{ a1 + a2 }>
| <{ a1 - a2 }>
| <{ a1 * a2 }> => vars_aexp a1 ++ vars_aexp a2
| <{ be ? a1 : a2 }> => vars_bexp be ++ vars_aexp a1 ++ vars_aexp a2
end
with vars_bexp (a:bexp) : list string :=
match a with
| <{ true }> | <{ false }> => []
| <{ a1 = a2 }>
| <{ a1 <> a2 }>
| <{ a1 <= a2 }>
| <{ a1 > a2 }> => vars_aexp a1 ++ vars_aexp a2
| <{ ~b }> => vars_bexp b
| <{ b1 && b2 }> => vars_bexp b1 ++ vars_bexp b2
end.
Fixpoint ultimate_slh (c:com) :=
(match c with
| <{{skip}}> => <{{skip}}>
| <{{x := e}}> => <{{x := e}}>
| <{{c1; c2}}> => <{{ ultimate_slh c1; ultimate_slh c2}}>
| <{{if be then c1 else c2 end}}> =>
let be' := if is_empty (vars_bexp be) then be (* optimized *)
else <{{"b" = 0 && be}}> in
<{{if be' then "b" := be' ? "b" : 1; ultimate_slh c1
else "b" := be' ? 1 : "b"; ultimate_slh c2 end}}>
| <{{while be do c end}}> =>
let be' := if is_empty (vars_bexp be) then be (* optimized *)
else <{{"b" = 0 && be}}> in
<{{while be' do "b" := be' ? "b" : 1; ultimate_slh c end;
"b" := be' ? 1 : "b"}}>
| <{{x <- a[[i]]}}> =>
let i' := if is_empty (vars_aexp i) then i (* optimized -- no mask even if it's out of bounds! *)
else <{{("b" = 1) ? 0 : i}}> in
<{{x <- a[[i']]}}>
| <{{a[i] <- e}}> =>
let i' := if is_empty (vars_aexp i) then i (* optimized -- no mask even if it's out of bounds! *)
else <{{("b" = 1) ? 0 : i}}> in
<{{a[i'] <- e}}> (* <- Doing nothing here in the is_empty (vars_aexp i) case okay for Spectre v1,
but problematic for return address or code pointer overwrites *)
end)%string.
(** The masking USLH does for indices requires that our arrays are nonempty. *)
Definition nonempty_arrs (ast : astate) :Prop :=
forall a, 0 < length (ast a).
(** * Ideal small-step evaluation *)
Reserved Notation
"'<((' c , st , ast , b '))>' '-->i_' ds '^^' os '<((' ct , stt , astt , bt '))>'"
(at level 40, c custom com at level 99, ct custom com at level 99,
st constr, ast constr, stt constr, astt constr at next level).
Inductive ideal_eval_small_step :
com -> state -> astate -> bool ->
com -> state -> astate -> bool -> dirs -> obs -> Prop :=
| ISM_Asgn : forall st ast b e n x,
aeval st e = n ->
<((x := e, st, ast, b))> -->i_[]^^[] <((skip, x !-> n; st, ast, b))>
| ISM_Seq : forall c1 st ast b ds os c1t stt astt bt c2,
<((c1, st, ast, b))> -->i_ds^^os <((c1t, stt, astt, bt))> ->
<(((c1;c2), st, ast, b))> -->i_ds^^os <(((c1t;c2), stt, astt, bt))>
| ISM_Seq_Skip : forall st ast b c2,
<(((skip;c2), st, ast, b))> -->i_[]^^[] <((c2, st, ast, b))>
| ISM_If : forall be ct cf st ast b c' b',
b' = (is_empty (vars_bexp be) || negb b) && beval st be ->
c' = (if b' then ct else cf) ->
<((if be then ct else cf end, st, ast, b))> -->i_[DStep]^^[OBranch b'] <((c', st, ast, b))>
| ISM_If_F : forall be ct cf st ast b c' b',
b' = (is_empty (vars_bexp be) || negb b) && beval st be ->
c' = (if b' then cf else ct) ->
<((if be then ct else cf end, st, ast, b))> -->i_[DForce]^^[OBranch b'] <((c', st, ast, true))>
| ISM_While : forall be c st ast b,
<((while be do c end, st, ast, b))> -->i_[]^^[]
<((if be then c; while be do c end else skip end, st, ast, b))>
| ISM_ARead : forall x a ie st ast (b :bool) i,
(if negb (is_empty (vars_aexp ie)) && b then 0 else (aeval st ie)) = i ->
i < length (ast a) ->
<((x <- a[[ie]], st, ast, b))> -->i_[DStep]^^[OARead a i]
<((skip, x !-> nth i (ast a) 0; st, ast, b))>
| ISM_ARead_U : forall x a ie st ast i a' i',
aeval st ie = i ->
is_empty (vars_aexp ie) = true ->
i >= length (ast a) ->
i' < length (ast a') ->
<((x <- a[[ie]], st, ast, true))> -->i_[DLoad a' i']^^[OARead a i]
<((skip, x !-> nth i' (ast a') 0; st, ast, true))>
| ISM_Write : forall a ie e st ast (b :bool) i n,
aeval st e = n ->
(if negb (is_empty (vars_aexp ie)) && b then 0 else (aeval st ie)) = i ->
i < length (ast a) ->
<((a[ie] <- e, st, ast, b))> -->i_[DStep]^^[OAWrite a i]
<((skip, st, a !-> upd i (ast a) n; ast, b))>
| ISM_Write_U : forall a ie e st ast i n a' i',
aeval st e = n ->
is_empty (vars_aexp ie) = true ->
aeval st ie = i ->
i >= length (ast a) ->
i' < length (ast a') ->
<((a[ie] <- e, st, ast, true))> -->i_[DStore a' i']^^[OAWrite a i]
<((skip, st, a' !-> upd i' (ast a') n; ast, true))>
where "<(( c , st , ast , b ))> -->i_ ds ^^ os <(( ct , stt , astt , bt ))>" :=
(ideal_eval_small_step c st ast b ct stt astt bt ds os).
(* HIDE: This one now has again `_U` cases because of out-of-bounds array
accesses at constant indices. Since the array sizes are also statically
known, we could easily reject such programs statically. *)
Reserved Notation
"'<((' c , st , ast , b '))>' '-->i*_' ds '^^' os '<((' ct , stt , astt , bt '))>'"
(at level 40, c custom com at level 99, ct custom com at level 99,
st constr, ast constr, stt constr, astt constr at next level).
Inductive multi_ideal (c:com) (st:state) (ast:astate) (b:bool) :
com -> state -> astate -> bool -> dirs -> obs -> Prop :=
| multi_ideal_refl : <((c, st, ast, b))> -->i*_[]^^[] <((c, st, ast, b))>
| multi_ideal_trans (c':com) (st':state) (ast':astate) (b':bool)
(c'':com) (st'':state) (ast'':astate) (b'':bool)
(ds1 ds2 : dirs) (os1 os2 : obs) :
<((c, st, ast, b))> -->i_ds1^^os1 <((c', st', ast', b'))> ->
<((c', st', ast', b'))> -->i*_ds2^^os2 <((c'', st'', ast'', b''))> ->
<((c, st, ast, b))> -->i*_(ds1++ds2)^^(os1++os2) <((c'', st'', ast'', b''))>
where "<(( c , st , ast , b ))> -->i*_ ds ^^ os <(( ct , stt , astt , bt ))>" :=
(multi_ideal c st ast b ct stt astt bt ds os).
Lemma multi_ideal_trans_nil_l c st ast b c' st' ast' b' ct stt astt bt ds os :
<((c, st, ast, b))> -->i_[]^^[] <((c', st', ast', b'))> ->
<((c', st', ast', b'))> -->i*_ds^^os <((ct, stt, astt, bt))> ->
<((c, st, ast, b))> -->i*_ds^^os <((ct, stt, astt, bt))>.
Proof.
intros. rewrite <- app_nil_l. rewrite <- app_nil_l with (l:=ds). eapply multi_ideal_trans; eassumption.
Qed.
Lemma multi_ideal_trans_nil_r c st ast b c' st' ast' b' ct stt astt bt ds os :
<((c, st, ast, b))> -->i_ds^^os <((c', st', ast', b'))> ->
<((c', st', ast', b'))> -->i*_[]^^[] <((ct, stt, astt, bt))> ->
<((c, st, ast, b))> -->i*_ds^^os <((ct, stt, astt, bt))>.
Proof.
intros. rewrite <- app_nil_r. rewrite <- app_nil_r with (l:=ds). eapply multi_ideal_trans; eassumption.
Qed.
Definition ideal_same_obs c st1 st2 ast1 ast2 : Prop :=
forall ds stt1 stt2 astt1 astt2 bt1 bt2 os1 os2 c1 c2,
<((c, st1, ast1, false))> -->i*_ds^^os1 <((c1, stt1, astt1, bt1))> ->
<((c, st2, ast2, false))> -->i*_ds^^os2 <((c2, stt2, astt2, bt2))> ->
os1 = os2.
Lemma multi_ideal_combined_executions :
forall c st ast b ds cm stm astm bm osm dsm ct stt astt bt ost,
<((c, st, ast, b))> -->i*_ds^^osm <((cm, stm, astm, bm))> ->
<((cm, stm, astm, bm))> -->i*_dsm^^ost <((ct, stt, astt, bt))> ->
<((c, st, ast, b))> -->i*_(ds++dsm)^^(osm++ost) <((ct, stt, astt, bt))>.
Proof.
intros c st ast b ds cm stm astm bm osm dsm ct stt astt bt ost Hev1 Hev2.
induction Hev1.
- do 2 rewrite app_nil_l. apply Hev2.
- do 2 rewrite <- app_assoc. eapply multi_ideal_trans.
+ eapply H.
+ apply IHHev1. apply Hev2.
Qed.
Lemma multi_ideal_add_snd_com : forall c st ast ct stt astt ds os c2 b bt,
<((c, st, ast, b))> -->i*_ds^^os <((ct, stt, astt, bt))> ->
<((c;c2, st, ast, b))> -->i*_ds^^os <((ct;c2, stt, astt, bt))>.
Proof.
intros. induction H; repeat econstructor; eauto.
Qed.
(** * Lemmas for the proof of [ideal_eval_relative_secure] *)
Lemma ideal_eval_small_step_spec_bit_monotonic : forall c st ast ds ct stt astt bt os,
<((c, st, ast, true))> -->i_ds^^os <((ct, stt, astt, bt))> ->
bt = true.
Proof.
intros c st ast ds ct stt astt bt os Heval. remember true as b eqn:Eqb.
induction Heval; subst; eauto.
Qed.
Lemma multi_ideal_spec_bit_monotonic : forall c st ast ds ct stt astt bt os,
<((c, st, ast, true))> -->i*_ds^^os <((ct, stt, astt, bt))> ->
bt = true.
Proof.
intros c st ast ds ct stt astt bt os Heval. remember true as b eqn:Eqb.
induction Heval; subst; eauto. apply ideal_eval_small_step_spec_bit_monotonic in H; subst.
auto.
Qed.
Lemma ideal_eval_final_spec_bit_false_one_step : forall c st ast ds stt astt os ct,
<((c, st, ast, false))> -->i_ds^^os <((ct, stt, astt, false))> ->
(forall d, In d ds -> d = DStep).
Proof.
intros. remember false as b. rewrite Heqb in H at 2. remember false as b'.
rewrite Heqb' in Heqb.
revert Heqb Heqb' d H0.
induction H; intros; (try discriminate); subst; try (now inversion H0).
+ apply IHideal_eval_small_step; tauto.
+ now invert H1.
+ now invert H1.
+ now invert H2.
Qed.
Lemma ideal_eval_final_spec_bit_false : forall c st ast ds stt astt os ct,
<((c, st, ast, false))> -->i*_ds^^os <((ct, stt, astt, false))> ->
(forall d, In d ds -> d = DStep).
Proof.
intros. remember false as b. rewrite Heqb in H at 2. remember false as b'.
rewrite Heqb' in Heqb. revert Heqb Heqb' d H0.
induction H; intros; subst.
+ now apply in_nil in H0.
+ destruct b'. { now apply multi_ideal_spec_bit_monotonic in H0. }
apply in_app_iff in H1. destruct H1.
- eapply ideal_eval_final_spec_bit_false_one_step in H; eassumption.
- apply IHmulti_ideal; tauto.
Qed.
Lemma ideal_eval_small_step_spec_needs_force : forall c st ast ds ct stt astt os,
<((c, st, ast, false))> -->i_ds^^os <((ct, stt, astt, true))> ->
ds = [DForce].
Proof.
intros c st ast ds ct stt astt os Hev.
remember false as b eqn:Eqb; remember true as bt eqn:Eqbt.
induction Hev; subst; simpl in *; try discriminate; auto.
Qed.
Lemma multi_ideal_spec_needs_force : forall c st ast ds ct stt astt os,
<((c, st, ast, false))> -->i*_ds^^os <((ct, stt, astt, true))> ->
In DForce ds.
Proof.
intros c st ast ds ct stt astt os Hev.
remember false as b eqn:Eqb; remember true as bt eqn:Eqbt.
induction Hev; subst; simpl in *; try discriminate.
apply in_or_app. destruct b' eqn:Eqb'.
- apply ideal_eval_small_step_spec_needs_force in H. subst. simpl. tauto.
- right. apply IHHev; auto.
Qed.
Lemma ideal_eval_spec_bit_deterministic :
forall c st1 st2 ast1 ast2 b ds stt1 stt2 astt1 astt2 bt1 bt2 os1 os2 c1 c2,
<(( c, st1, ast1, b ))> -->i*_ ds ^^ os1 <(( c1, stt1, astt1, bt1 ))> ->
<(( c, st2, ast2, b ))> -->i*_ ds ^^ os2 <(( c2, stt2, astt2, bt2 ))> ->
bt1 = bt2.
Proof.
intros c st1 st2 ast1 ast2 b ds stt1 stt2 astt1 astt2 bt1 bt2 os1 os2 c1 c2 Hev1 Hev2.
destruct b.
- apply multi_ideal_spec_bit_monotonic in Hev1, Hev2. congruence.
- destruct bt1, bt2; try reflexivity.
+ apply multi_ideal_spec_needs_force in Hev1.
now eapply ideal_eval_final_spec_bit_false in Hev2; [|eassumption].
+ apply multi_ideal_spec_needs_force in Hev2.
now eapply ideal_eval_final_spec_bit_false in Hev1; [|eassumption].
Qed.
Lemma ideal_eval_small_step_obs_length : forall c st ast b ds ct stt astt bt os,
<((c, st, ast, b))> -->i_ds^^os <((ct, stt, astt, bt))> ->
length ds = length os.
Proof.
intros c st ast b ds ct stt astt bt os Hev. induction Hev; simpl; auto.
Qed.
Lemma multi_ideal_obs_length : forall c st ast b ds ct stt astt bt os,
<((c, st, ast, b))> -->i*_ds^^os <((ct, stt, astt, bt))> ->
length ds = length os.
Proof.
intros c st ast b ds ct stt astt bt os Hev. induction Hev; simpl; auto.
do 2 rewrite app_length. apply ideal_eval_small_step_obs_length in H.
auto.
Qed.
Lemma ideal_eval_small_step_final_spec_bit_false : forall c st ast ds ct stt astt os,
<((c, st, ast, false))> -->i_ds^^os <((ct, stt, astt, false))> ->
(forall d, In d ds -> d = DStep).
Proof.
intros c st ast ds ct stt astt os Hev. remember false as b eqn:Eqb.
induction Hev; subst; intros d Hin; simpl in *; try destruct Hin;
try discriminate; try contradiction; auto.
Qed.
Lemma multi_ideal_final_spec_bit_false : forall c st ast ds ct stt astt os,
<((c, st, ast, false))> -->i*_ds^^os <((ct, stt, astt, false))> ->
(forall d, In d ds -> d = DStep).
Proof.
intros c st ast ds ct stt astt os Hev. remember false as b eqn:Eqb.
induction Hev; intros d Hin; simpl in *; subst; try contradiction.
destruct b' eqn:Eqb'.
- apply multi_ideal_spec_bit_monotonic in Hev. discriminate.
- apply in_app_or in Hin as [Hin | Hin].
+ destruct b eqn:Eqb.
* apply ideal_eval_small_step_spec_bit_monotonic in H. discriminate.
* eapply ideal_eval_small_step_final_spec_bit_false in Hin; eauto.
+ apply IHHev; auto.
Qed.
Lemma ideal_eval_small_step_no_spec : forall c st ast ds ct stt astt bt os,
<((c, st, ast, false))> -->i_ds^^os <((ct, stt, astt, bt))> ->
(forall d, In d ds -> d = DStep) ->
<((c, st, ast ))> -->^os <((ct, stt, astt))>.
Proof.
intros c st ast ds ct stt astt bt os Hev.
remember false as b eqn:Eqb. induction Hev; intros Hds;
try (now subst; rewrite ?orb_true_r, ?andb_false_r in *; econstructor; eauto).
+ specialize (Hds DForce). discriminate Hds. now left.
+ specialize (Hds (DLoad a' i')). discriminate Hds. now left.
+ specialize (Hds (DStore a' i')). discriminate Hds. now left.
Qed.
Lemma multi_ideal_no_spec : forall c st ast ds ct stt astt bt os,
<((c, st, ast, false))> -->i*_ds^^os <((ct, stt, astt, bt))> ->
(forall d, In d ds -> d = DStep) ->
<((c, st, ast ))> -->*^os <((ct, stt, astt))>.
Proof.
intros c st ast ds ct stt astt bt os Hev.
remember false as b eqn:Eqb. induction Hev; intros Hds; subst.
- apply multi_seq_refl.
- assert (L1: forall d, In d ds1 -> d = DStep).
{ intros d Hd. apply Hds. apply in_or_app. auto. }
assert (L2: forall d, In d ds2 -> d = DStep).
{ intros d Hd. apply Hds. apply in_or_app. auto. }
destruct b' eqn:Eqb'.
+ apply ideal_eval_small_step_spec_needs_force in H. subst.
simpl in L1. specialize (L1 DForce (or_introl (Logic.eq_refl DForce))). discriminate L1.
+ apply ideal_eval_small_step_no_spec in H; auto.
eapply multi_seq_trans.
* eapply H.
* apply IHHev; auto.
Qed.
Lemma seq_to_ideal : forall c st ast ct stt astt os,
<((c, st, ast ))> -->^os <((ct, stt, astt))> ->
<((c, st, ast, false))> -->i_(repeat DStep (length os))^^os <((ct, stt, astt, false))>.
Proof.
intros.
induction H; try now (constructor; rewrite ?orb_true_r, ?andb_false_r).
Qed.
Lemma seq_small_step_if_total : forall c be ct cf st ast,
c = <{{if be then ct else cf end}}> ->
exists c' stt astt os,
<((c, st, ast))> -->^os <((c', stt, astt))> /\ os <> [].
Proof.
intros c be ct cf st ast Heq. subst.
repeat econstructor. intros Contra. inversion Contra.
Qed.
Lemma seq_small_step_to_multi_seq : forall c st ast ct stt astt os,
<((c, st, ast))> -->^os <((ct, stt, astt))> ->
<((c, st, ast))> -->*^os <((ct, stt, astt))>.
Proof.
intros c st ast ct stt astt os Hev.
rewrite <- app_nil_r. eapply multi_seq_trans; eauto.
apply multi_seq_refl.
Qed.
Lemma seq_same_obs_com_if : forall be ct cf st1 st2 ast1 ast2,
seq_same_obs <{{ if be then ct else cf end }}> st1 st2 ast1 ast2 ->
beval st1 be = beval st2 be.
Proof.
intros be ct cf st1 st2 ast1 ast2 Hsec.
remember <{{if be then ct else cf end}}> as c eqn:Eqc.
assert (L1: exists c' stt astt os, <((c, st1, ast1))> -->^os <((c', stt, astt))> /\ os <> []).
{ eapply seq_small_step_if_total; eauto. }
assert (L2: exists c' stt astt os, <((c, st2, ast2))> -->^os <((c', stt, astt))> /\ os <> []).
{ eapply seq_small_step_if_total; eauto. }
destruct L1 as [c1 [stt1 [astt1 [os1 [Hev1 Hneq1] ] ] ] ].
destruct L2 as [c2 [stt2 [astt2 [os2 [Hev2 Hneq2] ] ] ] ].
apply seq_small_step_to_multi_seq in Hev1, Hev2.
eapply Hsec in Hev2 as Hpre; [| eapply Hev1].
inversion Hev1; subst; clear Hev1.
- destruct Hneq1; auto.
- inversion Hev2; subst; clear Hev2.
+ destruct Hneq2; auto.
+ inversion H1; subst; clear H1. inversion H; subst; clear H.
destruct Hpre as [Hpre | Hpre]; simpl in Hpre.
* apply prefix_heads in Hpre. inversion Hpre; auto.
* apply prefix_heads in Hpre. inversion Hpre; auto.
Qed.
Lemma multi_seq_add_snd_com : forall c st ast ct stt astt os c2,
<((c, st, ast))> -->*^os <((ct, stt, astt))> ->
<((c;c2, st, ast))> -->*^os <((ct;c2, stt, astt))>.
Proof.
intros c st ast ct stt astt os c2 Hev.
induction Hev.
- apply multi_seq_refl.
- eapply multi_seq_trans.
+ econstructor. eauto.
+ apply IHHev.
Qed.
Lemma seq_same_obs_com_seq : forall c1 c2 st1 st2 ast1 ast2,
seq_same_obs <{{ c1; c2 }}> st1 st2 ast1 ast2 ->
seq_same_obs c1 st1 st2 ast1 ast2.
Proof.
intros c1 c2 st1 st2 ast1 ast2 Hsec. unfold seq_same_obs.
intros stt1 stt2 astt1 astt2 os1 os2 ct1 ct2 Hev1 Hev2.
eapply multi_seq_add_snd_com in Hev1, Hev2. eapply Hsec in Hev2; eauto.
Qed.
Lemma ideal_one_step_force_obs : forall c ct st1 ast1 stt1 astt1 os1 st2 ast2 stt2 astt2 os2,
seq_same_obs c st1 st2 ast1 ast2 ->
<((c, st1, ast1, false))> -->i_[DForce]^^os1 <((ct, stt1, astt1, true))> ->
<((c, st2, ast2, false))> -->i_[DForce]^^os2 <((ct, stt2, astt2, true))> ->
os1 = os2.
Proof.
intros c ct st ast1 stt1 astt1 os1 st2 ast2 stt2 astt2 os2 Hobs Hev1.
generalize dependent os2; generalize dependent astt2;
generalize dependent stt2; generalize dependent ast2;
generalize dependent st2.
remember false as b eqn:Eqb; remember true as bt eqn:Eqbt.
induction Hev1; intros st2 ast2 Hobs stt2 astt2 os2 Hev2; try(inversion Hev2; subst; auto);
try discriminate.
- eapply IHHev1; eauto. eapply seq_same_obs_com_seq; eauto.
- apply seq_same_obs_com_if in Hobs. rewrite Hobs. reflexivity.
Qed.
(** * Relative Security of Ultimate Speculative Load Hardening *)
(** As in SpecCT and Spectre Declassified, an important step in the proof is
relating the speculative semantics of the hardened program with the ideal
semantics, by means of a backwards compiler correctness (BCC) result. *)
Lemma ideal_unused_overwrite_one_step : forall st ast b ds c c' st' ast' b' os X n,
unused X c ->
<((c, st, ast, b))> -->i_ds^^os <((c', st', ast', b'))> ->
<((c, X !-> n; st, ast, b))> -->i_ds^^os <((c', X !-> n; st', ast', b'))> /\ unused X c'.
Proof.
intros. induction H0.
+ invert H. repeat econstructor; [|assumption..].
rewrite t_update_permute; [constructor|assumption].
now apply aeval_unused_update.
+ invert H. eapply IHideal_eval_small_step in H1. destruct H1.
repeat econstructor; assumption.
+ split; [|now invert H]. apply ISM_Seq_Skip.
+ destruct H, H2. split; [|now destruct b'; subst]. constructor; [|tauto].
now rewrite beval_unused_update.
+ destruct H, H2. split; [|now destruct b'; subst]. constructor; [|tauto].
now rewrite beval_unused_update.
+ invert H. now repeat constructor.
+ invert H. repeat constructor. rewrite t_update_permute; [constructor|assumption].
{ now rewrite aeval_unused_update. } assumption.
+ invert H. rewrite t_update_permute; [|tauto]. repeat constructor; [now rewrite aeval_unused_update|assumption..].
+ invert H. repeat constructor; [now rewrite aeval_unused_update..|assumption].
+ invert H. repeat constructor. 1, 3 : now rewrite aeval_unused_update. all:assumption.
Qed.
Lemma ideal_unused_overwrite : forall st ast b ds c c' st' ast' b' os X n,
unused X c ->
<((c, st, ast, b))> -->i*_ds^^os <((c', st', ast', b'))> ->
<((c, X !-> n; st, ast, b))> -->i*_ds^^os <((c', X !-> n; st', ast', b'))>.
Proof.
intros. induction H0; [constructor|].
eapply ideal_unused_overwrite_one_step in H0; [|eassumption]. destruct H0.
econstructor; [eassumption|tauto].
Qed.
Lemma ideal_unused_update : forall st ast b ds c c' st' ast' b' os X n,
unused X c ->
<((c, X !-> n; st, ast, b))> -->i*_ds^^os <((c', X !-> n; st', ast', b'))> ->
<((c, st, ast, b))> -->i*_ds^^os <((c', X !-> st X; st', ast', b'))>.
Proof.
intros. rewrite <- (t_update_same _ st X) at 1.
eapply ideal_unused_overwrite with (X:=X) (n:=(st X)) in H0; [|assumption].
now rewrite !t_update_shadow in H0.
Qed.
Lemma spec_unused_overwrite_one_step : forall st ast b ds c c' st' ast' b' os X n,
unused X c ->
<((c, st, ast, b))> -->_ds^^os <((c', st', ast', b'))> ->
<((c, X !-> n; st, ast, b))> -->_ds^^os <((c', X !-> n; st', ast', b'))> /\ unused X c'.
Proof.
intros. induction H0.
+ invert H. repeat econstructor; [|assumption..].
rewrite t_update_permute; [constructor|assumption].
now apply aeval_unused_update.
+ invert H. eapply IHspec_eval_small_step in H1. destruct H1.
repeat econstructor; assumption.
+ split; [|now invert H]. apply SpecSM_Seq_Skip.
+ destruct H, H2. split; [|now destruct b'; subst]. constructor; [|tauto].
now rewrite beval_unused_update.
+ destruct H, H2. split; [|now destruct b'; subst]. constructor; [|tauto].
now rewrite beval_unused_update.
+ invert H. now repeat constructor.
+ invert H. repeat constructor. rewrite t_update_permute; [constructor|assumption].
{ now rewrite aeval_unused_update. } assumption.
+ invert H. repeat constructor. rewrite t_update_permute; [|tauto]. now constructor; [apply aeval_unused_update|..].
+ invert H. now repeat constructor; [apply aeval_unused_update..|].
+ invert H. now repeat constructor; [apply aeval_unused_update..| |].
Qed.
Lemma spec_unused_overwrite : forall st ast b ds c c' st' ast' b' os X n,
unused X c ->
<((c, st, ast, b))> -->*_ds^^os <((c', st', ast', b'))> ->
<((c, X !-> n; st, ast, b))> -->*_ds^^os <((c', X !-> n; st', ast', b'))>.
Proof.
intros. induction H0; [constructor|].
eapply spec_unused_overwrite_one_step in H0; [|eassumption]. destruct H0.
econstructor; [eassumption|tauto].
Qed.
Lemma spec_unused_update : forall st ast b ds c c' st' ast' b' os X n,
unused X c ->
<((c, X !-> n; st, ast, b))> -->*_ds^^os <((c', X !-> n; st', ast', b'))> ->
<((c, st, ast, b))> -->*_ds^^os <((c', X !-> st X; st', ast', b'))>.
Proof.
intros. rewrite <- (t_update_same _ st X) at 1.
eapply spec_unused_overwrite with (X:=X) (n:=(st X)) in H0; [|assumption].
now rewrite !t_update_shadow in H0.
Qed.
Lemma upd_length : forall l i a,
length (upd i l a) = length l.
Proof.
induction l; destruct i; auto.
intros. simpl. now f_equal.
Qed.
Lemma spec_eval_preserves_nonempty_arrs : forall c c' st ast b ds st' ast' b' os,
nonempty_arrs ast ->
<((c, st, ast, b))> -->*_ds^^os <((c', st', ast', b'))> ->
nonempty_arrs ast'.
Proof.
unfold nonempty_arrs.
intros. generalize dependent a. induction H0; eauto; subst.
apply IHmulti_spec. clear IHmulti_spec H1.
induction H0; eauto; subst.
2:clear H2 a. 1:rename a into a'.
all: intros; destruct (String.eqb a a') eqn:Heq.
2, 4: now apply String.eqb_neq in Heq; rewrite t_update_neq.
all: now apply String.eqb_eq in Heq; subst; rewrite t_update_eq, upd_length.
Qed.
Lemma ideal_eval_preserves_nonempty_arrs : forall c c' st ast b ds st' ast' b' os,
nonempty_arrs ast ->
<((c, st, ast, b))> -->i*_ds^^os <((c', st', ast', b'))> ->
nonempty_arrs ast'.
Proof.
unfold nonempty_arrs.
intros. generalize dependent a. induction H0; eauto; subst.
apply IHmulti_ideal. clear IHmulti_ideal H1.
induction H0; eauto; subst.
+ intros a'; destruct (String.eqb a a') eqn:Heq.
- now apply String.eqb_eq in Heq; subst; rewrite t_update_eq, upd_length.
- now apply String.eqb_neq in Heq; rewrite t_update_neq.
+ intros a''; destruct (String.eqb a' a'') eqn:Heq.
- now apply String.eqb_eq in Heq; subst; rewrite t_update_eq, upd_length.
- now apply String.eqb_neq in Heq; rewrite t_update_neq.
Qed.
Ltac solve_refl :=
match goal with
| Heq : beval ?ST _ = _, st_b : ?ST "b" = _, Hbe : is_empty _ = _ |- _ =>
simpl; eexists; (split; [|discriminate]); (try rewrite !app_nil_l); (try (eapply multi_ideal_trans_nil_l; [constructor|]));
(eapply multi_ideal_trans_nil_r; [|constructor]); simpl; rewrite ?Heq, ?st_b; simpl;
rewrite <- ?st_b, ?t_update_shadow, !t_update_same, ?andb_false_r; now (constructor; try rewrite ?Heq, ?Hbe, ?orb_true_r, ?andb_false_r)
end.
Ltac fold_cons :=
repeat match goal with
| |- context [?A :: ?B] =>
lazymatch B with
| [] => fail
| _ => change (A :: B) with ([A] ++ B)
end
end.
Ltac com_step :=
repeat ((try now apply multi_ideal_refl); (try now apply multi_spec_refl);
lazymatch goal with
| |- <(( <{{ skip; _ }}>, _, _, _ ))> -->i*_ _^^_ <(( _, _, _, _ ))> => eapply multi_ideal_trans_nil_l; [now apply ISM_Seq_Skip|]
| |- <(( <{{ _; ?C }}>, _, _, _ ))> -->i*_ _^^_ <(( <{{ _; ?C }}>, _, _, _ ))> => apply multi_ideal_add_snd_com; eassumption
| |- <(( <{{ _; _ }}>, _, _, _ ))> -->i*_ _^^_ <(( _, _, _, _ ))> => eapply multi_ideal_combined_executions; [apply multi_ideal_add_snd_com; eassumption|]
| |- <(( <{{ if _ then _ else _ end }}>, _, _, _ ))> -->i*_ [_]^^[_] <(( _, _, _, _ ))> => eapply multi_ideal_trans_nil_r; [|now constructor]
| Heq : beval _ _ = _, Hbe : is_empty _ = _ |- <(( <{{ if _ then _ else _ end }}>, _, _, _ ))> -->i*_ _^^_ <(( _, _, _, _ ))> =>
fold_cons; econstructor; [constructor; [(try now rewrite ?Heq, ?Hbe); now rewrite andb_comm, Heq|reflexivity]|]
| |- <(( <{{ if _ then _ else _ end }}>, _, _, _ ))> -->i*_ _^^_ <(( _, _, _, _ ))> => fold_cons; econstructor; [now constructor|]
| |- <(( <{{ while _ do _ end }}>, _, _, _ ))> -->i*_ _^^_ <(( _, _, _, _ ))> => eapply multi_ideal_trans_nil_l; [now constructor|]
| |- _ => now constructor
end).
Lemma ultimate_slh_bcc_generalized : forall c ds st ast (b b' : bool) c' st' ast' os,
nonempty_arrs ast ->
unused "b" c ->
st "b" = (if b then 1 else 0) ->
<((ultimate_slh c, st, ast, b))> -->*_ds^^os <((c', st', ast', b'))> ->
exists c'', <((c, st, ast, b))> -->i*_ds^^os <((c'', "b" !-> st "b"; st', ast', b'))>
/\ (c' = <{{ skip }}> -> c'' = <{{ skip }}> /\ st' "b" = (if b' then 1 else 0)). (* <- generalization *)
Proof.
intros c ds. apply prog_size_ind with (c:=c) (ds:=ds). clear.
intros c ds IH. intros until os. intros ast_arrs unused_c st_b st_st'.
invert st_st'.
{ rewrite t_update_same. eexists. split; [apply multi_ideal_refl|].
split; [|tauto]. now destruct c; try discriminate. }
destruct c; simpl in *; invert H.
- (* Asgn *)
invert H0; [|now inversion H].
eexists. split; [eapply multi_ideal_trans|split; [tauto|] ].
+ apply ISM_Asgn. reflexivity.
+ rewrite t_update_permute; [| tauto].
rewrite t_update_same. apply multi_ideal_refl.
+ rewrite t_update_neq; tauto.
- (* Seq *)
eapply multi_spec_seq in H0.
destruct H0.
+ do 8 destruct H. destruct H0, H1. subst.
eapply multi_spec_trans in H12; [|apply H1]. clear H1.
eapply IH in H12; [|prog_size_auto|tauto..].
destruct H12 as (c''&st_x&->&Hx); [reflexivity|].
eapply IH in H2.
{ destruct H2, H. exists x6. split; [|tauto]. rewrite !app_assoc. com_step.
erewrite <- t_update_same, <- t_update_shadow in H at 1.
apply ideal_unused_update in H; try tauto. rewrite t_update_eq in H; eauto. }
{ unfold prog_size. rewrite !app_length. simpl. lia. }
{ eapply ideal_eval_preserves_nonempty_arrs; eassumption. }
{ tauto. }
tauto.
+ do 2 destruct H. subst.
eapply multi_spec_trans in H12; [|apply H0].
eapply IH in H12; [|prog_size_auto|tauto..].
destruct H12 as (c''&st_st'&H').
exists <{{ c''; c2 }}>. split; [|discriminate]. com_step.
- (* Seq-Skip *)
destruct c1; invert H2.
eapply IH in H0; [destruct H0 as (c''&st'0_st'&H')|prog_size_auto|tauto..].
exists c''. split; [|tauto]. simpl. now com_step.
- (* If *)
destruct (is_empty (vars_bexp be)) eqn:Hbe.
+ simpl in H0. destruct (beval st'0 be) eqn:Heq.
* invert H0; [solve_refl|].
invert H. invert H12. invert H1; [solve_refl|].
invert H; [inversion H12|].
simpl in H0. rewrite st_b, Heq in H0. simpl in H0. rewrite <- st_b, t_update_same in H0.
eapply IH in H0; [destruct H0 as (c''&st'0_st'&H')|prog_size_auto|tauto..].
exists c''. simpl. split; [|tauto]. now com_step.
* invert H0; [solve_refl|].
invert H. invert H12. invert H1; [solve_refl|].
invert H; [inversion H12|].
simpl in H0. rewrite st_b, Heq in H0. simpl in H0. rewrite <- st_b, t_update_same in H0.
eapply IH in H0; [destruct H0 as (c''&st'0_st'&H')|prog_size_auto|tauto..].
exists c''. simpl. split; [|tauto]. now com_step.
+ case (beval st'0 be) eqn:Heq.
* simpl in H0; destruct b'0; rewrite st_b in H0; simpl in H0.
++ invert H0; [solve_refl|]. invert H. invert H12. invert H1; [solve_refl|].
invert H; [inversion H12|]. simpl in H0. rewrite st_b in H0; simpl in H0. rewrite <- st_b, t_update_same in H0.
apply IH in H0; [|prog_size_auto|tauto..]. destruct H0 as (c''&st'0_st'&H'). eexists. simpl. rewrite st_b at 2. simpl.
split; [|eassumption]. now com_step.
++ rewrite Heq in H0. invert H0; [solve_refl|]. invert H. invert H12. invert H1; [solve_refl|]. invert H; [inversion H12|].
simpl in H0. rewrite st_b, Heq in H0. simpl in H0. rewrite <- st_b, t_update_same in H0.
apply IH in H0; [|prog_size_auto|tauto..]. destruct H0 as (c''&st'0_st'&H'). eexists. simpl. rewrite st_b at 2. simpl.
split; [|eassumption]. com_step. now rewrite Heq.
* simpl in H0. rewrite Heq, andb_false_r in H0. invert H0; [solve_refl|]. invert H. invert H12. invert H1; [solve_refl|].
invert H; [inversion H12|]. simpl in H0. rewrite Heq, andb_false_r in H0. rewrite t_update_same in H0.
apply IH in H0; [|prog_size_auto|tauto..]. destruct H0 as (c''&st'0_st'&H'). eexists. simpl. rewrite Heq, andb_false_r. simpl.
split; [|eassumption]. now com_step.
- (* If-Force *)