vest_lib/regular/tag.rs
1use alloc::vec::Vec;
2
3use super::{
4 bytes,
5 leb128::{UInt, UnsignedLEB128},
6 modifier::{Pred, Refined, SpecPred},
7 uints::*,
8};
9use crate::properties::*;
10use vstd::prelude::*;
11
12verus! {
13
14/// tag predicate that matches the input with a given value
15pub struct TagPred<T>(pub T);
16
17impl<T: View> View for TagPred<T> {
18 type V = TagPred<T::V>;
19
20 open spec fn view(&self) -> Self::V {
21 TagPred(self.0@)
22 }
23}
24
25impl<T> SpecPred<T> for TagPred<T> {
26 open spec fn spec_apply(&self, i: &T) -> bool {
27 *i == self.0
28 }
29}
30
31/// Generic tag combinator that matches the input with a given value and discards it
32/// e.g. `Tag(U8, 0)` matches the byte `0`; `Tag(Fixed::<3>, &[1, 2, 3])` matches the
33/// bytes `[1, 2, 3]`
34pub struct Tag<Inner, T>(pub Refined<Inner, TagPred<T>>);
35
36impl<Inner, T> Tag<Inner, T> {
37 /// Creates a new `Tag` combinator.
38 pub fn new(inner: Inner, tag: T) -> (o: Self)
39 ensures
40 o == Tag(Refined { inner, predicate: TagPred(tag) }),
41 {
42 Tag(Refined { inner, predicate: TagPred(tag) })
43 }
44
45 /// Creates a new `Tag` combinator.
46 pub open spec fn spec_new(inner: Inner, tag: T) -> (o: Self) {
47 Tag(Refined { inner, predicate: TagPred(tag) })
48 }
49}
50
51impl<Inner: View, T: View> View for Tag<Inner, T> {
52 type V = Tag<Inner::V, T::V>;
53
54 open spec fn view(&self) -> Self::V {
55 Tag(self.0@)
56 }
57}
58
59impl<Inner: SpecCombinator<Type = T>, T> SpecCombinator for Tag<Inner, T> {
60 type Type = ();
61
62 open spec fn requires(&self) -> bool {
63 self.0.requires()
64 }
65
66 open spec fn wf(&self, v: Self::Type) -> bool {
67 self.0.wf(self.0.predicate.0)
68 }
69
70 open spec fn spec_parse(&self, s: Seq<u8>) -> Option<(int, Self::Type)> {
71 if let Some((n, _)) = self.0.spec_parse(s) {
72 Some((n, ()))
73 } else {
74 None
75 }
76 }
77
78 open spec fn spec_serialize(&self, v: Self::Type) -> Seq<u8> {
79 self.0.spec_serialize(self.0.predicate.0)
80 }
81}
82
83impl<Inner: SecureSpecCombinator<Type = T>, T> SecureSpecCombinator for Tag<Inner, T> {
84 open spec fn is_prefix_secure() -> bool {
85 Inner::is_prefix_secure()
86 }
87
88 open spec fn is_productive(&self) -> bool {
89 self.0.is_productive()
90 }
91
92 proof fn theorem_serialize_parse_roundtrip(&self, v: Self::Type) {
93 self.0.theorem_serialize_parse_roundtrip(self.0.predicate.0);
94 }
95
96 proof fn theorem_parse_serialize_roundtrip(&self, buf: Seq<u8>) {
97 self.0.theorem_parse_serialize_roundtrip(buf);
98 }
99
100 proof fn lemma_prefix_secure(&self, s1: Seq<u8>, s2: Seq<u8>) {
101 self.0.lemma_prefix_secure(s1, s2);
102 assert(Self::is_prefix_secure() ==> self.spec_parse(s1) is Some ==> self.spec_parse(
103 s1.add(s2),
104 ) == self.spec_parse(s1));
105 }
106
107 proof fn lemma_parse_length(&self, s: Seq<u8>) {
108 self.0.lemma_parse_length(s);
109 }
110
111 proof fn lemma_parse_productive(&self, s: Seq<u8>) {
112 self.0.lemma_parse_productive(s);
113 }
114}
115
116impl Pred<u8> for TagPred<u8> {
117 fn apply(&self, i: &u8) -> bool {
118 *i == self.0
119 }
120}
121
122impl Pred<u16> for TagPred<u16> {
123 fn apply(&self, i: &u16) -> bool {
124 *i == self.0
125 }
126}
127
128impl Pred<u32> for TagPred<u32> {
129 fn apply(&self, i: &u32) -> bool {
130 *i == self.0
131 }
132}
133
134impl Pred<u64> for TagPred<u64> {
135 fn apply(&self, i: &u64) -> bool {
136 *i == self.0
137 }
138}
139
140impl<'a, const N: usize> Pred<&'a [u8]> for TagPred<[u8; N]> {
141 fn apply(&self, i: &&'a [u8]) -> bool {
142 self.0.as_slice().compare(i)
143 }
144}
145
146macro_rules! impl_combinator_for_uint_tag {
147 ($combinator:ty, $int_type:ty) => {
148 ::vstd::prelude::verus! {
149 impl<'x, I, O> Combinator<'x, I, O> for Tag<$combinator, $int_type> where
150 I: VestPublicInput,
151 O: VestPublicOutput<I>,
152 {
153 type Type = ();
154
155 type SType = ();
156
157 fn length(&self, v: Self::SType) -> usize {
158 <_ as Combinator<I, O>>::length(&self.0, &self.0.predicate.0)
159 }
160
161 open spec fn ex_requires(&self) -> bool {
162 <_ as Combinator<'x, I, O>>::ex_requires(&self.0)
163 }
164
165 fn parse(&self, s: I) -> Result<(usize, Self::Type), ParseError> {
166 let (n, _) = <_ as Combinator<'x, I, O>>::parse(&self.0, s)?;
167 Ok((n, ()))
168 }
169
170 fn serialize(&self, v: Self::SType, data: &mut O, pos: usize) -> Result<usize, SerializeError> {
171 self.0.serialize(&self.0.predicate.0, data, pos)
172 }
173 }
174 } // verus!
175 };
176}
177
178impl_combinator_for_uint_tag!(U8, u8);
179
180impl_combinator_for_uint_tag!(U16Le, u16);
181
182// impl_combinator_for_uint_tag!(U24Le, u24);
183impl_combinator_for_uint_tag!(U32Le, u32);
184
185impl_combinator_for_uint_tag!(U64Le, u64);
186
187impl_combinator_for_uint_tag!(U16Be, u16);
188
189// impl_combinator_for_uint_tag!(U24Be, u24);
190impl_combinator_for_uint_tag!(U32Be, u32);
191
192impl_combinator_for_uint_tag!(U64Be, u64);
193
194impl_combinator_for_uint_tag!(UnsignedLEB128, UInt);
195
196impl<'x, const N: usize> Combinator<'x, &'x [u8], Vec<u8>> for Tag<
197 bytes::Fixed::<N>,
198 [u8; N],
199> where {
200 type Type = ();
201
202 type SType = ();
203
204 fn length(&self, _v: Self::SType) -> usize {
205 N
206 }
207
208 open spec fn ex_requires(&self) -> bool {
209 <_ as Combinator<'x, &'x [u8], Vec<u8>>>::ex_requires(&self.0)
210 }
211
212 fn parse(&self, s: &'x [u8]) -> Result<(usize, Self::Type), ParseError> {
213 let (n, _) = <_ as Combinator<'x, &'x [u8], Vec<u8>>>::parse(&self.0, s)?;
214 Ok((n, ()))
215 }
216
217 fn serialize(&self, v: Self::SType, data: &mut Vec<u8>, pos: usize) -> Result<
218 usize,
219 SerializeError,
220 > {
221 self.0.serialize(&self.0.predicate.0.as_slice(), data, pos)
222 }
223}
224
225// old code
226// /// generic tag combinator that matches the input with a given value and discards it
227// /// e.g. `Tag(Int::<u8>, 0)` matches the byte `0`; `Tag(Bytes::<3>, &[1, 2, 3])` matches the bytes `[1, 2, 3]`
228// pub struct Tag<Inner, T>(pub Inner, pub T);
229//
230// impl<Inner, T> View for Tag<Inner, T> where Inner: View, T: View {
231// type V = Tag<Inner::V, T::V>;
232//
233// open spec fn view(&self) -> Self::V {
234// Tag(self.0@, self.1@)
235// }
236// }
237//
238// impl<Inner, T> SpecCombinator for Tag<Inner, T> where Inner: SpecCombinator<SpecResult = T> {
239// type SpecResult = ();
240//
241// open spec fn spec_parse(&self, s: Seq<u8>) -> Result<(usize, Self::SpecResult), ()> {
242// match self.0.spec_parse(s) {
243// Ok((n, v)) if v == self.1 => Ok((n, ())),
244// _ => Err(()),
245// }
246// }
247//
248// open spec fn spec_serialize(&self, v: Self::SpecResult) -> Result<Seq<u8>, ()> {
249// self.0.spec_serialize(self.1)
250// }
251//
252// proof fn spec_parse_wf(&self, s: Seq<u8>) {
253// self.0.spec_parse_wf(s);
254// }
255// }
256//
257// impl<Inner, T> SecureSpecCombinator for Tag<Inner, T> where
258// Inner: SecureSpecCombinator<SpecResult = T>,
259// {
260// open spec fn spec_is_prefix_secure() -> bool {
261// Inner::spec_is_prefix_secure()
262// }
263//
264// proof fn theorem_serialize_parse_roundtrip(&self, v: ()) {
265// self.0.theorem_serialize_parse_roundtrip(self.1);
266// }
267//
268// proof fn theorem_parse_serialize_roundtrip(&self, buf: Seq<u8>) {
269// self.0.theorem_parse_serialize_roundtrip(buf);
270// }
271//
272// proof fn lemma_prefix_secure(&self, s1: Seq<u8>, s2: Seq<u8>) {
273// self.0.lemma_prefix_secure(s1, s2);
274// }
275// }
276//
277// // the line `for <'a, 'b>Inner::Result<'a>: Compare<Inner::Result<'b>> + From<T>`
278// // says that `Inner::Result<'a>` must impl `From<T> for all lifetimes `'a`
279// // at the type level, this means even a static `Inner::Result<'static>` can be converted from
280// // `T`, which in turn mandates that `T: 'static` (if both `T` and `Inner::Result<'a>` are
281// // types without actual lifetimes, e.g. `u8`, then it's fine)
282// //
283// // it would be nice if Rust supports "existential" lifetimes like:
284// // `exist <'a>Inner::Result<'a>: From<T>`
285// impl<Inner, T> Combinator for Tag<Inner, T> where
286// Inner: Combinator,
287// Inner::V: SecureSpecCombinator<SpecResult = T::V>,
288// T: View<V = <Inner::Owned as View>::V> + Copy,
289// for <'a, 'b>Inner::Result<'a>: Compare<Inner::Result<'b>> + From<T>,
290// {
291// type Result<'a> = ();
292//
293// type Owned = ();
294//
295// open spec fn spec_length(&self) -> Option<usize> {
296// self.0.spec_length()
297// }
298//
299// fn length(&self) -> Option<usize> {
300// self.0.length()
301// }
302//
303// fn exec_is_prefix_secure() -> bool {
304// Inner::exec_is_prefix_secure()
305// }
306//
307// open spec fn parse_requires(&self) -> bool {
308// self.0.parse_requires()
309// }
310//
311// fn parse(&self, s: &[u8]) -> (res: Result<(usize, ()), ()>) {
312// match self.0.parse(s) {
313// Ok((n, v)) if v.compare(&self.1.ex_into()) => Ok((n, ())),
314// _ => Err(()),
315// }
316// }
317//
318// open spec fn serialize_requires(&self) -> bool {
319// self.0.serialize_requires()
320// }
321//
322// fn serialize(&self, v: (), data: &mut Vec<u8>, pos: usize) -> (res: Result<usize, ()>) {
323// self.0.serialize(self.1.ex_into(), data, pos)
324// }
325// }
326//
327// pub type U8Tag = Tag<Int<u8>, u8>;
328//
329// pub type U16Tag = Tag<Int<u16>, u16>;
330//
331// pub type U32Tag = Tag<Int<u32>, u32>;
332//
333// pub type U64Tag = Tag<Int<u64>, u64>;
334//
335// pub type SpecStaticBytesTag<const N: usize> = Tag<BytesN<N>, Seq<u8>>;
336//
337// pub type StaticBytesTag<const N: usize> = Tag<BytesN<N>, &'static [u8; N]>;
338//
339// /// combinator for matching a dynamic byte slice
340// ///
341// /// **Note**: due to the current limitations of Rust borrow checker
342// /// the generic `Tag` combinator cannot be used with dynamic byte slices (`Tag<Bytes, &'a [u8]>`)
343// pub struct DynamicBytesTag<'a>(pub Bytes, pub &'a [u8]);
344//
345// pub struct SpecDynamicBytesTag(pub Bytes, pub Seq<u8>);
346//
347// impl<'a> View for DynamicBytesTag<'a> {
348// type V = SpecDynamicBytesTag;
349//
350// open spec fn view(&self) -> Self::V {
351// SpecDynamicBytesTag(self.0@, self.1@)
352// }
353// }
354//
355// impl SpecCombinator for SpecDynamicBytesTag {
356// type SpecResult = ();
357//
358// open spec fn spec_parse(&self, s: Seq<u8>) -> Result<(usize, Self::SpecResult), ()> {
359// match self.0.spec_parse(s) {
360// Ok((n, v)) if n == self.1.len() && v == self.1 => Ok((n, ())),
361// _ => Err(()),
362// }
363// }
364//
365// open spec fn spec_serialize(&self, v: Self::SpecResult) -> Result<Seq<u8>, ()> {
366// self.0.spec_serialize(self.1)
367// }
368//
369// proof fn spec_parse_wf(&self, s: Seq<u8>) {
370// }
371// }
372//
373// impl SecureSpecCombinator for SpecDynamicBytesTag {
374// open spec fn spec_is_prefix_secure() -> bool {
375// Bytes::spec_is_prefix_secure()
376// }
377//
378// proof fn theorem_serialize_parse_roundtrip(&self, v: ()) {
379// self.0.theorem_serialize_parse_roundtrip(self.1);
380// }
381//
382// proof fn theorem_parse_serialize_roundtrip(&self, buf: Seq<u8>) {
383// self.0.theorem_parse_serialize_roundtrip(buf);
384// }
385//
386// proof fn lemma_prefix_secure(&self, s1: Seq<u8>, s2: Seq<u8>) {
387// self.0.lemma_prefix_secure(s1, s2);
388// }
389// }
390//
391// impl<'a> Combinator for DynamicBytesTag<'a> {
392// type Result<'b> = ();
393//
394// type Owned = ();
395//
396// open spec fn spec_length(&self) -> Option<usize> {
397// Some(self.0.0)
398// }
399//
400// fn length(&self) -> Option<usize> {
401// Some(self.0.0)
402// }
403//
404// fn exec_is_prefix_secure() -> bool {
405// Bytes::exec_is_prefix_secure()
406// }
407//
408// fn parse(&self, s: &[u8]) -> (res: Result<(usize, Self::Result), ()>) {
409// match self.0.parse(s) {
410// Ok((n, v)) if compare_slice(v, self.1) => Ok((n, ())),
411// _ => Err(()),
412// }
413// }
414//
415// fn serialize(&self, v: Self::Result, data: &mut Vec<u8>, pos: usize) -> (res: Result<
416// usize,
417// (),
418// >) {
419// self.0.serialize(self.1, data, pos)
420// }
421// }
422//
423// #[cfg(test)]
424// mod test {
425// use super::*;
426//
427// const MAGIC: u8 = 0x42;
428//
429// spec const SPEC_BYTES_123: Seq<u8> = seq![1, 2, 3];
430//
431// exec static BYTES_123: [u8; 3]
432// ensures
433// BYTES_123@ == SPEC_BYTES_123,
434// {
435// let a: [u8; 3] = [1, 2, 3];
436// assert(a@ == SPEC_BYTES_123);
437// a
438// }
439//
440// spec fn spec_tag(input: Seq<u8>) -> (U8Tag, SpecStaticBytesTag<3>) {
441// let t1: U8Tag = Tag(U8, MAGIC);
442// let t2: SpecStaticBytesTag<3> = Tag(BytesN::<3>, SPEC_BYTES_123);
443// (t1, t2)
444// }
445//
446// fn tag(input: &[u8]) -> (res: (U8Tag, StaticBytesTag<3>))
447// ensures
448// res@ == spec_tag(input@),
449// {
450// let tem_magic: u8 = 0x42;
451// let t1: U8Tag = Tag(U8, tem_magic); // ok
452// let t1: U8Tag = Tag(U8, MAGIC); // ok
453// let t2: StaticBytesTag<3> = Tag(BytesN::<3>, &BYTES_123);
454// (t1, t2)
455// }
456//
457// fn tag2<'a>(input: &'a [u8]) {
458// // let tmp_bytes_123: [u8; 3] = [1, 2, 3];
459// // let t1 = Tag(BytesN::<3>, &tmp_bytes_123); // err: TMP_BYTES_123 does not live long enough
460// // it's required that `tmp_bytes_123` is borrowed for `'static`
461// // let t1 = Tag(Bytes(3), &TMP_BYTES_123); // same err
462// let t1 = Tag(Bytes(3), &BYTES_123); // ok
463// let _ = t1.parse(input);
464// }
465//
466// fn tag3<'a, 'b>(input: &'a [u8], tmp_bytes_123: &'b [u8; 3]) where 'b: 'a {
467// // let t1 = Tag(BytesN::<3>, tmp_bytes_123); // err: TMP_BYTES_123 does not live long enough
468// // let t1 = Tag(Bytes(3), tmp_bytes_123); // same err
469// let t1 = Tag(Bytes(3), &BYTES_123); // ok
470// let _ = t1.parse(input);
471// }
472//
473// }
474} // verus!