Skip to main content

vest_lib/asn1/
real.rs

1//! ASN.1 BER/DER REAL contents.
2//!
3//! REAL is represented by its exact contents octets rather than by a machine
4//! floating-point number. This covers arbitrary-size binary mantissas and
5//! exponents, ISO 6093 decimal forms, infinities, NaN, and minus zero without
6//! rounding or special-value equality problems. DER restricts this representation
7//! to the canonical subset required by X.690 §11.3.
8use crate::combinators::{Refined, Tail};
9use crate::core::exec::input::InputSlice;
10use crate::core::exec::output::OutputBuf;
11use crate::core::exec::{
12    parser::{PResult, Parser},
13    serializer::{ByteLen, PreSerializeError, Prepare, Serializer},
14    ParseError,
15};
16use crate::core::{proof::*, spec::*};
17use vstd::prelude::*;
18
19use super::RealFmt;
20
21verus! {
22
23pub type RealSpec = Seq<u8>;
24
25pub type RealInnerFmt = Refined<Tail, PredFnSpec<Seq<u8>>>;
26
27pub const REAL_PLUS_INFINITY: u8 = 0x40;
28
29pub const REAL_MINUS_INFINITY: u8 = 0x41;
30
31pub const REAL_NOT_A_NUMBER: u8 = 0x42;
32
33pub const REAL_MINUS_ZERO: u8 = 0x43;
34
35pub const REAL_DECIMAL_NR3: u8 = 0x03;
36
37pub const ASCII_SPACE: u8 = 0x20;
38
39pub const ASCII_ZERO: u8 = 0x30;
40
41pub const ASCII_ONE: u8 = 0x31;
42
43pub const ASCII_NINE: u8 = 0x39;
44
45pub const ASCII_MINUS: u8 = 0x2d;
46
47pub const ASCII_PLUS: u8 = 0x2b;
48
49pub const ASCII_FULL_STOP: u8 = 0x2e;
50
51pub const ASCII_COMMA: u8 = 0x2c;
52
53pub const ASCII_E: u8 = 0x45;
54
55pub const ASCII_LOWER_E: u8 = 0x65;
56
57pub open spec fn ascii_digit(b: u8) -> bool {
58    ASCII_ZERO <= b <= ASCII_NINE
59}
60
61pub open spec fn ascii_nonzero_digit(b: u8) -> bool {
62    ASCII_ONE <= b <= ASCII_NINE
63}
64
65pub open spec fn ascii_digits(bytes: Seq<u8>, start: int, end: int) -> bool {
66    forall|i: int| #![auto] start <= i < end ==> ascii_digit(bytes[i])
67}
68
69pub open spec fn ascii_digits_have_nonzero(bytes: Seq<u8>, start: int, end: int) -> bool {
70    exists|i: int| #![auto] start <= i < end && ascii_nonzero_digit(bytes[i])
71}
72
73pub open spec fn skip_ascii_spaces(bytes: Seq<u8>, start: nat) -> nat
74    decreases bytes.len() - start,
75{
76    if start < bytes.len() && bytes[start as int] == ASCII_SPACE {
77        skip_ascii_spaces(bytes, start + 1)
78    } else {
79        start
80    }
81}
82
83pub open spec fn scan_ascii_digits(bytes: Seq<u8>, start: nat) -> nat
84    decreases bytes.len() - start,
85{
86    if start < bytes.len() && ascii_digit(bytes[start as int]) {
87        scan_ascii_digits(bytes, start + 1)
88    } else {
89        start
90    }
91}
92
93pub open spec fn decimal_mark(b: u8) -> bool {
94    b == ASCII_FULL_STOP || b == ASCII_COMMA
95}
96
97pub open spec fn exponent_mark(b: u8) -> bool {
98    b == ASCII_E || b == ASCII_LOWER_E
99}
100
101pub open spec fn after_optional_sign(bytes: Seq<u8>, start: nat) -> nat {
102    if start < bytes.len() && (bytes[start as int] == ASCII_PLUS || bytes[start as int]
103        == ASCII_MINUS) {
104        start + 1
105    } else {
106        start
107    }
108}
109
110pub open spec fn ber_real_decimal_nr1_wf(bytes: Seq<u8>) -> bool {
111    let start = after_optional_sign(bytes, skip_ascii_spaces(bytes, 1));
112    let end = scan_ascii_digits(bytes, start);
113    &&& start < end
114    &&& end == bytes.len()
115    &&& ascii_digits_have_nonzero(bytes, start as int, end as int)
116}
117
118pub open spec fn ber_real_decimal_significand(bytes: Seq<u8>) -> Option<(nat, nat, nat, nat)> {
119    let before = after_optional_sign(bytes, skip_ascii_spaces(bytes, 1));
120    let mark = scan_ascii_digits(bytes, before);
121    if mark < bytes.len() && decimal_mark(bytes[mark as int]) {
122        let after = mark + 1;
123        let end = scan_ascii_digits(bytes, after);
124        if before < mark || after < end {
125            Some((before, mark, after, end))
126        } else {
127            None
128        }
129    } else {
130        None
131    }
132}
133
134pub open spec fn ber_real_decimal_mantissa_nonzero(
135    bytes: Seq<u8>,
136    before: nat,
137    mark: nat,
138    after: nat,
139    end: nat,
140) -> bool {
141    ||| ascii_digits_have_nonzero(bytes, before as int, mark as int)
142    ||| ascii_digits_have_nonzero(bytes, after as int, end as int)
143}
144
145pub open spec fn ber_real_decimal_nr2_wf(bytes: Seq<u8>) -> bool {
146    match ber_real_decimal_significand(bytes) {
147        Some((before, mark, after, end)) => {
148            &&& end == bytes.len()
149            &&& ber_real_decimal_mantissa_nonzero(bytes, before, mark, after, end)
150        },
151        None => false,
152    }
153}
154
155pub open spec fn ber_real_decimal_nr3_wf(bytes: Seq<u8>) -> bool {
156    match ber_real_decimal_significand(bytes) {
157        Some((before, mark, after, end)) => {
158            if end < bytes.len() && exponent_mark(bytes[end as int]) {
159                let exponent_sign = end + 1;
160                let exponent = exponent_sign + 1;
161                let exponent_end = scan_ascii_digits(bytes, exponent);
162                &&& exponent_sign < bytes.len()
163                &&& (bytes[exponent_sign as int] == ASCII_PLUS || bytes[exponent_sign as int]
164                    == ASCII_MINUS)
165                &&& exponent < exponent_end
166                &&& exponent_end == bytes.len()
167                &&& ber_real_decimal_mantissa_nonzero(bytes, before, mark, after, end)
168            } else {
169                false
170            }
171        },
172        None => false,
173    }
174}
175
176/// BER decimal REAL contents using an ISO 6093 NR1, NR2, or NR3 field.
177///
178/// X.690 §8.5.8 permits all three forms. Leading spaces and either case of the
179/// exponent mark follow ISO 6093; NR2/NR3 require an explicit decimal mark and
180/// NR3 requires a signed exponent. A decimal spelling of zero is rejected
181/// because X.690 §8.5.2 and §8.5.3 give zero dedicated encodings.
182pub open spec fn ber_real_decimal_wf(bytes: Seq<u8>) -> bool {
183    &&& bytes.len() > 1
184    &&& match bytes[0] {
185        0x01u8 => ber_real_decimal_nr1_wf(bytes),
186        0x02u8 => ber_real_decimal_nr2_wf(bytes),
187        0x03u8 => ber_real_decimal_nr3_wf(bytes),
188        _ => false,
189    }
190}
191
192pub open spec fn decimal_mantissa_start(bytes: Seq<u8>) -> int {
193    if bytes.len() > 1 && bytes[1] == ASCII_MINUS {
194        2
195    } else {
196        1
197    }
198}
199
200/// Canonical DER NR3 form (X.690 §11.3) at a proposed mantissa-terminating full stop.
201pub open spec fn der_real_decimal_at(bytes: Seq<u8>, dot: int) -> bool {
202    let start = decimal_mantissa_start(bytes);
203    let exponent = dot + 2;
204    &&& bytes.len() >= 6
205    &&& bytes[0] == REAL_DECIMAL_NR3
206    &&& start < dot < bytes.len()
207    &&& ascii_digits(bytes, start, dot)
208    &&& bytes[start] != ASCII_ZERO
209    &&& bytes[dot - 1] != ASCII_ZERO
210    &&& dot + 2 <= bytes.len()
211    &&& bytes[dot] == ASCII_FULL_STOP
212    &&& bytes[dot + 1] == ASCII_E
213    &&& {
214        // Exponent zero has the unique spelling "+0".
215        ||| exponent + 2 == bytes.len() && bytes[exponent] == ASCII_PLUS && bytes[exponent + 1]
216            == ASCII_ZERO
217        // Every non-zero exponent omits PLUS, has an optional MINUS, and no
218        // leading zero.
219        ||| {
220            let digits = if exponent < bytes.len() && bytes[exponent] == ASCII_MINUS {
221                exponent + 1
222            } else {
223                exponent
224            };
225            &&& exponent < bytes.len()
226            &&& bytes[exponent] != ASCII_PLUS
227            &&& digits < bytes.len()
228            &&& ASCII_ONE <= bytes[digits] <= ASCII_NINE
229            &&& ascii_digits(bytes, digits, bytes.len() as int)
230        }
231    }
232}
233
234pub open spec fn der_real_decimal_wf(bytes: Seq<u8>) -> bool {
235    exists|dot: int| der_real_decimal_at(bytes, dot)
236}
237
238pub open spec fn der_real_exponent_minimal(bytes: Seq<u8>, offset: int, len: int) -> bool {
239    &&& len > 0
240    &&& offset >= 0
241    &&& offset + len <= bytes.len()
242    &&& (len > 1 ==> {
243        &&& !(bytes[offset] == 0x00u8 && bytes[offset + 1] < 0x80u8)
244        &&& !(bytes[offset] == 0xffu8 && bytes[offset + 1] >= 0x80u8)
245    })
246}
247
248/// Canonical DER binary REAL contents.
249pub open spec fn der_real_binary_wf(bytes: Seq<u8>) -> bool {
250    if bytes.len() < 3 {
251        false
252    } else {
253        let info = bytes[0];
254        let form = info & 0x03u8;
255        let exponent_offset: int = if form == 0x03u8 {
256            2
257        } else {
258            1
259        };
260        let exponent_len: int = match form {
261            0x00u8 => 1,
262            0x01u8 => 2,
263            0x02u8 => 3,
264            _ => bytes[1] as int,
265        };
266        let mantissa_offset = exponent_offset + exponent_len;
267        &&& info & 0x80u8
268            != 0
269        // DER requires base 2 and a zero binary scaling factor.
270        &&& info & 0x30u8 == 0
271        &&& info & 0x0cu8
272            == 0
273        // The extended exponent-length form is canonical only when the three
274        // compact forms are insufficient.
275        &&& (form == 0x03u8 ==> exponent_len >= 4)
276        &&& der_real_exponent_minimal(bytes, exponent_offset, exponent_len)
277        &&& mantissa_offset
278            < bytes.len()
279        // M is unsigned, minimal, non-zero, and odd.
280        &&& bytes[mantissa_offset] != 0
281        &&& bytes.last() & 1u8 == 1u8
282    }
283}
284
285/// BER binary REAL contents as specified by X.690 §8.5.7.
286pub open spec fn ber_real_binary_wf(bytes: Seq<u8>) -> bool {
287    if bytes.len() < 3 {
288        false
289    } else {
290        let info = bytes[0];
291        let form = info & 0x03u8;
292        let exponent_offset: int = if form == 0x03u8 {
293            2
294        } else {
295            1
296        };
297        let exponent_len: int = match form {
298            0x00u8 => 1,
299            0x01u8 => 2,
300            0x02u8 => 3,
301            _ => bytes[1] as int,
302        };
303        let mantissa_offset = exponent_offset + exponent_len;
304        &&& info & 0x80u8
305            != 0
306        // Base 2, 8, and 16 are valid; 0b11 is reserved.
307        &&& info & 0x30u8
308            != 0x30u8
309        // The long exponent form has a non-zero length and X.690's
310        // "first nine bits" minimality requirement.
311        &&& (form == 0x03u8 ==> {
312            &&& exponent_len > 0
313            &&& der_real_exponent_minimal(bytes, exponent_offset, exponent_len)
314        })
315        &&& mantissa_offset
316            < bytes.len()
317        // N is a positive integer. BER permits redundant leading zero
318        // octets and an unnormalized (even) mantissa.
319        &&& exists|i: int| mantissa_offset <= i < bytes.len() && bytes[i] != 0u8
320    }
321}
322
323pub open spec fn der_real_special_wf(bytes: Seq<u8>) -> bool {
324    bytes.len() == 1 && (bytes[0] == REAL_PLUS_INFINITY || bytes[0] == REAL_MINUS_INFINITY
325        || bytes[0] == REAL_NOT_A_NUMBER || bytes[0] == REAL_MINUS_ZERO)
326}
327
328/// Complete canonical DER predicate for REAL contents octets.
329pub open spec fn der_real_bytes_wf(bytes: Seq<u8>) -> bool {
330    ||| bytes.len() == 0  // positive zero
331    ||| der_real_special_wf(bytes)
332    ||| der_real_binary_wf(bytes)
333    ||| der_real_decimal_wf(bytes)
334}
335
336/// Complete BER predicate for REAL contents octets.
337pub open spec fn ber_real_bytes_wf(bytes: Seq<u8>) -> bool {
338    ||| bytes.len() == 0  // positive zero
339    ||| der_real_special_wf(bytes)
340    ||| ber_real_binary_wf(bytes)
341    ||| ber_real_decimal_wf(bytes)
342}
343
344pub open spec fn real_bytes_wf<const DER: bool>(bytes: Seq<u8>) -> bool {
345    if DER {
346        der_real_bytes_wf(bytes)
347    } else {
348        ber_real_bytes_wf(bytes)
349    }
350}
351
352pub proof fn lemma_der_real_bytes_cases(bytes: Seq<u8>)
353    ensures
354        bytes.len() == 0 ==> der_real_bytes_wf(bytes),
355        bytes.len() == 1 ==> (der_real_bytes_wf(bytes) <==> der_real_special_wf(bytes)),
356        bytes.len() > 1 && bytes[0] & 0x80u8 != 0 ==> (der_real_bytes_wf(bytes)
357            <==> der_real_binary_wf(bytes)),
358        bytes.len() > 1 && bytes[0] & 0x80u8 == 0 && bytes[0] == REAL_DECIMAL_NR3 ==> (
359        der_real_bytes_wf(bytes) <==> der_real_decimal_wf(bytes)),
360        bytes.len() > 1 && bytes[0] & 0x80u8 == 0 && bytes[0] != REAL_DECIMAL_NR3
361            ==> !der_real_bytes_wf(bytes),
362{
363    if bytes.len() > 1 && bytes[0] & 0x80u8 != 0 {
364        if der_real_decimal_wf(bytes) {
365            let dot = choose|dot: int| der_real_decimal_at(bytes, dot);
366            assert(bytes[0] == REAL_DECIMAL_NR3);
367            assert(REAL_DECIMAL_NR3 & 0x80u8 == 0) by (bit_vector);
368        }
369    }
370}
371
372pub proof fn lemma_ber_real_bytes_cases(bytes: Seq<u8>)
373    ensures
374        bytes.len() == 0 ==> ber_real_bytes_wf(bytes),
375        bytes.len() == 1 ==> (ber_real_bytes_wf(bytes) <==> der_real_special_wf(bytes)),
376        bytes.len() > 1 && bytes[0] & 0x80u8 != 0 ==> (ber_real_bytes_wf(bytes)
377            <==> ber_real_binary_wf(bytes)),
378        bytes.len() > 1 && bytes[0] & 0x80u8 == 0 ==> (ber_real_bytes_wf(bytes)
379            <==> ber_real_decimal_wf(bytes)),
380{
381    if bytes.len() > 1 && bytes[0] & 0x80u8 != 0 {
382        if ber_real_decimal_wf(bytes) {
383            assert(bytes[0] == 0x01u8 || bytes[0] == 0x02u8 || bytes[0] == 0x03u8);
384            assert(0x01u8 & 0x80u8 == 0 && 0x02u8 & 0x80u8 == 0 && 0x03u8 & 0x80u8 == 0)
385                by (bit_vector);
386        }
387    }
388}
389
390pub open spec fn real_fmt<const DER: bool>() -> RealInnerFmt {
391    Refined(Tail, |bytes: Seq<u8>| real_bytes_wf::<DER>(bytes))
392}
393
394pub proof fn lemma_decimal_dot_matches_scan(bytes: Seq<u8>, start: int, scanned: int, dot: int)
395    requires
396        start == decimal_mantissa_start(bytes),
397        0 <= start <= scanned <= bytes.len(),
398        ascii_digits(bytes, start, scanned),
399        scanned == bytes.len() || !ascii_digit(bytes[scanned]),
400        der_real_decimal_at(bytes, dot),
401    ensures
402        dot == scanned,
403{
404    if dot < scanned {
405        assert(ascii_digit(bytes[dot]));
406        assert(bytes[dot] == ASCII_FULL_STOP);
407    } else if scanned < dot {
408        assert(scanned < bytes.len());
409        assert(ascii_digit(bytes[scanned]));
410    }
411}
412
413pub proof fn lemma_decimal_scan_characterizes(bytes: Seq<u8>, start: int, scanned: int)
414    requires
415        start == decimal_mantissa_start(bytes),
416        0 <= start <= scanned <= bytes.len(),
417        ascii_digits(bytes, start, scanned),
418        scanned == bytes.len() || !ascii_digit(bytes[scanned]),
419    ensures
420        der_real_decimal_wf(bytes) <==> der_real_decimal_at(bytes, scanned),
421{
422    if der_real_decimal_wf(bytes) {
423        let dot = choose|dot: int| der_real_decimal_at(bytes, dot);
424        lemma_decimal_dot_matches_scan(bytes, start, scanned, dot);
425    }
426}
427
428fn all_ascii_digits(bytes: &[u8], start: usize, end: usize) -> (ok: bool)
429    requires
430        start <= end <= bytes@.len(),
431    ensures
432        ok == ascii_digits(bytes@, start as int, end as int),
433{
434    let mut i = start;
435    while i < end
436        invariant
437            start <= i <= end <= bytes@.len(),
438            ascii_digits(bytes@, start as int, i as int),
439        decreases end - i,
440    {
441        if !(ASCII_ZERO <= bytes[i] && bytes[i] <= ASCII_NINE) {
442            assert(!ascii_digits(bytes@, start as int, end as int));
443            return false;
444        }
445        i += 1;
446    }
447    true
448}
449
450fn skip_ascii_spaces_exec(bytes: &[u8], start: usize) -> (end: usize)
451    requires
452        start <= bytes@.len(),
453    ensures
454        end == skip_ascii_spaces(bytes@, start as nat),
455        start <= end <= bytes@.len(),
456{
457    let mut i = start;
458    while i < bytes.len() && bytes[i] == ASCII_SPACE
459        invariant
460            start <= i <= bytes@.len(),
461            skip_ascii_spaces(bytes@, start as nat) == skip_ascii_spaces(bytes@, i as nat),
462        decreases bytes@.len() - i,
463    {
464        proof {
465            reveal(skip_ascii_spaces);
466            assert(skip_ascii_spaces(bytes@, i as nat) == skip_ascii_spaces(bytes@, i as nat + 1));
467        }
468        i += 1;
469    }
470    proof {
471        reveal(skip_ascii_spaces);
472        assert(skip_ascii_spaces(bytes@, i as nat) == i as nat);
473    }
474    i
475}
476
477fn scan_ascii_digits_exec(bytes: &[u8], start: usize) -> (end: usize)
478    requires
479        start <= bytes@.len(),
480    ensures
481        end == scan_ascii_digits(bytes@, start as nat),
482        start <= end <= bytes@.len(),
483        ascii_digits(bytes@, start as int, end as int),
484        end == bytes@.len() || !ascii_digit(bytes@[end as int]),
485{
486    let mut i = start;
487    while i < bytes.len() && ASCII_ZERO <= bytes[i] && bytes[i] <= ASCII_NINE
488        invariant
489            start <= i <= bytes@.len(),
490            scan_ascii_digits(bytes@, start as nat) == scan_ascii_digits(bytes@, i as nat),
491            ascii_digits(bytes@, start as int, i as int),
492        decreases bytes@.len() - i,
493    {
494        proof {
495            reveal(scan_ascii_digits);
496            assert(scan_ascii_digits(bytes@, i as nat) == scan_ascii_digits(bytes@, i as nat + 1));
497        }
498        i += 1;
499    }
500    proof {
501        reveal(scan_ascii_digits);
502        assert(scan_ascii_digits(bytes@, i as nat) == i as nat);
503    }
504    i
505}
506
507fn ascii_digits_have_nonzero_exec(bytes: &[u8], start: usize, end: usize) -> (found: bool)
508    requires
509        start <= end <= bytes@.len(),
510    ensures
511        found == ascii_digits_have_nonzero(bytes@, start as int, end as int),
512{
513    let mut i = start;
514    while i < end
515        invariant
516            start <= i <= end <= bytes@.len(),
517            forall|j: int| #![auto] start <= j < i ==> !ascii_nonzero_digit(bytes@[j]),
518        decreases end - i,
519    {
520        if ASCII_ONE <= bytes[i] && bytes[i] <= ASCII_NINE {
521            assert(ascii_digits_have_nonzero(bytes@, start as int, end as int)) by {
522                assert(ascii_nonzero_digit(bytes@[i as int]));
523            }
524            return true;
525        }
526        i += 1;
527    }
528    assert(!ascii_digits_have_nonzero(bytes@, start as int, end as int));
529    false
530}
531
532fn ber_real_decimal_wf_exec(bytes: &[u8]) -> (ok: bool)
533    ensures
534        ok == ber_real_decimal_wf(bytes@),
535{
536    if bytes.len() <= 1 {
537        return false;
538    }
539    let representation = bytes[0];
540    if representation != 0x01u8 && representation != 0x02u8 && representation != 0x03u8 {
541        return false;
542    }
543    let mut start = skip_ascii_spaces_exec(bytes, 1);
544    let ghost unsigned_start = start;
545    if start < bytes.len() && (bytes[start] == ASCII_PLUS || bytes[start] == ASCII_MINUS) {
546        start += 1;
547    }
548    assert(start as nat == after_optional_sign(bytes@, unsigned_start as nat));
549
550    if representation == 0x01u8 {
551        let end = scan_ascii_digits_exec(bytes, start);
552        if start >= end || end != bytes.len() {
553            return false;
554        }
555        return ascii_digits_have_nonzero_exec(bytes, start, end);
556    }
557    let mark = scan_ascii_digits_exec(bytes, start);
558    if mark >= bytes.len() || !(bytes[mark] == ASCII_FULL_STOP || bytes[mark] == ASCII_COMMA) {
559        return false;
560    }
561    let after = mark + 1;
562    let end = scan_ascii_digits_exec(bytes, after);
563    if start == mark && after == end {
564        return false;
565    }
566    assert(ber_real_decimal_significand(bytes@) == Some(
567        (start as nat, mark as nat, after as nat, end as nat),
568    ));
569    let before_nonzero = ascii_digits_have_nonzero_exec(bytes, start, mark);
570    let after_nonzero = ascii_digits_have_nonzero_exec(bytes, after, end);
571    let nonzero = before_nonzero || after_nonzero;
572
573    if representation == 0x02u8 {
574        return end == bytes.len() && nonzero;
575    }
576    if end >= bytes.len() || !(bytes[end] == ASCII_E || bytes[end] == ASCII_LOWER_E) {
577        return false;
578    }
579    let exponent_sign = end + 1;
580    if exponent_sign >= bytes.len() || !(bytes[exponent_sign] == ASCII_PLUS || bytes[exponent_sign]
581        == ASCII_MINUS) {
582        return false;
583    }
584    let exponent = exponent_sign + 1;
585    let exponent_end = scan_ascii_digits_exec(bytes, exponent);
586    exponent < exponent_end && exponent_end == bytes.len() && nonzero
587}
588
589fn scan_decimal_mantissa(bytes: &[u8], start: usize) -> (scanned: usize)
590    requires
591        start <= bytes@.len(),
592    ensures
593        start <= scanned <= bytes@.len(),
594        ascii_digits(bytes@, start as int, scanned as int),
595        scanned == bytes@.len() || !ascii_digit(bytes@[scanned as int]),
596{
597    let mut i = start;
598    while i < bytes.len() && ASCII_ZERO <= bytes[i] && bytes[i] <= ASCII_NINE
599        invariant
600            start <= i <= bytes@.len(),
601            ascii_digits(bytes@, start as int, i as int),
602        decreases bytes@.len() - i,
603    {
604        i += 1;
605    }
606    i
607}
608
609fn der_real_decimal_at_exec(bytes: &[u8], dot: usize) -> (ok: bool)
610    ensures
611        ok == der_real_decimal_at(bytes@, dot as int),
612{
613    if bytes.len() < 6 || bytes[0] != REAL_DECIMAL_NR3 {
614        return false;
615    }
616    let start = if bytes[1] == ASCII_MINUS {
617        2
618    } else {
619        1
620    };
621    if start >= dot || dot >= bytes.len() {
622        return false;
623    }
624    if !all_ascii_digits(bytes, start, dot) {
625        return false;
626    }
627    if bytes[start] == ASCII_ZERO || bytes[dot - 1] == ASCII_ZERO {
628        return false;
629    }
630    if dot > bytes.len() - 2 || bytes[dot] != ASCII_FULL_STOP || bytes[dot + 1] != ASCII_E {
631        return false;
632    }
633    let exponent = dot + 2;
634    if exponent <= bytes.len() - 2 && exponent + 2 == bytes.len() && bytes[exponent] == ASCII_PLUS
635        && bytes[exponent + 1] == ASCII_ZERO {
636        return true;
637    }
638    if exponent >= bytes.len() || bytes[exponent] == ASCII_PLUS {
639        return false;
640    }
641    let digits = if bytes[exponent] == ASCII_MINUS {
642        exponent + 1
643    } else {
644        exponent
645    };
646    if digits >= bytes.len() || bytes[digits] < ASCII_ONE || bytes[digits] > ASCII_NINE {
647        return false;
648    }
649    all_ascii_digits(bytes, digits, bytes.len())
650}
651
652fn der_real_decimal_wf_exec(bytes: &[u8]) -> (ok: bool)
653    ensures
654        ok == der_real_decimal_wf(bytes@),
655{
656    if bytes.len() < 2 || bytes[0] != REAL_DECIMAL_NR3 {
657        return false;
658    }
659    let start = if bytes[1] == ASCII_MINUS {
660        2
661    } else {
662        1
663    };
664    if start > bytes.len() {
665        return false;
666    }
667    let scanned = scan_decimal_mantissa(bytes, start);
668    let ok = der_real_decimal_at_exec(bytes, scanned);
669    proof {
670        assert(start as int == decimal_mantissa_start(bytes@));
671        lemma_decimal_scan_characterizes(bytes@, start as int, scanned as int);
672    }
673    ok
674}
675
676fn der_real_binary_wf_exec(bytes: &[u8]) -> (ok: bool)
677    ensures
678        ok == der_real_binary_wf(bytes@),
679{
680    if bytes.len() < 3 {
681        return false;
682    }
683    let info = bytes[0];
684    if info & 0x80u8 == 0 || info & 0x30u8 != 0 || info & 0x0cu8 != 0 {
685        return false;
686    }
687    let form = info & 0x03u8;
688    let exponent_offset = if form == 0x03u8 {
689        2usize
690    } else {
691        1usize
692    };
693    let exponent_len = if form == 0x00u8 {
694        1usize
695    } else if form == 0x01u8 {
696        2usize
697    } else if form == 0x02u8 {
698        3usize
699    } else {
700        bytes[1] as usize
701    };
702    let ghost spec_exponent_offset: int = if form == 0x03u8 {
703        2
704    } else {
705        1
706    };
707    let ghost spec_exponent_len: int = match form {
708        0x00u8 => 1,
709        0x01u8 => 2,
710        0x02u8 => 3,
711        _ => bytes@[1] as int,
712    };
713    proof {
714        assert(exponent_offset as int == spec_exponent_offset);
715        assert(exponent_len as int == spec_exponent_len);
716    }
717    if form == 0x03u8 && exponent_len < 4 {
718        return false;
719    }
720    if exponent_len == 0 || exponent_offset > bytes.len() || exponent_len > bytes.len()
721        - exponent_offset {
722        return false;
723    }
724    if exponent_len > 1 {
725        let first = bytes[exponent_offset];
726        let second = bytes[exponent_offset + 1];
727        if (first == 0x00 && second < 0x80) || (first == 0xff && second >= 0x80) {
728            proof {
729                assert(!der_real_exponent_minimal(bytes@, spec_exponent_offset, spec_exponent_len));
730                assert(!der_real_binary_wf(bytes@));
731            }
732            return false;
733        }
734    }
735    let mantissa_offset = exponent_offset + exponent_len;
736    proof {
737        assert(mantissa_offset as int == spec_exponent_offset + spec_exponent_len);
738    }
739    if mantissa_offset >= bytes.len() || bytes[mantissa_offset] == 0 {
740        proof {
741            assert(!der_real_binary_wf(bytes@));
742        }
743        return false;
744    }
745    bytes[bytes.len() - 1] & 1u8 == 1u8
746}
747
748fn has_nonzero_octet(bytes: &[u8], start: usize) -> (found: bool)
749    requires
750        start <= bytes@.len(),
751    ensures
752        found == exists|i: int| start <= i < bytes@.len() && bytes@[i] != 0u8,
753{
754    let mut i = start;
755    while i < bytes.len()
756        invariant
757            start <= i <= bytes@.len(),
758            forall|j: int| start <= j < i ==> bytes@[j] == 0u8,
759        decreases bytes@.len() - i,
760    {
761        if bytes[i] != 0 {
762            assert(exists|j: int| start <= j < bytes@.len() && bytes@[j] != 0u8);
763            return true;
764        }
765        i += 1;
766    }
767    assert(!(exists|j: int| start <= j < bytes@.len() && bytes@[j] != 0u8));
768    false
769}
770
771fn ber_real_binary_wf_exec(bytes: &[u8]) -> (ok: bool)
772    ensures
773        ok == ber_real_binary_wf(bytes@),
774{
775    if bytes.len() < 3 {
776        return false;
777    }
778    let info = bytes[0];
779    if info & 0x80u8 == 0 || info & 0x30u8 == 0x30u8 {
780        return false;
781    }
782    let form = info & 0x03u8;
783    let exponent_offset = if form == 0x03u8 {
784        2usize
785    } else {
786        1usize
787    };
788    let exponent_len = if form == 0x00u8 {
789        1usize
790    } else if form == 0x01u8 {
791        2usize
792    } else if form == 0x02u8 {
793        3usize
794    } else {
795        bytes[1] as usize
796    };
797    let ghost spec_exponent_offset: int = if form == 0x03u8 {
798        2
799    } else {
800        1
801    };
802    let ghost spec_exponent_len: int = match form {
803        0x00u8 => 1,
804        0x01u8 => 2,
805        0x02u8 => 3,
806        _ => bytes@[1] as int,
807    };
808    proof {
809        assert(exponent_offset as int == spec_exponent_offset);
810        assert(exponent_len as int == spec_exponent_len);
811    }
812
813    if form == 0x03u8 && exponent_len == 0 {
814        assert(!ber_real_binary_wf(bytes@));
815        return false;
816    }
817    if exponent_offset > bytes.len() || exponent_len > bytes.len() - exponent_offset {
818        proof {
819            if exponent_offset > bytes@.len() {
820                assert(spec_exponent_offset > bytes@.len());
821            } else if exponent_len > bytes.len() - exponent_offset {
822                assert(spec_exponent_offset + spec_exponent_len > bytes@.len());
823            }
824            assert(!ber_real_binary_wf(bytes@));
825        }
826        return false;
827    }
828    if form == 0x03u8 && exponent_len > 1 {
829        let first = bytes[exponent_offset];
830        let second = bytes[exponent_offset + 1];
831        if (first == 0x00 && second < 0x80) || (first == 0xff && second >= 0x80) {
832            proof {
833                assert(!der_real_exponent_minimal(bytes@, spec_exponent_offset, spec_exponent_len));
834            }
835            return false;
836        }
837    }
838    let mantissa_offset = exponent_offset + exponent_len;
839    proof {
840        assert(mantissa_offset as int == spec_exponent_offset + spec_exponent_len);
841    }
842    if mantissa_offset >= bytes.len() {
843        return false;
844    }
845    has_nonzero_octet(bytes, mantissa_offset)
846}
847
848/// Executable checker for all canonical DER REAL contents forms.
849pub fn der_real_bytes_wf_exec(bytes: &[u8]) -> (ok: bool)
850    ensures
851        ok == der_real_bytes_wf(bytes@),
852{
853    proof {
854        lemma_der_real_bytes_cases(bytes@);
855    }
856    if bytes.len() == 0 {
857        true
858    } else if bytes.len() == 1 {
859        matches!(
860            bytes[0],
861            REAL_PLUS_INFINITY | REAL_MINUS_INFINITY | REAL_NOT_A_NUMBER | REAL_MINUS_ZERO
862        )
863    } else if bytes[0] & 0x80u8 != 0 {
864        der_real_binary_wf_exec(bytes)
865    } else if bytes[0] == REAL_DECIMAL_NR3 {
866        der_real_decimal_wf_exec(bytes)
867    } else {
868        false
869    }
870}
871
872/// Executable checker for all BER REAL contents forms.
873pub fn ber_real_bytes_wf_exec(bytes: &[u8]) -> (ok: bool)
874    ensures
875        ok == ber_real_bytes_wf(bytes@),
876{
877    proof {
878        lemma_ber_real_bytes_cases(bytes@);
879    }
880    if bytes.len() == 0 {
881        true
882    } else if bytes.len() == 1 {
883        matches!(
884            bytes[0],
885            REAL_PLUS_INFINITY | REAL_MINUS_INFINITY | REAL_NOT_A_NUMBER | REAL_MINUS_ZERO
886        )
887    } else if bytes[0] & 0x80u8 != 0 {
888        ber_real_binary_wf_exec(bytes)
889    } else {
890        ber_real_decimal_wf_exec(bytes)
891    }
892}
893
894pub fn real_bytes_wf_exec<const DER: bool>(bytes: &[u8]) -> (ok: bool)
895    ensures
896        ok == real_bytes_wf::<DER>(bytes@),
897{
898    if DER {
899        der_real_bytes_wf_exec(bytes)
900    } else {
901        ber_real_bytes_wf_exec(bytes)
902    }
903}
904
905mod derived_specs {
906    use super::*;
907
908    impl<const DER: bool> SpecParser for RealFmt<DER> {
909        type PVal = RealSpec;
910
911        open spec fn spec_parse(&self, ibuf: Seq<u8>) -> Option<(int, Self::PVal)> {
912            real_fmt::<DER>().spec_parse(ibuf)
913        }
914    }
915
916    impl<const DER: bool> Consistency for RealFmt<DER> {
917        type Val = RealSpec;
918
919        open spec fn consistent(&self, v: Self::Val) -> bool {
920            real_fmt::<DER>().consistent(v)
921        }
922    }
923
924    impl<const DER: bool> SpecSerializerDps for RealFmt<DER> {
925        type SValue = RealSpec;
926
927        open spec fn spec_serialize_dps(&self, v: Self::SValue, obuf: Seq<u8>) -> Seq<u8> {
928            real_fmt::<DER>().spec_serialize_dps(v, obuf)
929        }
930    }
931
932    impl<const DER: bool> SpecSerializer for RealFmt<DER> {
933        type SVal = RealSpec;
934
935        open spec fn spec_serialize(&self, v: Self::SVal) -> Seq<u8> {
936            real_fmt::<DER>().spec_serialize(v)
937        }
938    }
939
940    impl<const DER: bool> SpecByteLen for RealFmt<DER> {
941        type T = RealSpec;
942
943        open spec fn byte_len(&self, v: Self::T) -> nat {
944            real_fmt::<DER>().byte_len(v)
945        }
946    }
947
948}
949
950mod derived_proofs {
951    use super::*;
952
953    impl<const DER: bool> SafeParser for RealFmt<DER> {
954        proof fn lemma_parse_safe(&self, ibuf: Seq<u8>) {
955            real_fmt::<DER>().lemma_parse_safe(ibuf);
956        }
957    }
958
959    impl<const DER: bool> Productive for RealFmt<DER> {
960        open spec fn productive_inv(&self) -> bool {
961            false
962        }
963
964        proof fn lemma_productive(&self, _ibuf: Seq<u8>) {
965        }
966    }
967
968    impl<const DER: bool> SoundParser for RealFmt<DER> {
969        proof fn lemma_parse_sound_consumption(&self, ibuf: Seq<u8>) {
970            real_fmt::<DER>().lemma_parse_sound_consumption(ibuf);
971        }
972
973        proof fn lemma_parse_sound_value(&self, ibuf: Seq<u8>) {
974            real_fmt::<DER>().lemma_parse_sound_value(ibuf);
975        }
976    }
977
978    impl<const DER: bool> GoodSerializer for RealFmt<DER> {
979        proof fn lemma_serialize_len(&self, v: Self::SVal) {
980            real_fmt::<DER>().lemma_serialize_len(v);
981        }
982    }
983
984    impl<const DER: bool> SPRoundTripDps for RealFmt<DER> {
985        proof fn theorem_serialize_dps_parse_roundtrip(&self, v: Self::T, obuf: Seq<u8>) {
986            real_fmt::<DER>().theorem_serialize_dps_parse_roundtrip(v, obuf);
987        }
988    }
989
990    impl<const DER: bool> NonMalleable for RealFmt<DER> {
991        proof fn lemma_parse_non_malleable(&self, buf1: Seq<u8>, buf2: Seq<u8>) {
992            real_fmt::<DER>().lemma_parse_non_malleable(buf1, buf2);
993        }
994    }
995
996    impl<const DER: bool> EquivSerializers for RealFmt<DER> {
997        proof fn lemma_serialize_equiv_on_empty(&self, v: Self::SVal) {
998            real_fmt::<DER>().lemma_serialize_equiv_on_empty(v);
999        }
1000    }
1001
1002}
1003
1004/// Borrowed, exact BER/DER REAL contents.
1005pub struct Real<'a, const DER: bool = true> {
1006    contents: &'a [u8],
1007}
1008
1009impl<'a, const DER: bool> DeepView for Real<'a, DER> {
1010    type V = RealSpec;
1011
1012    closed spec fn deep_view(&self) -> Self::V {
1013        self.contents.deep_view()
1014    }
1015}
1016
1017impl<'a, const DER: bool> Real<'a, DER> {
1018    #[verifier::type_invariant]
1019    spec fn wf(&self) -> bool {
1020        real_bytes_wf::<DER>(self.deep_view())
1021    }
1022
1023    fn new_verified(contents: &'a [u8]) -> (value: Self)
1024        requires
1025            real_bytes_wf::<DER>(contents@),
1026        ensures
1027            value.deep_view() == contents.deep_view(),
1028    {
1029        proof {
1030            assert(contents.deep_view() == contents@);
1031        }
1032        Self { contents }
1033    }
1034
1035    /// Validates and borrows REAL contents under this format's encoding rules.
1036    pub fn from_contents(contents: &'a [u8]) -> (value: Result<Self, ParseError>)
1037        ensures
1038            value matches Ok(v) ==> v.deep_view() == contents.deep_view(),
1039            value is Ok <==> real_bytes_wf::<DER>(contents@),
1040    {
1041        if real_bytes_wf_exec::<DER>(contents) {
1042            Ok(Self::new_verified(contents))
1043        } else {
1044            Err(ParseError::non_canonical())
1045        }
1046    }
1047
1048    pub fn contents(&self) -> (contents: &'a [u8])
1049        ensures
1050            contents.deep_view() == self.deep_view(),
1051    {
1052        self.contents
1053    }
1054}
1055
1056impl<'a> Real<'a, true> {
1057    /// Validates and borrows canonical DER REAL contents.
1058    pub fn from_der_contents(contents: &'a [u8]) -> (value: Result<Self, ParseError>)
1059        ensures
1060            value matches Ok(v) ==> v.deep_view() == contents.deep_view(),
1061            value is Ok <==> der_real_bytes_wf(contents@),
1062    {
1063        Self::from_contents(contents)
1064    }
1065}
1066
1067impl<'a> Real<'a, false> {
1068    /// Validates and borrows any well-formed BER REAL contents.
1069    pub fn from_ber_contents(contents: &'a [u8]) -> (value: Result<Self, ParseError>)
1070        ensures
1071            value matches Ok(v) ==> v.deep_view() == contents.deep_view(),
1072            value is Ok <==> ber_real_bytes_wf(contents@),
1073    {
1074        Self::from_contents(contents)
1075    }
1076}
1077
1078impl<'a, const DER: bool> Parser<&'a [u8]> for RealFmt<DER> {
1079    type PT = Real<'a, DER>;
1080
1081    fn parse(&self, ibuf: &&'a [u8]) -> PResult<Self::PT> {
1082        let (n, contents) = Tail.parse(ibuf)?;
1083        proof {
1084            contents.deep_view_eq_view();
1085        }
1086        if real_bytes_wf_exec::<DER>(contents) {
1087            let value = Real::new_verified(contents);
1088            Ok((n, value))
1089        } else {
1090            Err(ParseError::non_canonical())
1091        }
1092    }
1093}
1094
1095impl<'a, Output: OutputBuf, const DER: bool> Serializer<Output, Real<'a, DER>> for RealFmt<DER> {
1096    fn serialize_into(&self, v: &Real<'a, DER>, obuf: &mut Output) {
1097        proof {
1098            use_type_invariant(v);
1099        }
1100        Tail.serialize_into(&v.contents, obuf);
1101    }
1102}
1103
1104impl<'a, const DER: bool> Prepare<Real<'a, DER>> for RealFmt<DER> {
1105    fn prepare(&self, v: &Real<'a, DER>) -> Result<usize, PreSerializeError> {
1106        proof {
1107            use_type_invariant(v);
1108        }
1109        Tail.prepare(&v.contents)
1110    }
1111}
1112
1113impl<'a, const DER: bool> ByteLen<Real<'a, DER>> for RealFmt<DER> {
1114    fn length(&self, v: &Real<'a, DER>) -> usize {
1115        Tail.length(&v.contents)
1116    }
1117}
1118
1119} // verus!
1120#[cfg(test)]
1121mod tests {
1122    use super::*;
1123    use crate::asn1::ber::REAL as BER_REAL;
1124    use crate::asn1::der::REAL;
1125    use crate::core::exec::{Parser, Prepare, SerializerExt};
1126
1127    fn roundtrip(contents: &[u8]) {
1128        let mut input = vec![0x09, contents.len() as u8];
1129        input.extend_from_slice(contents);
1130        let (_, value) = REAL.parse(&&input[..]).unwrap();
1131        let mut output = vec![0; REAL.prepare(&value).unwrap()];
1132        REAL.serialize(&value, &mut output);
1133        assert_eq!(output, input);
1134    }
1135
1136    fn roundtrip_ber(contents: &[u8]) {
1137        let mut input = vec![0x09, contents.len() as u8];
1138        input.extend_from_slice(contents);
1139        let (_, value) = BER_REAL.parse(&&input[..]).unwrap();
1140        let mut output = vec![0; BER_REAL.prepare(&value).unwrap()];
1141        BER_REAL.serialize(&value, &mut output);
1142        assert_eq!(output, input);
1143    }
1144
1145    #[test]
1146    fn real_roundtrips_all_der_families() {
1147        roundtrip(&[]); // +0
1148        roundtrip(&[REAL_MINUS_ZERO]);
1149        roundtrip(&[REAL_PLUS_INFINITY]);
1150        roundtrip(&[REAL_MINUS_INFINITY]);
1151        roundtrip(&[REAL_NOT_A_NUMBER]);
1152        roundtrip(&[0x80, 0x00, 0x01]); // 1 * 2^0
1153        roundtrip(b"\x03123.E-2");
1154        roundtrip(b"\x031.E+0");
1155    }
1156
1157    #[test]
1158    fn real_rejects_noncanonical_forms() {
1159        for contents in [
1160            &b"\x031.0E+0"[..],        // mantissa ends in zero
1161            &b"\x031.E+1"[..],         // plus is forbidden for non-zero exponent
1162            &[0x80, 0x00, 0x02],       // even mantissa
1163            &[0x83, 0x01, 0x00, 0x01], // long exponent form used for one octet
1164        ] {
1165            let mut input = vec![0x09, contents.len() as u8];
1166            input.extend_from_slice(contents);
1167            assert!(REAL.parse(&&input[..]).is_err());
1168        }
1169    }
1170
1171    #[test]
1172    fn ber_real_roundtrips_additional_binary_and_decimal_forms() {
1173        roundtrip_ber(&[0x90, 0x00, 0x02]); // base 8, unnormalized mantissa
1174        roundtrip_ber(&[0x84, 0x00, 0x02]); // binary scale factor 1
1175        roundtrip_ber(&[0x83, 0x01, 0x00, 0x02]); // one-octet long exponent
1176        roundtrip_ber(b"\x01123"); // ISO 6093 NR1
1177        roundtrip_ber(b"\x02-12.5"); // ISO 6093 NR2
1178        roundtrip_ber(b"\x03 1.25E+2"); // ISO 6093 NR3
1179        roundtrip_ber(b"\x03.125e+3"); // no digit left of the decimal mark
1180    }
1181
1182    #[test]
1183    fn ber_real_rejects_reserved_or_non_real_contents() {
1184        for contents in [
1185            &[0xb0, 0x00, 0x01][..], // reserved binary base
1186            &[0x80, 0x00, 0x00],     // zero binary mantissa
1187            &b"\x010"[..],           // plus zero must have empty contents
1188            &b"\x0212"[..],          // NR2 requires a decimal mark
1189            &b"\x031.2E2"[..],       // NR3 exponent sign is mandatory
1190        ] {
1191            let mut input = vec![0x09, contents.len() as u8];
1192            input.extend_from_slice(contents);
1193            assert!(BER_REAL.parse(&&input[..]).is_err());
1194        }
1195    }
1196}