verdict_parser/asn1/
ia5_string.rs1use super::*;
2use std::fmt::{self, Debug, Formatter};
4use vstd::prelude::*;
5
6verus! {
7
8#[derive(Debug, View)]
12pub struct IA5String;
13
14asn1_tagged!(IA5String, tag_of!(IA5_STRING));
15
16pub type SpecIA5StringValue = Seq<char>;
17pub type IA5StringValue<'a> = &'a str;
18pub type IA5StringValueOwned = String;
19
20impl SpecCombinator for IA5String {
21 type SpecResult = SpecIA5StringValue;
22
23 closed spec fn spec_parse(&self, s: Seq<u8>) -> Result<(usize, Self::SpecResult), ()> {
24 Refined {
25 inner: UTF8String,
26 predicate: IA5StringPred,
27 }.spec_parse(s)
28 }
29
30 proof fn spec_parse_wf(&self, s: Seq<u8>) {
31 Refined {
32 inner: UTF8String,
33 predicate: IA5StringPred,
34 }.spec_parse_wf(s)
35 }
36
37 closed spec fn spec_serialize(&self, v: Self::SpecResult) -> Result<Seq<u8>, ()> {
38 Refined {
39 inner: UTF8String,
40 predicate: IA5StringPred,
41 }.spec_serialize(v)
42 }
43}
44
45impl SecureSpecCombinator for IA5String {
46 open spec fn is_prefix_secure() -> bool {
47 true
48 }
49
50 proof fn theorem_serialize_parse_roundtrip(&self, v: Self::SpecResult) {
51 Refined {
52 inner: UTF8String,
53 predicate: IA5StringPred,
54 }.theorem_serialize_parse_roundtrip(v);
55 }
56
57 proof fn theorem_parse_serialize_roundtrip(&self, buf: Seq<u8>) {
58 Refined {
59 inner: UTF8String,
60 predicate: IA5StringPred,
61 }.theorem_parse_serialize_roundtrip(buf);
62 }
63
64 proof fn lemma_prefix_secure(&self, s1: Seq<u8>, s2: Seq<u8>) {
65 Refined {
66 inner: UTF8String,
67 predicate: IA5StringPred,
68 }.lemma_prefix_secure(s1, s2);
69 }
70}
71
72impl Combinator for IA5String {
73 type Result<'a> = IA5StringValue<'a>;
74 type Owned = IA5StringValueOwned;
75
76 closed spec fn spec_length(&self) -> Option<usize> {
77 None
78 }
79
80 fn length(&self) -> Option<usize> {
81 None
82 }
83
84 #[inline(always)]
85 fn parse<'a>(&self, s: &'a [u8]) -> (res: Result<(usize, Self::Result<'a>), ParseError>) {
86 Refined {
87 inner: UTF8String,
88 predicate: IA5StringPred,
89 }.parse(s)
90 }
91
92 #[inline(always)]
93 fn serialize(&self, v: Self::Result<'_>, data: &mut Vec<u8>, pos: usize) -> (res: Result<usize, SerializeError>) {
94 Refined {
95 inner: UTF8String,
96 predicate: IA5StringPred,
97 }.serialize(v, data, pos)
98 }
99}
100
101#[derive(View)]
103pub struct IA5StringPred;
104
105impl IA5StringPred {
106 closed spec fn wf_char(c: char) -> bool {
107 c <= '\x7f'
108 }
109
110 #[inline(always)]
111 fn exec_wf_char(c: char) -> (res: bool)
112 ensures res == Self::wf_char(c)
113 {
114 c <= '\x7f'
115 }
116}
117
118impl SpecPred for IA5StringPred {
119 type Input = Seq<char>;
120
121 closed spec fn spec_apply(&self, s: &Self::Input) -> bool {
122 forall |i| 0 <= i < s.len() ==> #[trigger] Self::wf_char(s[i])
123 }
124}
125
126impl Pred for IA5StringPred {
127 type Input<'a> = &'a str;
128 type InputOwned = String;
129
130 fn apply(&self, s: &Self::Input<'_>) -> (res: bool)
131 {
132 let len = s.unicode_len();
133 for i in 0..len
134 invariant
135 len == s@.len(),
136 forall |j| 0 <= j < i ==> #[trigger] Self::wf_char(s@[j]),
137 {
138 if !Self::exec_wf_char(s.get_char(i)) {
139 return false;
140 }
141 }
142 return true;
143 }
144}
145
146}
147
148#[cfg(test)]
149mod tests {
150 use super::*;
151 use der::Encode;
152
153 fn serialize_ia5_string(v: &str) -> Result<Vec<u8>, SerializeError> {
154 let mut data = vec![0; v.len() + 10];
155 data[0] = 0x16; let len = IA5String.serialize(v, &mut data, 1)?;
157 data.truncate(len + 1);
158 Ok(data)
159 }
160
161 #[test]
162 fn diff_with_der() {
163 let diff = |s: &str| {
164 let res1 = serialize_ia5_string(s).map_err(|_| ());
165 let res2 = der::asn1::Ia5StringRef::new(s)
166 .unwrap()
167 .to_der()
168 .map_err(|_| ());
169 assert_eq!(res1, res2);
170 };
171
172 diff("");
173 diff("\x7f");
174 diff("asdsad");
175 diff("aaaaaa");
176 diff("aaaaa".repeat(100).as_str());
177 }
178}