Skip to main content

der/asn1/
real.rs

1//! ASN.1 `REAL` support.
2
3// TODO(tarcieri): checked arithmetic
4#![allow(
5    clippy::cast_lossless,
6    clippy::cast_sign_loss,
7    clippy::arithmetic_side_effects
8)]
9
10use crate::{
11    BytesRef, DecodeValue, EncodeValue, Error, FixedTag, Header, Length, Reader, Result, StringRef,
12    Tag, Writer,
13};
14
15use super::integer::uint::strip_leading_zeroes;
16
17impl<'a> DecodeValue<'a> for f64 {
18    type Error = Error;
19
20    fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
21        let bytes = <&'a BytesRef>::decode_value(reader, header)?.as_slice();
22
23        if header.length() == Length::ZERO {
24            Ok(0.0)
25        } else if is_nth_bit_one::<7>(bytes) {
26            // Binary encoding from section 8.5.7 applies
27            let sign: u64 = u64::from(is_nth_bit_one::<6>(bytes));
28
29            // Section 8.5.7.2: Check the base -- the DER specs say that only base 2 should be supported in DER
30            let base = mnth_bits_to_u8::<5, 4>(bytes);
31
32            if base != 0 {
33                // Real related error: base is not DER compliant (base encoded in enum)
34                return Err(reader.error(Tag::Real.value_error()));
35            }
36
37            // Section 8.5.7.3
38            let scaling_factor = mnth_bits_to_u8::<3, 2>(bytes);
39
40            // Section 8.5.7.4
41            let mantissa_start;
42            let exponent = match mnth_bits_to_u8::<1, 0>(bytes) {
43                0 => {
44                    mantissa_start = 2;
45                    let ebytes = (i16::from_be_bytes([0x0, bytes[1]])).to_be_bytes();
46                    u64::from_be_bytes([0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ebytes[0], ebytes[1]])
47                }
48                1 => {
49                    mantissa_start = 3;
50                    let ebytes = (i16::from_be_bytes([bytes[1], bytes[2]])).to_be_bytes();
51                    u64::from_be_bytes([0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ebytes[0], ebytes[1]])
52                }
53                _ => {
54                    // Real related error: encoded exponent cannot be represented on an IEEE-754 double
55                    return Err(reader.error(Tag::Real.value_error()));
56                }
57            };
58            // Section 8.5.7.5: Read the remaining bytes for the mantissa
59            let mut n_bytes = [0x0; 8];
60            for (pos, byte) in bytes[mantissa_start..].iter().rev().enumerate() {
61                n_bytes[7 - pos] = *byte;
62            }
63            let n = u64::from_be_bytes(n_bytes);
64            // Multiply byte 2^F corresponds to just a left shift
65            let mantissa = n << scaling_factor;
66            // Create the f64
67            Ok(encode_f64(sign, exponent, mantissa))
68        } else if is_nth_bit_one::<6>(bytes) {
69            // This either a special value, or it's the value minus zero is encoded, section 8.5.9 applies
70            match mnth_bits_to_u8::<1, 0>(bytes) {
71                0 => Ok(f64::INFINITY),
72                1 => Ok(f64::NEG_INFINITY),
73                2 => Ok(f64::NAN),
74                3 => Ok(-0.0_f64),
75                _ => Err(reader.error(Tag::Real.value_error())),
76            }
77        } else {
78            let astr = StringRef::from_bytes(&bytes[1..])?;
79            match astr.as_str().parse::<f64>() {
80                Ok(val) => Ok(val),
81                // Real related error: encoding not supported or malformed
82                Err(_) => Err(reader.error(Tag::Real.value_error())),
83            }
84        }
85    }
86}
87
88impl EncodeValue for f64 {
89    fn value_len(&self) -> Result<Length> {
90        if self.is_sign_positive() && (*self) < f64::MIN_POSITIVE {
91            // Zero: positive yet smaller than the minimum positive number
92            Ok(Length::ZERO)
93        } else if self.is_nan()
94            || self.is_infinite()
95            || (self.is_sign_negative() && -self < f64::MIN_POSITIVE)
96        {
97            // NaN, infinite (positive or negative), or negative zero (negative but its negative is less than the min positive number)
98            Ok(Length::ONE)
99        } else {
100            // The length is that of the first octets plus those needed for the exponent plus those needed for the mantissa
101            let (_sign, exponent, mantissa) = decode_f64(*self);
102
103            let exponent_len = if exponent == 0 {
104                // Section 8.5.7.4: there must be at least one octet for exponent encoding
105                // But, if the exponent is zero, it'll be skipped, so we make sure force it to 1
106                Length::ONE
107            } else {
108                let ebytes = exponent.to_be_bytes();
109                Length::try_from(strip_leading_zeroes(&ebytes).len())?
110            };
111
112            let mantissa_len = if mantissa == 0 {
113                Length::ONE
114            } else {
115                let mbytes = mantissa.to_be_bytes();
116                Length::try_from(strip_leading_zeroes(&mbytes).len())?
117            };
118
119            exponent_len + mantissa_len + Length::ONE
120        }
121    }
122
123    fn encode_value(&self, writer: &mut impl Writer) -> Result<()> {
124        // Check if special value
125        // Encode zero first, if it's zero
126        // Special value from section 8.5.9 if non zero
127        if self.is_nan()
128            || self.is_infinite()
129            || (self.is_sign_negative() && -self < f64::MIN_POSITIVE)
130            || (self.is_sign_positive() && (*self) < f64::MIN_POSITIVE)
131        {
132            if self.is_sign_positive() && (*self) < f64::MIN_POSITIVE {
133                // Zero
134                return Ok(());
135            } else if self.is_nan() {
136                // Not a number
137                writer.write_byte(0b0100_0010)?;
138            } else if self.is_infinite() {
139                if self.is_sign_negative() {
140                    // Negative infinity
141                    writer.write_byte(0b0100_0001)?;
142                } else {
143                    // Plus infinity
144                    writer.write_byte(0b0100_0000)?;
145                }
146            } else {
147                // Minus zero
148                writer.write_byte(0b0100_0011)?;
149            }
150        } else {
151            // Always use binary encoding, set bit 8 to 1
152            let mut first_byte = 0b1000_0000;
153
154            if self.is_sign_negative() {
155                // Section 8.5.7.1: set bit 7 to 1 if negative
156                first_byte |= 0b0100_0000;
157            }
158
159            // Bits 6 and 5 are set to 0 to specify that binary encoding is used
160            //
161            // NOTE: the scaling factor is only used to align the implicit point of the mantissa.
162            // This is unnecessary in DER because the base is 2, and therefore necessarily aligned.
163            // Therefore, we do not modify the mantissa in anyway after this function call, which
164            // already adds the implicit one of the IEEE 754 representation.
165            let (_sign, exponent, mantissa) = decode_f64(*self);
166
167            // Encode the exponent as two's complement on 16 bits and remove the bias
168            let exponent_bytes = exponent.to_be_bytes();
169            let ebytes = strip_leading_zeroes(&exponent_bytes);
170
171            match ebytes.len() {
172                0 | 1 => {}
173                2 => first_byte |= 0b0000_0001,
174                3 => first_byte |= 0b0000_0010,
175                _ => {
176                    // TODO: support multi octet exponent encoding?
177                    return Err(Tag::Real.value_error().into());
178                }
179            }
180
181            writer.write_byte(first_byte)?;
182
183            // Encode both bytes or just the last one, handled by encode_bytes directly
184            // Rust already encodes the data as two's complement, so no further processing is needed
185            writer.write(ebytes)?;
186
187            // Now, encode the mantissa as unsigned binary number
188            let mantissa_bytes = mantissa.to_be_bytes();
189            let mbytes = strip_leading_zeroes(&mantissa_bytes);
190            writer.write(mbytes)?;
191        }
192
193        Ok(())
194    }
195}
196
197impl FixedTag for f64 {
198    const TAG: Tag = Tag::Real;
199}
200
201/// Is the N-th bit 1 in the first octet?
202/// NOTE: this function is zero indexed
203pub(crate) fn is_nth_bit_one<const N: usize>(bytes: &[u8]) -> bool {
204    if N < 8 {
205        bytes.first().is_some_and(|byte| byte & (1 << N) != 0)
206    } else {
207        false
208    }
209}
210
211/// Convert bits M, N into a u8, in the first octet only
212pub(crate) fn mnth_bits_to_u8<const M: usize, const N: usize>(bytes: &[u8]) -> u8 {
213    let bit_m = is_nth_bit_one::<M>(bytes);
214    let bit_n = is_nth_bit_one::<N>(bytes);
215    ((bit_m as u8) << 1) | bit_n as u8
216}
217
218/// Decode an f64 as its sign, exponent, and mantissa in u64 and in that order, using bit shifts and masks.
219/// Note: this function **removes** the 1023 bias from the exponent and adds the implicit 1
220#[allow(clippy::cast_possible_truncation)]
221pub(crate) fn decode_f64(f: f64) -> (u64, u64, u64) {
222    let bits = f.to_bits();
223    let sign = bits >> 63;
224    let exponent = (bits >> 52) & 0x7ff;
225    let exponent_bytes_no_bias = (exponent as i16 - 1023).to_be_bytes();
226    let exponent_no_bias = u64::from_be_bytes([
227        0x0,
228        0x0,
229        0x0,
230        0x0,
231        0x0,
232        0x0,
233        exponent_bytes_no_bias[0],
234        exponent_bytes_no_bias[1],
235    ]);
236    let mantissa = bits & 0xfffffffffffff;
237    (sign, exponent_no_bias, mantissa + 1)
238}
239
240/// Encode an f64 from its sign, exponent (**without** the 1023 bias), and (mantissa - 1) using bit shifts as received by ASN1
241pub(crate) fn encode_f64(sign: u64, exponent: u64, mantissa: u64) -> f64 {
242    // Add the bias to the exponent
243    let exponent_with_bias =
244        (i16::from_be_bytes([exponent.to_be_bytes()[6], exponent.to_be_bytes()[7]]) + 1023) as u64;
245    let bits = (sign << 63) | (exponent_with_bias << 52) | (mantissa - 1);
246    f64::from_bits(bits)
247}
248
249#[cfg(test)]
250#[allow(clippy::unwrap_used)]
251mod tests {
252    use crate::{Decode, Encode};
253
254    #[test]
255    fn decode_subnormal() {
256        assert!(f64::from_der(&[0x09, 0x01, 0b0100_0010]).unwrap().is_nan());
257        let plus_infty = f64::from_der(&[0x09, 0x01, 0b0100_0000]).unwrap();
258        assert!(plus_infty.is_infinite() && plus_infty.is_sign_positive());
259        let neg_infty = f64::from_der(&[0x09, 0x01, 0b0100_0001]).unwrap();
260        assert!(neg_infty.is_infinite() && neg_infty.is_sign_negative());
261        let neg_zero = f64::from_der(&[0x09, 0x01, 0b0100_0011]).unwrap();
262        assert!(neg_zero.is_sign_negative() && neg_zero.abs() < f64::EPSILON);
263    }
264
265    #[test]
266    fn encode_subnormal() {
267        // All subnormal fit in three bytes
268        let mut buffer = [0u8; 3];
269        assert_eq!(
270            &[0x09, 0x01, 0b0100_0010],
271            f64::NAN.encode_to_slice(&mut buffer).unwrap()
272        );
273        assert_eq!(
274            &[0x09, 0x01, 0b0100_0000],
275            f64::INFINITY.encode_to_slice(&mut buffer).unwrap()
276        );
277        assert_eq!(
278            &[0x09, 0x01, 0b0100_0001],
279            f64::NEG_INFINITY.encode_to_slice(&mut buffer).unwrap()
280        );
281        assert_eq!(
282            &[0x09, 0x01, 0b0100_0011],
283            (-0.0_f64).encode_to_slice(&mut buffer).unwrap()
284        );
285    }
286
287    #[test]
288    fn encdec_normal() {
289        // The comments correspond to the decoded value from the ASN.1 playground when the bytes are inputted.
290        {
291            // rec1value R ::= 0
292            let val = 0.0;
293            let expected = &[0x09, 0x0];
294            let mut buffer = [0u8; 2];
295            let encoded = val.encode_to_slice(&mut buffer).unwrap();
296            assert_eq!(
297                expected, encoded,
298                "invalid encoding of {val}:\ngot  {encoded:x?}\nwant: {expected:x?}"
299            );
300            let decoded = f64::from_der(encoded).unwrap();
301            assert!(
302                (decoded - val).abs() < f64::EPSILON,
303                "wanted: {val}\tgot: {decoded}"
304            );
305        }
306
307        {
308            // rec1value R ::= { mantissa 1, base 2, exponent 0 }
309            let val = 1.0;
310            let expected = &[0x09, 0x03, 0x80, 0x00, 0x01];
311            let mut buffer = [0u8; 5];
312            let encoded = val.encode_to_slice(&mut buffer).unwrap();
313            assert_eq!(
314                expected, encoded,
315                "invalid encoding of {val}:\ngot  {encoded:x?}\nwant: {expected:x?}"
316            );
317            let decoded = f64::from_der(encoded).unwrap();
318            assert!(
319                (decoded - val).abs() < f64::EPSILON,
320                "wanted: {val}\tgot: {decoded}"
321            );
322        }
323
324        {
325            // rec1value R ::= { mantissa -1, base 2, exponent 0 }
326            let val = -1.0;
327            let expected = &[0x09, 0x03, 0xc0, 0x00, 0x01];
328            let mut buffer = [0u8; 5];
329            let encoded = val.encode_to_slice(&mut buffer).unwrap();
330            assert_eq!(
331                expected, encoded,
332                "invalid encoding of {val}:\ngot  {encoded:x?}\nwant: {expected:x?}"
333            );
334            let decoded = f64::from_der(encoded).unwrap();
335            assert!(
336                (decoded - val).abs() < f64::EPSILON,
337                "wanted: {val}\tgot: {decoded}"
338            );
339        }
340
341        {
342            // rec1value R ::= { mantissa -1, base 2, exponent 1 }
343            let val = -1.0000000000000002;
344            let expected = &[0x09, 0x03, 0xc0, 0x00, 0x02];
345            let mut buffer = [0u8; 5];
346            let encoded = val.encode_to_slice(&mut buffer).unwrap();
347            assert_eq!(
348                expected, encoded,
349                "invalid encoding of {val}:\ngot  {encoded:x?}\nwant: {expected:x?}"
350            );
351            let decoded = f64::from_der(encoded).unwrap();
352            assert!(
353                (decoded - val).abs() < f64::EPSILON,
354                "wanted: {val}\tgot: {decoded}"
355            );
356        }
357
358        {
359            // rec1value R ::= { mantissa 1, base 2, exponent -1022 }
360            // NOTE: f64::MIN_EXP == -1021 so the exponent decoded by ASN.1 is what we expect
361            let val = f64::MIN_POSITIVE;
362            let expected = &[0x09, 0x04, 0x81, 0xfc, 0x02, 0x01];
363            let mut buffer = [0u8; 7];
364            let encoded = val.encode_to_slice(&mut buffer).unwrap();
365            assert_eq!(
366                expected, encoded,
367                "invalid encoding of {val}:\ngot  {encoded:x?}\nwant: {expected:x?}"
368            );
369            let decoded = f64::from_der(encoded).unwrap();
370            assert!(
371                (decoded - val).abs() < f64::EPSILON,
372                "wanted: {val}\tgot: {decoded}"
373            );
374        }
375
376        {
377            // rec4value R ::= { mantissa 1, base 2, exponent 3 }
378            let val = 1.0000000000000016;
379            let expected = &[0x09, 0x03, 0x80, 0x00, 0x08];
380            let mut buffer = [0u8; 5];
381            let encoded = val.encode_to_slice(&mut buffer).unwrap();
382            assert_eq!(
383                expected, encoded,
384                "invalid encoding of {val}:\ngot  {encoded:x?}\nwant: {expected:x?}"
385            );
386            let decoded = f64::from_der(encoded).unwrap();
387            assert!(
388                (decoded - val).abs() < f64::EPSILON,
389                "wanted: {val}\tgot: {decoded}"
390            );
391        }
392
393        {
394            // rec5value R ::= { mantissa 4222124650659841, base 2, exponent 4 }
395            let val = 31.0;
396            let expected = &[
397                0x9, 0x9, 0x80, 0x04, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
398            ];
399            let mut buffer = [0u8; 11];
400            let encoded = val.encode_to_slice(&mut buffer).unwrap();
401            assert_eq!(
402                expected, encoded,
403                "invalid encoding of {val}:\ngot  {encoded:x?}\nwant: {expected:x?}"
404            );
405            let decoded = f64::from_der(encoded).unwrap();
406            assert!(
407                (decoded - val).abs() < f64::EPSILON,
408                "wanted: {val}\tgot: {decoded}"
409            );
410        }
411    }
412
413    #[test]
414    fn encdec_irrationals() {
415        {
416            let val = core::f64::consts::PI;
417            let expected = &[
418                0x09, 0x09, 0x80, 0x01, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2d, 0x19,
419            ];
420            let mut buffer = [0u8; 11];
421            let encoded = val.encode_to_slice(&mut buffer).unwrap();
422            assert_eq!(
423                expected, encoded,
424                "invalid encoding of {val}:\ngot  {encoded:x?}\nwant: {expected:x?}"
425            );
426            let decoded = f64::from_der(encoded).unwrap();
427            assert!(
428                (decoded - val).abs() < f64::EPSILON,
429                "wanted: {val}\tgot: {decoded}"
430            );
431        }
432
433        {
434            let val = core::f64::consts::E;
435            let expected = &[
436                0x09, 0x09, 0x80, 0x01, 0x05, 0xbf, 0x0a, 0x8b, 0x14, 0x57, 0x6a,
437            ];
438            let mut buffer = [0u8; 12];
439            let encoded = val.encode_to_slice(&mut buffer).unwrap();
440            assert_eq!(
441                expected, encoded,
442                "invalid encoding of {val}:\ngot  {encoded:x?}\nwant: {expected:x?}"
443            );
444            let decoded = f64::from_der(encoded).unwrap();
445            assert!(
446                (decoded - val).abs() < f64::EPSILON,
447                "wanted: {val}\tgot: {decoded}"
448            );
449        }
450        {
451            let val = core::f64::consts::LN_2;
452            let expected = &[
453                0x09, 0x0a, 0x81, 0xff, 0xff, 0x6, 0x2e, 0x42, 0xfe, 0xfa, 0x39, 0xf0,
454            ];
455            let mut buffer = [0u8; 12];
456            let encoded = val.encode_to_slice(&mut buffer).unwrap();
457            assert_eq!(
458                expected, encoded,
459                "invalid encoding of {val}:\ngot  {encoded:x?}\nwant: {expected:x?}"
460            );
461            let decoded = f64::from_der(encoded).unwrap();
462            assert!(
463                (decoded - val).abs() < f64::EPSILON,
464                "wanted: {val}\tgot: {decoded}"
465            );
466        }
467    }
468
469    #[test]
470    fn encdec_reasonable_f64() {
471        // Tests the encoding and decoding of reals with some arbitrary numbers
472        {
473            // rec1value R ::= { mantissa 2414341043715239, base 2, exponent 21 }
474            let val = 3221417.1584163485;
475            let expected = &[
476                0x9, 0x9, 0x80, 0x15, 0x8, 0x93, 0xd4, 0x94, 0x46, 0xfc, 0xa7,
477            ];
478            let mut buffer = [0u8; 11];
479            let encoded = val.encode_to_slice(&mut buffer).unwrap();
480            assert_eq!(
481                expected, encoded,
482                "invalid encoding of {val}:\ngot  {encoded:x?}\nwant: {expected:x?}"
483            );
484            let decoded = f64::from_der(encoded).unwrap();
485            assert!(
486                (decoded - val).abs() < f64::EPSILON,
487                "wanted: {val}\tgot: {decoded}"
488            );
489        }
490
491        {
492            // rec1value R ::= { mantissa 2671155248072715, base 2, exponent 23 }
493            let val = 13364022.365665454;
494            let expected = &[
495                0x09, 0x09, 0x80, 0x17, 0x09, 0x7d, 0x66, 0xcb, 0xb3, 0x88, 0x0b,
496            ];
497            let mut buffer = [0u8; 12];
498            let encoded = val.encode_to_slice(&mut buffer).unwrap();
499            assert_eq!(
500                expected, encoded,
501                "invalid encoding of {val}:\ngot  {encoded:x?}\nwant: {expected:x?}"
502            );
503            let decoded = f64::from_der(encoded).unwrap();
504            assert!(
505                (decoded - val).abs() < f64::EPSILON,
506                "wanted: {val}\tgot: {decoded}"
507            );
508        }
509
510        {
511            // rec1value R ::= { mantissa -4386812962460287, base 2, exponent 14 }
512            let val = -32343.132588105735;
513            let expected = &[
514                0x09, 0x09, 0xc0, 0x0e, 0x0f, 0x95, 0xc8, 0x7c, 0x52, 0xd2, 0x7f,
515            ];
516            let mut buffer = [0u8; 12];
517            let encoded = val.encode_to_slice(&mut buffer).unwrap();
518            assert_eq!(
519                expected, encoded,
520                "invalid encoding of {val}:\ngot  {encoded:x?}\nwant: {expected:x?}"
521            );
522            let decoded = f64::from_der(encoded).unwrap();
523            assert!(
524                (decoded - val).abs() < f64::EPSILON,
525                "wanted: {val}\tgot: {decoded}"
526            );
527        }
528
529        {
530            let val = -27084.866751869475;
531            let expected = &[
532                0x09, 0x09, 0xc0, 0x0e, 0x0a, 0x73, 0x37, 0x78, 0xdc, 0xd5, 0x4a,
533            ];
534            let mut buffer = [0u8; 12];
535            let encoded = val.encode_to_slice(&mut buffer).unwrap();
536            assert_eq!(
537                expected, encoded,
538                "invalid encoding of {val}:\ngot  {encoded:x?}\nwant: {expected:x?}"
539            );
540            let decoded = f64::from_der(encoded).unwrap();
541            assert!(
542                (decoded - val).abs() < f64::EPSILON,
543                "wanted: {val}\tgot: {decoded}"
544            );
545        }
546
547        {
548            // rec1value R ::= { mantissa -4372913134428149, base 2, exponent 7 }
549            let val = -252.28566647111404;
550            let expected = &[
551                0x09, 0x09, 0xc0, 0x07, 0x0f, 0x89, 0x24, 0x2e, 0x02, 0xdf, 0xf5,
552            ];
553            let mut buffer = [0u8; 12];
554            let encoded = val.encode_to_slice(&mut buffer).unwrap();
555            assert_eq!(
556                expected, encoded,
557                "invalid encoding of {val}:\ngot  {encoded:x?}\nwant: {expected:x?}"
558            );
559            let decoded = f64::from_der(encoded).unwrap();
560            assert!(
561                (decoded - val).abs() < f64::EPSILON,
562                "wanted: {val}\tgot: {decoded}"
563            );
564        }
565
566        {
567            let val = -14.399709612928548;
568            let expected = &[
569                0x09, 0x09, 0xc0, 0x03, 0x0c, 0xcc, 0xa6, 0xbd, 0x06, 0xd9, 0x92,
570            ];
571            let mut buffer = [0u8; 12];
572            let encoded = val.encode_to_slice(&mut buffer).unwrap();
573            assert_eq!(
574                expected, encoded,
575                "invalid encoding of {val}:\ngot  {encoded:x?}\nwant: {expected:x?}"
576            );
577            let decoded = f64::from_der(encoded).unwrap();
578            assert!(
579                (decoded - val).abs() < f64::EPSILON,
580                "wanted: {val}\tgot: {decoded}"
581            );
582        }
583
584        {
585            let val = -0.08340570261832964;
586            let expected = &[
587                0x09, 0x0a, 0xc1, 0xff, 0xfc, 0x05, 0x5a, 0x13, 0x7d, 0x0b, 0xae, 0x3d,
588            ];
589            let mut buffer = [0u8; 12];
590            let encoded = val.encode_to_slice(&mut buffer).unwrap();
591            assert_eq!(
592                expected, encoded,
593                "invalid encoding of {val}:\ngot  {encoded:x?}\nwant: {expected:x?}"
594            );
595            let decoded = f64::from_der(encoded).unwrap();
596            assert!(
597                (decoded - val).abs() < f64::EPSILON,
598                "wanted: {val}\tgot: {decoded}"
599            );
600        }
601
602        {
603            let val = 0.00536851453803701;
604            let expected = &[
605                0x09, 0x0a, 0x81, 0xff, 0xf8, 0x05, 0xfd, 0x4b, 0xa5, 0xe7, 0x4c, 0x93,
606            ];
607            let mut buffer = [0u8; 12];
608            let encoded = val.encode_to_slice(&mut buffer).unwrap();
609            assert_eq!(
610                expected, encoded,
611                "invalid encoding of {val}:\ngot  {encoded:x?}\nwant: {expected:x?}"
612            );
613            let decoded = f64::from_der(encoded).unwrap();
614            assert!(
615                (decoded - val).abs() < f64::EPSILON,
616                "wanted: {val}\tgot: {decoded}"
617            );
618        }
619
620        {
621            let val = 0.00045183525648866433;
622            let expected = &[
623                0x09, 0x0a, 0x81, 0xff, 0xf4, 0x0d, 0x9c, 0x89, 0xa6, 0x59, 0x33, 0x39,
624            ];
625            let mut buffer = [0u8; 12];
626            let encoded = val.encode_to_slice(&mut buffer).unwrap();
627            assert_eq!(
628                expected, encoded,
629                "invalid encoding of {val}:\ngot  {encoded:x?}\nwant: {expected:x?}"
630            );
631            let decoded = f64::from_der(encoded).unwrap();
632            assert!(
633                (decoded - val).abs() < f64::EPSILON,
634                "wanted: {val}\tgot: {decoded}"
635            );
636        }
637
638        {
639            let val = 0.000033869092002682955;
640            let expected = &[
641                0x09, 0x0a, 0x81, 0xff, 0xf1, 0x01, 0xc1, 0xd5, 0x23, 0xd5, 0x54, 0x7c,
642            ];
643            let mut buffer = [0u8; 12];
644            let encoded = val.encode_to_slice(&mut buffer).unwrap();
645            assert_eq!(
646                expected, encoded,
647                "invalid encoding of {val}:\ngot  {encoded:x?}\nwant: {expected:x?}"
648            );
649            let decoded = f64::from_der(encoded).unwrap();
650            assert!(
651                (decoded - val).abs() < f64::EPSILON,
652                "wanted: {val}\tgot: {decoded}"
653            );
654        }
655
656        {
657            let val = 0.0000011770891033600088;
658            let expected = &[
659                0x09, 0x0a, 0x81, 0xff, 0xec, 0x03, 0xbf, 0x8f, 0x27, 0xf4, 0x62, 0x56,
660            ];
661            let mut buffer = [0u8; 12];
662            let encoded = val.encode_to_slice(&mut buffer).unwrap();
663            assert_eq!(
664                expected, encoded,
665                "invalid encoding of {val}:\ngot  {encoded:x?}\nwant: {expected:x?}"
666            );
667            let decoded = f64::from_der(encoded).unwrap();
668            assert!(
669                (decoded - val).abs() < f64::EPSILON,
670                "wanted: {val}\tgot: {decoded}"
671            );
672        }
673
674        {
675            let val = 0.00000005549514041997082;
676            let expected = &[
677                0x09, 0x0a, 0x81, 0xff, 0xe7, 0x0d, 0xcb, 0x31, 0xab, 0x6e, 0xb8, 0xd7,
678            ];
679            let mut buffer = [0u8; 12];
680            let encoded = val.encode_to_slice(&mut buffer).unwrap();
681            assert_eq!(
682                expected, encoded,
683                "invalid encoding of {val}:\ngot  {encoded:x?}\nwant: {expected:x?}"
684            );
685            let decoded = f64::from_der(encoded).unwrap();
686            assert!(
687                (decoded - val).abs() < f64::EPSILON,
688                "wanted: {val}\tgot: {decoded}"
689            );
690        }
691
692        {
693            let val = 0.0000000012707044685547803;
694            let expected = &[
695                0x09, 0x0a, 0x81, 0xff, 0xe2, 0x05, 0xd4, 0x9e, 0x0a, 0xf2, 0xff, 0x1f,
696            ];
697            let mut buffer = [0u8; 12];
698            let encoded = val.encode_to_slice(&mut buffer).unwrap();
699            assert_eq!(
700                expected, encoded,
701                "invalid encoding of {val}:\ngot  {encoded:x?}\nwant: {expected:x?}"
702            );
703            let decoded = f64::from_der(encoded).unwrap();
704            assert!(
705                (decoded - val).abs() < f64::EPSILON,
706                "wanted: {val}\tgot: {decoded}"
707            );
708        }
709
710        {
711            let val = 0.00000000002969611878378562;
712            let expected = &[
713                0x09, 0x09, 0x81, 0xff, 0xdd, 0x53, 0x5b, 0x6f, 0x97, 0xee, 0xb6,
714            ];
715            let mut buffer = [0u8; 11];
716            let encoded = val.encode_to_slice(&mut buffer).unwrap();
717            assert_eq!(
718                expected, encoded,
719                "invalid encoding of {val}:\ngot  {encoded:x?}\nwant: {expected:x?}"
720            );
721            let decoded = f64::from_der(encoded).unwrap();
722            assert!(
723                (decoded - val).abs() < f64::EPSILON,
724                "wanted: {val}\tgot: {decoded}"
725            );
726        }
727    }
728
729    #[test]
730    fn reject_non_canonical() {
731        assert!(f64::from_der(&[0x09, 0x81, 0x00]).is_err());
732    }
733
734    #[test]
735    fn encdec_f64() {
736        use super::{decode_f64, encode_f64};
737        // Test that the extraction and recreation works
738        for val in [
739            1.0,
740            0.1,
741            -0.1,
742            -1.0,
743            0.0,
744            f64::MIN_POSITIVE,
745            f64::MAX,
746            f64::MIN,
747            core::f64::consts::PI,
748            -core::f64::consts::PI,
749            951.2357864,
750            -951.2357864,
751        ] {
752            let (s, e, m) = decode_f64(val);
753            let val2 = encode_f64(s, e, m);
754            assert!(
755                (val - val2).abs() < f64::EPSILON,
756                "fail - want {val}\tgot {val2}"
757            );
758        }
759    }
760
761    #[test]
762    fn validation_cases() {
763        // Caveat: these test cases are validated on the ASN.1 playground: https://asn1.io/asn1playground/ .
764        // The test case consists in inputting the bytes in the "decode" field and checking that the decoded
765        // value corresponds to the one encoded here.
766        // This tool encodes _all_ values that are non-zero in the ISO 6093 NR3 representation.
767        // This does not seem to perfectly adhere to the ITU specifications, Special Cases section.
768        // The implementation of this crate correctly supports decoding such values. It will, however,
769        // systematically encode REALs in their base 2 form, with a scaling factor where needed to
770        // ensure that the mantissa is either odd or zero (as per section 11.3.1).
771
772        // Positive trivial numbers
773        {
774            let expect = 10.0;
775            let testcase = &[0x09, 0x05, 0x03, 0x31, 0x2E, 0x45, 0x31];
776            let decoded = f64::from_der(testcase).unwrap();
777            assert!(
778                (decoded - expect).abs() < f64::EPSILON,
779                "wanted: {expect}\tgot: {decoded}"
780            );
781        }
782        {
783            let expect = 100.0;
784            let testcase = &[0x09, 0x05, 0x03, 0x31, 0x2E, 0x45, 0x32];
785            let decoded = f64::from_der(testcase).unwrap();
786            assert!(
787                (decoded - expect).abs() < f64::EPSILON,
788                "wanted: {expect}\tgot: {decoded}"
789            );
790        }
791        {
792            let expect = 101.0;
793            let testcase = &[0x09, 0x08, 0x03, 0x31, 0x30, 0x31, 0x2E, 0x45, 0x2B, 0x30];
794            let decoded = f64::from_der(testcase).unwrap();
795            assert!(
796                (decoded - expect).abs() < f64::EPSILON,
797                "wanted: {expect}\tgot: {decoded}"
798            );
799        }
800        {
801            let expect = 101.0;
802            let testcase = &[0x09, 0x08, 0x03, 0x31, 0x30, 0x31, 0x2E, 0x45, 0x2B, 0x30];
803            let decoded = f64::from_der(testcase).unwrap();
804            assert!(
805                (decoded - expect).abs() < f64::EPSILON,
806                "wanted: {expect}\tgot: {decoded}"
807            );
808        }
809        {
810            let expect = 0.0;
811            let testcase = &[0x09, 0x00];
812            let decoded = f64::from_der(testcase).unwrap();
813            assert!(
814                (decoded - expect).abs() < f64::EPSILON,
815                "wanted: {expect}\tgot: {decoded}"
816            );
817        }
818        {
819            let expect = 951.2357864;
820            let testcase = &[
821                0x09, 0x0F, 0x03, 0x39, 0x35, 0x31, 0x32, 0x33, 0x35, 0x37, 0x38, 0x36, 0x34, 0x2E,
822                0x45, 0x2D, 0x37,
823            ];
824            let decoded = f64::from_der(testcase).unwrap();
825            assert!(
826                (decoded - expect).abs() < f64::EPSILON,
827                "wanted: {expect}\tgot: {decoded}"
828            );
829        }
830        // Negative trivial numbers
831        {
832            let expect = -10.0;
833            let testcase = &[0x09, 0x06, 0x03, 0x2D, 0x31, 0x2E, 0x45, 0x31];
834            let decoded = f64::from_der(testcase).unwrap();
835            assert!(
836                (decoded - expect).abs() < f64::EPSILON,
837                "wanted: {expect}\tgot: {decoded}"
838            );
839        }
840        {
841            let expect = -100.0;
842            let testcase = &[0x09, 0x06, 0x03, 0x2D, 0x31, 0x2E, 0x45, 0x32];
843            let decoded = f64::from_der(testcase).unwrap();
844            assert!(
845                (decoded - expect).abs() < f64::EPSILON,
846                "wanted: {expect}\tgot: {decoded}"
847            );
848        }
849        {
850            let expect = -101.0;
851            let testcase = &[
852                0x09, 0x09, 0x03, 0x2D, 0x31, 0x30, 0x31, 0x2E, 0x45, 0x2B, 0x30,
853            ];
854            let decoded = f64::from_der(testcase).unwrap();
855            assert!(
856                (decoded - expect).abs() < f64::EPSILON,
857                "wanted: {expect}\tgot: {decoded}"
858            );
859        }
860        {
861            let expect = -0.5;
862            let testcase = &[0x09, 0x07, 0x03, 0x2D, 0x35, 0x2E, 0x45, 0x2D, 0x31];
863            let decoded = f64::from_der(testcase).unwrap();
864            assert!(
865                (decoded - expect).abs() < f64::EPSILON,
866                "wanted: {expect}\tgot: {decoded}"
867            );
868        }
869        {
870            let expect = -0.0;
871            let testcase = &[0x09, 0x03, 0x01, 0x2D, 0x30];
872            let decoded = f64::from_der(testcase).unwrap();
873            assert!(
874                (decoded - expect).abs() < f64::EPSILON,
875                "wanted: {expect}\tgot: {decoded}"
876            );
877        }
878        {
879            // Test NR3 decoding
880            let expect = -951.2357864;
881            let testcase = &[
882                0x09, 0x10, 0x03, 0x2D, 0x39, 0x35, 0x31, 0x32, 0x33, 0x35, 0x37, 0x38, 0x36, 0x34,
883                0x2E, 0x45, 0x2D, 0x37,
884            ];
885            let decoded = f64::from_der(testcase).unwrap();
886            assert!(
887                (decoded - expect).abs() < f64::EPSILON,
888                "wanted: {expect}\tgot: {decoded}"
889            );
890        }
891    }
892}