ssi_status/impl/bitstring_status_list/syntax/
mod.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
use std::io::{Read, Write};

use flate2::{read::GzDecoder, write::GzEncoder, Compression};
use multibase::Base;
use serde::{Deserialize, Serialize};

mod status_list;
pub use status_list::*;

mod entry_set;
pub use entry_set::*;

/// Multibase-encoded base64url (with no padding) representation of the
/// GZIP-compressed bitstring values for the associated range of a bitstring
/// status list verifiable credential.
#[derive(Debug, Serialize, Deserialize)]
#[serde(transparent)]
pub struct EncodedList(String);

impl EncodedList {
    /// Minimum bitstring size (16KB).
    pub const MINIMUM_SIZE: usize = 16 * 1024;

    /// Default maximum bitstring size allowed by the `decode` function.
    ///
    /// 16MB.
    pub const DEFAULT_LIMIT: u64 = 16 * 1024 * 1024;

    pub fn new(value: String) -> Self {
        Self(value)
    }

    pub fn encode(bytes: &[u8]) -> Self {
        let mut encoder = GzEncoder::new(Vec::new(), Compression::default());
        encoder.write_all(bytes).unwrap();

        // Add padding to satisfy the minimum bitstring size constraint.
        const PADDING_BUFFER_LEN: usize = 1024;
        let padding = [0; PADDING_BUFFER_LEN];
        let mut it = (bytes.len()..Self::MINIMUM_SIZE)
            .step_by(PADDING_BUFFER_LEN)
            .peekable();
        while let Some(start) = it.next() {
            let end = it.peek().copied().unwrap_or(Self::MINIMUM_SIZE);
            let len = end - start;
            encoder.write_all(&padding[..len]).unwrap();
        }

        let compressed = encoder.finish().unwrap();
        Self(multibase::encode(Base::Base64Url, compressed))
    }

    pub fn decode(&self, limit: Option<u64>) -> Result<Vec<u8>, DecodeError> {
        let limit = limit.unwrap_or(Self::DEFAULT_LIMIT);
        let (_base, compressed) = multibase::decode(&self.0)?;
        let mut decoder = GzDecoder::new(compressed.as_slice()).take(limit);
        let mut bytes = Vec::new();
        decoder.read_to_end(&mut bytes).map_err(DecodeError::Gzip)?;
        Ok(bytes)
    }
}