vest_lib/asn1/
ia5string.rs1use super::utf8string::{is_valid_utf8, utf8_from_bytes_unchecked};
3use crate::core::exec::input::{InputBuf, InputSlice};
4use crate::core::exec::output::*;
5use crate::core::exec::{
6 parser::{PResult, Parser},
7 serializer::{ByteLen, PreSerializeError, Prepare, Serializer},
8 ParseError,
9};
10use crate::{
11 combinators::{mapped::spec::FnSpecMapper, Mapped, Refined, Tail},
12 core::{proof::*, spec::*},
13};
14#[cfg(feature = "alloc")]
15use alloc::string::String;
16use vstd::prelude::*;
17use vstd::string::StringSliceAdditionalSpecFns;
18use OutputBuf;
19
20verus! {
21
22pub struct Ia5String<'a> {
23 inner: &'a str,
24}
25
26#[cfg(feature = "alloc")]
29pub struct Ia5StringOwned {
30 inner: String,
31}
32
33#[verifier::ext_equal]
34pub struct Ia5StringSpec {
35 pub inner: Seq<char>,
36}
37
38impl<'a> DeepView for Ia5String<'a> {
39 type V = Ia5StringSpec;
40
41 closed spec fn deep_view(&self) -> Self::V {
42 Ia5StringSpec { inner: self.inner.deep_view() }
43 }
44}
45
46#[cfg(feature = "alloc")]
47impl DeepView for Ia5StringOwned {
48 type V = Ia5StringSpec;
49
50 closed spec fn deep_view(&self) -> Self::V {
51 Ia5StringSpec { inner: self.inner.deep_view() }
52 }
53}
54
55impl<'a> Ia5String<'a> {
56 #[verifier::type_invariant]
57 spec fn wf(&self) -> bool {
58 self.deep_view().wf()
59 }
60
61 pub fn new(inner: &'a str) -> (res: Self)
62 requires
63 is_valid_ia5_string_spec(vstd::utf8::encode_utf8(inner.deep_view())),
64 ensures
65 res.deep_view() == (Ia5StringSpec { inner: inner.deep_view() }),
66 {
67 Ia5String { inner }
68 }
69
70 pub fn inner(&self) -> (res: &'a str)
71 ensures
72 res.deep_view() == self.deep_view().inner,
73 {
74 self.inner
75 }
76}
77
78#[cfg(feature = "alloc")]
79impl Ia5StringOwned {
80 #[verifier::type_invariant]
81 spec fn wf(&self) -> bool {
82 self.deep_view().wf()
83 }
84
85 pub fn new(inner: String) -> (res: Self)
86 requires
87 is_valid_ia5_string_spec(vstd::utf8::encode_utf8(inner.deep_view())),
88 ensures
89 res.deep_view() == (Ia5StringSpec { inner: inner.deep_view() }),
90 {
91 Self { inner }
92 }
93
94 pub fn inner(&self) -> (res: &str)
95 ensures
96 res.deep_view() == self.deep_view().inner,
97 {
98 self.inner.as_str()
99 }
100}
101
102impl Ia5StringSpec {
103 pub open spec fn wf(&self) -> bool {
104 is_valid_ia5_string_spec(vstd::utf8::encode_utf8(self.inner))
105 }
106}
107
108pub open spec fn is_valid_ia5_string_spec(bytes: Seq<u8>) -> bool {
109 forall|i: int| 0 <= i < bytes.len() ==> #[trigger] bytes[i] <= 127
110}
111
112pub fn is_valid_ia5_string(bytes: &[u8]) -> (res: bool)
113 ensures
114 res == is_valid_ia5_string_spec(bytes.deep_view()),
115{
116 for b in iter: bytes.iter()
117 invariant
118 forall|k: int| 0 <= k < iter.index() ==> #[trigger] bytes.deep_view()[k] <= 127,
119 {
120 if *b > 127 {
121 assert(bytes.deep_view()[iter.index()] > 127);
122 return false;
123 }
124 }
125 true
126}
127
128type Ia5StringFmt = Mapped<
129 Refined<Tail, PredFnSpec<Seq<u8>>>,
130 FnSpecMapper<Seq<u8>, Ia5StringSpec>,
131>;
132
133pub open spec fn ia5string_fmt() -> Ia5StringFmt {
134 Mapped {
135 inner: Refined(
136 Tail,
137 |bytes: Seq<u8>| is_valid_ia5_string_spec(bytes) && vstd::utf8::valid_utf8(bytes),
138 ),
139 mapper: (
140 |bytes: Seq<u8>| Ia5StringSpec { inner: vstd::utf8::decode_utf8(bytes) },
141 |s: Ia5StringSpec| vstd::utf8::encode_utf8(s.inner),
142 ),
143 }
144}
145
146mod derived_specs {
147 use super::*;
148
149 impl SpecParser for super::super::Ia5StringFmt {
150 type PVal = Ia5StringSpec;
151
152 open spec fn spec_parse(&self, ibuf: Seq<u8>) -> Option<(int, Self::PVal)> {
153 ia5string_fmt().spec_parse(ibuf)
154 }
155 }
156
157 impl Consistency for super::super::Ia5StringFmt {
158 type Val = Ia5StringSpec;
159
160 open spec fn consistent(&self, v: Self::Val) -> bool {
161 ia5string_fmt().consistent(v)
162 }
163 }
164
165 impl SpecSerializerDps for super::super::Ia5StringFmt {
166 type SValue = Ia5StringSpec;
167
168 open spec fn spec_serialize_dps(&self, v: Self::SValue, obuf: Seq<u8>) -> Seq<u8> {
169 ia5string_fmt().spec_serialize_dps(v, obuf)
170 }
171 }
172
173 impl SpecSerializer for super::super::Ia5StringFmt {
174 type SVal = Ia5StringSpec;
175
176 open spec fn spec_serialize(&self, v: Self::SVal) -> Seq<u8> {
177 ia5string_fmt().spec_serialize(v)
178 }
179 }
180
181 impl SpecByteLen for super::super::Ia5StringFmt {
182 type T = Ia5StringSpec;
183
184 open spec fn byte_len(&self, v: Self::T) -> nat {
185 ia5string_fmt().byte_len(v)
186 }
187 }
188
189}
190
191mod derived_proofs {
192 use super::*;
193
194 impl SafeParser for super::super::Ia5StringFmt {
195 proof fn lemma_parse_safe(&self, ibuf: Seq<u8>) {
196 ia5string_fmt().lemma_parse_safe(ibuf);
197 }
198 }
199
200 impl Productive for super::super::Ia5StringFmt {
201 open spec fn productive_inv(&self) -> bool {
202 false
203 }
204
205 proof fn lemma_productive(&self, s: Seq<u8>) {
206 }
207 }
208
209 impl SoundParser for super::super::Ia5StringFmt {
210 proof fn lemma_parse_sound_consumption(&self, ibuf: Seq<u8>) {
211 broadcast use vstd::utf8::decode_utf8_encode_utf8;
212
213 ia5string_fmt().lemma_parse_sound_consumption(ibuf);
214 }
215
216 proof fn lemma_parse_sound_value(&self, ibuf: Seq<u8>) {
217 broadcast use vstd::utf8::decode_utf8_encode_utf8;
218
219 ia5string_fmt().lemma_parse_sound_value(ibuf);
220 }
221 }
222
223 impl GoodSerializer for super::super::Ia5StringFmt {
224 proof fn lemma_serialize_len(&self, v: Self::SVal) {
225 ia5string_fmt().lemma_serialize_len(v);
226 }
227 }
228
229 impl SPRoundTripDps for super::super::Ia5StringFmt {
230 proof fn theorem_serialize_dps_parse_roundtrip(&self, v: Self::T, obuf: Seq<u8>) {
231 broadcast use vstd::utf8::encode_utf8_decode_utf8;
232
233 ia5string_fmt().theorem_serialize_dps_parse_roundtrip(v, obuf);
234 }
235 }
236
237 impl NonMalleable for super::super::Ia5StringFmt {
238 proof fn lemma_parse_non_malleable(&self, buf1: Seq<u8>, buf2: Seq<u8>) {
239 broadcast use vstd::utf8::decode_utf8_encode_utf8;
240
241 ia5string_fmt().lemma_parse_non_malleable(buf1, buf2);
242 }
243 }
244
245 impl EquivSerializers for super::super::Ia5StringFmt {
246 proof fn lemma_serialize_equiv_on_empty(&self, v: Self::SVal) {
247 ia5string_fmt().lemma_serialize_equiv_on_empty(v);
248 }
249 }
250
251}
252
253impl<'i> Parser<&'i [u8]> for super::Ia5StringFmt {
254 type PT = Ia5String<'i>;
255
256 fn parse(&self, ibuf: &&'i [u8]) -> PResult<Self::PT> {
257 let (n, bytes) = Tail.parse(ibuf)?;
258 if !is_valid_ia5_string(bytes) {
259 Err(ParseError::custom("Invalid Ia5String"))
260 } else if !is_valid_utf8(bytes) {
261 Err(ParseError::custom("Invalid UTF-8"))
262 } else {
263 let inner = utf8_from_bytes_unchecked(bytes);
264 Ok((n, Ia5String::new(inner)))
265 }
266 }
267}
268
269impl<Output: OutputBuf, 'i> Serializer<Output, Ia5String<'i>> for super::Ia5StringFmt {
270 fn serialize_into(&self, v: &Ia5String<'i>, obuf: &mut Output) {
271 proof {
272 use_type_invariant(v);
273 }
274 let bytes = v.inner.as_bytes();
275 Tail.serialize_into(&bytes, obuf);
276 }
277}
278
279impl<'i> Prepare<Ia5String<'i>> for super::Ia5StringFmt {
280 fn prepare(&self, v: &Ia5String<'i>) -> Result<usize, PreSerializeError> {
281 broadcast use vstd::utf8::encode_utf8_valid_utf8;
282
283 proof {
284 use_type_invariant(v);
285 }
286 let bytes = v.inner.as_bytes();
287 Tail.prepare(&bytes)
288 }
289}
290
291impl<'i> ByteLen<Ia5String<'i>> for super::Ia5StringFmt {
292 fn length(&self, v: &Ia5String<'i>) -> usize {
293 proof {
294 use_type_invariant(v);
295 }
296 let bytes = v.inner.as_bytes();
297 Tail.length(&bytes)
298 }
299}
300
301#[cfg(feature = "alloc")]
302impl<Output: OutputBuf> Serializer<Output, Ia5StringOwned> for super::Ia5StringFmt {
303 fn serialize_into(&self, v: &Ia5StringOwned, obuf: &mut Output) {
304 proof {
305 use_type_invariant(v);
306 }
307 let bytes = v.inner.as_str().as_bytes();
308 Tail.serialize_into(&bytes, obuf);
309 }
310}
311
312#[cfg(feature = "alloc")]
313impl Prepare<Ia5StringOwned> for super::Ia5StringFmt {
314 fn prepare(&self, v: &Ia5StringOwned) -> Result<usize, PreSerializeError> {
315 broadcast use vstd::utf8::encode_utf8_valid_utf8;
316
317 proof {
318 use_type_invariant(v);
319 }
320 let bytes = v.inner.as_str().as_bytes();
321 Tail.prepare(&bytes)
322 }
323}
324
325#[cfg(feature = "alloc")]
326impl ByteLen<Ia5StringOwned> for super::Ia5StringFmt {
327 fn length(&self, v: &Ia5StringOwned) -> usize {
328 proof {
329 use_type_invariant(v);
330 }
331 let bytes = v.inner.as_str().as_bytes();
332 Tail.length(&bytes)
333 }
334}
335
336}