forest_cid/
lib.rs

1// Copyright 2020 ChainSafe Systems
2// SPDX-License-Identifier: Apache-2.0, MIT
3
4mod mh_code;
5mod prefix;
6mod to_cid;
7
8pub use self::mh_code::{Code, Multihash, POSEIDON_BLS12_381_A1_FC1, SHA2_256_TRUNC254_PADDED};
9pub use self::prefix::Prefix;
10use cid::CidGeneric;
11pub use cid::{Error, Version};
12pub use multihash;
13use multihash::MultihashDigest;
14use std::convert::TryFrom;
15use std::fmt;
16
17#[cfg(feature = "cbor")]
18use serde::{de, ser};
19#[cfg(feature = "cbor")]
20use serde_cbor::tags::Tagged;
21
22#[cfg(feature = "cbor")]
23const CBOR_TAG_CID: u64 = 42;
24/// multibase identity prefix
25/// https://github.com/ipld/specs/blob/master/block-layer/codecs/dag-cbor.md#link-format
26#[cfg(feature = "cbor")]
27const MULTIBASE_IDENTITY: u8 = 0;
28
29#[cfg(feature = "json")]
30pub mod json;
31
32pub const DAG_CBOR: u64 = 0x71;
33pub const FIL_COMMITMENT_SEALED: u64 = 0xf102;
34pub const FIL_COMMITMENT_UNSEALED: u64 = 0xf101;
35pub const RAW: u64 = 0x55;
36
37/// Constructs a cid with bytes using default version and codec
38pub fn new_from_cbor(bz: &[u8], code: Code) -> Cid {
39    let hash = code.digest(bz);
40    Cid::new_v1(DAG_CBOR, hash)
41}
42
43/// Create a new CID from a prefix and some data.
44pub fn new_from_prefix(prefix: &Prefix, data: &[u8]) -> Result<Cid, Error> {
45    let hash: Multihash = Code::try_from(prefix.mh_type)?.digest(data);
46    Cid::new(prefix.version, prefix.codec, hash)
47}
48
49#[derive(PartialEq, Eq, Clone, Copy, Default, Hash, PartialOrd, Ord)]
50pub struct Cid(CidGeneric<multihash::U32>);
51
52// This is just a wrapper around the rust-cid `Cid` type that is needed in order to make the
53// interaction with Serde smoother.
54impl Cid {
55    /// Create a new CID.
56    pub fn new(version: Version, codec: u64, hash: Multihash) -> Result<Self, Error> {
57        Ok(Cid(CidGeneric::new(version, codec, hash)?))
58    }
59
60    /// Create a new CIDv1.
61    pub fn new_v1(codec: u64, hash: Multihash) -> Self {
62        Cid(CidGeneric::new_v1(codec, hash))
63    }
64
65    /// Returns the cid version.
66    pub fn version(&self) -> Version {
67        self.0.version()
68    }
69
70    /// Returns the cid codec.
71    pub fn codec(&self) -> u64 {
72        self.0.codec()
73    }
74
75    /// Returns the cid multihash.
76    pub fn hash(&self) -> &Multihash {
77        &self.0.hash()
78    }
79
80    /// Reads the bytes from a byte stream.
81    pub fn read_bytes<R: std::io::Read>(reader: R) -> Result<Self, Error> {
82        Ok(Cid(CidGeneric::read_bytes(reader)?))
83    }
84
85    /// Returns the encoded bytes of the `Cid`.
86    pub fn to_bytes(&self) -> Vec<u8> {
87        self.0.to_bytes()
88    }
89}
90
91#[cfg(feature = "cbor")]
92impl ser::Serialize for Cid {
93    fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
94    where
95        S: ser::Serializer,
96    {
97        let mut cid_bytes = self.to_bytes();
98
99        // or for all Cid bytes (byte is irrelevant and redundant)
100        cid_bytes.insert(0, MULTIBASE_IDENTITY);
101
102        let value = serde_bytes::Bytes::new(&cid_bytes);
103        Tagged::new(Some(CBOR_TAG_CID), &value).serialize(s)
104    }
105}
106
107#[cfg(feature = "cbor")]
108impl<'de> de::Deserialize<'de> for Cid {
109    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
110    where
111        D: de::Deserializer<'de>,
112    {
113        let tagged = Tagged::<serde_bytes::ByteBuf>::deserialize(deserializer)?;
114        match tagged.tag {
115            Some(CBOR_TAG_CID) | None => {
116                let mut bz = tagged.value.into_vec();
117
118                if bz.first() == Some(&MULTIBASE_IDENTITY) {
119                    bz.remove(0);
120                }
121
122                Ok(Cid::try_from(bz)
123                    .map_err(|e| de::Error::custom(format!("Failed to deserialize Cid: {}", e)))?)
124            }
125            Some(_) => Err(de::Error::custom("unexpected tag")),
126        }
127    }
128}
129
130impl fmt::Display for Cid {
131    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
132        write!(f, "{}", self.0)
133    }
134}
135
136impl fmt::Debug for Cid {
137    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
138        write!(f, "Cid(\"{}\")", self)
139    }
140}