-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathProducer.v
3035 lines (2876 loc) · 131 KB
/
Producer.v
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
Require Export Block.
From mathcomp Require Import all_ssreflect.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
Set Bullet Behavior "Strict Subproofs".
(** Producer **)
Section Producer.
Definition populate_packets (id: nat) (model : packet) (contents: list (list byte)) : list packet :=
map (fun l => let newHeader := copy_fix_header (p_header model) l in mk_pkt newHeader l id) contents.
(*Finally, we can define what it means to encode a block with a model*)
Definition encode_block_aux (b: block) (model: packet) : block * seq fpacket :=
let packetsNoFec := populate_packets (blk_id b) model
(encoder_list (blk_h b) (blk_k b) (blk_c b) (packet_mx b)) in
let packetsWithFec := map_with_idx packetsNoFec (fun p i =>
mk_fecpkt p (mk_data (blk_k b) (blk_h b) true (blk_id b) (Z.to_nat((blk_k b) + i)))) in
(b <| parity_packets := map Some packetsWithFec |>, packetsWithFec).
(*Encoding a block chooses an appropriate model packet - either the inputted packet
or the last packet in the block*)
Definition encode_block (b: block) (o: option packet) : block * list fpacket :=
match (pmap id (data_packets b)), o with
| nil, None => (b, nil) (*can't happen*)
| _, Some p => encode_block_aux b p
| h :: t, _ => encode_block_aux b (f_packet (last h (h :: t)))
end.
(*From here, we need a few utility functions for block so we can create the encoder predicate*)
Definition get_fec_packet (p: packet) (b: block) : fpacket :=
mk_fecpkt p (mk_data (blk_k b) (blk_h b) false (blk_id b) (Z.to_nat (Zindex None (data_packets b)))).
Definition new_fec_packet (p: packet) (k: Z) (h: Z) : fpacket :=
mk_fecpkt p (mk_data k h false (p_seqNum p) 0).
Definition add_packet_to_block_red (p: packet) (b: block) : block :=
let idx := Zindex None (data_packets b) in
b <| data_packets := upd_Znth idx (data_packets b) (Some (get_fec_packet p b)) |>.
Definition create_block_with_packet_red (p: packet) (k: Z) (h: Z) : block :=
let f := new_fec_packet p k h in
mk_blk (p_seqNum p) (upd_Znth 0 (zseq k None) (Some f)) (zseq h None) k h false 0.
(** Encoder predicate*)
(*We will write our Producer first as a function (with inputted k and h), then write the predicate, where
we quantify over k and h*)
(*We include 2 pieces of state: the list of blocks include all previous blocks, and the current block is
represented separately as a block option*)
(*For the situations when we start a new block*)
Definition produce_new (p: packet) (k' h': Z) : list block * option block * list fpacket :=
let blk := create_block_with_packet_red p k' h' in
let t := encode_block blk (Some p) in
if Z.eq_dec k' 1 then ([:: t.1], None, new_fec_packet p k' h' :: t.2) else (nil, Some blk, [ :: new_fec_packet p k' h']).
(*For the situation when we add to an existing block*)
Definition produce_exist (p :packet) (b: block) : list block * option block * list fpacket :=
let newBlock := add_packet_to_block_red p b in
let t := encode_block newBlock (Some p) in
if Z.eq_dec (Zlength (filter isSome (data_packets newBlock))) (blk_k newBlock) then
([:: t.1], None, get_fec_packet p b :: t.2) else (nil, Some newBlock, [ :: get_fec_packet p b]).
Definition producer_one_step (blocks: list block) (currBlock : option block) (curr: packet)
(k h: Z) : list block * option block * list fpacket :=
match currBlock with
| None => (*last block finished, need to create a new one*)
let t := produce_new curr k h in
(t.1.1 ++ blocks, t.1.2, t.2)
| Some b =>
if ~~(Z.eq_dec (blk_k b) k) || ~~(Z.eq_dec (blk_h b) h)
then let t1 := encode_block b None in
let t2 := produce_new curr k h in
(t2.1.1 ++ [:: t1.1] ++ blocks, t2.1.2, t1.2 ++ t2.2)
else
let t := produce_exist curr b in
(t.1.1 ++ blocks, t.1.2, t.2)
end.
(*For proofs, a version which concatenates all of the results of producer_one_step*)
Definition producer_all_steps (orig: list packet) (params: list (Z * Z)) : list block * option block * list fpacket :=
foldl (fun (acc: list block * option block * list fpacket) (x : packet * (Z * Z)) =>
let t := producer_one_step acc.1.1 acc.1.2 x.1 x.2.1 x.2.2 in
(t.1.1, t.1.2, acc.2 ++ t.2)) (nil, None, nil) (combine orig params).
Definition rse_produce_func orig params curr k h :=
(producer_one_step (producer_all_steps orig params).1.1 (producer_all_steps orig params).1.2 curr k h).2.
(*For the final predicate, we need to find the past parameters that were used. We can do so with
the following:*)
Definition get_produce_params (l: list fpacket) : option (Z * Z) :=
match filter (fun (x: fpacket) => ~~ (fd_isParity x)) l with
| [ :: p] => Some (fd_k p, fd_h p)
| _ => None
end.
Lemma encode_block_aux_filter: forall b p,
[seq x <- (encode_block_aux b p).2 | ~~ fd_isParity (p_fec_data' x)] = [::].
Proof.
move => b p. erewrite eq_in_filter. apply filter_pred0.
move => x. rewrite in_mem_In /= In_Znth_iff; zlist_simpl. move => [i] [Hi]. zlist_simpl.
by move <-.
Qed.
Lemma encode_block_filter : forall b o,
[seq x <- (encode_block b o).2 | ~~ fd_isParity (p_fec_data' x)] = nil.
Proof.
move => b o. rewrite /encode_block/=.
case Hmap: (pmap id (data_packets b)) => [// | h t ]; case : o => [p |//]; apply encode_block_aux_filter.
Qed.
Lemma produce_func_get_params: forall l orig params curr k h,
l = rse_produce_func orig params curr k h ->
get_produce_params l = Some (k, h).
Proof.
move => l orig params curr k h. rewrite /rse_produce_func /producer_one_step/produce_new/produce_exist/=/get_produce_params.
case : (producer_all_steps orig params).1.2 => [b | ].
- case Hneq: (~~ Z.eq_dec (blk_k b) k || ~~ Z.eq_dec (blk_h b) h).
+ case : (Z.eq_dec k 1) => Hk1 //=.
* move ->. rewrite filter_cat/=.
by rewrite encode_block_filter /= encode_block_filter.
* move ->. rewrite filter_cat/=. by rewrite encode_block_filter.
+ apply orb_false_elim in Hneq.
case : Hneq => [Hkeq Hneq]. apply negbFE in Hkeq. apply negbFE in Hneq. solve_sumbool.
case: (Z.eq_dec
(Zlength
[seq x <- upd_Znth (Zindex None (data_packets b)) (data_packets b)
(Some (get_fec_packet curr b))
| isSome x]) (blk_k b)) => /= Hk ->/=.
* rewrite encode_block_filter. by subst.
* by subst.
- case: (Z.eq_dec k 1) => Hk/= -> //=.
by rewrite encode_block_filter.
Qed.
Corollary produce_func_get_params': forall orig params curr k h,
get_produce_params (rse_produce_func orig params curr k h) = Some (k, h).
Proof.
move => orig params curr k h. by eapply produce_func_get_params.
Qed.
End Producer.
(*We want to prove the properties we will need of our producer.
We express this (eventually) through a large invariant. Unlike the
decoder, we only need to consider 1 version, and we prove all
the properties we may need in 1 go.
The main result: all blocks from the Producer are well formed
(as is the resulting packet stream) and they are complete if
they are recoverable.*)
Section ProducerBlocks.
(*The following tactic will be helpful. First, we have a few lemmas to avoid unfolding*)
Lemma populate_packets_Zlength: forall i model s,
Zlength (populate_packets i model s) = Zlength s.
Proof.
move => i model s. by rewrite Zlength_map.
Qed.
Lemma encoder_list_Zlength: forall h k c packets,
0 <= h ->
0 <= c ->
Zlength (encoder_list h k c packets) = h.
Proof.
move => h k c pkts Hh Hc.
by rewrite /encoder_list (proj1 (ListMatrix.lmatrix_multiply_wf _ _ _ _ _)); rep_lia.
Qed.
Lemma encoder_list_Znth_Zlength: forall h k c packets i,
0 <= c ->
0 <= i < h ->
Zlength (Znth i (encoder_list h k c packets)) = c.
Proof.
move => h k c pkts i Hc Hi.
have: ListMatrix.wf_lmatrix (encoder_list h k c pkts) h c. {
apply encoder_wf; lia. }
rewrite /ListMatrix.wf_lmatrix/ListMatrix.rect => [[Hlen [_ Hnth]]].
move: Hnth. by rewrite Forall_Znth Hlen => /(_ _ Hi).
Qed.
Ltac len_encode :=
zlist_simpl;
repeat match goal with
| [H: context [Zlength (populate_packets _ _ _) ] |- _] => move: H
| |- context [Zlength (populate_packets ?i ?p ?s) ] => rewrite populate_packets_Zlength
| |- context [Zlength (encoder_list _ _ _ _) ] => rewrite encoder_list_Zlength
| |- context [Zlength (Znth ?x (encoder_list _ _ _ _)) ] => rewrite encoder_list_Znth_Zlength
| |- 0 <= blk_c ?b => apply blk_c_nonneg
end; try rep_lia.
(** Lemmas about [encode_block]*)
(*If we give a valid packet as a template and start with a well-formed, in-progress block,
encoding this block with p as the template gives a well-formed block*)
Lemma encode_block_aux_wf: forall b p,
packet_valid p ->
block_in_progress b ->
block_wf b ->
block_wf (encode_block_aux b p).1.
Proof.
move => b p Hpval Hprog. rewrite /block_wf/encode_block_aux/= =>
[[Hkbound [Hhbound [Hkh [Hid [Hidx [Hk [Hh [Henc [Hvalid [Hdats Hpars]]]]]]]]]]].
split_all => //; try lia.
- move => p'; rewrite packet_in_block_eq => /orP/=[Hdat | Hpar].
+ apply Hkh. by apply data_in_block.
+ move: Hpar. rewrite mem_map; last first. apply some_inj.
by move => /mapWithIdxP[ j [y [Hj [Hjth Hp']]]]; subst.
- move => p'; rewrite packet_in_block_eq => /orP/=[Hdat | Hpar].
+ apply Hid. by rewrite data_in_block.
+ move: Hpar. rewrite mem_map; last first. apply some_inj.
by move => /mapWithIdxP[ j [y [Hj [Hjth Hp']]]]; subst.
- (*the hard step*)
move => p' i; rewrite packet_in_block_eq => /orP/= [Hdat | Hpar].
+ have Hin:=Hdat. move: Hin => /inP. rewrite In_Znth_iff => [[j [Hj Hjth]]].
split.
* have [Hi | [Hi | Hout]]: 0 <= i < blk_k b \/ blk_k b <= i < blk_k b + blk_h b \/
(0 > i \/ i >= blk_k b + blk_h b) by lia.
-- rewrite Znth_app1; try lia.
move: Hidx => /(_ p' i). rewrite data_in_block // Znth_app1; try lia.
move => H.
by apply H.
-- rewrite Znth_app2; try lia. len_encode.
move => [Hp']. subst => //=. lia.
-- rewrite Znth_outofbounds // Zlength_app. len_encode.
* move ->. have Hj': j = Z.of_nat (fd_blockIndex p'). apply Hidx.
by apply data_in_block.
by rewrite Znth_app1 //; simpl in *; lia.
rewrite Znth_app1; simpl in *; try lia. by subst.
+ move: Hpar => /mapP => /(_ fec_data_eq_dec) [x Hinx [Hxp]].
subst. move: Hinx => /mapWithIdxP[ j [y [Hj [Hjth Hp']]]]; subst => //=.
have Hj': 0 <= j < blk_h b by len_encode.
rewrite {Hj}. split.
* have [Hi | [Hi | Hout]]: 0 <= i < blk_k b \/ blk_k b <= i < blk_k b + blk_h b \/
(0 > i \/ i >= blk_k b + blk_h b) by lia.
-- rewrite Znth_app1; try lia. set p':= {|
p_packet :=
Znth j (populate_packets (blk_id b) p (encoder_list (blk_h b) (blk_k b) (blk_c b) (packet_mx b)));
p_fec_data :=
{|
fd_k := blk_k b;
fd_h := blk_h b;
fd_isParity := true;
fd_blockId := blk_id b;
fd_blockIndex := Z.to_nat (blk_k b + j)
|}
|}. move => Hith. have /inP Hin: In (Some p') (data_packets b).
rewrite In_Znth_iff. exists i. split => //.
by rewrite Hk. (*why doesnt lia work*)
move: Hith. subst p'.
rewrite -((Znth_app1 _ _ _ (parity_packets b))); try lia.
rewrite Hidx/=. simpl in *. rep_lia. by apply data_in_block.
-- rewrite Znth_app2; try lia. len_encode.
move => [Heq]. rep_lia.
-- rewrite Znth_outofbounds // Zlength_app. len_encode.
* move ->. rewrite Znth_app2; rewrite Z2Nat.id; try rep_lia.
have->:(blk_k b + j - Zlength (data_packets b)) = j by lia. by len_encode.
- len_encode.
- move => p'; rewrite packet_in_block_eq => /orP /= [Hdat | Hpar].
+ apply Hvalid. by apply data_in_block.
+ move: Hpar. rewrite mem_map; last first. apply some_inj.
move => /mapWithIdxP[ j [y [Hj [Hjth Hp']]]]; subst.
rewrite Znth_map;[|len_encode] => /=.
rewrite /packet_valid/=. apply copy_fix_header_valid with(con1:=(p_contents p)).
* have: 0 <= j < blk_h b by len_encode. move: Hj => _ Hj. len_encode.
(*need in_progress for bound here*)
have Hc: blk_c b <= fec_max_cols by apply blk_c_bound.
move: Hpval. rewrite /packet_valid /valid_fec_packet => Hval. apply header_bound in Hval.
rewrite /Endian.Short.max_unsigned/=. rep_lia.
* apply Hpval.
- move => p'. by rewrite /packet_in_parity/= => /mapP => /(_ fec_data_eq_dec)
[x /mapWithIdxP [i [x' [_ [_ Hxeq]]]] [Hx]]; subst.
Qed.
Lemma encode_block_some_wf: forall b p,
packet_valid p ->
block_in_progress b ->
block_wf b ->
block_wf (encode_block b (Some p)).1.
Proof.
move => b p Hval Hprog Hwf. rewrite /encode_block.
case Hdat: (pmap id (data_packets b)) => [|h t];
by apply encode_block_aux_wf.
Qed.
Lemma encode_block_aux_comp: forall b p,
black_complete (encode_block_aux b p).1 = black_complete b.
Proof.
move => b p. by [].
Qed.
Lemma encode_block_black_comp: forall b o,
black_complete (encode_block b o).1 = black_complete b.
Proof.
move => b o. rewrite /encode_block/=. case : (pmap id(data_packets b)) => [/= | h t]; case : o => [x|//];
apply encode_block_aux_comp.
Qed.
Lemma encode_block_time: forall b o,
black_time (encode_block b o).1 = black_time b.
Proof.
move => b o. rewrite /encode_block/=. by case : (pmap id(data_packets b)) => [/= | h t]; case : o => [x|//].
Qed.
Lemma data_packets_encode: forall b o,
data_packets (encode_block b o).1 = data_packets b.
Proof.
move => b o. rewrite /encode_block/=.
by case Hmpap: (pmap id (data_packets b)) => [/=|h t /=]; case : o.
Qed.
Lemma encode_block_nonempty: forall b o,
data_elt b ->
data_elt (encode_block b o).1.
Proof.
move => b o. by rewrite /data_elt data_packets_encode.
Qed.
Lemma encode_some: forall b p,
encode_block b (Some p) = encode_block_aux b p.
Proof.
move => b p. rewrite /encode_block. by case: (pmap id (data_packets b)).
Qed.
Lemma c_encode_aux: forall (b: block) (p: packet),
0 <= blk_h b ->
block_in_progress b ->
blk_c (encode_block_aux b p).1 = blk_c b.
Proof.
move => b p Hh Hprog. rewrite /encode_block_aux/= {1}/blk_c/= {2}/blk_c/=.
rewrite pars_in_progress //.
case Hpars: [seq x <- [seq Some i
| i <- map_with_idx
(populate_packets (blk_id b) p
(encoder_list (blk_h b) (blk_k b) (blk_c b) (packet_mx b)))
(fun (p0 : packet) (i : Z) =>
{|
p_packet := p0;
p_fec_data :=
{|
fd_k := blk_k b;
fd_h := blk_h b;
fd_isParity := true;
fd_blockId := blk_id b;
fd_blockIndex := Z.to_nat (blk_k b + i)
|}
|})]
| isSome x] => [//| h t /=]. move: Hpars.
case : h => [p' /= | //]. move => Hpars'.
have: (Some p') \in [seq x <- [seq Some i
| i <- map_with_idx
(populate_packets (blk_id b) p
(encoder_list (blk_h b) (blk_k b) (blk_c b) (packet_mx b)))
(fun (p0 : packet) (i : Z) =>
{|
p_packet := p0;
p_fec_data :=
{|
fd_k := blk_k b;
fd_h := blk_h b;
fd_isParity := true;
fd_blockId := blk_id b;
fd_blockIndex := Z.to_nat (blk_k b + i)
|}
|})]
| isSome x].
move => Heq. rewrite Hpars'. by rewrite in_cons eq_refl.
move => /(_ fec_data_eq_dec). (*why do i get these weird goals?*)
rewrite mem_filter/=. rewrite (@mem_map fpacket); last first.
by apply some_inj.
rewrite in_mem_In In_Znth_iff. len_encode. move => [i [Hi Hith]]. subst.
len_encode => /=. rewrite Znth_map; len_encode => /=. len_encode.
by rewrite /blk_c pars_in_progress.
Qed.
Lemma encode_block_aux_encoded: forall b p,
0 <= blk_h b ->
block_in_progress b ->
data_elt b ->
block_encoded (encode_block_aux b p).1.
Proof.
move => b p Hh Hprog Helt. rewrite /block_encoded c_encode_aux //.
split_all.
- rewrite /= blk_c_in_progress //.
move: Helt. rewrite /data_elt.
case Hpmap: (pmap id (data_packets b)) => [// | hd tl /=].
have Hhd: (Some hd) \in (data_packets b) by rewrite pmap_id_some Hpmap in_cons eq_refl.
(*have Hhd: In (Some hd) (data_packets b) by rewrite -in_mem_In.*)
have Hfhd: 0 <= Zlength (p_header hd ++ p_contents hd) by list_solve.
have [o ] := (@list_max_nonneg_exists _ (fun o : option fpacket =>
match o with
| Some p1 => Zlength (p_header p1 ++ p_contents p1)
| None => 0
end) _ _ Hhd Hfhd).
case : o => [y |//=].
+ (*normal case*)
move => [Hiny Hymax] _. by exists y.
+ (*weird case where all packets empty*)
move => [Hin Hmax] _. exists hd. split => //.
have [H0 | Hgt]: 0 = Zlength (p_header hd ++ p_contents hd) \/
0 < Zlength (p_header hd ++ p_contents hd) by lia.
* lia.
* have//: 0 < 0. have: Zlength (p_header hd ++ p_contents hd) <= 0; last first. lia.
rewrite -Hmax.
have Hmax' := (@list_max_nonneg_in _(fun o : option fpacket =>
match o with
| Some p1 => Zlength (p_header p1 ++ p_contents p1)
| None => 0
end) (data_packets b) (Some hd) Hfhd Hhd). simpl in *; lia.
- move => p'/=; rewrite /packet_in_parity/= => /inP.
rewrite In_Znth_iff; len_encode. move => [i [Hi]]. len_encode.
move => [Hp']. subst => /=.
by rewrite Znth_map/=; len_encode.
- move => p'/=. rewrite blk_c_in_progress //. move => Hin. rewrite /packet_bytes.
have Hnonneg: 0 <= Zlength (p_header p' ++ p_contents p') by list_solve.
have Hb:= (@list_max_nonneg_in _ (fun o : option fpacket =>
match o with
| Some p1 => Zlength (p_header p1 ++ p_contents p1)
| None => 0
end) (data_packets b) (Some p') Hnonneg Hin). simpl in *; lia.
- (*the key one: parities are valid*)
rewrite /= /packet_mx/= -/(packet_mx b) /parity_mx/=/parities_valid; len_encode.
move => i j Hi Hj.
len_encode. f_equal. by rewrite Znth_map/=; len_encode.
Qed.
Lemma encode_block_encoded: forall b o,
0 <= blk_h b ->
block_in_progress b ->
data_elt b ->
block_encoded (encode_block b o).1.
Proof.
move => b o Hh Hprog Helt. rewrite /encode_block. have Helt':=Helt.
move: Helt. rewrite /data_elt.
case Hpmap: (pmap id (data_packets b)) => [//|hd tl/=].
move => _.
case : o => [p|]; by apply encode_block_aux_encoded.
Qed.
Lemma encode_block_id: forall (b: block) o,
blk_id (encode_block b o).1 = blk_id b.
Proof.
move => b o. rewrite /encode_block. by case : o => /=[p|]; case: (pmap id (data_packets b)).
Qed.
Lemma encode_in_aux: forall b m (p: fpacket),
(p \in (encode_block_aux b m).2) =
((Some p) \in (parity_packets (encode_block_aux b m).1)).
Proof.
move => b m p. rewrite /= mem_map //. apply some_inj.
Qed.
Lemma encode_in: forall b o (p: fpacket),
p \in (encode_block b o).2 ->
(Some p) \in (parity_packets (encode_block b o).1).
Proof.
move => b o p. rewrite /encode_block.
by case Hpmap:(pmap id (data_packets b)) => [//= | hd tl /=]; case o => [p' | //]; rewrite encode_in_aux.
Qed.
Lemma in_encode: forall b o (p: fpacket),
data_elt b ->
(Some p) \in (parity_packets (encode_block b o).1) ->
p \in (encode_block b o).2.
Proof.
move => b o p. rewrite /data_elt /encode_block.
by case Hmap: (pmap id (data_packets b)) => [//= | hd tl /=] _; case o => [p' |//]; rewrite encode_in_aux.
Qed.
Lemma encode_block_k: forall (b: block) (o: option packet),
blk_k (encode_block b o).1 = blk_k b.
Proof.
move => b o. rewrite /encode_block. case : (pmap id (data_packets b)) => [/=| Hd tl /=]; by case : o.
Qed.
Lemma encode_block_h: forall (b: block) (o: option packet),
blk_h (encode_block b o).1 = blk_h b.
Proof.
move => b o. rewrite /encode_block. case : (pmap id (data_packets b)) => [/=| Hd tl /=]; by case : o.
Qed.
Lemma encode_parities_Zlength_aux: forall (b: block) p,
block_wf b ->
Zlength (parity_packets (encode_block_aux b p).1) = blk_h b.
Proof.
move => b p Hwf/=. len_encode. case : Hwf. lia.
Qed.
Lemma encode_parities_Zlength: forall (b: block) o,
block_wf b ->
Zlength (parity_packets (encode_block b o).1) = blk_h b.
Proof.
move => b o Hwf. rewrite /encode_block.
case : (pmap id (data_packets b)) => [//= | h t /=]; case : o => [p|]//; try by apply encode_parities_Zlength_aux.
rewrite /=. apply Hwf.
Qed.
(*We can switch between None and Some for encode_block*)
Lemma encode_block_none_some: forall (b: block),
data_elt b ->
exists model, (Some model) \in (map (omap (@p_packet _)) (data_packets b)) /\
encode_block b None = encode_block b (Some model).
Proof.
move => b. rewrite /data_elt /encode_block.
case Hmap: (pmap id (data_packets b)) => [// | h t /=] _.
exists (last h t). split => //.
apply /mapP. exists (Some (last h t)) => //.
by rewrite pmap_id_some Hmap mem_last.
Qed.
(** Lemmas about [create_block_with_packet_red]*)
Lemma create_block_red_wf: forall p k h,
packet_valid p ->
encodable p ->
0 < k <= ByteFacts.fec_n - 1 - ByteFacts.fec_max_h ->
0 < h <= ByteFacts.fec_max_h ->
block_wf (create_block_with_packet_red p k h).
Proof.
move => p k h Hval Henc Hk Hh. rewrite /create_block_with_packet_red/block_wf/=.
(*These will help with a bunch:*)
have Hin1: forall p',
(Some p') \in (upd_Znth 0 (zseq k None) (Some (new_fec_packet p k h))) -> p' = (new_fec_packet p k h). {
move => p' /inP Hin. apply In_upd_Znth in Hin. case : Hin => [[Hp']// | Hin].
move: Hin. rewrite In_Znth_iff => [[i]]. rewrite zseq_Zlength; try lia; move => [Hi]. by zlist_simpl. }
have Hin2: forall p',
((Some p') \in (upd_Znth 0 (zseq k None) (Some (new_fec_packet p k h)))) || ((Some p') \in (zseq h None)) ->
p' = (new_fec_packet p k h). {
move => p' /orP[ Hinp' | /inP]. by apply Hin1.
rewrite In_Znth_iff => [[i]].
rewrite zseq_Zlength; try lia; move => [Hi]. by zlist_simpl. }
split_all => //; try lia.
- move => p'; rewrite packet_in_block_eq/= => Hinp'. apply Hin2 in Hinp'. by subst.
- move => p'; rewrite packet_in_block_eq/==> Hinp'. apply Hin2 in Hinp'. by subst.
- move => p' i; rewrite packet_in_block_eq/==> Hinp'. apply Hin2 in Hinp'. subst => /=.
split.
+ have [Hi1 | [Hi2 | Hiout]]: (0 <= i < k \/ k <= i < k + h \/ (i < 0 \/ i >= k + h)) by lia.
* rewrite Znth_app1; zlist_simpl.
rewrite (upd_Znth_lookup' k); zlist_simpl.
by case : (Z.eq_dec i 0).
* by rewrite Znth_app2; zlist_simpl.
* rewrite Znth_outofbounds // Zlength_app. by zlist_simpl.
+ move ->. rewrite Znth_app1; zlist_simpl.
rewrite upd_Znth_same //. by zlist_simpl.
- by zlist_simpl.
- by zlist_simpl.
- move => p' Hinp'. apply Hin1 in Hinp'. by subst.
- move => p' Hinp'. apply Hin2 in Hinp'. by subst.
- move => p' Hinp'. apply Hin1 in Hinp'. by subst.
- move => p'. rewrite /packet_in_parity/= => /inP.
rewrite In_Znth_iff => [[i] [Hi]].
have Hi': 0 <= i < h by move: Hi; zlist_simpl.
by zlist_simpl.
Qed.
Lemma create_red_nonempty: forall p h k,
0 < h ->
data_elt (create_block_with_packet_red p h k).
Proof.
move => p h k Hh. rewrite /data_elt/=.
have Hin: (new_fec_packet p h k) \in pmap id (upd_Znth 0 (zseq h None) (Some (new_fec_packet p h k))). {
rewrite -pmap_id_some in_mem_In In_Znth_iff. exists 0. zlist_simpl. split; try lia.
rewrite (upd_Znth_lookup' h); zlist_simpl. by case (Z.eq_dec 0 0).
}
move: Hin. by case : ( pmap id (upd_Znth 0 (zseq h None) (Some (new_fec_packet p h k)))).
Qed.
Lemma create_red_in_progress: forall p k h,
0 <= h ->
block_in_progress (create_block_with_packet_red p k h).
Proof.
move => p k h Hh. rewrite /block_in_progress/=. apply /allP => x.
rewrite in_mem_In In_Znth_iff => [[i [Hi]]]. zlist_simpl. by move <-. move: Hi; zlist_simpl.
Qed.
Lemma create_red_Zindex: forall p k h,
1 <= k ->
Zindex None (data_packets (create_block_with_packet_red p k h)) = 1.
Proof.
move => p k h Hk. rewrite /Zindex /index/=.
rewrite zseq_hd; try lia. rewrite upd_Znth0.
simpl find.
have [Hk1 | Hk1]: k = 1 \/ k > 1 by lia.
- subst. by have->:1-1 = 0 by [].
- by rewrite zseq_hd; try lia.
Qed.
Lemma create_block_in: forall p k h,
0 < k ->
(Some p) \in (map (omap (@p_packet _)) (data_packets (create_block_with_packet_red p k h))).
Proof.
move => p k h Hk. rewrite /create_block_with_packet_red/=.
apply /mapP. exists (Some (new_fec_packet p k h)) =>//.
apply/inP. apply upd_Znth_In. zlist_simpl.
Qed.
(** Lemmas about [add_packet_to_block_red]*)
Lemma add_red_k: forall p b,
blk_k (add_packet_to_block_red p b) = blk_k b.
Proof.
by [].
Qed.
Lemma add_red_h: forall p b,
blk_h (add_packet_to_block_red p b) = blk_h b.
Proof.
by [].
Qed.
Lemma add_red_id: forall p b,
blk_id (add_packet_to_block_red p b) = blk_id b.
Proof.
by [].
Qed.
Lemma add_red_parity: forall p b,
parity_packets (add_packet_to_block_red p b) = parity_packets b.
Proof.
by [].
Qed.
Lemma add_black_comp: forall b p,
black_complete (add_packet_to_block_red p b) = black_complete b.
Proof.
by [].
Qed.
Lemma add_red_wf: forall p b,
block_wf b ->
packet_valid p ->
encodable p ->
Zindex None (data_packets b) < blk_k b ->
block_wf (add_packet_to_block_red p b).
Proof.
move => p b Hwf Hval Henc Hzidx. rewrite /block_wf add_red_k add_red_h add_red_parity/=.
case : Hwf => [Hkbound [Hhbound [Hkh [Hid [Hidx [Hk [Hh [Henc' [Hvalid [Hdats Hpars]]]]]]]]]].
have Hnonneg:=(@Zindex_nonneg _ None (data_packets b)).
split_all => //; try lia.
- move => p'; rewrite packet_in_block_eq => /orP[/inP Hinp | Hinp]; last first.
by apply Hkh; apply parity_in_block.
apply In_upd_Znth in Hinp. case: Hinp => [[Hp'] | Hinp']; subst => //.
apply Hkh. apply data_in_block. by apply /inP.
- move => p'; rewrite packet_in_block_eq => /orP[/inP Hinp | Hinp]; last first.
by apply Hid; apply parity_in_block.
apply In_upd_Znth in Hinp. case: Hinp => [[Hp'] | Hinp']; subst => //.
by apply Hid; apply data_in_block; apply /inP.
- simpl in *. move => p' i.
rewrite cat_app -upd_Znth_app1; try lia.
rewrite packet_in_block_eq -mem_cat cat_app /= -upd_Znth_app1; try lia.
move: p' i.
apply block_wf_list_upd_Znth.
move => p' i Hin. apply Hidx. by rewrite packet_in_block_eq -mem_cat.
list_solve.
rewrite Znth_app1; try lia. apply Znth_Zindex. apply Zindex_In. simpl in *; lia.
rewrite /= Z2Nat.id; lia.
- rewrite upd_Znth_Zlength; simpl in *; try lia.
- move => p' /inP Hinp.
apply In_upd_Znth in Hinp. case: Hinp => [[Hp'] | Hinp']; subst => //.
by apply Henc'; apply /inP.
- move => p'; rewrite packet_in_block_eq => /orP[/inP Hinp | Hinp]; last first.
by apply Hvalid; apply parity_in_block.
apply In_upd_Znth in Hinp. case: Hinp => [[Hp'] | Hinp']; subst => //.
by apply Hvalid; apply data_in_block; apply /inP.
- move => p' /inP Hinp. apply In_upd_Znth in Hinp. case: Hinp => [[Hp'] | Hinp']; subst => //.
by apply Hdats; apply /inP.
Qed.
(*not the strongest spec, but OK for us*)
Lemma add_red_nonempty: forall (b: block) p,
data_elt b ->
data_elt (add_packet_to_block_red p b).
Proof.
move => b p. rewrite /data_elt.
case Hpmap: (pmap id (data_packets b)) => [// | h t /=] _.
have Hin: In (Some h) (data_packets b) by rewrite -in_mem_In pmap_id_some Hpmap in_cons eq_refl.
have Hidxlen:=(@Zindex_leq_Zlength _ (data_packets b) None). apply Zle_lt_or_eq in Hidxlen.
have: h \in pmap id (upd_Znth (Zindex None (data_packets b)) (data_packets b) (Some (get_fec_packet p b))). {
rewrite -pmap_id_some in_mem_In. case: Hidxlen => [Hlt | Heq].
- apply In_upd_Znth_old => //. rewrite Znth_Zindex //. by apply Zindex_In.
have H:=(@Zindex_nonneg _ None (data_packets b)). lia.
- rewrite upd_Znth_out_of_range //=. right. rewrite Heq/=. lia.
}
by case: (pmap id (upd_Znth (Zindex None (data_packets b)) (data_packets b) (Some (get_fec_packet p b)))).
Qed.
(*When we add a packet to a red block, it gets 1 packet bigger*)
Lemma add_red_size: forall b p,
Zindex None (data_packets b) < Zlength (data_packets b) ->
Zlength [seq x <- data_packets b | isSome x] + 1 =
Zlength [seq x <- (data_packets (add_packet_to_block_red p b)) | isSome x ].
Proof.
move => b p Hidx. rewrite /= upd_Znth_Zindex_Zlength //. apply Z.add_comm.
Qed.
Lemma add_block_in: forall (p: packet) (b: block),
Zindex None (data_packets b) < Zlength (data_packets b) ->
(Some p) \in [seq omap (p_packet (fec_data:=fec_data)) i | i <- data_packets (add_packet_to_block_red p b)].
Proof.
move => p b Hidx /=. apply /mapP. exists (Some (get_fec_packet p b)).
apply /inP.
apply upd_Znth_In. split => //. apply Zindex_nonneg. by [].
Qed.
(*Results about uniqeness of packet outputs (and packet outputs
more generally)*)
Section Uniq.
Lemma encode_block_aux_uniq: forall b p,
0 <= blk_k b ->
uniq (encode_block_aux b p).2.
Proof.
move=> b p Hk. rewrite /encode_block_aux/=.
apply map_with_idx_uniq => z1 z2 a1 a2 Hz1 Hz2 Hneq C.
inversion C. lia.
Qed.
Lemma encode_block_uniq: forall b o,
0 <= blk_k b ->
uniq (encode_block b o).2.
Proof.
move=> b o Hk.
rewrite /encode_block. by case: (pmap id (data_packets b)) =>// [| a l];
case: o=>//; try move=>x; apply encode_block_aux_uniq.
Qed.
Lemma produce_new_uniq: forall p k h,
uniq (produce_new p k h).2.
Proof.
move=> p k h. rewrite /produce_new.
case: (Z.eq_dec k 1)=>//= ->.
rewrite encode_block_aux_uniq; last by simpl; lia.
rewrite andbT. apply /negP => /mapP [[p' z]]/=.
rewrite -zip_combine => Hin.
apply mem_zip in Hin.
rewrite /new_fec_packet => Heq. inversion Heq.
Qed.
Lemma in_produce_new_kh: forall p k h (p': fpacket),
p' \in (produce_new p k h).2 ->
fd_k p' = k /\ fd_h p' = h.
Proof.
move=> p k h p'. rewrite /produce_new.
case: (Z.eq_dec k 1)=>//= Hk1.
- rewrite in_cons => /orP[/eqP -> // |]. by
rewrite encode_some/= => /mapWithIdxP [x] [p''] [] _ [] _ ->.
- by rewrite in_cons orbF => /eqP ->.
Qed.
Lemma in_encode_block_aux_kh: forall (p: fpacket) b (m: packet),
p \in (encode_block_aux b m).2 ->
fd_k p = blk_k b /\ fd_h p = blk_h b.
Proof.
move=> p b m.
by rewrite /encode_block_aux/= => /mapWithIdxP [i [x [] _ [] _ ->]].
Qed.
Lemma in_encode_block_kh: forall (p: fpacket) b o,
p \in (encode_block b o).2 ->
fd_k p = blk_k b /\ fd_h p = blk_h b.
Proof.
move=> p b o. rewrite /encode_block.
case: (pmap id (data_packets b)) => //= [| h t ]; case: o=>//.
- move=> a. by apply in_encode_block_aux_kh.
- move=> a. by apply in_encode_block_aux_kh.
- by apply in_encode_block_aux_kh.
Qed.
Lemma in_encode_block_aux_parity: forall (p: fpacket) b (m: packet),
p \in (encode_block_aux b m).2 ->
fd_isParity p = true.
Proof.
move=> p b m.
by rewrite /encode_block_aux/= => /mapWithIdxP [i [x [] _ [] _ ->]].
Qed.
Lemma in_encode_block_parity: forall (p: fpacket) b o,
p \in (encode_block b o).2 ->
fd_isParity p = true.
Proof.
move=> p b o. rewrite /encode_block.
case: (pmap id (data_packets b)) => //= [| h t ]; case: o=>//.
- move=> a. by apply in_encode_block_aux_parity.
- move=> a. by apply in_encode_block_aux_parity.
- by apply in_encode_block_aux_parity.
Qed.
Lemma produce_exist_uniq: forall p b,
uniq (produce_exist p b).2.
Proof.
move=> p b. rewrite /produce_exist.
case: (Z.eq_dec
(Zlength [seq x <- data_packets (add_packet_to_block_red p b) | isSome x])
(blk_k (add_packet_to_block_red p b)))=>//= Hkeq.
rewrite encode_block_uniq; last by
rewrite add_red_k; list_solve.
rewrite andbT. apply /negP => C.
by apply in_encode_block_parity in C.
Qed.
Lemma in_encode_block_aux_id: forall (p: fpacket) b (m: packet),
p \in (encode_block_aux b m).2 ->
fd_blockId p = blk_id b.
Proof.
move=> p b m.
by rewrite /encode_block_aux/= => /mapWithIdxP [i [x [] _ [] _ ->]].
Qed.
Lemma in_encode_block_id: forall (p: fpacket) b o,
p \in (encode_block b o).2 ->
fd_blockId p = blk_id b.
Proof.
move=> p b o. rewrite /encode_block.
case: (pmap id (data_packets b)) => //= [| h t ]; case: o=>//.
- move=> a. by apply in_encode_block_aux_id.
- move=> a. by apply in_encode_block_aux_id.
- by apply in_encode_block_aux_id.
Qed.
End Uniq.
(** Producer properties *)
(*To prove the main theorem about the Producer, we need to show that a number of properties are preserved in
each run of producer_one_step. To reduce repetition and make things
cleaner, we group the properties together and prove the 3 different cases we need before proving the full theorem*)
Definition block_option_list (x: list block * option block) : list block :=
match x.2 with
| None => x.1
| Some b => b :: x.1
end.
Definition producer_props (orig: list packet) (blks: list block) (currBlock: option block)
(pkts: seq fpacket) : Prop :=
perm_eq (get_blocks pkts) (block_option_list (blks, currBlock)) /\
(forall b, b \in (block_option_list (blks, currBlock)) -> block_wf b) /\
(forall b, b \in (block_option_list (blks, currBlock)) -> black_complete b = false) /\
(forall b, b \in (block_option_list (blks, currBlock)) -> black_time b = 0) /\
(forall b, b \in (block_option_list (blks, currBlock)) -> data_elt b) /\
(forall b p, b \in (block_option_list (blks, currBlock)) ->
packet_in_data p b ->
(p_packet p) \in orig) /\
(forall b, b \in (block_option_list (blks, currBlock)) -> exists p,
packet_in_data p b /\ blk_id b = p_seqNum p) /\
(*All previous blocks are done; the current is either done (with k packets) or has no parities*)
(forall b, b \in blks -> block_encoded b) /\
(forall b, currBlock = Some b -> block_in_progress b) /\
wf_packet_stream pkts /\
uniq pkts /\
(*The underlying packets of the data packets are unique*)
uniq (map (@p_packet _) (filter (fun (f: fpacket) => ~~ fd_isParity f) pkts)).
Lemma producer_props_orig_rev: forall orig blks currBlock pkts,
producer_props orig blks currBlock pkts ->
producer_props (rev orig) blks currBlock pkts.
Proof.
move => orig blks currBlock pkts. rewrite /producer_props => Henc; split_all; try apply Henc.
move => b p Hinp Hin. rewrite mem_rev. move: Hinp Hin. by apply Henc.
Qed.
Lemma producer_props_orig_rev_iff: forall orig blks currBlock pkts,
producer_props orig blks currBlock pkts <->
producer_props (rev orig) blks currBlock pkts.
Proof.
move => orig blks currBlock pkts. split; move => Henc.
- by apply producer_props_orig_rev.
- rewrite -(revK orig). by apply producer_props_orig_rev.
Qed.
(** Lemmas for main theorem *)
(* Overall, we need 3 cases to prove the theorem:
1. the properties are preserved when we start a new block
2. the properties are preserved when we encode the current block
3. the properties are preserved when we add a packet to the current block
We prove these properties after several helper lemmas below:*)
Lemma create_red_encode_block_lists: forall (p: packet) h k,
0 < h <= fec_max_h ->
0 < k <= fec_n - 1 - fec_max_h ->
packet_valid p ->
encodable p ->
al (get_block_lists (new_fec_packet p k h :: (encode_block (create_block_with_packet_red p k h) (Some p)).2)) =
[:: block_to_btuple (encode_block (create_block_with_packet_red p k h) (Some p)).1 ].
Proof.
move => p h k Hh0 Hk0 Hval Henc.
apply get_block_lists_single.
- apply encode_block_some_wf => //.
apply create_red_in_progress; lia.
by apply create_block_red_wf.
- apply data_block_elt. apply encode_block_nonempty.
apply create_red_nonempty; lia.
- move => p'. rewrite encode_some/= in_cons/=.
split.
+ move => /orP[/eqP Hp' | Hin].
* subst. apply /orP. left. apply /inP. apply upd_Znth_In. by zlist_simpl.
* apply /orP. right. by apply map_f.
+ move => /orP[ Hinp | Hinp].
* apply /orP. left. apply /eqP. move: Hinp => /inP Hinp.
apply In_upd_Znth in Hinp. case: Hinp => [[Hp']// | Hinp'].
move: Hinp'. rewrite In_Znth_iff => [[i [Hlen]]]. zlist_simpl => //.
move: Hlen; zlist_simpl.
* apply /orP. right. move: Hinp => /inP /inP; rewrite mem_map //.
by apply some_inj.
Qed.
(*Extend this easily*)
Lemma create_red_encode_blocks: forall (p: packet) h k,
0 < h <= fec_max_h ->
0 < k <= fec_n - 1 - fec_max_h ->
packet_valid p ->
encodable p ->
get_blocks (new_fec_packet p k h :: (encode_block (create_block_with_packet_red p k h) (Some p)).2) =
[:: (encode_block (create_block_with_packet_red p k h) (Some p)).1 ].
Proof.
move => p h k Hh Hk Hvalid Henc. rewrite /get_blocks create_red_encode_block_lists //= btuple_block_inv //=.
- apply encode_block_some_wf => //. apply create_red_in_progress; lia.
by apply create_block_red_wf.
- by rewrite encode_block_black_comp.
- by rewrite encode_block_time.
- apply data_block_elt. apply encode_block_nonempty. apply create_red_nonempty; lia.
Qed.
(*An easier case*)
Lemma create_red_block: forall (p: packet) h k,
0 < k ->
0 <= h ->
get_blocks [:: new_fec_packet p k h] = [:: create_block_with_packet_red p k h].
Proof.
move => b h k Hk Hh. rewrite /get_blocks/=/create_block_with_packet_red/new_packet_list/new_fec_packet/=.
set p:= {|
p_packet := b;
p_fec_data :=
{|
fd_k := k;
fd_h := h;
fd_isParity := false;
fd_blockId := p_seqNum b;
fd_blockIndex := 0
|}
|}.
rewrite /btuple_to_block/={1}zseq_hd; try lia. rewrite upd_Znth0/=.
f_equal. f_equal.
- rewrite sublist_upd_Znth_lr; zlist_simpl => //=. f_equal.
rewrite zseq_sublist; try lia. f_equal. lia.
- rewrite sublist_upd_Znth_r; zlist_simpl.
rewrite zseq_sublist; try lia. f_equal. lia.
Qed.
(*If there is no block in progress, we can get useful information about the sequence numbers of all
packets in pkts*)
Lemma in_pkts_id_new_block: forall orig blks pkts h,
producer_props orig blks None pkts ->
p_seqNum h \notin (map p_seqNum orig) ->
forall (p: fpacket),
p \in pkts ->
fd_blockId p != p_seqNum h.
Proof.
move => orig blks pkts h [IHperm [IHallwf [IHblackcomp [IHtime
[IHdata [IHinorig [IHids [IHencoded [IHprog [IHwfpkts IHuniqpkts]]]]]]]]]]
Hht p Hpin.
(*have Hpin': In p pkts by rewrite -in_mem_In.*)
have Hprop: get_block_lists_prop pkts (map block_to_btuple blks). {
eapply perm_get_block_lists_prop. by apply get_block_lists_spec. have Hperm':=IHperm.
move: Hperm'. rewrite /get_blocks => Hperm'. apply (perm_map (block_to_btuple)) in Hperm'.
rewrite -map_comp in Hperm'. rewrite (btuple_block_inv_list IHwfpkts) in Hperm' => //.
by apply get_block_lists_spec.
}
have [pkts' [Hinpkts Hinp]] :=(get_block_lists_allin_in IHwfpkts Hprop Hpin).
move: Hinpkts => /mapP.
(*idea: p is in a block b which is in blks. We know by IH that blk_id b = seqNum of some
packet (which must be in pkts). Thus, by uniqueness of sequence numbers, different than h's*)
rewrite /block_to_btuple/= => [[b] Hinb [Hid Hpkts']]. rewrite Hid.
move: IHids => /(_ _ Hinb) [p'] [Hinp' Hidp']. rewrite Hidp'.
move: IHinorig => /(_ _ _ Hinb Hinp') Hint.
case: (p_seqNum p' == p_seqNum h) /eqP => Heq //. move: Hht.
have->//: p_seqNum h \in [seq p_seqNum i | i <- orig]. rewrite -Heq.
by apply map_f.
Qed.
(*Case 1: If there is no block in progress, we can add a new block and packet, preserving the invariant*)
Lemma producer_props_new_block: forall p orig blks pkts k h,
0 < k <= fec_n - 1 - fec_max_h ->
0 < h <= fec_max_h ->
packet_valid p ->
encodable p ->
p_seqNum p \notin (map p_seqNum orig) ->
producer_props orig blks None pkts ->
producer_props (p :: orig) blks (Some (create_block_with_packet_red p k h))
(pkts ++ [:: new_fec_packet p k h]).
Proof.