Module multiformats.cid
Implementation of the CID spec.
Core functionality is provided by the CID
class:
>>> from multiformats import CID
CIDs can be decoded from bytestrings or (multi)base encoded strings:
>>> cid = CID.decode("zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA")
>>> cid
CID('base58btc', 1, 'raw',
'12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95')
CIDs can be created programmatically, and their fields accessed individually:
>>> cid = CID("base58btc", 1, "raw",
... "12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95")
>>> cid.base
Multibase(name='base58btc', code='z',
status='default', description='base58 bitcoin')
>>> cid.codec
Multicodec(name='raw', tag='ipld', code='0x55',
status='permanent', description='raw binary')
>>> cid.hashfun
Multicodec(name='sha2-256', tag='multihash', code='0x12',
status='permanent', description='')
>>> cid.digest.hex()
'12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95'
>>> cid.raw_digest.hex()
'6e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95'
CIDs can be converted to bytestrings or (multi)base encoded strings:
>>> str(cid)
'zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA'
>>> bytes(cid).hex()
'015512206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95'
>>> cid.encode("base32") # encode with different multibase
'bafkreidon73zkcrwdb5iafqtijxildoonbwnpv7dyd6ef3qdgads2jc4su'
Additionally, the CID.peer_id()
static method can be used to pack the raw
hash of a public key into a CIDv1 PeerID,
according to the PeerID spec.
For full details, see the CID
documentation below.
Expand source code
"""
Implementation of the [CID spec](https://github.com/multiformats/cid).
Core functionality is provided by the `CID` class:
```py
>>> from multiformats import CID
```
CIDs can be decoded from bytestrings or (multi)base encoded strings:
```py
>>> cid = CID.decode("zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA")
>>> cid
CID('base58btc', 1, 'raw',
'12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95')
```
CIDs can be created programmatically, and their fields accessed individually:
```py
>>> cid = CID("base58btc", 1, "raw",
... "12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95")
>>> cid.base
Multibase(name='base58btc', code='z',
status='default', description='base58 bitcoin')
>>> cid.codec
Multicodec(name='raw', tag='ipld', code='0x55',
status='permanent', description='raw binary')
>>> cid.hashfun
Multicodec(name='sha2-256', tag='multihash', code='0x12',
status='permanent', description='')
>>> cid.digest.hex()
'12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95'
>>> cid.raw_digest.hex()
'6e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95'
```
CIDs can be converted to bytestrings or (multi)base encoded strings:
```py
>>> str(cid)
'zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA'
>>> bytes(cid).hex()
'015512206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95'
>>> cid.encode("base32") # encode with different multibase
'bafkreidon73zkcrwdb5iafqtijxildoonbwnpv7dyd6ef3qdgads2jc4su'
```
Additionally, the `CID.peer_id` static method can be used to pack the raw
hash of a public key into a CIDv1 [PeerID](https://docs.libp2p.io/concepts/peer-id/),
according to the [PeerID spec](https://github.com/libp2p/specs/blob/master/peer-ids/peer-ids.md).
For full details, see the `CID` documentation below.
"""
from typing import Any, cast, FrozenSet, Tuple, Type, TypeVar, Union
from typing_extensions import Literal, Final
from typing_validation import validate
from bases import base58btc
from multiformats import varint, multicodec, multibase, multihash
from multiformats.multicodec import Multicodec
from multiformats.multibase import Multibase
from multiformats.multihash import Multihash, _validate_raw_digest_size
from multiformats.varint import BytesLike, byteslike
_CIDSubclass = TypeVar("_CIDSubclass", bound="CID")
CIDVersion = Literal[0, 1]
CIDVersionNumbers: Final[FrozenSet[int]] = frozenset({0, 1})
def _binary_cid_from_str(cid: str) -> Tuple[bytes, Multibase]:
if len(cid) == 46 and cid.startswith("Qm"):
# CIDv0 to be decoded as base58btc
return base58btc.decode(cid), multibase.get("base58btc")
mb, b = multibase.decode_raw(cid)
if b[0] == 0x12:
# CIDv0 may not be multibase encoded (0x12 is the first byte of sha2-256 multihashes)
# CIDv18 (first byte 18=0x12) will be skipped to prevent ambiguity
raise ValueError("CIDv0 may not be multibase encoded (found multibase encoded bytes starting with 0x12).")
return b, mb
def _CID_validate_multibase(base: Union[str, Multibase]) -> Multibase:
if isinstance(base, str):
base = multibase.get(base)
else:
multibase.validate_multibase(base)
return base
def _CID_validate_multicodec(codec: Union[str, int, Multicodec]) -> Multicodec:
if isinstance(codec, str):
codec = multicodec.get(codec)
elif isinstance(codec, int):
codec = multicodec.get(code=codec)
else:
multicodec.validate_multicodec(codec)
return codec
def _CID_validate_multihash(hashfun: Union[str, int, Multihash]) -> Multihash:
if isinstance(hashfun, str):
hashfun = multihash.get(hashfun)
elif isinstance(hashfun, int):
hashfun = multihash.get(code=hashfun)
else:
pass
return hashfun
def _CID_validate_raw_digest(raw_digest: Union[str, BytesLike], hashfun: Multihash) -> bytes:
if isinstance(raw_digest, str):
raw_digest = bytes.fromhex(raw_digest)
else:
validate(raw_digest, BytesLike)
if not isinstance(raw_digest, bytes):
raw_digest = bytes(raw_digest)
_, max_digest_size = hashfun.implementation
_validate_raw_digest_size(hashfun.name, raw_digest, max_digest_size)
return raw_digest
def _CID_validate_multihash_digest(digest: Union[str, BytesLike]) -> Tuple[Multihash, bytes]:
if isinstance(digest, str):
digest = bytes.fromhex(digest)
raw_digest: BytesLike
code, raw_digest = multihash.unwrap_raw(digest)
hashfun = _CID_validate_multihash(code)
raw_digest = _CID_validate_raw_digest(raw_digest, hashfun)
return hashfun, raw_digest
def _CID_validate_version(version: int, base: Multibase, codec: Multicodec, hashfun: Multihash) -> int:
if version in (2, 3):
raise ValueError("CID versions 2 and 3 are reserved for future use.")
if version not in (0, 1):
raise ValueError(f"CID version {version} is not allowed.")
if version == 0:
if base.name != 'base58btc':
raise ValueError(f"CIDv0 multibase must be 'base58btc', found {repr(base.name)} instead.")
if codec.name != "dag-pb":
raise ValueError(f"CIDv0 multicodec must be 'dag-pb', found {repr(codec.name)} instead.")
if hashfun.name != "sha2-256":
raise ValueError(f"CIDv0 multihash must be 'sha2-256', found {repr(hashfun.name)} instead.")
return version
class CID:
"""
Container class for [Content IDentifiers](https://github.com/multiformats/cid).
CIDs can be decoded from a bytestring or a (multi)base encoded string, using `CID.decode`:
```py
>>> cid = CID.decode("zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA")
>>> cid
CID('base58btc', 1, 'raw',
'12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95')
```
CIDs can be explicitly instantiated by passing the `base`, `version`, `codec` and multihash `digest` to the constructor:
```py
>>> cid = CID("base58btc", 1, "raw",
... "12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95")
>>> str(cid)
'zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA'
```
Alternatively, a `(multihash_codec, raw_digest)` pair can be passed in lieu of `digest`:
```py
>>> raw_digest = bytes.fromhex(
... "6e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95")
>>> cid = CID("base58btc", 1, "raw", ("sha2-256", raw_digest))
>>> str(cid)
'zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA'
```
The `digest` and `raw_digest` parameters can be passed either as `bytes`-like objects
or as the corresponding hex strings (which will be converted to `bytes` using `bytes.fromhex`):
```py
>>> isinstance(raw_digest, bytes)
True
>>> raw_digest.hex()
'6e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95'
```
Note: the hex strings are not multibase encoded.
Calling `bytes(cid)` returns the binary representation of `cid`, as a `bytes` object:
```py
>>> cid = CID("base58btc", 1, "raw",
... "12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95")
>>> raw_digest.hex()
'6e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95'
>>> bytes(cid).hex()
'015512206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95'
#^^ 0x01 = CIDv1
# ^^ 0x55 = 'raw' codec
>>> bytes(cid)
```
"""
_base: Multibase
_version: CIDVersion
_codec: Multicodec
_hashfun: Multihash
_digest: bytes
__slots__ = ("__weakref__", "_base", "_version", "_codec", "_hashfun", "_digest")
def __new__(cls: Type[_CIDSubclass],
base: Union[str, Multibase],
version: int,
codec: Union[str, int, Multicodec],
digest: Union[str, BytesLike, Tuple[Union[str, int, Multihash], Union[str, BytesLike]]],
) -> _CIDSubclass:
# pylint: disable = too-many-arguments
base = _CID_validate_multibase(base)
codec = _CID_validate_multicodec(codec)
raw_digest: Union[str, bytes]
hashfun: Union[str, int, Multihash]
if isinstance(digest, (str,)+byteslike):
hashfun, raw_digest = _CID_validate_multihash_digest(digest)
else:
validate(digest, Tuple[Union[str, int, Multihash], Union[str, BytesLike]])
hashfun, raw_digest = digest
hashfun = _CID_validate_multihash(hashfun)
raw_digest = _CID_validate_raw_digest(raw_digest, hashfun)
version = _CID_validate_version(version, base, codec, hashfun)
if isinstance(digest, bytes):
return CID._new_instance(cls, base, version, codec, hashfun, digest)
return CID._new_instance(cls, base, version, codec, hashfun, (hashfun, raw_digest))
@staticmethod
def _new_instance(CID_subclass: Type[_CIDSubclass],
base: Multibase,
version: int,
codec: Multicodec,
hashfun: Multihash,
digest: Union[bytes, Tuple[Multihash, bytes]],
) -> _CIDSubclass:
# pylint: disable = too-many-arguments
instance: _CIDSubclass = super().__new__(CID_subclass)
instance._base = base
assert version in (0, 1)
instance._version = cast(Literal[0, 1], version)
instance._codec = codec
instance._hashfun = hashfun
if isinstance(digest, bytes):
instance._digest = digest
elif isinstance(digest, byteslike):
instance._digest = bytes(digest)
else:
_hashfun, raw_digest = digest
if not isinstance(raw_digest, bytes):
raw_digest = bytes(raw_digest)
assert _hashfun == hashfun, "You passed different multihashes to a _new_instance call with digest as a pair."
instance._digest = hashfun.wrap(raw_digest)
return instance
@property
def version(self) -> CIDVersion:
"""
CID version.
Example usage:
```py
>>> s = "zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA"
>>> cid = CID.decode(s)
>>> cid.version
1
```
"""
return self._version
@property
def base(self) -> Multibase:
"""
Multibase used to encode the CID:
- if a CIDv1 was decoded from a multibase-encoded string, the encoding multibase is used
- if a CIDv1 was decoded from a bytestring, the 'base58btc' multibase is used
- for a CIDv0, 'base58btc' is always used
Example usage:
```py
>>> s = "zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA"
>>> cid = CID.decode(s)
>>> cid.base
Multibase(name='base58btc', code='z',
status='default', description='base58 bitcoin')
```
"""
return self._base
@property
def codec(self) -> Multicodec:
"""
Codec that the multihash digest refers to.
Example usage:
```py
>>> s = "zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA"
>>> cid = CID.decode(s)
>>> cid.codec
Multicodec(name='raw', tag='ipld', code='0x55',
status='permanent', description='raw binary')
```
"""
return self._codec
@property
def hashfun(self) -> Multihash:
"""
Multihash used to produce the multihash digest.
Example usage:
```py
>>> s = "zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA"
>>> cid = CID.decode(s)
>>> cid.hashfun
Multicodec(name='sha2-256', tag='multihash', code='0x12',
status='permanent', description='')
```
"""
return self._hashfun
@property
def digest(self) -> bytes:
"""
Multihash digest.
Example usage:
```py
>>> s = "zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA"
>>> cid = CID.decode(s)
>>> cid.digest.hex()
'12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95'
```
"""
return self._digest
@property
def raw_digest(self) -> bytes:
"""
Raw hash digest, decoded from the multihash digest.
Example usage:
```py
>>> s = "zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA"
>>> cid = CID.decode(s)
>>> cid.raw_digest.hex()
'6e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95'
```
"""
return multihash.unwrap(self._digest)
@property
def human_readable(self) -> str:
"""
Human-readable representation of the CID.
Example usage:
```py
>>> s = "zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA"
>>> cid = CID.decode(s)
>>> cid.human_readable
'base58btc - cidv1 - raw - (sha2-256 : 256 : 6E6FF7950A36187A801613426E858DCE686CD7D7E3C0FC42EE0330072D245C95)'
```
"""
raw_digest = self.raw_digest
hashfun_str = f"({self.hashfun.name} : {len(raw_digest)*8} : {raw_digest.hex().upper()})"
return f"{self.base.name} - cidv{self.version} - {self.codec.name} - {hashfun_str}"
def encode(self, base: Union[None, str, Multibase] = None) -> str:
"""
Encodes the CID using a given multibase. If no multibase is given,
the CID's own multibase is used by default.
Example usage:
```py
>>> s = "zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA"
>>> cid = CID.decode(s)
>>> cid.encode() # default: cid.base
'zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA'
>>> cid.encode("base32")
'bafkreidon73zkcrwdb5iafqtijxildoonbwnpv7dyd6ef3qdgads2jc4su'
```
"""
if self.version == 0:
if base is not None:
raise ValueError("CIDv0 cannot be multibase-encoded, please set multibase=None.")
return base58btc.encode(bytes(self))
if base is None or base == self.base:
base = self.base # use CID's own multibase as default
else:
if isinstance(base, str):
base = multibase.get(base)
else:
multibase.validate_multibase(base)
return base.encode(bytes(self))
def set(self, *,
base: Union[None, str, Multibase] = None,
version: Union[None, int] = None,
codec: Union[None, str, int, Multicodec] = None
) -> "CID":
"""
Returns a new CID obtained by setting new values for one or more of:
`base`, `version`, or `codec`.
Example usage:
```py
>>> s = "zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA"
>>> cid = CID.decode(s)
>>> cid
CID('base58btc', 1, 'raw',
'12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95')
>>> cid.set(base="base32")
CID('base32', 1, 'raw',
'12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95')
>>> cid.set(codec="dag-cbor")
CID('base58btc', 1, 'dag-cbor',
'12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95')
>>> cid.set(version=0, codec="dag-pb")
CID('base58btc', 0, 'dag-pb',
'12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95')
>>> cid
CID('base58btc', 1, 'raw',
'12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95')
# Note: 'CID.set' returns new instances,
# the original 'cid' instance is unchanged
```
If setting `version` to 0, `base` must be 'base58btc' and `codec` must be 'dag-pb'.
```py
>>> s = "zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA"
>>> cid = CID.decode(s)
>>> cid
CID('base58btc', 1, 'raw',
'12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95')
>>> cid.set(version=0, codec="dag-pb")
CID('base58btc', 0, 'dag-pb',
'12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95')
>>> cid.set(version=0)
ValueError: CIDv0 multicodec must be 'dag-pb', found 'raw' instead.
>>> cid.set(version=0, codec="dag-pb", base="base32")
ValueError: CIDv0 multibase must be 'base58btc', found 'base32' instead
```
"""
hashfun = self.hashfun
digest = self.digest
if base is not None and base not in (self.base, self.base.name):
base = _CID_validate_multibase(base)
else:
base = self.base
if codec is not None and codec not in (self.codec, self.codec.name, self.codec.code):
codec = _CID_validate_multicodec(codec)
else:
codec = self.codec
if version is not None and version != self.version:
_CID_validate_version(version, base, codec, hashfun)
else:
version = self.version
return CID._new_instance(CID, base, version, codec, hashfun, digest)
def __bytes__(self) -> bytes:
if self.version == 0:
return self.digest
return varint.encode(self.version)+varint.encode(self.codec.code)+self.digest
def __str__(self) -> str:
return self.encode()
def __repr__(self) -> str:
mb = self.base.name
v = self.version
mc = self.codec.name
d = self.digest
return f"CID({repr(mb)}, {v}, {repr(mc)}, {repr(d.hex())})"
@property
def _as_tuple(self) -> Tuple[Type["CID"], Multibase, int, Multicodec, bytes]:
return (CID, self.base, self.version, self.codec, self.digest)
def __hash__(self) -> int:
return hash(self._as_tuple)
def __eq__(self, other: Any) -> bool:
if self is other:
return True
if not isinstance(other, CID):
return NotImplemented
return self._as_tuple == other._as_tuple
@staticmethod
def decode(cid: Union[str, BytesLike]) -> "CID":
"""
Decodes a CID from a bytestring or a hex string (which will be converted to `bytes`
using `bytes.fromhex`). Note: the hex string is not multibase encoded.
Example usage for CIDv1 multibase-encoded string:
```py
>>> s = "zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA"
>>> CID.decode(s)
CID('base58btc', 1, 'raw',
'12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95')
```
Example usage for CIDv1 bytestring (multibase always set to 'base58btc'):
```py
>>> b = bytes.fromhex(
... "015512206e6ff7950a36187a801613426e85"
... "8dce686cd7d7e3c0fc42ee0330072d245c95")
>>> CID.decode(b)
CID('base58btc', 1, 'raw',
'12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95')
```
Example usage for CIDv0 base58-encoded string:
```py
>>> s = "QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR"
>>> CID.decode(s)
CID('base58btc', 0, 'dag-pb',
'1220c3c4733ec8affd06cf9e9ff50ffc6bcd2ec85a6170004bb709669c31de94391a')
```
Example usage for CIDv0 bytestring (multibase always set to 'base58btc'):
```py
>>> b = bytes.fromhex(
... "1220c3c4733ec8affd06cf9e9ff50ffc6b"
... "cd2ec85a6170004bb709669c31de94391a")
>>> CID.decode(b)
CID('base58btc', 0, 'dag-pb',
'1220c3c4733ec8affd06cf9e9ff50ffc6bcd2ec85a6170004bb709669c31de94391a')
```
"""
if isinstance(cid, str):
cid, mb = _binary_cid_from_str(cid)
else:
mb = multibase.get("base58btc")
validate(cid, BytesLike)
cid = memoryview(cid)
# if len(cid) == 34 and cid.startswith(b"\x12\x20"):
if len(cid) == 34 and cid[0] == 0x12 and cid[1] == 0x20:
v = 0 # CID version
mc_code = 0x70 # multicodec.get("dag-pb")
digest = cid # multihash digest is what's left
else:
v, _, cid = varint.decode_raw(cid) # CID version
if v == 0:
raise ValueError("CIDv0 is malformed.")
if v in (2, 3):
raise ValueError("CID versions 2 and 3 are reserved for future use.")
if v != 1:
raise ValueError(f"CIDv{v} is currently not supported.")
mc_code, _, cid = multicodec.unwrap_raw(cid) # multicodec
digest = cid # multihash digest is what's left
mc = multicodec.get(code=mc_code)
mh_code, _ = multihash.unwrap_raw(digest)
mh = multihash.get(code=mh_code)
return CID._new_instance(CID, mb, v, mc, mh, digest)
@staticmethod
def peer_id(pk_bytes: Union[str, BytesLike]) -> "CID":
"""
Wraps the raw hash of a public key into a [PeerID](https://docs.libp2p.io/concepts/peer-id/), as a CIDv1.
The `pk_bytes` argument should be the binary public key, encoded according to the
[PeerID spec](https://github.com/libp2p/specs/blob/master/peer-ids/peer-ids.md).
This can be passed as a bytestring or as a hex string (which will be converted to `bytes` using `bytes.fromhex`).
Note: the hex string is not multibase encoded.
Example usage with Ed25519 public key:
```py
>>> pk_bytes = bytes.fromhex(
... "1498b5467a63dffa2dc9d9e069caf075d16fc33fdd4c3b01bfadae6433767d93")
... # a 32-byte Ed25519 public key
>>> peer_id = CID.peer_id(pk_bytes)
>>> peer_id
CID('base32', 1, 'libp2p-key',
'00201498b5467a63dffa2dc9d9e069caf075d16fc33fdd4c3b01bfadae6433767d93')
#^^ 0x00 = 'identity' multihash used (public key length <= 42)
# ^^ 0x20 = 32-bytes of raw hash digestlength
>>> str(peer_id)
'bafzaaiautc2um6td375c3soz4bu4v4dv2fx4gp65jq5qdp5nvzsdg5t5sm'
```
Snippet showing how to obtain the [Ed25519](https://cryptography.io/en/latest/hazmat/primitives/asymmetric/ed25519/)
public key bytestring using the [`cryptography`](https://github.com/pyca/cryptography) library:
```py
>>> from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
>>> from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat
>>> private_key = Ed25519PrivateKey.generate()
>>> public_key = private_key.public_key()
>>> pk_bytes = public_key.public_bytes(
... encoding=Encoding.Raw,
... format=PublicFormat.Raw
... )
>>> pk_bytes.hex()
"1498b5467a63dffa2dc9d9e069caf075d16fc33fdd4c3b01bfadae6433767d93"
```
Example usage with DER-encoded RSA public key:
```py
>>> pk_bytes = bytes.fromhex(
... "30820122300d06092a864886f70d01010105000382010f003082010a02820101"
... "009a56a5c11e2705d0bfe0cd1fa66d5e519095cc741b62ed99ddf129c32e046e"
... "5ba3958bb8a068b05a95a6a0623cc3c889b1581793cd84a34cc2307e0dd74c70"
... "b4f230c74e5063ecd8e906d372be4eba13f47d04427a717ac78cb12b4b9c2ab5"
... "591f36f98021a70f84d782c36c51819054228ff35a45efa3f82b27849ec89036"
... "26b4a4c4b40f9f74b79caf55253687124c79cb10cd3bc73f0c44fbd341e5417d"
... "2e85e900d22849d2bc85ca6bf037f1f5b4f9759b4b6942fccdf1140b30ea7557"
... "87deb5c373c5953c14d64b523959a76a32a599903974a98cf38d4aaac7e359f8"
... "6b00a91dcf424bf794592139e7097d7e65889259227c07155770276b6eda4cec"
... "370203010001")
... # a 294-byte RSA public key
>>> peer_id = CID.peer_id(pk_bytes)
>>> peer_id
CID('base32', 1, 'libp2p-key',
'1220c1a6513ffb14f202f75453c49666a5b9d7ed9a1a068891daf824d477573f829f')
#^^ 0x12 = 'sha2-256' multihash used (public key length > 42)
# ^^ 0x20 = 32-bytes of raw hash digest length
>>> str(peer_id)
'bafzbeigbuzit76yu6ibpovctyslgnjnz27wzugqgrci5v6be2r3vop4ct4'
```
Snippet showing how to obtain the [RSA](https://cryptography.io/en/latest/hazmat/primitives/asymmetric/rsa/)
public key bytestring using the [`cryptography`](https://github.com/pyca/cryptography) library:
```py
>>> from cryptography.hazmat.primitives.asymmetric import rsa
>>> from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat
>>> private_key = rsa.generate_private_key(
... public_exponent=65537,
... key_size=2048,
... )
>>> public_key = private_key.public_key()
>>> pk_bytes = public_key.public_bytes(
... encoding=Encoding.DER,
... format=PublicFormat.SubjectPublicKeyInfo
... )
>>> pk_bytes.hex()
"30820122300d06092a864886f70d01010105000382010f003082010a02820101"
"009a56a5c11e2705d0bfe0cd1fa66d5e519095cc741b62ed99ddf129c32e046e"
"5ba3958bb8a068b05a95a6a0623cc3c889b1581793cd84a34cc2307e0dd74c70"
"b4f230c74e5063ecd8e906d372be4eba13f47d04427a717ac78cb12b4b9c2ab5"
"591f36f98021a70f84d782c36c51819054228ff35a45efa3f82b27849ec89036"
"26b4a4c4b40f9f74b79caf55253687124c79cb10cd3bc73f0c44fbd341e5417d"
"2e85e900d22849d2bc85ca6bf037f1f5b4f9759b4b6942fccdf1140b30ea7557"
"87deb5c373c5953c14d64b523959a76a32a599903974a98cf38d4aaac7e359f8"
"6b00a91dcf424bf794592139e7097d7e65889259227c07155770276b6eda4cec"
"370203010001"
```
"""
if isinstance(pk_bytes, str):
pk_bytes = bytes.fromhex(pk_bytes)
else:
validate(pk_bytes, BytesLike)
if len(pk_bytes) <= 42:
mh = multihash.get("identity")
digest = multihash.digest(pk_bytes, mh)
else:
mh = multihash.get("sha2-256")
digest = multihash.digest(pk_bytes, mh)
mc = multicodec.get(code=0x72) # multicodec.get("libp2p-key")
mb = multibase.get("base32")
return CID._new_instance(CID, mb, 1, mc, mh, digest)
Classes
class CID (base: Union[str, Multibase], version: int, codec: Union[str, int, Multicodec], digest: Union[str, bytes, bytearray, memoryview, Tuple[Union[str, int, Multihash], Union[str, bytes, bytearray, memoryview]]])
-
Container class for Content IDentifiers. CIDs can be decoded from a bytestring or a (multi)base encoded string, using
CID.decode()
:>>> cid = CID.decode("zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA") >>> cid CID('base58btc', 1, 'raw', '12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95')
CIDs can be explicitly instantiated by passing the
base
,version
,codec
and multihashdigest
to the constructor:>>> cid = CID("base58btc", 1, "raw", ... "12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95") >>> str(cid) 'zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA'
Alternatively, a
(multihash_codec, raw_digest)
pair can be passed in lieu ofdigest
:>>> raw_digest = bytes.fromhex( ... "6e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95") >>> cid = CID("base58btc", 1, "raw", ("sha2-256", raw_digest)) >>> str(cid) 'zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA'
The
digest
andraw_digest
parameters can be passed either asbytes
-like objects or as the corresponding hex strings (which will be converted tobytes
usingbytes.fromhex
):>>> isinstance(raw_digest, bytes) True >>> raw_digest.hex() '6e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95'
Note: the hex strings are not multibase encoded.
Calling
bytes(cid)
returns the binary representation ofcid
, as abytes
object:>>> cid = CID("base58btc", 1, "raw", ... "12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95") >>> raw_digest.hex() '6e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95' >>> bytes(cid).hex() '015512206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95' #^^ 0x01 = CIDv1 # ^^ 0x55 = 'raw' codec >>> bytes(cid)
Expand source code
class CID: """ Container class for [Content IDentifiers](https://github.com/multiformats/cid). CIDs can be decoded from a bytestring or a (multi)base encoded string, using `CID.decode`: ```py >>> cid = CID.decode("zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA") >>> cid CID('base58btc', 1, 'raw', '12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95') ``` CIDs can be explicitly instantiated by passing the `base`, `version`, `codec` and multihash `digest` to the constructor: ```py >>> cid = CID("base58btc", 1, "raw", ... "12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95") >>> str(cid) 'zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA' ``` Alternatively, a `(multihash_codec, raw_digest)` pair can be passed in lieu of `digest`: ```py >>> raw_digest = bytes.fromhex( ... "6e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95") >>> cid = CID("base58btc", 1, "raw", ("sha2-256", raw_digest)) >>> str(cid) 'zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA' ``` The `digest` and `raw_digest` parameters can be passed either as `bytes`-like objects or as the corresponding hex strings (which will be converted to `bytes` using `bytes.fromhex`): ```py >>> isinstance(raw_digest, bytes) True >>> raw_digest.hex() '6e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95' ``` Note: the hex strings are not multibase encoded. Calling `bytes(cid)` returns the binary representation of `cid`, as a `bytes` object: ```py >>> cid = CID("base58btc", 1, "raw", ... "12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95") >>> raw_digest.hex() '6e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95' >>> bytes(cid).hex() '015512206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95' #^^ 0x01 = CIDv1 # ^^ 0x55 = 'raw' codec >>> bytes(cid) ``` """ _base: Multibase _version: CIDVersion _codec: Multicodec _hashfun: Multihash _digest: bytes __slots__ = ("__weakref__", "_base", "_version", "_codec", "_hashfun", "_digest") def __new__(cls: Type[_CIDSubclass], base: Union[str, Multibase], version: int, codec: Union[str, int, Multicodec], digest: Union[str, BytesLike, Tuple[Union[str, int, Multihash], Union[str, BytesLike]]], ) -> _CIDSubclass: # pylint: disable = too-many-arguments base = _CID_validate_multibase(base) codec = _CID_validate_multicodec(codec) raw_digest: Union[str, bytes] hashfun: Union[str, int, Multihash] if isinstance(digest, (str,)+byteslike): hashfun, raw_digest = _CID_validate_multihash_digest(digest) else: validate(digest, Tuple[Union[str, int, Multihash], Union[str, BytesLike]]) hashfun, raw_digest = digest hashfun = _CID_validate_multihash(hashfun) raw_digest = _CID_validate_raw_digest(raw_digest, hashfun) version = _CID_validate_version(version, base, codec, hashfun) if isinstance(digest, bytes): return CID._new_instance(cls, base, version, codec, hashfun, digest) return CID._new_instance(cls, base, version, codec, hashfun, (hashfun, raw_digest)) @staticmethod def _new_instance(CID_subclass: Type[_CIDSubclass], base: Multibase, version: int, codec: Multicodec, hashfun: Multihash, digest: Union[bytes, Tuple[Multihash, bytes]], ) -> _CIDSubclass: # pylint: disable = too-many-arguments instance: _CIDSubclass = super().__new__(CID_subclass) instance._base = base assert version in (0, 1) instance._version = cast(Literal[0, 1], version) instance._codec = codec instance._hashfun = hashfun if isinstance(digest, bytes): instance._digest = digest elif isinstance(digest, byteslike): instance._digest = bytes(digest) else: _hashfun, raw_digest = digest if not isinstance(raw_digest, bytes): raw_digest = bytes(raw_digest) assert _hashfun == hashfun, "You passed different multihashes to a _new_instance call with digest as a pair." instance._digest = hashfun.wrap(raw_digest) return instance @property def version(self) -> CIDVersion: """ CID version. Example usage: ```py >>> s = "zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA" >>> cid = CID.decode(s) >>> cid.version 1 ``` """ return self._version @property def base(self) -> Multibase: """ Multibase used to encode the CID: - if a CIDv1 was decoded from a multibase-encoded string, the encoding multibase is used - if a CIDv1 was decoded from a bytestring, the 'base58btc' multibase is used - for a CIDv0, 'base58btc' is always used Example usage: ```py >>> s = "zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA" >>> cid = CID.decode(s) >>> cid.base Multibase(name='base58btc', code='z', status='default', description='base58 bitcoin') ``` """ return self._base @property def codec(self) -> Multicodec: """ Codec that the multihash digest refers to. Example usage: ```py >>> s = "zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA" >>> cid = CID.decode(s) >>> cid.codec Multicodec(name='raw', tag='ipld', code='0x55', status='permanent', description='raw binary') ``` """ return self._codec @property def hashfun(self) -> Multihash: """ Multihash used to produce the multihash digest. Example usage: ```py >>> s = "zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA" >>> cid = CID.decode(s) >>> cid.hashfun Multicodec(name='sha2-256', tag='multihash', code='0x12', status='permanent', description='') ``` """ return self._hashfun @property def digest(self) -> bytes: """ Multihash digest. Example usage: ```py >>> s = "zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA" >>> cid = CID.decode(s) >>> cid.digest.hex() '12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95' ``` """ return self._digest @property def raw_digest(self) -> bytes: """ Raw hash digest, decoded from the multihash digest. Example usage: ```py >>> s = "zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA" >>> cid = CID.decode(s) >>> cid.raw_digest.hex() '6e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95' ``` """ return multihash.unwrap(self._digest) @property def human_readable(self) -> str: """ Human-readable representation of the CID. Example usage: ```py >>> s = "zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA" >>> cid = CID.decode(s) >>> cid.human_readable 'base58btc - cidv1 - raw - (sha2-256 : 256 : 6E6FF7950A36187A801613426E858DCE686CD7D7E3C0FC42EE0330072D245C95)' ``` """ raw_digest = self.raw_digest hashfun_str = f"({self.hashfun.name} : {len(raw_digest)*8} : {raw_digest.hex().upper()})" return f"{self.base.name} - cidv{self.version} - {self.codec.name} - {hashfun_str}" def encode(self, base: Union[None, str, Multibase] = None) -> str: """ Encodes the CID using a given multibase. If no multibase is given, the CID's own multibase is used by default. Example usage: ```py >>> s = "zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA" >>> cid = CID.decode(s) >>> cid.encode() # default: cid.base 'zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA' >>> cid.encode("base32") 'bafkreidon73zkcrwdb5iafqtijxildoonbwnpv7dyd6ef3qdgads2jc4su' ``` """ if self.version == 0: if base is not None: raise ValueError("CIDv0 cannot be multibase-encoded, please set multibase=None.") return base58btc.encode(bytes(self)) if base is None or base == self.base: base = self.base # use CID's own multibase as default else: if isinstance(base, str): base = multibase.get(base) else: multibase.validate_multibase(base) return base.encode(bytes(self)) def set(self, *, base: Union[None, str, Multibase] = None, version: Union[None, int] = None, codec: Union[None, str, int, Multicodec] = None ) -> "CID": """ Returns a new CID obtained by setting new values for one or more of: `base`, `version`, or `codec`. Example usage: ```py >>> s = "zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA" >>> cid = CID.decode(s) >>> cid CID('base58btc', 1, 'raw', '12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95') >>> cid.set(base="base32") CID('base32', 1, 'raw', '12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95') >>> cid.set(codec="dag-cbor") CID('base58btc', 1, 'dag-cbor', '12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95') >>> cid.set(version=0, codec="dag-pb") CID('base58btc', 0, 'dag-pb', '12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95') >>> cid CID('base58btc', 1, 'raw', '12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95') # Note: 'CID.set' returns new instances, # the original 'cid' instance is unchanged ``` If setting `version` to 0, `base` must be 'base58btc' and `codec` must be 'dag-pb'. ```py >>> s = "zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA" >>> cid = CID.decode(s) >>> cid CID('base58btc', 1, 'raw', '12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95') >>> cid.set(version=0, codec="dag-pb") CID('base58btc', 0, 'dag-pb', '12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95') >>> cid.set(version=0) ValueError: CIDv0 multicodec must be 'dag-pb', found 'raw' instead. >>> cid.set(version=0, codec="dag-pb", base="base32") ValueError: CIDv0 multibase must be 'base58btc', found 'base32' instead ``` """ hashfun = self.hashfun digest = self.digest if base is not None and base not in (self.base, self.base.name): base = _CID_validate_multibase(base) else: base = self.base if codec is not None and codec not in (self.codec, self.codec.name, self.codec.code): codec = _CID_validate_multicodec(codec) else: codec = self.codec if version is not None and version != self.version: _CID_validate_version(version, base, codec, hashfun) else: version = self.version return CID._new_instance(CID, base, version, codec, hashfun, digest) def __bytes__(self) -> bytes: if self.version == 0: return self.digest return varint.encode(self.version)+varint.encode(self.codec.code)+self.digest def __str__(self) -> str: return self.encode() def __repr__(self) -> str: mb = self.base.name v = self.version mc = self.codec.name d = self.digest return f"CID({repr(mb)}, {v}, {repr(mc)}, {repr(d.hex())})" @property def _as_tuple(self) -> Tuple[Type["CID"], Multibase, int, Multicodec, bytes]: return (CID, self.base, self.version, self.codec, self.digest) def __hash__(self) -> int: return hash(self._as_tuple) def __eq__(self, other: Any) -> bool: if self is other: return True if not isinstance(other, CID): return NotImplemented return self._as_tuple == other._as_tuple @staticmethod def decode(cid: Union[str, BytesLike]) -> "CID": """ Decodes a CID from a bytestring or a hex string (which will be converted to `bytes` using `bytes.fromhex`). Note: the hex string is not multibase encoded. Example usage for CIDv1 multibase-encoded string: ```py >>> s = "zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA" >>> CID.decode(s) CID('base58btc', 1, 'raw', '12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95') ``` Example usage for CIDv1 bytestring (multibase always set to 'base58btc'): ```py >>> b = bytes.fromhex( ... "015512206e6ff7950a36187a801613426e85" ... "8dce686cd7d7e3c0fc42ee0330072d245c95") >>> CID.decode(b) CID('base58btc', 1, 'raw', '12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95') ``` Example usage for CIDv0 base58-encoded string: ```py >>> s = "QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR" >>> CID.decode(s) CID('base58btc', 0, 'dag-pb', '1220c3c4733ec8affd06cf9e9ff50ffc6bcd2ec85a6170004bb709669c31de94391a') ``` Example usage for CIDv0 bytestring (multibase always set to 'base58btc'): ```py >>> b = bytes.fromhex( ... "1220c3c4733ec8affd06cf9e9ff50ffc6b" ... "cd2ec85a6170004bb709669c31de94391a") >>> CID.decode(b) CID('base58btc', 0, 'dag-pb', '1220c3c4733ec8affd06cf9e9ff50ffc6bcd2ec85a6170004bb709669c31de94391a') ``` """ if isinstance(cid, str): cid, mb = _binary_cid_from_str(cid) else: mb = multibase.get("base58btc") validate(cid, BytesLike) cid = memoryview(cid) # if len(cid) == 34 and cid.startswith(b"\x12\x20"): if len(cid) == 34 and cid[0] == 0x12 and cid[1] == 0x20: v = 0 # CID version mc_code = 0x70 # multicodec.get("dag-pb") digest = cid # multihash digest is what's left else: v, _, cid = varint.decode_raw(cid) # CID version if v == 0: raise ValueError("CIDv0 is malformed.") if v in (2, 3): raise ValueError("CID versions 2 and 3 are reserved for future use.") if v != 1: raise ValueError(f"CIDv{v} is currently not supported.") mc_code, _, cid = multicodec.unwrap_raw(cid) # multicodec digest = cid # multihash digest is what's left mc = multicodec.get(code=mc_code) mh_code, _ = multihash.unwrap_raw(digest) mh = multihash.get(code=mh_code) return CID._new_instance(CID, mb, v, mc, mh, digest) @staticmethod def peer_id(pk_bytes: Union[str, BytesLike]) -> "CID": """ Wraps the raw hash of a public key into a [PeerID](https://docs.libp2p.io/concepts/peer-id/), as a CIDv1. The `pk_bytes` argument should be the binary public key, encoded according to the [PeerID spec](https://github.com/libp2p/specs/blob/master/peer-ids/peer-ids.md). This can be passed as a bytestring or as a hex string (which will be converted to `bytes` using `bytes.fromhex`). Note: the hex string is not multibase encoded. Example usage with Ed25519 public key: ```py >>> pk_bytes = bytes.fromhex( ... "1498b5467a63dffa2dc9d9e069caf075d16fc33fdd4c3b01bfadae6433767d93") ... # a 32-byte Ed25519 public key >>> peer_id = CID.peer_id(pk_bytes) >>> peer_id CID('base32', 1, 'libp2p-key', '00201498b5467a63dffa2dc9d9e069caf075d16fc33fdd4c3b01bfadae6433767d93') #^^ 0x00 = 'identity' multihash used (public key length <= 42) # ^^ 0x20 = 32-bytes of raw hash digestlength >>> str(peer_id) 'bafzaaiautc2um6td375c3soz4bu4v4dv2fx4gp65jq5qdp5nvzsdg5t5sm' ``` Snippet showing how to obtain the [Ed25519](https://cryptography.io/en/latest/hazmat/primitives/asymmetric/ed25519/) public key bytestring using the [`cryptography`](https://github.com/pyca/cryptography) library: ```py >>> from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey >>> from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat >>> private_key = Ed25519PrivateKey.generate() >>> public_key = private_key.public_key() >>> pk_bytes = public_key.public_bytes( ... encoding=Encoding.Raw, ... format=PublicFormat.Raw ... ) >>> pk_bytes.hex() "1498b5467a63dffa2dc9d9e069caf075d16fc33fdd4c3b01bfadae6433767d93" ``` Example usage with DER-encoded RSA public key: ```py >>> pk_bytes = bytes.fromhex( ... "30820122300d06092a864886f70d01010105000382010f003082010a02820101" ... "009a56a5c11e2705d0bfe0cd1fa66d5e519095cc741b62ed99ddf129c32e046e" ... "5ba3958bb8a068b05a95a6a0623cc3c889b1581793cd84a34cc2307e0dd74c70" ... "b4f230c74e5063ecd8e906d372be4eba13f47d04427a717ac78cb12b4b9c2ab5" ... "591f36f98021a70f84d782c36c51819054228ff35a45efa3f82b27849ec89036" ... "26b4a4c4b40f9f74b79caf55253687124c79cb10cd3bc73f0c44fbd341e5417d" ... "2e85e900d22849d2bc85ca6bf037f1f5b4f9759b4b6942fccdf1140b30ea7557" ... "87deb5c373c5953c14d64b523959a76a32a599903974a98cf38d4aaac7e359f8" ... "6b00a91dcf424bf794592139e7097d7e65889259227c07155770276b6eda4cec" ... "370203010001") ... # a 294-byte RSA public key >>> peer_id = CID.peer_id(pk_bytes) >>> peer_id CID('base32', 1, 'libp2p-key', '1220c1a6513ffb14f202f75453c49666a5b9d7ed9a1a068891daf824d477573f829f') #^^ 0x12 = 'sha2-256' multihash used (public key length > 42) # ^^ 0x20 = 32-bytes of raw hash digest length >>> str(peer_id) 'bafzbeigbuzit76yu6ibpovctyslgnjnz27wzugqgrci5v6be2r3vop4ct4' ``` Snippet showing how to obtain the [RSA](https://cryptography.io/en/latest/hazmat/primitives/asymmetric/rsa/) public key bytestring using the [`cryptography`](https://github.com/pyca/cryptography) library: ```py >>> from cryptography.hazmat.primitives.asymmetric import rsa >>> from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat >>> private_key = rsa.generate_private_key( ... public_exponent=65537, ... key_size=2048, ... ) >>> public_key = private_key.public_key() >>> pk_bytes = public_key.public_bytes( ... encoding=Encoding.DER, ... format=PublicFormat.SubjectPublicKeyInfo ... ) >>> pk_bytes.hex() "30820122300d06092a864886f70d01010105000382010f003082010a02820101" "009a56a5c11e2705d0bfe0cd1fa66d5e519095cc741b62ed99ddf129c32e046e" "5ba3958bb8a068b05a95a6a0623cc3c889b1581793cd84a34cc2307e0dd74c70" "b4f230c74e5063ecd8e906d372be4eba13f47d04427a717ac78cb12b4b9c2ab5" "591f36f98021a70f84d782c36c51819054228ff35a45efa3f82b27849ec89036" "26b4a4c4b40f9f74b79caf55253687124c79cb10cd3bc73f0c44fbd341e5417d" "2e85e900d22849d2bc85ca6bf037f1f5b4f9759b4b6942fccdf1140b30ea7557" "87deb5c373c5953c14d64b523959a76a32a599903974a98cf38d4aaac7e359f8" "6b00a91dcf424bf794592139e7097d7e65889259227c07155770276b6eda4cec" "370203010001" ``` """ if isinstance(pk_bytes, str): pk_bytes = bytes.fromhex(pk_bytes) else: validate(pk_bytes, BytesLike) if len(pk_bytes) <= 42: mh = multihash.get("identity") digest = multihash.digest(pk_bytes, mh) else: mh = multihash.get("sha2-256") digest = multihash.digest(pk_bytes, mh) mc = multicodec.get(code=0x72) # multicodec.get("libp2p-key") mb = multibase.get("base32") return CID._new_instance(CID, mb, 1, mc, mh, digest)
Static methods
def decode(cid: Union[str, bytes, bytearray, memoryview]) ‑> CID
-
Decodes a CID from a bytestring or a hex string (which will be converted to
bytes
usingbytes.fromhex
). Note: the hex string is not multibase encoded.Example usage for CIDv1 multibase-encoded string:
>>> s = "zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA" >>> CID.decode(s) CID('base58btc', 1, 'raw', '12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95')
Example usage for CIDv1 bytestring (multibase always set to 'base58btc'):
>>> b = bytes.fromhex( ... "015512206e6ff7950a36187a801613426e85" ... "8dce686cd7d7e3c0fc42ee0330072d245c95") >>> CID.decode(b) CID('base58btc', 1, 'raw', '12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95')
Example usage for CIDv0 base58-encoded string:
>>> s = "QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR" >>> CID.decode(s) CID('base58btc', 0, 'dag-pb', '1220c3c4733ec8affd06cf9e9ff50ffc6bcd2ec85a6170004bb709669c31de94391a')
Example usage for CIDv0 bytestring (multibase always set to 'base58btc'):
>>> b = bytes.fromhex( ... "1220c3c4733ec8affd06cf9e9ff50ffc6b" ... "cd2ec85a6170004bb709669c31de94391a") >>> CID.decode(b) CID('base58btc', 0, 'dag-pb', '1220c3c4733ec8affd06cf9e9ff50ffc6bcd2ec85a6170004bb709669c31de94391a')
Expand source code
@staticmethod def decode(cid: Union[str, BytesLike]) -> "CID": """ Decodes a CID from a bytestring or a hex string (which will be converted to `bytes` using `bytes.fromhex`). Note: the hex string is not multibase encoded. Example usage for CIDv1 multibase-encoded string: ```py >>> s = "zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA" >>> CID.decode(s) CID('base58btc', 1, 'raw', '12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95') ``` Example usage for CIDv1 bytestring (multibase always set to 'base58btc'): ```py >>> b = bytes.fromhex( ... "015512206e6ff7950a36187a801613426e85" ... "8dce686cd7d7e3c0fc42ee0330072d245c95") >>> CID.decode(b) CID('base58btc', 1, 'raw', '12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95') ``` Example usage for CIDv0 base58-encoded string: ```py >>> s = "QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR" >>> CID.decode(s) CID('base58btc', 0, 'dag-pb', '1220c3c4733ec8affd06cf9e9ff50ffc6bcd2ec85a6170004bb709669c31de94391a') ``` Example usage for CIDv0 bytestring (multibase always set to 'base58btc'): ```py >>> b = bytes.fromhex( ... "1220c3c4733ec8affd06cf9e9ff50ffc6b" ... "cd2ec85a6170004bb709669c31de94391a") >>> CID.decode(b) CID('base58btc', 0, 'dag-pb', '1220c3c4733ec8affd06cf9e9ff50ffc6bcd2ec85a6170004bb709669c31de94391a') ``` """ if isinstance(cid, str): cid, mb = _binary_cid_from_str(cid) else: mb = multibase.get("base58btc") validate(cid, BytesLike) cid = memoryview(cid) # if len(cid) == 34 and cid.startswith(b"\x12\x20"): if len(cid) == 34 and cid[0] == 0x12 and cid[1] == 0x20: v = 0 # CID version mc_code = 0x70 # multicodec.get("dag-pb") digest = cid # multihash digest is what's left else: v, _, cid = varint.decode_raw(cid) # CID version if v == 0: raise ValueError("CIDv0 is malformed.") if v in (2, 3): raise ValueError("CID versions 2 and 3 are reserved for future use.") if v != 1: raise ValueError(f"CIDv{v} is currently not supported.") mc_code, _, cid = multicodec.unwrap_raw(cid) # multicodec digest = cid # multihash digest is what's left mc = multicodec.get(code=mc_code) mh_code, _ = multihash.unwrap_raw(digest) mh = multihash.get(code=mh_code) return CID._new_instance(CID, mb, v, mc, mh, digest)
def peer_id(pk_bytes: Union[str, bytes, bytearray, memoryview]) ‑> CID
-
Wraps the raw hash of a public key into a PeerID, as a CIDv1.
The
pk_bytes
argument should be the binary public key, encoded according to the PeerID spec. This can be passed as a bytestring or as a hex string (which will be converted tobytes
usingbytes.fromhex
). Note: the hex string is not multibase encoded.Example usage with Ed25519 public key:
>>> pk_bytes = bytes.fromhex( ... "1498b5467a63dffa2dc9d9e069caf075d16fc33fdd4c3b01bfadae6433767d93") ... # a 32-byte Ed25519 public key >>> peer_id = CID.peer_id(pk_bytes) >>> peer_id CID('base32', 1, 'libp2p-key', '00201498b5467a63dffa2dc9d9e069caf075d16fc33fdd4c3b01bfadae6433767d93') #^^ 0x00 = 'identity' multihash used (public key length <= 42) # ^^ 0x20 = 32-bytes of raw hash digestlength >>> str(peer_id) 'bafzaaiautc2um6td375c3soz4bu4v4dv2fx4gp65jq5qdp5nvzsdg5t5sm'
Snippet showing how to obtain the Ed25519 public key bytestring using the
cryptography
library:>>> from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey >>> from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat >>> private_key = Ed25519PrivateKey.generate() >>> public_key = private_key.public_key() >>> pk_bytes = public_key.public_bytes( ... encoding=Encoding.Raw, ... format=PublicFormat.Raw ... ) >>> pk_bytes.hex() "1498b5467a63dffa2dc9d9e069caf075d16fc33fdd4c3b01bfadae6433767d93"
Example usage with DER-encoded RSA public key:
>>> pk_bytes = bytes.fromhex( ... "30820122300d06092a864886f70d01010105000382010f003082010a02820101" ... "009a56a5c11e2705d0bfe0cd1fa66d5e519095cc741b62ed99ddf129c32e046e" ... "5ba3958bb8a068b05a95a6a0623cc3c889b1581793cd84a34cc2307e0dd74c70" ... "b4f230c74e5063ecd8e906d372be4eba13f47d04427a717ac78cb12b4b9c2ab5" ... "591f36f98021a70f84d782c36c51819054228ff35a45efa3f82b27849ec89036" ... "26b4a4c4b40f9f74b79caf55253687124c79cb10cd3bc73f0c44fbd341e5417d" ... "2e85e900d22849d2bc85ca6bf037f1f5b4f9759b4b6942fccdf1140b30ea7557" ... "87deb5c373c5953c14d64b523959a76a32a599903974a98cf38d4aaac7e359f8" ... "6b00a91dcf424bf794592139e7097d7e65889259227c07155770276b6eda4cec" ... "370203010001") ... # a 294-byte RSA public key >>> peer_id = CID.peer_id(pk_bytes) >>> peer_id CID('base32', 1, 'libp2p-key', '1220c1a6513ffb14f202f75453c49666a5b9d7ed9a1a068891daf824d477573f829f') #^^ 0x12 = 'sha2-256' multihash used (public key length > 42) # ^^ 0x20 = 32-bytes of raw hash digest length >>> str(peer_id) 'bafzbeigbuzit76yu6ibpovctyslgnjnz27wzugqgrci5v6be2r3vop4ct4'
Snippet showing how to obtain the RSA public key bytestring using the
cryptography
library:>>> from cryptography.hazmat.primitives.asymmetric import rsa >>> from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat >>> private_key = rsa.generate_private_key( ... public_exponent=65537, ... key_size=2048, ... ) >>> public_key = private_key.public_key() >>> pk_bytes = public_key.public_bytes( ... encoding=Encoding.DER, ... format=PublicFormat.SubjectPublicKeyInfo ... ) >>> pk_bytes.hex() "30820122300d06092a864886f70d01010105000382010f003082010a02820101" "009a56a5c11e2705d0bfe0cd1fa66d5e519095cc741b62ed99ddf129c32e046e" "5ba3958bb8a068b05a95a6a0623cc3c889b1581793cd84a34cc2307e0dd74c70" "b4f230c74e5063ecd8e906d372be4eba13f47d04427a717ac78cb12b4b9c2ab5" "591f36f98021a70f84d782c36c51819054228ff35a45efa3f82b27849ec89036" "26b4a4c4b40f9f74b79caf55253687124c79cb10cd3bc73f0c44fbd341e5417d" "2e85e900d22849d2bc85ca6bf037f1f5b4f9759b4b6942fccdf1140b30ea7557" "87deb5c373c5953c14d64b523959a76a32a599903974a98cf38d4aaac7e359f8" "6b00a91dcf424bf794592139e7097d7e65889259227c07155770276b6eda4cec" "370203010001"
Expand source code
@staticmethod def peer_id(pk_bytes: Union[str, BytesLike]) -> "CID": """ Wraps the raw hash of a public key into a [PeerID](https://docs.libp2p.io/concepts/peer-id/), as a CIDv1. The `pk_bytes` argument should be the binary public key, encoded according to the [PeerID spec](https://github.com/libp2p/specs/blob/master/peer-ids/peer-ids.md). This can be passed as a bytestring or as a hex string (which will be converted to `bytes` using `bytes.fromhex`). Note: the hex string is not multibase encoded. Example usage with Ed25519 public key: ```py >>> pk_bytes = bytes.fromhex( ... "1498b5467a63dffa2dc9d9e069caf075d16fc33fdd4c3b01bfadae6433767d93") ... # a 32-byte Ed25519 public key >>> peer_id = CID.peer_id(pk_bytes) >>> peer_id CID('base32', 1, 'libp2p-key', '00201498b5467a63dffa2dc9d9e069caf075d16fc33fdd4c3b01bfadae6433767d93') #^^ 0x00 = 'identity' multihash used (public key length <= 42) # ^^ 0x20 = 32-bytes of raw hash digestlength >>> str(peer_id) 'bafzaaiautc2um6td375c3soz4bu4v4dv2fx4gp65jq5qdp5nvzsdg5t5sm' ``` Snippet showing how to obtain the [Ed25519](https://cryptography.io/en/latest/hazmat/primitives/asymmetric/ed25519/) public key bytestring using the [`cryptography`](https://github.com/pyca/cryptography) library: ```py >>> from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey >>> from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat >>> private_key = Ed25519PrivateKey.generate() >>> public_key = private_key.public_key() >>> pk_bytes = public_key.public_bytes( ... encoding=Encoding.Raw, ... format=PublicFormat.Raw ... ) >>> pk_bytes.hex() "1498b5467a63dffa2dc9d9e069caf075d16fc33fdd4c3b01bfadae6433767d93" ``` Example usage with DER-encoded RSA public key: ```py >>> pk_bytes = bytes.fromhex( ... "30820122300d06092a864886f70d01010105000382010f003082010a02820101" ... "009a56a5c11e2705d0bfe0cd1fa66d5e519095cc741b62ed99ddf129c32e046e" ... "5ba3958bb8a068b05a95a6a0623cc3c889b1581793cd84a34cc2307e0dd74c70" ... "b4f230c74e5063ecd8e906d372be4eba13f47d04427a717ac78cb12b4b9c2ab5" ... "591f36f98021a70f84d782c36c51819054228ff35a45efa3f82b27849ec89036" ... "26b4a4c4b40f9f74b79caf55253687124c79cb10cd3bc73f0c44fbd341e5417d" ... "2e85e900d22849d2bc85ca6bf037f1f5b4f9759b4b6942fccdf1140b30ea7557" ... "87deb5c373c5953c14d64b523959a76a32a599903974a98cf38d4aaac7e359f8" ... "6b00a91dcf424bf794592139e7097d7e65889259227c07155770276b6eda4cec" ... "370203010001") ... # a 294-byte RSA public key >>> peer_id = CID.peer_id(pk_bytes) >>> peer_id CID('base32', 1, 'libp2p-key', '1220c1a6513ffb14f202f75453c49666a5b9d7ed9a1a068891daf824d477573f829f') #^^ 0x12 = 'sha2-256' multihash used (public key length > 42) # ^^ 0x20 = 32-bytes of raw hash digest length >>> str(peer_id) 'bafzbeigbuzit76yu6ibpovctyslgnjnz27wzugqgrci5v6be2r3vop4ct4' ``` Snippet showing how to obtain the [RSA](https://cryptography.io/en/latest/hazmat/primitives/asymmetric/rsa/) public key bytestring using the [`cryptography`](https://github.com/pyca/cryptography) library: ```py >>> from cryptography.hazmat.primitives.asymmetric import rsa >>> from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat >>> private_key = rsa.generate_private_key( ... public_exponent=65537, ... key_size=2048, ... ) >>> public_key = private_key.public_key() >>> pk_bytes = public_key.public_bytes( ... encoding=Encoding.DER, ... format=PublicFormat.SubjectPublicKeyInfo ... ) >>> pk_bytes.hex() "30820122300d06092a864886f70d01010105000382010f003082010a02820101" "009a56a5c11e2705d0bfe0cd1fa66d5e519095cc741b62ed99ddf129c32e046e" "5ba3958bb8a068b05a95a6a0623cc3c889b1581793cd84a34cc2307e0dd74c70" "b4f230c74e5063ecd8e906d372be4eba13f47d04427a717ac78cb12b4b9c2ab5" "591f36f98021a70f84d782c36c51819054228ff35a45efa3f82b27849ec89036" "26b4a4c4b40f9f74b79caf55253687124c79cb10cd3bc73f0c44fbd341e5417d" "2e85e900d22849d2bc85ca6bf037f1f5b4f9759b4b6942fccdf1140b30ea7557" "87deb5c373c5953c14d64b523959a76a32a599903974a98cf38d4aaac7e359f8" "6b00a91dcf424bf794592139e7097d7e65889259227c07155770276b6eda4cec" "370203010001" ``` """ if isinstance(pk_bytes, str): pk_bytes = bytes.fromhex(pk_bytes) else: validate(pk_bytes, BytesLike) if len(pk_bytes) <= 42: mh = multihash.get("identity") digest = multihash.digest(pk_bytes, mh) else: mh = multihash.get("sha2-256") digest = multihash.digest(pk_bytes, mh) mc = multicodec.get(code=0x72) # multicodec.get("libp2p-key") mb = multibase.get("base32") return CID._new_instance(CID, mb, 1, mc, mh, digest)
Instance variables
var base : Multibase
-
Multibase used to encode the CID:
- if a CIDv1 was decoded from a multibase-encoded string, the encoding multibase is used
- if a CIDv1 was decoded from a bytestring, the 'base58btc' multibase is used
- for a CIDv0, 'base58btc' is always used
Example usage:
>>> s = "zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA" >>> cid = CID.decode(s) >>> cid.base Multibase(name='base58btc', code='z', status='default', description='base58 bitcoin')
Expand source code
@property def base(self) -> Multibase: """ Multibase used to encode the CID: - if a CIDv1 was decoded from a multibase-encoded string, the encoding multibase is used - if a CIDv1 was decoded from a bytestring, the 'base58btc' multibase is used - for a CIDv0, 'base58btc' is always used Example usage: ```py >>> s = "zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA" >>> cid = CID.decode(s) >>> cid.base Multibase(name='base58btc', code='z', status='default', description='base58 bitcoin') ``` """ return self._base
var codec : Multicodec
-
Codec that the multihash digest refers to.
Example usage:
>>> s = "zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA" >>> cid = CID.decode(s) >>> cid.codec Multicodec(name='raw', tag='ipld', code='0x55', status='permanent', description='raw binary')
Expand source code
@property def codec(self) -> Multicodec: """ Codec that the multihash digest refers to. Example usage: ```py >>> s = "zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA" >>> cid = CID.decode(s) >>> cid.codec Multicodec(name='raw', tag='ipld', code='0x55', status='permanent', description='raw binary') ``` """ return self._codec
var digest : bytes
-
Multihash digest.
Example usage:
>>> s = "zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA" >>> cid = CID.decode(s) >>> cid.digest.hex() '12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95'
Expand source code
@property def digest(self) -> bytes: """ Multihash digest. Example usage: ```py >>> s = "zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA" >>> cid = CID.decode(s) >>> cid.digest.hex() '12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95' ``` """ return self._digest
var hashfun : Multihash
-
Multihash used to produce the multihash digest.
Example usage:
>>> s = "zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA" >>> cid = CID.decode(s) >>> cid.hashfun Multicodec(name='sha2-256', tag='multihash', code='0x12', status='permanent', description='')
Expand source code
@property def hashfun(self) -> Multihash: """ Multihash used to produce the multihash digest. Example usage: ```py >>> s = "zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA" >>> cid = CID.decode(s) >>> cid.hashfun Multicodec(name='sha2-256', tag='multihash', code='0x12', status='permanent', description='') ``` """ return self._hashfun
var human_readable : str
-
Human-readable representation of the CID.
Example usage:
>>> s = "zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA" >>> cid = CID.decode(s) >>> cid.human_readable 'base58btc - cidv1 - raw - (sha2-256 : 256 : 6E6FF7950A36187A801613426E858DCE686CD7D7E3C0FC42EE0330072D245C95)'
Expand source code
@property def human_readable(self) -> str: """ Human-readable representation of the CID. Example usage: ```py >>> s = "zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA" >>> cid = CID.decode(s) >>> cid.human_readable 'base58btc - cidv1 - raw - (sha2-256 : 256 : 6E6FF7950A36187A801613426E858DCE686CD7D7E3C0FC42EE0330072D245C95)' ``` """ raw_digest = self.raw_digest hashfun_str = f"({self.hashfun.name} : {len(raw_digest)*8} : {raw_digest.hex().upper()})" return f"{self.base.name} - cidv{self.version} - {self.codec.name} - {hashfun_str}"
var raw_digest : bytes
-
Raw hash digest, decoded from the multihash digest.
Example usage:
>>> s = "zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA" >>> cid = CID.decode(s) >>> cid.raw_digest.hex() '6e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95'
Expand source code
@property def raw_digest(self) -> bytes: """ Raw hash digest, decoded from the multihash digest. Example usage: ```py >>> s = "zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA" >>> cid = CID.decode(s) >>> cid.raw_digest.hex() '6e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95' ``` """ return multihash.unwrap(self._digest)
var version : Literal[0, 1]
-
CID version.
Example usage:
>>> s = "zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA" >>> cid = CID.decode(s) >>> cid.version 1
Expand source code
@property def version(self) -> CIDVersion: """ CID version. Example usage: ```py >>> s = "zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA" >>> cid = CID.decode(s) >>> cid.version 1 ``` """ return self._version
Methods
def encode(self, base: Union[ForwardRef(None), str, Multibase] = None) ‑> str
-
Encodes the CID using a given multibase. If no multibase is given, the CID's own multibase is used by default.
Example usage:
>>> s = "zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA" >>> cid = CID.decode(s) >>> cid.encode() # default: cid.base 'zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA' >>> cid.encode("base32") 'bafkreidon73zkcrwdb5iafqtijxildoonbwnpv7dyd6ef3qdgads2jc4su'
Expand source code
def encode(self, base: Union[None, str, Multibase] = None) -> str: """ Encodes the CID using a given multibase. If no multibase is given, the CID's own multibase is used by default. Example usage: ```py >>> s = "zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA" >>> cid = CID.decode(s) >>> cid.encode() # default: cid.base 'zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA' >>> cid.encode("base32") 'bafkreidon73zkcrwdb5iafqtijxildoonbwnpv7dyd6ef3qdgads2jc4su' ``` """ if self.version == 0: if base is not None: raise ValueError("CIDv0 cannot be multibase-encoded, please set multibase=None.") return base58btc.encode(bytes(self)) if base is None or base == self.base: base = self.base # use CID's own multibase as default else: if isinstance(base, str): base = multibase.get(base) else: multibase.validate_multibase(base) return base.encode(bytes(self))
def set(self, *, base: Union[ForwardRef(None), str, Multibase] = None, version: Optional[None] = None, codec: Union[ForwardRef(None), str, int, Multicodec] = None) ‑> CID
-
Returns a new CID obtained by setting new values for one or more of:
base
,version
, orcodec
.Example usage:
>>> s = "zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA" >>> cid = CID.decode(s) >>> cid CID('base58btc', 1, 'raw', '12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95') >>> cid.set(base="base32") CID('base32', 1, 'raw', '12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95') >>> cid.set(codec="dag-cbor") CID('base58btc', 1, 'dag-cbor', '12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95') >>> cid.set(version=0, codec="dag-pb") CID('base58btc', 0, 'dag-pb', '12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95') >>> cid CID('base58btc', 1, 'raw', '12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95') # Note: 'CID.set' returns new instances, # the original 'cid' instance is unchanged
If setting
version
to 0,base
must be 'base58btc' andcodec
must be 'dag-pb'.>>> s = "zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA" >>> cid = CID.decode(s) >>> cid CID('base58btc', 1, 'raw', '12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95') >>> cid.set(version=0, codec="dag-pb") CID('base58btc', 0, 'dag-pb', '12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95') >>> cid.set(version=0) ValueError: CIDv0 multicodec must be 'dag-pb', found 'raw' instead. >>> cid.set(version=0, codec="dag-pb", base="base32") ValueError: CIDv0 multibase must be 'base58btc', found 'base32' instead
Expand source code
def set(self, *, base: Union[None, str, Multibase] = None, version: Union[None, int] = None, codec: Union[None, str, int, Multicodec] = None ) -> "CID": """ Returns a new CID obtained by setting new values for one or more of: `base`, `version`, or `codec`. Example usage: ```py >>> s = "zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA" >>> cid = CID.decode(s) >>> cid CID('base58btc', 1, 'raw', '12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95') >>> cid.set(base="base32") CID('base32', 1, 'raw', '12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95') >>> cid.set(codec="dag-cbor") CID('base58btc', 1, 'dag-cbor', '12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95') >>> cid.set(version=0, codec="dag-pb") CID('base58btc', 0, 'dag-pb', '12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95') >>> cid CID('base58btc', 1, 'raw', '12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95') # Note: 'CID.set' returns new instances, # the original 'cid' instance is unchanged ``` If setting `version` to 0, `base` must be 'base58btc' and `codec` must be 'dag-pb'. ```py >>> s = "zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA" >>> cid = CID.decode(s) >>> cid CID('base58btc', 1, 'raw', '12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95') >>> cid.set(version=0, codec="dag-pb") CID('base58btc', 0, 'dag-pb', '12206e6ff7950a36187a801613426e858dce686cd7d7e3c0fc42ee0330072d245c95') >>> cid.set(version=0) ValueError: CIDv0 multicodec must be 'dag-pb', found 'raw' instead. >>> cid.set(version=0, codec="dag-pb", base="base32") ValueError: CIDv0 multibase must be 'base58btc', found 'base32' instead ``` """ hashfun = self.hashfun digest = self.digest if base is not None and base not in (self.base, self.base.name): base = _CID_validate_multibase(base) else: base = self.base if codec is not None and codec not in (self.codec, self.codec.name, self.codec.code): codec = _CID_validate_multicodec(codec) else: codec = self.codec if version is not None and version != self.version: _CID_validate_version(version, base, codec, hashfun) else: version = self.version return CID._new_instance(CID, base, version, codec, hashfun, digest)