1use crate::core::spec::SpecParser;
4
5use super::spec::*;
6use vstd::prelude::*;
7
8verus! {
9
10pub trait SPRoundTripDps where
25 Self: SpecByteLen +
26 Consistency<Val = Self::T> +
27 SpecParser<PVal = Self::T> +
28 SpecSerializerDps<SValue = Self::T>,
29 {
30 open spec fn unambiguous(&self) -> bool {
31 true
32 }
33
34 proof fn theorem_serialize_dps_parse_roundtrip(&self, v: Self::T, obuf: Seq<u8>)
35 requires
36 self.unambiguous(),
37 self.consistent(v),
38 ensures
39 ({
40 let ibuf = self.spec_serialize_dps(v, obuf);
41 let n = self.byte_len(v) as int;
42 self.spec_parse(ibuf) == Some((n, v))
43 }),
44 ;
45}
46
47pub trait SPRoundTrip where
57 Self: SpecByteLen +
58 SpecParser<PVal = Self::T> +
59 SpecSerializer<SVal = Self::T> +
60 Consistency<Val = Self::T> +
61{
62 open spec fn sp_roundtrip_inv(&self) -> bool {
63 true
64 }
65
66 proof fn theorem_serialize_parse_roundtrip(&self, v: Self::T)
67 requires
68 self.sp_roundtrip_inv(),
69 self.consistent(v),
70 ensures
71 ({
72 let bytes = self.spec_serialize(v);
73 self.spec_parse(bytes) == Some((bytes.len() as int, v))
74 }),
75 ;
76}
77
78impl<C: SPRoundTripDps + GoodSerializer + EquivSerializers> SPRoundTrip for C {
79 open spec fn sp_roundtrip_inv(&self) -> bool {
80 self.serialize_inv() && self.equiv_inv() && self.unambiguous()
81 }
82
83 proof fn theorem_serialize_parse_roundtrip(&self, v: Self::T) {
84 let empty = Seq::empty();
85 self.theorem_serialize_dps_parse_roundtrip(v, empty);
86 self.lemma_serialize_equiv_on_empty(v);
87 self.lemma_serialize_len(v);
88 }
89}
90
91
92pub trait NonAmbiguous where
98 Self: Consistency + SpecSerializer<SVal = Self::Val>
99{
100 open spec fn nonamb_inv(&self) -> bool {
102 true
103 }
104
105 proof fn lemma_serialize_injective(&self, v1: Self::Val, v2: Self::Val)
107 requires
108 self.nonamb_inv(),
109 self.consistent(v1),
110 self.consistent(v2),
111 ensures
112 self.spec_serialize(v1) == self.spec_serialize(v2) ==> v1 == v2
113 ;
114
115 proof fn corollary_serialize_injective_contrapositive(&self, v1: Self::Val, v2: Self::Val)
117 requires
118 self.nonamb_inv(),
119 self.consistent(v1),
120 self.consistent(v2),
121 ensures
122 v1 != v2 ==> self.spec_serialize(v1) != self.spec_serialize(v2),
123 {
124 self.lemma_serialize_injective(v1, v2);
125 }
126}
127
128impl<C: SPRoundTrip> NonAmbiguous for C {
129 open spec fn nonamb_inv(&self) -> bool {
130 self.sp_roundtrip_inv()
131 }
132
133 proof fn lemma_serialize_injective(&self, v1: Self::Val, v2: Self::Val) {
134 self.theorem_serialize_parse_roundtrip(v1);
135 self.theorem_serialize_parse_roundtrip(v2);
136 }
137}
138
139
140pub trait PSRoundTrip where
148 Self: SpecByteLen +
149 SpecParser<PVal = Self::T> +
150 SpecSerializer<SVal = Self::T> +
151{
152 open spec fn ps_roundtrip_inv(&self) -> bool {
153 true
154 }
155
156 proof fn theorem_parse_serialize_roundtrip(&self, ibuf: Seq<u8>)
157 requires
158 self.ps_roundtrip_inv(),
159 ensures
160 self.spec_parse(ibuf) matches Some((n, v)) ==> self.spec_serialize(v) == ibuf.take(n),
161 ;
162
163 proof fn corollary_parse_non_malleable(&self, buf1: Seq<u8>, buf2: Seq<u8>)
164 requires
165 self.ps_roundtrip_inv(),
166 ensures
167 self.spec_parse(buf1) matches Some((n1, v1)) ==>
168 self.spec_parse(buf2) matches Some((n2, v2)) ==>
169 v1 == v2 ==> buf1.take(n1) == buf2.take(n2),
170 {
171 self.theorem_parse_serialize_roundtrip(buf1);
172 self.theorem_parse_serialize_roundtrip(buf2);
173 }
174}
175
176impl<C: SPRoundTrip + NonMalleable + SoundParser> PSRoundTrip for C {
177 open spec fn ps_roundtrip_inv(&self) -> bool {
178 self.safe_inv() && self.sound_inv() && self.nonmal_inv() && self.sp_roundtrip_inv()
179 }
180
181 proof fn theorem_parse_serialize_roundtrip(&self, ibuf: Seq<u8>) {
182 let c = self;
183 if let Some((n, v)) = c.spec_parse(ibuf) {
184 c.lemma_parse_sound_value(ibuf);
185 c.theorem_serialize_parse_roundtrip(v);
186
187 let serialized = c.spec_serialize(v);
188 assert((c.spec_parse(serialized)->0).1 == v);
189
190 c.lemma_parse_non_malleable(ibuf, serialized);
192 assert(ibuf.take(n) == serialized);
193 }
194 }
195}
196
197pub trait NonMalleable: SafeParser {
202 open spec fn nonmal_inv(&self) -> bool {
205 true
206 }
207
208 #[verusfmt::skip]
209 proof fn lemma_parse_non_malleable(&self, buf1: Seq<u8>, buf2: Seq<u8>)
210 requires
211 self.safe_inv(),
212 self.nonmal_inv(),
213 ensures
214 self.spec_parse(buf1) matches Some((n1, v1)) ==>
215 self.spec_parse(buf2) matches Some((n2, v2)) ==>
216 v1 == v2 ==> buf1.take(n1) == buf2.take(n2),
217 ;
218}
219
220pub trait NoLookAhead: SafeParser {
227 open spec fn no_lookahead_inv(&self) -> bool {
228 true
229 }
230
231 #[verusfmt::skip]
232 proof fn lemma_no_lookahead(&self, i1: Seq<u8>, i2: Seq<u8>)
233 requires
234 self.safe_inv(),
235 self.no_lookahead_inv(),
236 ensures
237 self.spec_parse(i1) matches Some((n, v)) ==>
238 0 <= n <= i2.len() ==> i2.take(n) == i1.take(n) ==>
239 self.spec_parse(i2) == Some((n, v)),
240 ;
241
242 proof fn corollary_non_extensible(&self, i1: Seq<u8>, i2: Seq<u8>)
243 requires
244 self.safe_inv(),
245 self.no_lookahead_inv(),
246 ensures
247 self.spec_parse(i1) matches Some((n, v)) ==> self.spec_parse(i1 + i2) == Some((n, v)),
248 {
249 self.lemma_no_lookahead(i1, i1 + i2);
250 if let Some((n, v)) = self.spec_parse(i1) {
251 self.lemma_parse_safe(i1);
252 assert(0 <= n <= (i1 + i2).len());
253 assert(i1.take(n) == (i1 + i2).take(n));
254 }
255 }
256}
257
258pub trait Productive: SafeParser {
273 open spec fn productive_inv(&self) -> bool {
274 true
275 }
276
277 broadcast proof fn lemma_productive(&self, s: Seq<u8>)
278 requires
279 self.safe_inv(),
280 self.productive_inv(),
281 ensures
282 #[trigger] self.spec_parse(s) matches Some((n, _)) ==> n > 0,
283 ;
284}
285
286pub trait EquivSerializersGeneral: SpecSerializer + SpecSerializerDps<SValue = Self::SVal> {
290 open spec fn equiv_general_inv(&self) -> bool {
291 true
292 }
293
294 proof fn lemma_serialize_equiv(&self, v: Self::SVal, obuf: Seq<u8>)
296 requires
297 self.equiv_general_inv(),
298 ensures
299 self.spec_serialize_dps(v, obuf) == self.spec_serialize(v) + obuf,
300 ;
301}
302
303pub trait EquivSerializers: SpecSerializer + SpecSerializerDps<SValue = Self::SVal> {
307 open spec fn equiv_inv(&self) -> bool {
308 true
309 }
310
311 proof fn lemma_serialize_equiv_on_empty(&self, v: Self::SVal)
313 requires
314 self.equiv_inv(),
315 ensures
316 self.spec_serialize_dps(v, seq![]) == self.spec_serialize(v),
317 ;
318}
319
320pub trait StrictCombinator:
322 SafeParser +
323 Productive +
324 SoundParser +
325 NonMalleable +
326 GoodSerializer +
327 NonTailFmt +
328 SPRoundTripDps +
329 EquivSerializersGeneral {
330
331}
332
333impl<Body> StrictCombinator for Body where
334 Body:
335 SafeParser +
336 Productive +
337 SoundParser +
338 NonMalleable +
339 GoodSerializer +
340 NonTailFmt +
341 SPRoundTripDps +
342 EquivSerializersGeneral,
343 {
344
345}
346
347pub trait Leaf:
357 SafeParser +
358 GoodSerializer +
359 NonTailFmt +
360 SPRoundTripDps +
361 EquivSerializersGeneral {
362 proof fn leaf_inv(&self)
363 ensures
364 self.unambiguous(),
365 self.safe_inv(),
366 self.serialize_inv(),
367 self.serialize_dps_inv(),
368 self.equiv_general_inv(),
369 ;
370}
371
372pub trait LeafNonMalleable:
374 Leaf +
375 SoundParser +
376 NonMalleable {
377 proof fn nonmal_leaf_inv(&self)
378 ensures
379 self.unambiguous(),
380 self.safe_inv(),
381 self.sound_inv(),
382 self.nonmal_inv(),
383 self.serialize_inv(),
384 self.serialize_dps_inv(),
385 self.equiv_general_inv(),
386 ;
387}
388
389impl<Fmt: LeafNonMalleable> Leaf for Fmt {
390 proof fn leaf_inv(&self) {
391 self.nonmal_leaf_inv();
392 }
393}
394
395}