-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCap9.thy
4619 lines (3814 loc) · 227 KB
/
Cap9.thy
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
section \<open>Preliminaries\<close>
theory Cap9
imports
"HOL-Word.Word"
"HOL-Library.Adhoc_Overloading"
"HOL-Library.DAList"
"HOL-Library.AList"
"HOL-Library.Rewrite"
"Word_Lib/Word_Lemmas"
begin
subsection \<open>Type class instantiations\<close>
text \<open>
Instantiate @{class len} type class to extract lengths from word
types avoiding repeated explicit numeric specification of the length e.g.
@{text "LENGTH(byte)"} or @{text "LENGTH('a :: len word)"} instead of @{text 8} or
@{term "LENGTH('a :: len)"}, where @{text "'a"} cannot be directly extracted from a type
such as @{text "'a word"}.
\<close>
instantiation word :: (len) len begin
definition len_word[simp]: "len_of (_ :: 'a::len word itself) = LENGTH('a)"
instance by (standard, simp)
end
lemma len_word': "LENGTH('a::len word) = LENGTH('a)" by (rule len_word)
text \<open>
Instantiate @{class size} type class for types of the form @{text "'a itself"}. This allows
us to parametrize operations by word lengths using the dummy variables of type
@{text "'a word itself"}. The operations cannot be directly parametrized by numbers as there is
no lifting from term numbers to type numbers due to the lack of dependent types.
\<close>
instantiation itself :: (len) size begin
definition size_itself where [simp, code]: "size (n::'a::len itself) = LENGTH('a)"
instance ..
end
declare unat_word_ariths[simp] word_size[simp] is_up_def[simp] wsst_TYs(1,2)[simp]
subsection \<open>Word width\<close>
text \<open>
We introduce definition of the least number of bits to hold the current value of a word. This is
needed because in our specification we often word with @{const "ucast"}'ed values
(right aligned subranges of bits), largely
again due to the lack of dependent types (or true type-level functions),
e.g. the it's hard to specify that the length of
@{text "a \<Join> b"} (where @{text "\<Join>"} stands for concatenation) is the sum of the length of
@{text "a"} and @{text "b"}, since length is a type parameter and there's no equivalent of
sum on the type level. So we instead fix the length of @{text "a \<Join> b"} to be the maximum
possible one (say, 32 bytes) and then use conditions of the form @{text "width a \<le> s"} to
specify that the actual ``size'' of @{text "a"} is @{text "s"}.
\<close>
definition "width w \<equiv> LEAST n. unat w < 2 ^ n" for w :: "'a::len word"
lemma widthI[intro]: "\<lbrakk>\<And> u. u < n \<Longrightarrow> 2 ^ u \<le> unat w; unat w < 2 ^ n\<rbrakk> \<Longrightarrow> width w = n"
unfolding width_def Least_def
using not_le
apply (intro the_equality, blast)
by (meson nat_less_le)
lemma width_wf: "\<exists>! n. (\<forall> u < n. 2 ^ u \<le> unat w) \<and> unat w < 2 ^ n"
(is "?Ex1 (unat w)")
proof (induction ("unat w"))
case 0
show "?Ex1 0" by (intro ex1I[of _ 0], auto)
next
case (Suc x)
then obtain n where x:"(\<forall>u<n. 2 ^ u \<le> x) \<and> x < 2 ^ n " by auto
show "?Ex1 (Suc x)"
proof (cases "Suc x < 2 ^ n")
case True
thus "?Ex1 (Suc x)"
using x
apply (intro ex1I[of _ "n"], auto)
by (meson Suc_lessD leD linorder_neqE_nat)
next
case False
thus "?Ex1 (Suc x)"
using x
apply (intro ex1I[of _ "Suc n"], auto simp add: less_Suc_eq)
apply (intro antisym)
apply (metis One_nat_def Suc_lessI Suc_n_not_le_n leI numeral_2_eq_2 power_increasing_iff)
by (metis Suc_lessD le_antisym not_le not_less_eq_eq)
qed
qed
lemma width_iff[iff]: "(width w = n) = ((\<forall> u < n. 2 ^ u \<le> unat w) \<and> unat w < 2 ^ n)"
using width_wf widthI by metis
lemma width_le_size: "width x \<le> size x"
proof-
{
assume "size x < width x"
hence "2 ^ size x \<le> unat x" using width_iff by metis
hence "2 ^ size x \<le> uint x" unfolding unat_def by simp
}
thus ?thesis using uint_range_size[of x] by (force simp del:word_size)
qed
lemma width_le_size'[simp]: "size x \<le> n \<Longrightarrow> width x \<le> n" by (insert width_le_size[of x], simp)
lemma nth_width_high[simp]: "width x \<le> i \<Longrightarrow> \<not> x !! i"
proof (cases "i < size x")
case False
thus ?thesis by (simp add: test_bit_bin')
next
case True
hence "(x < 2 ^ i) = (unat x < 2 ^ i)"
unfolding unat_def
using word_2p_lem by fastforce
moreover assume "width x \<le> i"
then obtain n where "unat x < 2 ^ n" and "n \<le> i" using width_iff by metis
hence "unat x < 2 ^ i"
by (meson le_less_trans nat_power_less_imp_less not_less zero_less_numeral)
ultimately show ?thesis using bang_is_le by force
qed
lemma width_zero[iff]: "(width x = 0) = (x = 0)"
proof
show "width x = 0 \<Longrightarrow> x = 0" using nth_width_high[of x] word_eq_iff[of x 0] nth_0 by (metis le0)
show "x = 0 \<Longrightarrow> width x = 0" by simp
qed
lemma width_zero'[simp]: "width 0 = 0" by simp
lemma width_one[simp]: "width 1 = 1" by simp
lemma high_zeros_less: "(\<forall> i \<ge> u. \<not> x !! i) \<Longrightarrow> unat x < 2 ^ u"
(is "?high \<Longrightarrow> _") for x :: "'a::len word"
proof-
assume ?high
have size:"size (mask u :: 'a word) = size x" by simp
{
fix i
from \<open>?high\<close> have "(x AND mask u) !! i = x !! i"
using nth_mask[of u i] size test_bit_size[of x i]
by (subst word_ao_nth) (elim allE[of _ i], auto)
}
with \<open>?high\<close> have "x AND mask u = x" using word_eq_iff by blast
thus ?thesis unfolding unat_def using mask_eq_iff by auto
qed
lemma nth_width_msb[simp]: "x \<noteq> 0 \<Longrightarrow> x !! (width x - 1)"
proof (rule ccontr)
fix x :: "'a word"
assume "x \<noteq> 0"
hence width:"width x > 0" using width_zero by fastforce
assume "\<not> x !! (width x - 1)"
with width have "\<forall> i \<ge> width x - 1. \<not> x !! i"
using nth_width_high[of x] antisym_conv2 by fastforce
hence "unat x < 2 ^ (width x - 1)" using high_zeros_less[of "width x - 1" x] by simp
moreover from width have "unat x \<ge> 2 ^ (width x - 1)" using width_iff[of x "width x"] by simp
ultimately show False by simp
qed
lemma width_iff': "((\<forall> i > u. \<not> x !! i) \<and> x !! u) = (width x = Suc u)"
proof (rule; (elim conjE | intro conjI))
assume "x !! u" and "\<forall> i > u. \<not> x !! i"
show "width x = Suc u"
proof (rule antisym)
from \<open>x !! u\<close> show "width x \<ge> Suc u" using not_less nth_width_high by force
from \<open>x !! u\<close> have "x \<noteq> 0" by auto
with \<open>\<forall> i > u. \<not> x !! i\<close> have "width x - 1 \<le> u" using not_less nth_width_msb by metis
thus "width x \<le> Suc u" by simp
qed
next
assume "width x = Suc u"
show "\<forall>i>u. \<not> x !! i" by (simp add:\<open>width x = Suc u\<close>)
from \<open>width x = Suc u\<close> show "x !! u" using nth_width_msb width_zero
by (metis diff_Suc_1 old.nat.distinct(2))
qed
lemma width_word_log2: "x \<noteq> 0 \<Longrightarrow> width x = Suc (word_log2 x)"
using word_log2_nth_same word_log2_nth_not_set width_iff' test_bit_size
by metis
lemma width_ucast[OF refl, simp]: "uc = ucast \<Longrightarrow> is_up uc \<Longrightarrow> width (uc x) = width x"
by (metis uint_up_ucast unat_def width_def)
lemma width_ucast'[OF refl, simp]:
"uc = ucast \<Longrightarrow> width x \<le> size (uc x) \<Longrightarrow> width (uc x) = width x"
proof-
have "unat x < 2 ^ width x" unfolding width_def by (rule LeastI_ex, auto)
moreover assume "width x \<le> size (uc x)"
ultimately have "unat x < 2 ^ size (uc x)" by (simp add: less_le_trans)
moreover assume "uc = ucast"
ultimately have "unat x = unat (uc x)" by (metis unat_ucast mod_less word_size)
thus ?thesis unfolding width_def by simp
qed
lemma width_lshift[simp]:
"\<lbrakk>x \<noteq> 0; n \<le> size x - width x\<rbrakk> \<Longrightarrow> width (x << n) = width x + n"
(is "\<lbrakk>_; ?nbound\<rbrakk> \<Longrightarrow> _")
proof-
assume "x \<noteq> 0"
hence 0:"width x = Suc (width x - 1)" using width_zero by (metis Suc_pred' neq0_conv)
from \<open>x \<noteq> 0\<close> have 1:"width x > 0" by (auto intro:gr_zeroI)
assume ?nbound
{
fix i
from \<open>?nbound\<close> have "i \<ge> size x \<Longrightarrow> \<not> x !! (i - n)" by (auto simp add:le_diff_conv2)
hence "(x << n) !! i = (n \<le> i \<and> x !! (i - n))" using nth_shiftl'[of x n i] by auto
} note corr = this
hence "\<forall> i > width x + n - 1. \<not> (x << n) !! i" by auto
moreover from corr have "(x << n) !! (width x + n - 1)"
using width_iff'[of "width x - 1" x] 1
by auto
ultimately have "width (x << n) = Suc (width x + n - 1)" using width_iff' by auto
thus ?thesis using 0 by simp
qed
lemma width_lshift'[simp]: "n \<le> size x - width x \<Longrightarrow> width (x << n) \<le> width x + n"
using width_zero width_lshift shiftl_0 by (metis eq_iff le0)
lemma width_or[simp]: "width (x OR y) = max (width x) (width y)"
proof-
{
fix a b
assume "width x = Suc a" and "width y = Suc b"
hence "width (x OR y) = Suc (max a b)"
using width_iff' word_ao_nth[of x y] max_less_iff_conj[of "a" "b"]
by (metis (no_types) max_def)
} note succs = this
thus ?thesis
proof (cases "width x = 0 \<or> width y = 0")
case True
thus ?thesis using width_zero word_log_esimps(3,9) by (metis max_0L max_0R)
next
case False
with succs show ?thesis by (metis max_Suc_Suc not0_implies_Suc)
qed
qed
subsection \<open>Right zero-padding\<close>
text \<open>
Here's the first time we use @{const width}. If @{text x} is a value of size @{text n}
right-aligned in a word of size @{text "s = size x"} (note there's nowhere to keep the value n,
since the size of @{text x} is some @{text "s \<ge> n"}, so we require it to be
provided explicitly),
then @{text "rpad n x"} will move the value @{text x} to the left. For the operation to be
correct (no losing of significant higher bits) we need the precondition @{text "width x \<le> n"}
in all the lemmas, hence the need for @{const width}.
\<close>
definition rpad where "rpad n x \<equiv> x << size x - n"
lemma rpad_low[simp]: "\<lbrakk>width x \<le> n; i < size x - n\<rbrakk> \<Longrightarrow> \<not> (rpad n x) !! i"
unfolding rpad_def by (simp add:nth_shiftl)
lemma rpad_high[simp]:
"\<lbrakk>width x \<le> n; n \<le> size x; size x - n \<le> i\<rbrakk> \<Longrightarrow> (rpad n x) !! i = x !! (i + n - size x)"
(is "\<lbrakk>?xbound; ?nbound; i \<ge> ?ibound\<rbrakk> \<Longrightarrow> ?goal i")
proof-
fix i
assume ?xbound ?nbound and "i \<ge> ?ibound"
moreover from \<open>?nbound\<close> have "i + n - size x = i - ?ibound" by simp
moreover from \<open>?xbound\<close> have "x !! (i + n - size x) \<Longrightarrow> i < size x" by - (rule ccontr, simp)
ultimately show "?goal i" unfolding rpad_def by (subst nth_shiftl', metis)
qed
lemma rpad_inj: "\<lbrakk>width x \<le> n; width y \<le> n; n \<le> size x\<rbrakk> \<Longrightarrow> rpad n x = rpad n y \<Longrightarrow> x = y"
(is "\<lbrakk>?xbound; ?ybound; ?nbound; _\<rbrakk> \<Longrightarrow> _")
unfolding inj_def word_eq_iff
proof (intro allI impI)
fix i
let ?i' = "i + size x - n"
assume ?xbound ?ybound ?nbound
assume "\<forall>j < LENGTH('a). rpad n x !! j = rpad n y !! j"
hence "\<And> j. rpad n x !! j = rpad n y !! j" using test_bit_bin by blast
from this[of ?i'] and \<open>?xbound\<close> \<open>?ybound\<close> \<open>?nbound\<close> show "x !! i = y !! i" by simp
qed
subsection \<open>Spanning concatenation\<close>
abbreviation ucastl ("'(ucast')\<^bsub>_\<^esub> _" [1000, 100] 100) where
"(ucast)\<^bsub>l\<^esub> a \<equiv> ucast a :: 'b word" for l :: "'b::len0 itself"
notation (input) ucastl ("'(ucast')\<^sub>_ _" [1000, 100] 100)
definition pad_join :: "'a::len word \<Rightarrow> nat \<Rightarrow> 'c::len itself \<Rightarrow> 'b::len word \<Rightarrow> 'c word"
("_ \<^bsub>_\<^esub>\<diamond>\<^bsub>_\<^esub> _" [60, 1000, 1000, 61] 60) where
"x \<^bsub>n\<^esub>\<diamond>\<^bsub>l\<^esub> y \<equiv> rpad n (ucast x) OR ucast y"
notation (input) pad_join ("_ \<^sub>_\<diamond>\<^sub>_ _" [60, 1000, 1000, 61] 60)
lemma pad_join_high:
"\<lbrakk>width a \<le> n; n \<le> size l; width b \<le> size l - n; size l - n \<le> i\<rbrakk>
\<Longrightarrow> (a \<^sub>n\<diamond>\<^sub>l b) !! i = a !! (i + n - size l)"
unfolding pad_join_def
using nth_ucast nth_width_high by fastforce
lemma pad_join_high'[simp]:
"\<lbrakk>width a \<le> n; n \<le> size l; width b \<le> size l - n\<rbrakk> \<Longrightarrow> a !! i = (a \<^sub>n\<diamond>\<^sub>l b) !! (i + size l - n)"
using pad_join_high[of a n l b "i + size l - n"] by simp
lemma pad_join_mid[simp]:
"\<lbrakk>width a \<le> n; n \<le> size l; width b \<le> size l - n; width b \<le> i; i < size l - n\<rbrakk>
\<Longrightarrow> \<not> (a \<^sub>n\<diamond>\<^sub>l b) !! i"
unfolding pad_join_def by auto
lemma pad_join_low[simp]:
"\<lbrakk>width a \<le> n; n \<le> size l; width b \<le> size l - n; i < width b\<rbrakk> \<Longrightarrow> (a \<^sub>n\<diamond>\<^sub>l b) !! i = b !! i"
unfolding pad_join_def by (auto simp add: nth_ucast)
lemma pad_join_inj:
assumes eq:"a \<^sub>n\<diamond>\<^sub>l b = c \<^sub>n\<diamond>\<^sub>l d"
assumes a:"width a \<le> n" and c:"width c \<le> n"
assumes n: "n \<le> size l"
assumes b:"width b \<le> size l - n"
assumes d:"width d \<le> size l - n"
shows "a = c" and "b = d"
proof-
from eq have eq':"\<And>j. (a \<^sub>n\<diamond>\<^sub>l b) !! j = (c \<^sub>n\<diamond>\<^sub>l d) !! j"
using test_bit_bin unfolding word_eq_iff by auto
moreover from a n b
have "\<And> i. a !! i = (a \<^sub>n\<diamond>\<^sub>l b) !! (i + size l - n)" by simp
moreover from c n d
have "\<And> i. c !! i = (c \<^sub>n\<diamond>\<^sub>l d) !! (i + size l - n)" by simp
ultimately show "a = c" unfolding word_eq_iff by auto
{
fix i
from a n b have "i < width b \<Longrightarrow> b !! i = (a \<^sub>n\<diamond>\<^sub>l b) !! i" by simp
moreover from c n d have "i < width d \<Longrightarrow> d !! i = (c \<^sub>n\<diamond>\<^sub>l d) !! i" by simp
moreover have "i \<ge> width b \<Longrightarrow> \<not> b !! i" and "i \<ge> width d \<Longrightarrow> \<not> d !! i" by auto
ultimately have "b !! i = d !! i"
using eq'[of i] b d
pad_join_mid[of a n l b i, OF a n b]
pad_join_mid[of c n l d i, OF c n d]
by (meson leI less_le_trans)
}
thus "b = d" unfolding word_eq_iff by simp
qed
lemma pad_join_inj'[dest!]:
"\<lbrakk>a \<^sub>n\<diamond>\<^sub>l b = c \<^sub>n\<diamond>\<^sub>l d;
width a \<le> n; width c \<le> n; n \<le> size l;
width b \<le> size l - n;
width d \<le> size l - n\<rbrakk> \<Longrightarrow> a = c \<and> b = d"
apply (rule conjI)
subgoal by (frule (4) pad_join_inj(1))
by (frule (4) pad_join_inj(2))
lemma pad_join_and[simp]:
assumes "width x \<le> n" "n \<le> m" "width a \<le> m" "m \<le> size l" "width b \<le> size l - m"
shows "(a \<^sub>m\<diamond>\<^sub>l b) AND rpad n x = rpad m a AND rpad n x"
unfolding word_eq_iff
proof ((subst word_ao_nth)+, intro allI impI)
from assms have 0:"n \<le> size x" by simp
from assms have 1:"m \<le> size a" by simp
fix i
assume "i < LENGTH('a)"
from assms show "((a \<^bsub>m\<^esub>\<diamond>\<^bsub>l\<^esub> b) !! i \<and> rpad n x !! i) = (rpad m a !! i \<and> rpad n x !! i)"
using rpad_low[of x n i, OF assms(1)] rpad_high[of x n i, OF assms(1) 0]
rpad_low[of a m i, OF assms(3)] rpad_high[of a m i, OF assms(3) 1]
pad_join_high[of a m l b i, OF assms(3,4,5)]
size_itself_def[of l] word_size[of x] word_size[of a]
by (metis add.commute add_lessD1 le_Suc_ex le_diff_conv not_le)
qed
subsection \<open>Deal with partially undefined results\<close>
definition restrict :: "'a::len word \<Rightarrow> nat set \<Rightarrow> 'a word" (infixl "\<restriction>" 60) where
"restrict x s \<equiv> BITS i. i \<in> s \<and> x !! i"
lemma nth_restrict[iff]: "(x \<restriction> s) !! n = (n \<in> s \<and> x !! n)"
unfolding restrict_def
by (simp add: bang_conj_lt test_bit.eq_norm)
lemma restrict_inj2:
assumes eq:"f x\<^sub>1 y\<^sub>1 OR v\<^sub>1 \<restriction> s = f x\<^sub>2 y\<^sub>2 OR v\<^sub>2 \<restriction> s"
assumes fi:"\<And> x y i. i \<in> s \<Longrightarrow> \<not> f x y !! i"
assumes inj:"\<And> x\<^sub>1 y\<^sub>1 x\<^sub>2 y\<^sub>2. f x\<^sub>1 y\<^sub>1 = f x\<^sub>2 y\<^sub>2 \<Longrightarrow> x\<^sub>1 = x\<^sub>2 \<and> y\<^sub>1 = y\<^sub>2"
shows "x\<^sub>1 = x\<^sub>2 \<and> y\<^sub>1 = y\<^sub>2"
proof-
from eq and fi have "f x\<^sub>1 y\<^sub>1 = f x\<^sub>2 y\<^sub>2" unfolding word_eq_iff by auto
with inj show ?thesis .
qed
lemma restrict_ucast_inv[simp]:
"\<lbrakk>a = LENGTH('a); b = LENGTH('b)\<rbrakk> \<Longrightarrow> (ucast x OR y \<restriction> {a..<b}) AND mask a = ucast x"
for x :: "'a::len word" and y :: "'b::len word"
unfolding word_eq_iff
by (rewrite nth_ucast word_ao_nth nth_mask nth_restrict test_bit_bin)+ auto
lemmas restrict_inj_pad_join[dest] = restrict_inj2[of "\<lambda> x y. x \<^sub>_\<diamond>\<^sub>_ y"]
subsection \<open>Plain concatenation\<close>
definition join :: "'a::len word \<Rightarrow> 'c::len itself \<Rightarrow> nat \<Rightarrow> 'b::len word \<Rightarrow> 'c word"
("_ \<^bsub>_\<^esub>\<Join>\<^bsub>_\<^esub> _" [62,1000,1000,61] 61) where
"(a \<^bsub>l\<^esub>\<Join>\<^bsub>n\<^esub> b) \<equiv> (ucast a << n) OR (ucast b)"
notation (input) join ("_ \<^sub>_\<Join>\<^sub>_ _" [62,1000,1000,61] 61)
lemma width_join:
"\<lbrakk>width a + n \<le> size l; width b \<le> n\<rbrakk> \<Longrightarrow> width (a \<^sub>l\<Join>\<^sub>n b) \<le> width a + n"
(is "\<lbrakk>?abound; ?bbound\<rbrakk> \<Longrightarrow> _")
proof-
assume ?abound and ?bbound
moreover hence "width b \<le> size l" by simp
ultimately show ?thesis
using width_lshift'[of n "(ucast)\<^sub>l a"]
unfolding join_def
by simp
qed
lemma width_join'[simp]:
"\<lbrakk>width a + n \<le> size l; width b \<le> n; width a + n \<le> q\<rbrakk> \<Longrightarrow> width (a \<^sub>l\<Join>\<^sub>n b) \<le> q"
by (drule (1) width_join, simp)
lemma join_high[simp]:
"\<lbrakk>width a + n \<le> size l; width b \<le> n; width a + n \<le> i\<rbrakk> \<Longrightarrow> \<not> (a \<^sub>l\<Join>\<^sub>n b) !! i"
by (drule (1) width_join, simp)
lemma join_mid:
"\<lbrakk>width a + n \<le> size l; width b \<le> n; n \<le> i; i < width a + n\<rbrakk> \<Longrightarrow> (a \<^sub>l\<Join>\<^sub>n b) !! i = a !! (i - n)"
apply (subgoal_tac "i < size ((ucast)\<^sub>l a) \<and> size ((ucast)\<^sub>l a) = size l")
unfolding join_def
using word_ao_nth nth_ucast nth_width_high nth_shiftl'
apply (metis less_imp_diff_less order_trans word_size)
by simp
lemma join_mid'[simp]:
"\<lbrakk>width a + n \<le> size l; width b \<le> n\<rbrakk> \<Longrightarrow> a !! i = (a \<^sub>l\<Join>\<^sub>n b) !! (i + n)"
using join_mid[of a n l b "i + n"] nth_width_high[of a i] join_high[of a n l b "i + n"]
by force
lemma join_low[simp]:
"\<lbrakk>width a + n \<le> size l; width b \<le> n; i < n\<rbrakk> \<Longrightarrow> (a \<^sub>l\<Join>\<^sub>n b) !! i = b !! i"
unfolding join_def
by (simp add: nth_shiftl nth_ucast)
lemma join_inj:
assumes eq:"a \<^sub>l\<Join>\<^sub>n b = c \<^sub>l\<Join>\<^sub>n d"
assumes "width a + n \<le> size l" and "width b \<le> n"
assumes "width c + n \<le> size l" and "width d \<le> n"
shows "a = c" and "b = d"
proof-
from assms show "a = c" unfolding word_eq_iff using join_mid' eq by metis
from assms show "b = d" unfolding word_eq_iff using join_low nth_width_high
by (metis eq less_le_trans not_le)
qed
lemma join_inj'[dest!]:
"\<lbrakk>a \<^sub>l\<Join>\<^sub>n b = c \<^sub>l\<Join>\<^sub>n d;
width a + n \<le> size l; width b \<le> n;
width c + n \<le> size l; width d \<le> n\<rbrakk> \<Longrightarrow> a = c \<and> b = d"
apply (rule conjI)
subgoal by (frule (4) join_inj(1))
by (frule (4) join_inj(2))
lemma join_and:
assumes "width x \<le> n" "n \<le> size l" "k \<le> size l" "m \<le> k"
"n \<le> k - m" "width a \<le> k - m" "width a + m \<le> k" "width b \<le> m"
shows "rpad k (a \<^sub>l\<Join>\<^sub>m b) AND rpad n x = rpad (k - m) a AND rpad n x"
unfolding word_eq_iff
proof ((subst word_ao_nth)+, intro allI impI)
from assms have 0:"n \<le> size x" by simp
from assms have 1:"k - m \<le> size a" by simp
from assms have 2:"width (a \<^bsub>l\<^esub>\<Join>\<^bsub>m\<^esub> b) \<le> k" by simp
from assms have 3:"k \<le> size (a \<^bsub>l\<^esub>\<Join>\<^bsub>m\<^esub> b)" by simp
from assms have 4:"width a + m \<le> size l" by simp
fix i
assume "i < LENGTH('a)"
moreover with assms have "i + k - size (a \<^bsub>l\<^esub>\<Join>\<^bsub>m\<^esub> b) - m = i + (k - m) - size a" by simp
moreover from assms have "i + k - size (a \<^bsub>l\<^esub>\<Join>\<^bsub>m\<^esub> b) < m \<Longrightarrow> i < size x - n" by simp
moreover from assms have
"\<lbrakk>i \<ge> size l - k; m \<le> i + k - size (a \<^bsub>l\<^esub>\<Join>\<^bsub>m\<^esub> b)\<rbrakk> \<Longrightarrow> size a - (k - m) \<le> i" by simp
moreover from assms have "width a + m \<le> i + k - size (a \<^bsub>l\<^esub>\<Join>\<^bsub>m\<^esub> b) \<Longrightarrow> \<not> rpad (k - m) a !! i"
by (simp add: nth_shiftl' rpad_def)
moreover from assms have "\<not> i \<ge> size l - k \<Longrightarrow> i < size x - n" by simp
ultimately show "(rpad k (a \<^bsub>l\<^esub>\<Join>\<^bsub>m\<^esub> b) !! i \<and> rpad n x !! i) =
(rpad (k - m) a !! i \<and> rpad n x !! i)"
using assms
rpad_high[of x n i, OF assms(1) 0] rpad_low[of x n i, OF assms(1)]
rpad_high[of a "k - m" i, OF assms(6) 1] rpad_low[of a "k - m" i, OF assms(6)]
rpad_high[of "a \<^sub>l\<Join>\<^sub>m b" k i, OF 2 3] rpad_low[of "a \<^sub>l\<Join>\<^sub>m b" k i, OF 2]
join_high[of a m l b "i + k - size (a \<^bsub>l\<^esub>\<Join>\<^bsub>m\<^esub> b)", OF 4 assms(8)]
join_mid[of a m l b "i + k - size (a \<^bsub>l\<^esub>\<Join>\<^bsub>m\<^esub> b)", OF 4 assms(8)]
join_low[of a m l b "i + k - size (a \<^bsub>l\<^esub>\<Join>\<^bsub>m\<^esub> b)", OF 4 assms(8)]
size_itself_def[of l] word_size[of x] word_size[of a] word_size[of "a \<^bsub>l\<^esub>\<Join>\<^bsub>m\<^esub> b"]
by (metis not_le)
qed
lemma join_and'[simp]:
"\<lbrakk>width x \<le> n; n \<le> size l; k \<le> size l; m \<le> k;
n \<le> k - m; width a \<le> k - m; width a + m \<le> k; width b \<le> m\<rbrakk> \<Longrightarrow>
rpad k (a \<^sub>l\<Join>\<^sub>m b) AND rpad n x = rpad (k - m) (ucast a) AND rpad n x"
using join_and[of x n l k m "ucast a" b] unfolding join_def
by (simp add: ucast_id)
section \<open>Data formats\<close>
text \<open>This section contains definitions of various data formats used in the specification.\<close>
subsection \<open>Common notation\<close>
text \<open>Before we proceed some common notation that would be used later will be established.\<close>
subsubsection \<open>Machine words\<close>
text \<open>Procedure keys are represented as 24-byte (192 bits) machine words.\<close>
type_synonym word24 = "192 word" \<comment> \<open>24 bytes\<close>
type_synonym key = word24
text \<open>Byte is 8-bit machine word.\<close>
type_synonym byte = "8 word"
text \<open>32-byte machine words that are used to model keys and values of the storage.\<close>
type_synonym word32 = "256 word" \<comment> \<open>32 bytes\<close>
text \<open>
Storage is a function that takes a 32-byte word (key) and returns another
32-byte word (value).
\<close>
type_synonym storage = "word32 \<Rightarrow> word32"
subsubsection \<open>Concatenation operations\<close>
text \<open>
Specialize previously defined general concatenation operations for the fixed result size of
32 bytes. Thus we avoid lots of redundant type annotations for every intermediate result
(note that these intermediate types cannot be inferred automatically
(in a purely Hindley-Milner setting as in Isabelle),
because this would require type-level functions/dependent types).
\<close>
abbreviation "len (_ :: 'a::len word itself) \<equiv> TYPE('a)"
no_notation join ("_ \<^bsub>_\<^esub>\<Join>\<^bsub>_\<^esub> _" [62,1000,1000,61] 61)
no_notation (input) join ("_ \<^sub>_\<Join>\<^sub>_ _" [62,1000,1000,61] 61)
abbreviation join32 ("_ \<Join>\<^bsub>_\<^esub> _" [62,1000,61] 61) where
"a \<Join>\<^bsub>n\<^esub> b \<equiv> join a (len TYPE(word32)) (n * 8) b"
abbreviation (output) join32_out ("_ \<Join>\<^bsub>_\<^esub> _" [62,1000,61] 61) where
"join32_out a n b \<equiv> join a (TYPE(256)) n b"
notation (input) join32 ("_ \<Join>\<^sub>_ _" [62,1000,61] 61)
no_notation pad_join ("_ \<^bsub>_\<^esub>\<diamond>\<^bsub>_\<^esub> _" [60,1000,1000,61] 60)
no_notation (input) pad_join ("_ \<^sub>_\<diamond>\<^sub>_ _" [60,1000,1000,61] 60)
abbreviation pad_join32 ("_ \<^bsub>_\<^esub>\<diamond> _" [60,1000,61] 60) where
"a \<^bsub>n\<^esub>\<diamond> b \<equiv> pad_join a (n * 8) (len TYPE(word32)) b"
abbreviation (output) pad_join32_out ("_ \<^bsub>_\<^esub>\<diamond> _" [60,1000,61] 60) where
"pad_join32_out a n b \<equiv> pad_join a n (TYPE(256)) b"
notation (input) pad_join32 ("_ \<^sub>_\<diamond> _" [60,1000,61] 60)
text \<open>
Override treatment of hexidecimal numeric constants to make them monomorphic words of
fixed length, mimicking the notation used in the informal specification (e.g. @{term "0x01"})
is always a word 1 byte long and is not, say, the natural number one). Otherwise, again, lots
of redundant type annotations would arise.
\<close>
parse_ast_translation \<open>
let
open Ast
fun mk_numeral t = mk_appl (Constant @{syntax_const "_Numeral"}) t
fun mk_word_numeral num t =
if String.isPrefix "0x" num then
mk_appl (Constant @{syntax_const "_constrain"})
[mk_numeral t,
mk_appl (Constant @{type_syntax "word"})
[mk_appl (Constant @{syntax_const "_NumeralType"})
[Variable (4 * (size num - 2) |> string_of_int)]]]
else
mk_numeral t
fun numeral_ast_tr ctxt (t as [Appl [Constant @{syntax_const "_constrain"},
Constant num,
_]])
= mk_word_numeral num t
| numeral_ast_tr ctxt (t as [Constant num]) = mk_word_numeral num t
| numeral_ast_tr _ t = mk_numeral t
| numeral_ast_tr _ t = raise AST (@{syntax_const "_Numeral"}, t)
in
[(@{syntax_const "_Numeral"}, numeral_ast_tr)]
end
\<close>
subsection \<open>Datatypes\<close>
text \<open>
Introduce generic notation for mapping of various entities into high-level and low-level
representations. A high-level representation of an entity @{text e} would be written as
@{text "\<lceil>e\<rceil>"} and a low-level as @{text "\<lfloor>e\<rfloor>"} accordingly. Using a high-level representation it is
easier to express and proof some properties and invariants, but some of them can be expressed only
using a low-level representation.
We use adhoc overloading to use the same notation for various types of entities (indices, offsets,
addresses, capabilities etc.).
\<close>
no_notation floor ("\<lfloor>_\<rfloor>")
consts rep :: "'a \<Rightarrow> 'b" ("\<lfloor>_\<rfloor>")
no_notation ceiling ("\<lceil>_\<rceil>")
consts abs :: "'a \<Rightarrow> 'b" ("\<lceil>_\<rceil>")
subsubsection \<open>Deterministic inverse functions\<close>
definition "maybe_inv f y \<equiv> if y \<in> range f then Some (the_inv f y) else None"
lemma maybe_inv_inj[intro]: "inj f \<Longrightarrow> maybe_inv f (f x) = Some x"
unfolding maybe_inv_def
by (auto simp add:inj_def the_inv_f_f)
lemma maybe_inv_inj'[dest]: "\<lbrakk>inj f; maybe_inv f y = Some x\<rbrakk> \<Longrightarrow> f x = y"
unfolding maybe_inv_def
by (auto intro:f_the_inv_into_f simp add:inj_def split:if_splits)
locale invertible =
fixes rep :: "'a \<Rightarrow> 'b" ("\<lfloor>_\<rfloor>")
assumes inj:"inj rep"
begin
definition inv :: "'b \<Rightarrow> 'a option" where "inv \<equiv> maybe_inv rep"
lemmas inv_inj[folded inv_def, simp] = maybe_inv_inj[OF inj]
lemmas inv_inj'[folded inv_def, dest] = maybe_inv_inj'[OF inj]
end
definition "range2 f \<equiv> {y. \<exists>x\<^sub>1 \<in> UNIV. \<exists> x\<^sub>2 \<in> UNIV. y = f x\<^sub>1 x\<^sub>2}"
definition "the_inv2 f \<equiv> \<lambda> x. THE y. \<exists> y'. f y y' = x"
definition "maybe_inv2 f y \<equiv> if y \<in> range2 f then Some (the_inv2 f y) else None"
definition "inj2 f \<equiv> \<forall> x\<^sub>1 x\<^sub>2 y\<^sub>1 y\<^sub>2. f x\<^sub>1 y\<^sub>1 = f x\<^sub>2 y\<^sub>2 \<longrightarrow> x\<^sub>1 = x\<^sub>2"
lemma inj2I: "(\<And> x\<^sub>1 x\<^sub>2 y\<^sub>1 y\<^sub>2. f x\<^sub>1 y\<^sub>1 = f x\<^sub>2 y\<^sub>2 \<Longrightarrow> x\<^sub>1 = x\<^sub>2) \<Longrightarrow> inj2 f" unfolding inj2_def
by blast
lemma maybe_inv2_inj[intro]: "inj2 f \<Longrightarrow> maybe_inv2 f (f x y) = Some x"
unfolding maybe_inv2_def the_inv2_def inj2_def range2_def
by (simp split:if_splits, blast)
lemma maybe_inv2_inj'[dest]:
"\<lbrakk>inj2 f; maybe_inv2 f y = Some x\<rbrakk> \<Longrightarrow> \<exists> y'. f x y' = y"
unfolding maybe_inv2_def the_inv2_def range2_def inj2_def
by (force split:if_splits intro:theI)
locale invertible2 =
fixes rep :: "'a \<Rightarrow> 'c \<Rightarrow> 'c" ("\<lfloor>_\<rfloor>")
assumes inj:"inj2 rep"
begin
definition inv2 :: "'c \<Rightarrow> 'a option" where "inv2 \<equiv> maybe_inv2 rep"
lemmas inv2_inj[folded inv2_def, simp] = maybe_inv2_inj[OF inj]
lemmas inv2_inj'[folded inv_def, dest] = maybe_inv2_inj'[OF inj]
end
subsubsection \<open>Capability\<close>
text \<open>
Introduce capability type. Note that we don't include @{text Null} capability into it.
@{text Null} is only handled specially inside the call delegation, otherwise it only complicates
the proofs with side additional cases.
There will be separate type @{text call} defined as @{text "capability option"} to respect
the fact that in some places it can indeed be @{text Null}.
\<close>
datatype capability =
Call
| Reg
| Del
| Entry
| Write
| Log
| Send
text \<open>
In general, in the following we strive to make all encoding functions injective without any
preconditions. All the necessary invariants are built into the type definitions.
Capability representation would be its assigned number.
\<close>
definition cap_type_rep :: "capability \<Rightarrow> byte" where
"cap_type_rep c \<equiv> case c of
Call \<Rightarrow> 0x03
| Reg \<Rightarrow> 0x04
| Del \<Rightarrow> 0x05
| Entry \<Rightarrow> 0x06
| Write \<Rightarrow> 0x07
| Log \<Rightarrow> 0x08
| Send \<Rightarrow> 0x09"
adhoc_overloading rep cap_type_rep
text \<open>
Capability representation range from @{text 3} to @{text 9} since @{text Null} is not included
and @{text 2} does not exist.
\<close>
lemma cap_type_rep_rng[simp]: "\<lfloor>c\<rfloor> \<in> {0x03..0x09}" for c :: capability
unfolding cap_type_rep_def by (simp split:capability.split)
text \<open>Capability representation is injective.\<close>
lemma cap_type_rep_inj[dest]: "\<lfloor>c\<^sub>1\<rfloor> = \<lfloor>c\<^sub>2\<rfloor> \<Longrightarrow> c\<^sub>1 = c\<^sub>2" for c\<^sub>1 c\<^sub>2 :: capability
unfolding cap_type_rep_def
by (simp split:capability.splits)
text \<open>@{text 4} bits is sufficient to store a capability number.\<close>
lemma width_cap_type: "width \<lfloor>c\<rfloor> \<le> 4" for c :: capability
proof (rule ccontr, drule not_le_imp_less)
assume "4 < width \<lfloor>c\<rfloor>"
moreover hence "\<lfloor>c\<rfloor> !! (width \<lfloor>c\<rfloor> - 1)" using nth_width_msb by force
ultimately obtain n where "\<lfloor>c\<rfloor> !! n" and "n \<ge> 4" by (metis le_step_down_nat nat_less_le)
thus False unfolding cap_type_rep_def by (simp split:capability.splits)
qed
text \<open>So, any number greater than or equal to @{text 4} will be enough.\<close>
lemma width_cap_type'[simp]: "4 \<le> n \<Longrightarrow> width \<lfloor>c\<rfloor> \<le> n" for c :: capability
using width_cap_type[of c] by simp
text \<open>Capability representation can't be zero.\<close>
lemma cap_type_nonzero[simp]: "\<lfloor>c\<rfloor> \<noteq> 0" for c :: capability
unfolding cap_type_rep_def by (simp split:capability.splits)
subsubsection \<open>Capability index\<close>
text \<open>Introduce capability index type that is a natural number in range from 0 to 254.\<close>
typedef capability_index = "{i :: nat. i < 2 ^ LENGTH(byte) - 1}"
morphisms cap_index_rep' cap_index
by (intro exI[of _ "0"], simp)
adhoc_overloading rep cap_index_rep'
adhoc_overloading abs cap_index
text \<open>
Capability index representation is a byte. Zero byte is reserved, so capability index
representation starts with 1.
\<close>
definition "cap_index_rep i \<equiv> of_nat (\<lfloor>i\<rfloor> + 1) :: byte" for i :: capability_index
adhoc_overloading rep cap_index_rep
text \<open>
A single byte is sufficient to store the least number of bits of capability index representation.
\<close>
lemma width_cap_index: "width \<lfloor>i\<rfloor> \<le> LENGTH(byte)" for i :: capability_index by simp
lemma width_cap_index'[simp]: "LENGTH(byte) \<le> n \<Longrightarrow> width \<lfloor>i\<rfloor> \<le> n"
for i :: capability_index by simp
text \<open>Capability index representation can't be zero byte.\<close>
lemma cap_index_nonzero[simp]: "\<lfloor>i\<rfloor> \<noteq> 0x00" for i :: capability_index
unfolding cap_index_rep_def using cap_index_rep'[of i] of_nat_neq_0[of "Suc \<lfloor>i\<rfloor>"]
by force
text \<open>Capability index representation is injective.\<close>
lemma cap_index_inj[dest]: "(\<lfloor>i\<^sub>1\<rfloor> :: byte) = \<lfloor>i\<^sub>2\<rfloor> \<Longrightarrow> i\<^sub>1 = i\<^sub>2" for i\<^sub>1 i\<^sub>2 :: capability_index
unfolding cap_index_rep_def
using cap_index_rep'[of i\<^sub>1] cap_index_rep'[of i\<^sub>2] word_of_nat_inj[of "\<lfloor>i\<^sub>1\<rfloor>" "\<lfloor>i\<^sub>2\<rfloor>"]
cap_index_rep'_inject
by force
text \<open>Representation function is invertible.\<close>
lemmas cap_index_invertible[intro] = invertible.intro[OF injI, OF cap_index_inj]
interpretation cap_index_inv: invertible cap_index_rep ..
adhoc_overloading abs cap_index_inv.inv
subsubsection \<open>Capability offset\<close>
text \<open>The following datatype specifies data offsets for addresses in the procedure heap.\<close>
type_synonym capability_offset = byte
datatype data_offset =
Addr
| Index
| Ncaps capability
| Cap capability capability_index capability_offset
text \<open>
Machine word representation of data offsets. Using these offsets the following data can be
obtained:
\begin{itemize}
\item @{text Addr}: procedure Ethereum address;
\item @{text Index}: procedure index;
\item @{text "Ncaps ty"}: the number of capabilities of type @{text "ty"};
\item @{text "Cap ty i off"}: capability of type @{text "ty"}, with index @{text "ty"} and
offset @{text "off"} into that capability.
\end{itemize}
\<close>
definition data_offset_rep :: "data_offset \<Rightarrow> word32" where
"data_offset_rep off \<equiv> case off of
Addr \<Rightarrow> 0x00 \<Join>\<^sub>2 0x00 \<Join>\<^sub>1 0x00
| Index \<Rightarrow> 0x00 \<Join>\<^sub>2 0x00 \<Join>\<^sub>1 0x01
| Ncaps ty \<Rightarrow> \<lfloor>ty\<rfloor> \<Join>\<^sub>2 0x00 \<Join>\<^sub>1 0x00
| Cap ty i off \<Rightarrow> \<lfloor>ty\<rfloor> \<Join>\<^sub>2 \<lfloor>i\<rfloor> \<Join>\<^sub>1 off"
adhoc_overloading rep data_offset_rep
text \<open>Data offset representation is injective.\<close>
lemma data_offset_inj[dest]:
"\<lfloor>d\<^sub>1\<rfloor> = \<lfloor>d\<^sub>2\<rfloor> \<Longrightarrow> d\<^sub>1 = d\<^sub>2" for d\<^sub>1 d\<^sub>2 :: data_offset
unfolding data_offset_rep_def
by (auto split:data_offset.splits)
text \<open>Least number of bytes to hold the current value of a data offset is @{text 3}.\<close>
lemma width_data_offset: "width \<lfloor>d\<rfloor> \<le> 3 * LENGTH(byte)" for d :: data_offset
unfolding data_offset_rep_def
by (simp split:data_offset.splits)
lemma width_data_offset'[simp]: "3 * LENGTH(byte) \<le> n \<Longrightarrow> width \<lfloor>d\<rfloor> \<le> n" for d :: data_offset
using width_data_offset[of d] by simp
subsubsection \<open>Kernel storage address\<close>
text \<open>
Type definition for procedure indices. A procedure index is represented as a natural number that
is smaller then @{text "2\<^sup>1\<^sup>9\<^sup>2 - 1"}. It can be zero here, to simplify its future use as an array
index, but its low-level representation will start from @{text 1}.
\<close>
typedef key_index = "{i :: nat. i < 2 ^ LENGTH(key) - 1}" morphisms key_index_rep' key_index
by (rule exI[of _ "0"], simp)
adhoc_overloading rep key_index_rep'
adhoc_overloading abs key_index
text \<open>Introduce address datatype that describes possible addresses in the kernel storage.\<close>
datatype address =
Heap_proc key data_offset
| Nprocs
| Proc_key key_index
| Kernel
| Curr_proc
| Entry_proc
text \<open>Low-level representation of a procedure index is a machine word that starts from @{text 1}.\<close>
definition "key_index_rep i \<equiv> of_nat (\<lfloor>i\<rfloor> + 1) :: key" for i :: key_index
adhoc_overloading rep key_index_rep
text \<open>Proof that low-level representation can't be @{text 0}.\<close>
lemma key_index_nonzero[simp]: "\<lfloor>i\<rfloor> \<noteq> (0 :: key)" for i :: key_index
unfolding key_index_rep_def using key_index_rep'[of i]
by (intro of_nat_neq_0, simp_all)
text \<open>Low-level representation is injective.\<close>
lemma key_index_inj[dest]: "(\<lfloor>i\<^sub>1\<rfloor> :: key) = \<lfloor>i\<^sub>2\<rfloor> \<Longrightarrow> i\<^sub>1 = i\<^sub>2" for i :: key_index
unfolding key_index_rep_def using key_index_rep'[of i\<^sub>1] key_index_rep'[of i\<^sub>2]
by (simp add:key_index_rep'_inject of_nat_inj)
text \<open>Address prefix for all addresses that belong to the kernel storage.\<close>
abbreviation "kern_prefix \<equiv> 0xffffffff"
text \<open>
Machine word representation of the kernel storage layout, which consists of the following
addresses:
\begin{itemize}
\item @{text "Heap_proc k offs"}: procedure heap of key @{text k} and data offset @{text offs};
\item @{text Nprocs}: number of procedures;
\item @{text "Proc_key i"}: a procedure with index @{text i} in the procedure list;
\item @{text Kernel}: kernel Ethereum address;
\item @{text Curr_proc}: current procedure;
\item @{text Entry_proc}: entry procedure.
\end{itemize}
\<close>
definition addr_rep :: "address \<Rightarrow> word32" where
"addr_rep a \<equiv> case a of
Heap_proc k offs \<Rightarrow> kern_prefix \<Join>\<^sub>1 0x00 \<^sub>5\<diamond> k \<Join>\<^sub>3 \<lfloor>offs\<rfloor>
| Nprocs \<Rightarrow> kern_prefix \<Join>\<^sub>1 0x01 \<^sub>5\<diamond> (0 :: key) \<Join>\<^sub>3 0x000000
| Proc_key i \<Rightarrow> kern_prefix \<Join>\<^sub>1 0x01 \<^sub>5\<diamond> \<lfloor>i\<rfloor> \<Join>\<^sub>3 0x000000
| Kernel \<Rightarrow> kern_prefix \<Join>\<^sub>1 0x02 \<^sub>5\<diamond> (0 :: key) \<Join>\<^sub>3 0x000000
| Curr_proc \<Rightarrow> kern_prefix \<Join>\<^sub>1 0x03 \<^sub>5\<diamond> (0 :: key) \<Join>\<^sub>3 0x000000
| Entry_proc \<Rightarrow> kern_prefix \<Join>\<^sub>1 0x04 \<^sub>5\<diamond> (0 :: key) \<Join>\<^sub>3 0x000000"
adhoc_overloading rep addr_rep
text \<open>Kernel storage address representation is injective.\<close>
lemma addr_inj[dest]: "\<lfloor>a\<^sub>1\<rfloor> = \<lfloor>a\<^sub>2\<rfloor> \<Longrightarrow> a\<^sub>1 = a\<^sub>2" for a\<^sub>1 a\<^sub>2 :: address
unfolding addr_rep_def
by (split address.splits) (force split:address.splits)+
text \<open>Representation function is invertible.\<close>
lemmas addr_invertible[intro] = invertible.intro[OF injI, OF addr_inj]
interpretation addr_inv: invertible addr_rep ..
adhoc_overloading abs addr_inv.inv
text \<open>Lowest address of the kernel storage (0xffffffff0000...).\<close>
abbreviation "prefix_bound \<equiv> rpad (size kern_prefix) (ucast kern_prefix :: word32)"
lemma prefix_bound: "unat prefix_bound < 2 ^ LENGTH(word32)" unfolding rpad_def by simp
lemma prefix_bound'[simplified, simp]: "x \<le> unat prefix_bound \<Longrightarrow> x < 2 ^ LENGTH(word32)"
using prefix_bound by simp
text \<open>All addresses in the kernel storage are indeed start with the kernel prefix (0xffffffff).\<close>
lemma addr_prefix[simp, intro]: "limited_and prefix_bound \<lfloor>a\<rfloor>" for a :: address
unfolding limited_and_def addr_rep_def
by (subst word_bw_comms) (auto split:address.split simp del:ucast_bintr)
subsection \<open>Capability formats\<close>
text \<open>
We define capability format generally as a @{text locale}. It has two parameters: first one is a
@{text "subset"} function (denoted as @{text "\<subseteq>\<^sub>c"}), and second one is a @{text "set_of"} function,
which maps a capability to its high-level representation that is expressed as a set.
We have an assumption that @{text "Capability A"} is a subset of @{text "Capability B"} if and
only if their high-level representations are also subsets of each other.
We call it the well-definedness assumption (denoted as wd) and using it we can prove abstractly
that such generic capability format satisfies the properties of reflexivity and transitivity.
Then using this locale we can prove that capability formats of all available system calls
satisfy the properties of reflexivity and transitivity simply by formalizing corresponding
@{text "subset"} and @{text "set_of"} functions and then proving the well-definedness assumption.
This process is called locale interpretation.
\<close>
no_notation abs ("\<lceil>_\<rceil>")
locale cap_sub =
fixes set_of :: "'a \<Rightarrow> 'b set" ("\<lceil>_\<rceil>")
fixes sub :: "'a \<Rightarrow> 'a \<Rightarrow> bool" ("(_/ \<subseteq>\<^sub>c _)" [51, 51] 50)
assumes wd:"a \<subseteq>\<^sub>c b = (\<lceil>a\<rceil> \<subseteq> \<lceil>b\<rceil>)" begin
lemma sub_refl: "a \<subseteq>\<^sub>c a" using wd by auto
lemma sub_trans: "\<lbrakk>a \<subseteq>\<^sub>c b; b \<subseteq>\<^sub>c c\<rbrakk> \<Longrightarrow> a \<subseteq>\<^sub>c c" using wd by blast
end
notation abs ("\<lceil>_\<rceil>")
consts sub :: "'a \<Rightarrow> 'a \<Rightarrow> bool" ("(_/ \<subseteq>\<^sub>c _)" [51, 51] 50)
subsubsection \<open>Call, Register and Delete capabilities\<close>
text \<open>
Call, Register and Delete capabilities have the same format, so we combine them together here.
The capability format defines a range of procedure keys that the capability allows one
to call. This is defined as a base procedure key and a prefix.
Prefix is defined as a natural number, whose length is bounded by a maximum length of a procedure
key.
\<close>
typedef prefix_size = "{n :: nat. n \<le> LENGTH(key)}"
morphisms prefix_size_rep' prefix_size
by auto
adhoc_overloading rep prefix_size_rep'
text \<open>Low-level representation of a prefix is a 8-bit machine word (or simply a byte).\<close>
definition "prefix_size_rep s \<equiv> of_nat \<lfloor>s\<rfloor> :: byte" for s :: prefix_size
adhoc_overloading rep prefix_size_rep
text \<open>Prefix representation is injective.\<close>
lemma prefix_size_inj[dest]: "(\<lfloor>s\<^sub>1\<rfloor> :: byte) = \<lfloor>s\<^sub>2\<rfloor> \<Longrightarrow> s\<^sub>1 = s\<^sub>2" for s\<^sub>1 s\<^sub>2 :: prefix_size
unfolding prefix_size_rep_def using prefix_size_rep'[of s\<^sub>1] prefix_size_rep'[of s\<^sub>2]
by (simp add:prefix_size_rep'_inject of_nat_inj)
text \<open>