OXYGENHUB

Coverage / crates/spectra-core/src/cbor.rs 90.7%

175 of 193 lines run, 44 of 52 functions · run #30 on main · run missed

1
//! Deterministic CBOR (RFC 8949 §4.2), as much of it as Spectra encodes:
2
//! unsigned integers, byte and text strings, arrays, maps with integer
3
//! keys, null and booleans. Shortest forms, definite lengths, map keys in
4
//! ascending order; the decoder refuses anything else, so one value has
5
//! exactly one encoding and hashing it is meaningful (spec §9.5).
6
7
use std::collections::BTreeMap;
8
9
#[derive(Clone, Debug, PartialEq, Eq)]
10
pub enum Value {
11
    Uint(u64),
12
    Bytes(Vec<u8>),
13
    Text(String),
14
    Array(Vec<Value>),
15
    Map(BTreeMap<u64, Value>),
16
    Bool(bool),
17
    Null,
18
}
19
20
impl Value {
2165132×
    pub fn map<const N: usize>(entries: [(u64, Value); N]) -> Value {
2265132×
        Value::Map(entries.into_iter().collect())
2365132×
    }
244477×
    pub fn as_uint(&self) -> Option<u64> {
254477×
        match self {
264477×
            Value::Uint(u) => Some(*u),
270×
            _ => None,
28
        }
294477×
    }
3011800×
    pub fn as_bytes(&self) -> Option<&[u8]> {
3111800×
        match self {
3211800×
            Value::Bytes(b) => Some(b),
330×
            _ => None,
34
        }
3511800×
    }
364063×
    pub fn as_text(&self) -> Option<&str> {
374063×
        match self {
384063×
            Value::Text(t) => Some(t),
390×
            _ => None,
40
        }
414063×
    }
421543×
    pub fn as_array(&self) -> Option<&[Value]> {
431543×
        match self {
441543×
            Value::Array(a) => Some(a),
450×
            _ => None,
46
        }
471543×
    }
485277×
    pub fn as_map(&self) -> Option<&BTreeMap<u64, Value>> {
495277×
        match self {
505277×
            Value::Map(m) => Some(m),
510×
            _ => None,
52
        }
535277×
    }
540×
    pub fn is_null(&self) -> bool {
550×
        matches!(self, Value::Null)
560×
    }
57
}
58
59954627×
fn head(out: &mut Vec<u8>, major: u8, n: u64) {
60954627×
    let m = major << 5;
61954627×
    match n {
62954627×
        0..=23 => out.push(m | n as u8),
63182820×
        24..=0xff => out.extend_from_slice(&[m | 24, n as u8]),
6486762×
        0x100..=0xffff => {
6530277×
            out.push(m | 25);
6630277×
            out.extend_from_slice(&(n as u16).to_be_bytes());
6730277×
        }
6856485×
        0x1_0000..=0xffff_ffff => {
690×
            out.push(m | 26);
700×
            out.extend_from_slice(&(n as u32).to_be_bytes());
710×
        }
7256485×
        _ => {
7356485×
            out.push(m | 27);
7456485×
            out.extend_from_slice(&n.to_be_bytes());
7556485×
        }
76
    }
77954627×
}
78
79588888×
fn put(out: &mut Vec<u8>, v: &Value) {
80588888×
    match v {
81183366×
        Value::Uint(n) => head(out, 0, *n),
8281635×
        Value::Bytes(b) => {
8381635×
            head(out, 2, b.len() as u64);
8481635×
            out.extend_from_slice(b);
8581635×
        }
8691554×
        Value::Text(t) => {
8791554×
            head(out, 3, t.len() as u64);
8891554×
            out.extend_from_slice(t.as_bytes());
8991554×
        }
9032388×
        Value::Array(a) => {
9132388×
            head(out, 4, a.len() as u64);
9255104×
            for x in a {
9355104×
                put(out, x);
9455104×
            }
95
        }
96
        // BTreeMap iterates keys ascending, which for unsigned integers is
97
        // the order of their shortest encodings.
9865132×
        Value::Map(m) => {
9965132×
            head(out, 5, m.len() as u64);
100500552×
            for (k, x) in m {
101500552×
                head(out, 0, *k);
102500552×
                put(out, x);
103500552×
            }
104
        }
1050×
        Value::Bool(false) => out.push(0xf4),
1061×
        Value::Bool(true) => out.push(0xf5),
107134812×
        Value::Null => out.push(0xf6),
108
    }
109588888×
}
110
11133232×
pub fn encode(v: &Value) -> Vec<u8> {
11233232×
    let mut out = Vec::new();
11333232×
    put(&mut out, v);
11433232×
    out
11533232×
}
116
117
/// Why bytes are not a value Spectra encodes.
118
#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]
119
#[error("malformed CBOR: {0}")]
120
pub struct Error(pub String);
121
122
struct Reader<'a> {
123
    b: &'a [u8],
124
    at: usize,
125
    depth: usize,
126
}
127
128
const MAX_DEPTH: usize = 32;
129
130
impl<'a> Reader<'a> {
13186298×
    fn take(&mut self, n: usize) -> Result<&'a [u8], Error> {
13286298×
        let end = self.at.checked_add(n).filter(|e| *e <= self.b.len()).ok_or_else(|| Error("truncated".into()))?;
13386298×
        let s = &self.b[self.at..end];
13486298×
        self.at = end;
13586298×
        Ok(s)
13686298×
    }
137
13857059×
    fn head(&mut self) -> Result<(u8, u64), Error> {
13957059×
        let first = self.take(1)?[0];
14057059×
        let (major, info) = (first >> 5, first & 0x1f);
14157058×
        let n = match info {
14257059×
            0..=23 => info as u64,
1438046×
            24 => self.take(1)?[0] as u64,
1442782×
            25 => u16::from_be_bytes(self.take(2)?.try_into().unwrap()) as u64,
1451×
            26 => u32::from_be_bytes(self.take(4)?.try_into().unwrap()) as u64,
1462545×
            27 => u64::from_be_bytes(self.take(8)?.try_into().unwrap()),
1471×
            _ if major == 7 => return Ok((7, info as u64)),
1481×
            _ => return Err(Error("an indefinite length or a reserved form".into())),
149
        };
15057058×
        let minimal = match info {
1518046×
            24 => n >= 24,
1522782×
            25 => n > 0xff,
1531×
            26 => n > 0xffff,
1542545×
            27 => n > 0xffff_ffff,
15543684×
            _ => true,
156
        };
15757058×
        if !minimal && major != 7 {
1581×
            return Err(Error("a length or number not in its shortest form".into()));
15957057×
        }
16057057×
        Ok((major, n))
16157059×
    }
162
16322721×
    fn len(&mut self, n: u64) -> Result<usize, Error> {
16422721×
        let n = usize::try_from(n).map_err(|_| Error("too long".into()))?;
16522721×
        if n > self.b.len() - self.at {
1661×
            return Err(Error("truncated".into()));
16722720×
        }
16822720×
        Ok(n)
16922721×
    }
170
17130701×
    fn value(&mut self) -> Result<Value, Error> {
17230701×
        self.depth += 1;
17330701×
        if self.depth > MAX_DEPTH {
1741×
            return Err(Error("nested too deeply".into()));
17530700×
        }
17630700×
        let (major, n) = self.head()?;
17730698×
        let v = match major {
1784507×
            0 => Value::Uint(n),
179
            2 => {
18011802×
                let l = self.len(n)?;
18111801×
                Value::Bytes(self.take(l)?.to_vec())
182
            }
183
            3 => {
1844064×
                let l = self.len(n)?;
1854064×
                Value::Text(String::from_utf8(self.take(l)?.to_vec()).map_err(|_| Error("text that is not UTF-8".into()))?)
186
            }
187
            4 => {
1881576×
                let l = self.len(n)?;
1891576×
                let mut a = Vec::with_capacity(l);
1901576×
                for _ in 0..l {
1911140×
                    a.push(self.value()?);
192
                }
1931544×
                Value::Array(a)
194
            }
195
            5 => {
1965279×
                let l = self.len(n)?;
1975279×
                let mut m = BTreeMap::new();
1985279×
                let mut last: Option<u64> = None;
1995279×
                for _ in 0..l {
20026359×
                    let (km, k) = self.head()?;
20126359×
                    if km != 0 {
2020×
                        return Err(Error("a map key that is not an unsigned integer".into()));
20326359×
                    }
20426359×
                    if last.is_some_and(|p| k <= p) {
2051×
                        return Err(Error("map keys out of order or repeated".into()));
20626358×
                    }
20726358×
                    last = Some(k);
20826358×
                    m.insert(k, self.value()?);
209
                }
2105278×
                Value::Map(m)
211
            }
2123469×
            7 => match n {
2130×
                20 => Value::Bool(false),
2141×
                21 => Value::Bool(true),
2153468×
                22 => Value::Null,
2160×
                _ => return Err(Error("an unsupported simple value or float".into())),
217
            },
2181×
            _ => return Err(Error("a negative integer or a tag".into())),
219
        };
22030663×
        self.depth -= 1;
22130663×
        Ok(v)
22230701×
    }
223
}
224
225
/// Decode exactly one value, refusing any non-canonical encoding.
2263203×
pub fn decode(b: &[u8]) -> Result<Value, Error> {
2273203×
    let mut r = Reader { b, at: 0, depth: 0 };
2283203×
    let v = r.value()?;
2293197×
    if r.at != b.len() {
2301×
        return Err(Error("bytes after the value".into()));
2313196×
    }
2323196×
    Ok(v)
2333203×
}
234
235
#[cfg(test)]
236
mod tests {
237
    use super::*;
238
239
    #[test]
2401×
    fn round_trips_and_known_encodings() {
2411×
        let v = Value::map([
2421×
            (0, Value::Uint(1)),
2431×
            (1, Value::Text("é".into())),
2441×
            (2, Value::Bytes(vec![1, 2])),
2451×
            (3, Value::Array(vec![Value::Null, Value::Bool(true), Value::Uint(500)])),
2461×
            (24, Value::Uint(u64::MAX)),
2471×
        ]);
2481×
        let b = encode(&v);
2491×
        assert_eq!(decode(&b).unwrap(), v);
2501×
        assert_eq!(encode(&Value::Uint(23)), [0x17]);
2511×
        assert_eq!(encode(&Value::Uint(24)), [0x18, 24]);
2521×
        assert_eq!(encode(&Value::Uint(1000)), [0x19, 0x03, 0xe8]);
2531×
        assert_eq!(encode(&Value::Text("a".into())), [0x61, b'a']);
2541×
    }
255
256
    #[test]
2571×
    fn refuses_what_is_not_canonical() {
2581×
        assert!(decode(&[0x18, 5]).is_err(), "5 in two bytes");
2591×
        assert!(decode(&[0xa2, 0x01, 0x00, 0x00, 0x00]).is_err(), "keys out of order");
2601×
        assert!(decode(&[0x5f]).is_err(), "indefinite length");
2611×
        assert!(decode(&[0x01, 0x02]).is_err(), "trailing bytes");
2621×
        assert!(decode(&[0x5a, 0xff, 0xff, 0xff, 0xff]).is_err(), "truncated");
2631×
        assert!(decode(&[0x20]).is_err(), "negative");
2641×
        let deep = [0x81u8; 64];
2651×
        assert!(decode(&deep).is_err(), "too deep");
2661×
    }
267
}