refactor: don't depend on multihash features

All we need from the multihash is for it to be a data structure that we pass around. We only ever use the identity "hasher" and the sha256 hasher. Those are easily implemented without depending the (fairly heavy) machinery in `multihash`.

Unfortunately, this patch by itself does not yet lighten our dependency tree because `multiaddr` activates those features unconditionally. I opened a companion PR for this: https://github.com/multiformats/rust-multiaddr/pull/77.

https://github.com/multiformats/rust-multiaddr/pull/77 is another breaking change and we are trying to delay those at the moment. However, it will (hopefully) land eventually which should then be much easier to implement.

Fixes #3276.

Pull-Request: #3514.
This commit is contained in:
Thomas Eizinger
2023-03-30 19:47:35 +02:00
committed by GitHub
parent 75f967f4da
commit dfa7bd6b57
14 changed files with 71 additions and 54 deletions

3
Cargo.lock generated
View File

@ -2945,6 +2945,7 @@ dependencies = [
"rand 0.8.5", "rand 0.8.5",
"rcgen 0.9.3", "rcgen 0.9.3",
"serde", "serde",
"sha2 0.10.6",
"stun", "stun",
"thiserror", "thiserror",
"tinytemplate", "tinytemplate",
@ -3214,13 +3215,11 @@ checksum = "835d6ff01d610179fbce3de1694d007e500bf33a7f29689838941d6bf783ae40"
dependencies = [ dependencies = [
"arbitrary", "arbitrary",
"core2", "core2",
"digest 0.10.6",
"multihash-derive", "multihash-derive",
"quickcheck", "quickcheck",
"rand 0.8.5", "rand 0.8.5",
"serde", "serde",
"serde-big-array", "serde-big-array",
"sha2 0.10.6",
"unsigned-varint", "unsigned-varint",
] ]

View File

@ -19,7 +19,7 @@ instant = "0.1.11"
libp2p-identity = { version = "0.1", path = "../identity", features = ["peerid", "ed25519"] } libp2p-identity = { version = "0.1", path = "../identity", features = ["peerid", "ed25519"] }
log = "0.4" log = "0.4"
multiaddr = { version = "0.17.0" } multiaddr = { version = "0.17.0" }
multihash = { version = "0.17.0", default-features = false, features = ["std", "multihash-impl", "identity", "sha2"] } multihash = { version = "0.17.0", default-features = false, features = ["std"] }
multistream-select = { version = "0.12.1", path = "../misc/multistream-select" } multistream-select = { version = "0.12.1", path = "../misc/multistream-select" }
once_cell = "1.17.1" once_cell = "1.17.1"
parking_lot = "0.12.0" parking_lot = "0.12.0"

View File

@ -18,7 +18,7 @@ ed25519-dalek = { version = "1.0.1", optional = true }
libsecp256k1 = { version = "0.7.0", optional = true } libsecp256k1 = { version = "0.7.0", optional = true }
log = "0.4" log = "0.4"
multiaddr = { version = "0.17.0", optional = true } multiaddr = { version = "0.17.0", optional = true }
multihash = { version = "0.17.0", default-features = false, features = ["std", "multihash-impl", "identity", "sha2"], optional = true } multihash = { version = "0.17.0", default-features = false, features = ["std"], optional = true }
p256 = { version = "0.12", default-features = false, features = ["ecdsa", "std"], optional = true } p256 = { version = "0.12", default-features = false, features = ["ecdsa", "std"], optional = true }
prost = { version = "0.11", optional = true } prost = { version = "0.11", optional = true }
quick-protobuf = "0.8.1" quick-protobuf = "0.8.1"
@ -38,7 +38,7 @@ secp256k1 = [ "libsecp256k1", "asn1_der", "prost", "rand", "sha2", "zeroize" ]
ecdsa = [ "p256", "prost", "rand", "void", "zeroize", "sec1" ] ecdsa = [ "p256", "prost", "rand", "void", "zeroize", "sec1" ]
rsa = [ "dep:ring", "asn1_der", "prost", "rand", "zeroize" ] rsa = [ "dep:ring", "asn1_der", "prost", "rand", "zeroize" ]
ed25519 = [ "ed25519-dalek", "prost", "rand", "zeroize" ] ed25519 = [ "ed25519-dalek", "prost", "rand", "zeroize" ]
peerid = [ "multihash", "multiaddr", "bs58", "rand", "thiserror" ] peerid = [ "multihash", "multiaddr", "bs58", "rand", "thiserror", "sha2" ]
[dev-dependencies] [dev-dependencies]
quickcheck = { package = "quickcheck-ext", path = "../misc/quickcheck-ext" } quickcheck = { package = "quickcheck-ext", path = "../misc/quickcheck-ext" }

View File

@ -110,6 +110,7 @@ impl Keypair {
#[cfg(feature = "ed25519")] #[cfg(feature = "ed25519")]
pub fn into_ed25519(self) -> Option<ed25519::Keypair> { pub fn into_ed25519(self) -> Option<ed25519::Keypair> {
#[allow(deprecated)] #[allow(deprecated)]
#[allow(unreachable_patterns)]
match self { match self {
Keypair::Ed25519(inner) => Some(inner), Keypair::Ed25519(inner) => Some(inner),
_ => None, _ => None,
@ -119,6 +120,7 @@ impl Keypair {
#[cfg(feature = "secp256k1")] #[cfg(feature = "secp256k1")]
pub fn into_secp256k1(self) -> Option<secp256k1::Keypair> { pub fn into_secp256k1(self) -> Option<secp256k1::Keypair> {
#[allow(deprecated)] #[allow(deprecated)]
#[allow(unreachable_patterns)]
match self { match self {
Keypair::Secp256k1(inner) => Some(inner), Keypair::Secp256k1(inner) => Some(inner),
_ => None, _ => None,
@ -128,6 +130,7 @@ impl Keypair {
#[cfg(all(feature = "rsa", not(target_arch = "wasm32")))] #[cfg(all(feature = "rsa", not(target_arch = "wasm32")))]
pub fn into_rsa(self) -> Option<rsa::Keypair> { pub fn into_rsa(self) -> Option<rsa::Keypair> {
#[allow(deprecated)] #[allow(deprecated)]
#[allow(unreachable_patterns)]
match self { match self {
Keypair::Rsa(inner) => Some(inner), Keypair::Rsa(inner) => Some(inner),
_ => None, _ => None,
@ -137,6 +140,7 @@ impl Keypair {
#[cfg(feature = "ecdsa")] #[cfg(feature = "ecdsa")]
pub fn into_ecdsa(self) -> Option<ecdsa::Keypair> { pub fn into_ecdsa(self) -> Option<ecdsa::Keypair> {
#[allow(deprecated)] #[allow(deprecated)]
#[allow(unreachable_patterns)]
match self { match self {
Keypair::Ecdsa(inner) => Some(inner), Keypair::Ecdsa(inner) => Some(inner),
_ => None, _ => None,
@ -354,6 +358,7 @@ impl PublicKey {
#[cfg(feature = "ed25519")] #[cfg(feature = "ed25519")]
pub fn into_ed25519(self) -> Option<ed25519::PublicKey> { pub fn into_ed25519(self) -> Option<ed25519::PublicKey> {
#[allow(deprecated)] #[allow(deprecated)]
#[allow(unreachable_patterns)]
match self { match self {
PublicKey::Ed25519(inner) => Some(inner), PublicKey::Ed25519(inner) => Some(inner),
_ => None, _ => None,
@ -363,6 +368,7 @@ impl PublicKey {
#[cfg(feature = "secp256k1")] #[cfg(feature = "secp256k1")]
pub fn into_secp256k1(self) -> Option<secp256k1::PublicKey> { pub fn into_secp256k1(self) -> Option<secp256k1::PublicKey> {
#[allow(deprecated)] #[allow(deprecated)]
#[allow(unreachable_patterns)]
match self { match self {
PublicKey::Secp256k1(inner) => Some(inner), PublicKey::Secp256k1(inner) => Some(inner),
_ => None, _ => None,
@ -372,6 +378,7 @@ impl PublicKey {
#[cfg(all(feature = "rsa", not(target_arch = "wasm32")))] #[cfg(all(feature = "rsa", not(target_arch = "wasm32")))]
pub fn into_rsa(self) -> Option<rsa::PublicKey> { pub fn into_rsa(self) -> Option<rsa::PublicKey> {
#[allow(deprecated)] #[allow(deprecated)]
#[allow(unreachable_patterns)]
match self { match self {
PublicKey::Rsa(inner) => Some(inner), PublicKey::Rsa(inner) => Some(inner),
_ => None, _ => None,
@ -381,6 +388,7 @@ impl PublicKey {
#[cfg(feature = "ecdsa")] #[cfg(feature = "ecdsa")]
pub fn into_ecdsa(self) -> Option<ecdsa::PublicKey> { pub fn into_ecdsa(self) -> Option<ecdsa::PublicKey> {
#[allow(deprecated)] #[allow(deprecated)]
#[allow(unreachable_patterns)]
match self { match self {
PublicKey::Ecdsa(inner) => Some(inner), PublicKey::Ecdsa(inner) => Some(inner),
_ => None, _ => None,

View File

@ -19,11 +19,19 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
use multiaddr::{Multiaddr, Protocol}; use multiaddr::{Multiaddr, Protocol};
use multihash::{Code, Error, Multihash}; use multihash::{Code, Error, MultihashGeneric};
use rand::Rng; use rand::Rng;
use sha2::Digest as _;
use std::{convert::TryFrom, fmt, str::FromStr}; use std::{convert::TryFrom, fmt, str::FromStr};
use thiserror::Error; use thiserror::Error;
/// Local type-alias for multihash.
///
/// Must be big enough to accommodate for `MAX_INLINE_KEY_LENGTH`.
/// 64 satisfies that and can hold 512 bit hashes which is what the ecosystem typically uses.
/// Given that this appears in our type-signature, using a "common" number here makes us more compatible.
type Multihash = MultihashGeneric<64>;
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -31,6 +39,9 @@ use serde::{Deserialize, Serialize};
/// automatically used as the peer id using an identity multihash. /// automatically used as the peer id using an identity multihash.
const MAX_INLINE_KEY_LENGTH: usize = 42; const MAX_INLINE_KEY_LENGTH: usize = 42;
const MULTIHASH_IDENTITY_CODE: u64 = 0;
const MULTIHASH_SHA256_CODE: u64 = 0x12;
/// Identifier of a peer of the network. /// Identifier of a peer of the network.
/// ///
/// The data is a CIDv0 compatible multihash of the protobuf encoded public key of the peer /// The data is a CIDv0 compatible multihash of the protobuf encoded public key of the peer
@ -55,18 +66,16 @@ impl fmt::Display for PeerId {
impl PeerId { impl PeerId {
/// Builds a `PeerId` from a public key. /// Builds a `PeerId` from a public key.
pub fn from_public_key(key: &crate::keypair::PublicKey) -> PeerId { pub fn from_public_key(key: &crate::keypair::PublicKey) -> PeerId {
use multihash::MultihashDigest as _;
let key_enc = key.to_protobuf_encoding(); let key_enc = key.to_protobuf_encoding();
let hash_algorithm = if key_enc.len() <= MAX_INLINE_KEY_LENGTH { let multihash = if key_enc.len() <= MAX_INLINE_KEY_LENGTH {
Code::Identity Multihash::wrap(MULTIHASH_IDENTITY_CODE, &key_enc)
.expect("64 byte multihash provides sufficient space")
} else { } else {
Code::Sha2_256 Multihash::wrap(MULTIHASH_SHA256_CODE, &sha2::Sha256::digest(key_enc))
.expect("64 byte multihash provides sufficient space")
}; };
let multihash = hash_algorithm.digest(&key_enc);
PeerId { multihash } PeerId { multihash }
} }
@ -82,9 +91,9 @@ impl PeerId {
/// or the hash value does not satisfy the constraints for a hashed /// or the hash value does not satisfy the constraints for a hashed
/// peer ID, it is returned as an `Err`. /// peer ID, it is returned as an `Err`.
pub fn from_multihash(multihash: Multihash) -> Result<PeerId, Multihash> { pub fn from_multihash(multihash: Multihash) -> Result<PeerId, Multihash> {
match Code::try_from(multihash.code()) { match multihash.code() {
Ok(Code::Sha2_256) => Ok(PeerId { multihash }), MULTIHASH_SHA256_CODE => Ok(PeerId { multihash }),
Ok(Code::Identity) if multihash.digest().len() <= MAX_INLINE_KEY_LENGTH => { MULTIHASH_IDENTITY_CODE if multihash.digest().len() <= MAX_INLINE_KEY_LENGTH => {
Ok(PeerId { multihash }) Ok(PeerId { multihash })
} }
_ => Err(multihash), _ => Err(multihash),

View File

@ -24,13 +24,13 @@ use super::*;
use crate::kbucket::Distance; use crate::kbucket::Distance;
use crate::record::{store::MemoryStore, Key}; use crate::record::{store::MemoryStore, Key};
use crate::K_VALUE; use crate::{K_VALUE, SHA_256_MH};
use futures::{executor::block_on, future::poll_fn, prelude::*}; use futures::{executor::block_on, future::poll_fn, prelude::*};
use futures_timer::Delay; use futures_timer::Delay;
use libp2p_core::{ use libp2p_core::{
connection::ConnectedPoint, connection::ConnectedPoint,
multiaddr::{multiaddr, Multiaddr, Protocol}, multiaddr::{multiaddr, Multiaddr, Protocol},
multihash::{Code, Multihash, MultihashDigest}, multihash::Multihash,
transport::MemoryTransport, transport::MemoryTransport,
upgrade, Endpoint, Transport, upgrade, Endpoint, Transport,
}; };
@ -138,7 +138,7 @@ fn build_fully_connected_nodes_with_config(
} }
fn random_multihash() -> Multihash { fn random_multihash() -> Multihash {
Multihash::wrap(Code::Sha2_256.into(), &thread_rng().gen::<[u8; 32]>()).unwrap() Multihash::wrap(SHA_256_MH, &thread_rng().gen::<[u8; 32]>()).unwrap()
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -1100,7 +1100,10 @@ fn disjoint_query_does_not_finish_before_all_paths_did() {
let mut trudy = build_node(); // Trudy the intrudor, an adversary. let mut trudy = build_node(); // Trudy the intrudor, an adversary.
let mut bob = build_node(); let mut bob = build_node();
let key = Key::from(Code::Sha2_256.digest(&thread_rng().gen::<[u8; 32]>())); let key = Key::from(
Multihash::wrap(SHA_256_MH, &thread_rng().gen::<[u8; 32]>())
.expect("32 array to fit into 64 byte multihash"),
);
let record_bob = Record::new(key.clone(), b"bob".to_vec()); let record_bob = Record::new(key.clone(), b"bob".to_vec());
let record_trudy = Record::new(key.clone(), b"trudy".to_vec()); let record_trudy = Record::new(key.clone(), b"trudy".to_vec());

View File

@ -196,7 +196,7 @@ impl Distance {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use libp2p_core::multihash::Code; use crate::SHA_256_MH;
use quickcheck::*; use quickcheck::*;
impl Arbitrary for Key<PeerId> { impl Arbitrary for Key<PeerId> {
@ -208,7 +208,7 @@ mod tests {
impl Arbitrary for Key<Multihash> { impl Arbitrary for Key<Multihash> {
fn arbitrary(g: &mut Gen) -> Key<Multihash> { fn arbitrary(g: &mut Gen) -> Key<Multihash> {
let hash: [u8; 32] = core::array::from_fn(|_| u8::arbitrary(g)); let hash: [u8; 32] = core::array::from_fn(|_| u8::arbitrary(g));
Key::from(Multihash::wrap(Code::Sha2_256.into(), &hash).unwrap()) Key::from(Multihash::wrap(SHA_256_MH, &hash).unwrap())
} }
} }

View File

@ -100,3 +100,7 @@ pub const K_VALUE: NonZeroUsize = unsafe { NonZeroUsize::new_unchecked(20) };
/// ///
/// The current value is `3`. /// The current value is `3`.
pub const ALPHA_VALUE: NonZeroUsize = unsafe { NonZeroUsize::new_unchecked(3) }; pub const ALPHA_VALUE: NonZeroUsize = unsafe { NonZeroUsize::new_unchecked(3) };
/// Constant shared across tests for the [`Multihash`](libp2p_core::multihash::Multihash) type.
#[cfg(test)]
const SHA_256_MH: u64 = 0x12;

View File

@ -475,7 +475,8 @@ enum PeerState {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use libp2p_core::multihash::{Code, Multihash}; use crate::SHA_256_MH;
use libp2p_core::multihash::Multihash;
use libp2p_identity::PeerId; use libp2p_identity::PeerId;
use quickcheck::*; use quickcheck::*;
use rand::{rngs::StdRng, Rng, SeedableRng}; use rand::{rngs::StdRng, Rng, SeedableRng};
@ -484,9 +485,7 @@ mod tests {
fn random_peers<R: Rng>(n: usize, g: &mut R) -> Vec<PeerId> { fn random_peers<R: Rng>(n: usize, g: &mut R) -> Vec<PeerId> {
(0..n) (0..n)
.map(|_| { .map(|_| {
PeerId::from_multihash( PeerId::from_multihash(Multihash::wrap(SHA_256_MH, &g.gen::<[u8; 32]>()).unwrap())
Multihash::wrap(Code::Sha2_256.into(), &g.gen::<[u8; 32]>()).unwrap(),
)
.unwrap() .unwrap()
}) })
.collect() .collect()
@ -505,8 +504,7 @@ mod tests {
fn arbitrary(g: &mut Gen) -> ArbitraryPeerId { fn arbitrary(g: &mut Gen) -> ArbitraryPeerId {
let hash: [u8; 32] = core::array::from_fn(|_| u8::arbitrary(g)); let hash: [u8; 32] = core::array::from_fn(|_| u8::arbitrary(g));
let peer_id = let peer_id =
PeerId::from_multihash(Multihash::wrap(Code::Sha2_256.into(), &hash).unwrap()) PeerId::from_multihash(Multihash::wrap(SHA_256_MH, &hash).unwrap()).unwrap();
.unwrap();
ArbitraryPeerId(peer_id) ArbitraryPeerId(peer_id)
} }
} }

View File

@ -444,8 +444,8 @@ impl<I: Iterator<Item = Key<PeerId>>> Iterator for ResultIter<I> {
mod tests { mod tests {
use super::*; use super::*;
use crate::K_VALUE; use crate::{K_VALUE, SHA_256_MH};
use libp2p_core::multihash::{Code, Multihash}; use libp2p_core::multihash::Multihash;
use quickcheck::*; use quickcheck::*;
use std::collections::HashSet; use std::collections::HashSet;
use std::iter; use std::iter;
@ -531,8 +531,7 @@ mod tests {
fn arbitrary(g: &mut Gen) -> ArbitraryPeerId { fn arbitrary(g: &mut Gen) -> ArbitraryPeerId {
let hash: [u8; 32] = core::array::from_fn(|_| u8::arbitrary(g)); let hash: [u8; 32] = core::array::from_fn(|_| u8::arbitrary(g));
let peer_id = let peer_id =
PeerId::from_multihash(Multihash::wrap(Code::Sha2_256.into(), &hash).unwrap()) PeerId::from_multihash(Multihash::wrap(SHA_256_MH, &hash).unwrap()).unwrap();
.unwrap();
ArbitraryPeerId(peer_id) ArbitraryPeerId(peer_id)
} }
} }

View File

@ -161,14 +161,14 @@ impl ProviderRecord {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use libp2p_core::multihash::Code; use crate::SHA_256_MH;
use quickcheck::*; use quickcheck::*;
use std::time::Duration; use std::time::Duration;
impl Arbitrary for Key { impl Arbitrary for Key {
fn arbitrary(g: &mut Gen) -> Key { fn arbitrary(g: &mut Gen) -> Key {
let hash: [u8; 32] = core::array::from_fn(|_| u8::arbitrary(g)); let hash: [u8; 32] = core::array::from_fn(|_| u8::arbitrary(g));
Key::from(Multihash::wrap(Code::Sha2_256.into(), &hash).unwrap()) Key::from(Multihash::wrap(SHA_256_MH, &hash).unwrap())
} }
} }

View File

@ -216,12 +216,13 @@ impl RecordStore for MemoryStore {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use libp2p_core::multihash::{Code, Multihash}; use crate::SHA_256_MH;
use libp2p_core::multihash::Multihash;
use quickcheck::*; use quickcheck::*;
use rand::Rng; use rand::Rng;
fn random_multihash() -> Multihash { fn random_multihash() -> Multihash {
Multihash::wrap(Code::Sha2_256.into(), &rand::thread_rng().gen::<[u8; 32]>()).unwrap() Multihash::wrap(SHA_256_MH, &rand::thread_rng().gen::<[u8; 32]>()).unwrap()
} }
fn distance(r: &ProviderRecord) -> kbucket::Distance { fn distance(r: &ProviderRecord) -> kbucket::Distance {

View File

@ -22,7 +22,8 @@ libp2p-core = { version = "0.39.0", path = "../../core" }
libp2p-noise = { version = "0.42.0", path = "../../transports/noise" } libp2p-noise = { version = "0.42.0", path = "../../transports/noise" }
libp2p-identity = { version = "0.1.0", path = "../../identity" } libp2p-identity = { version = "0.1.0", path = "../../identity" }
log = "0.4" log = "0.4"
multihash = { version = "0.17.0", default-features = false, features = ["sha2"] } sha2 = "0.10.6"
multihash = { version = "0.17.0", default-features = false }
quick-protobuf = "0.8" quick-protobuf = "0.8"
quick-protobuf-codec = { version = "0.1", path = "../../misc/quick-protobuf-codec" } quick-protobuf-codec = { version = "0.1", path = "../../misc/quick-protobuf-codec" }
rand = "0.8" rand = "0.8"

View File

@ -18,12 +18,15 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
use multihash::{Code, Hasher, Multihash, MultihashDigest}; use multihash::MultihashGeneric;
use sha2::Digest as _;
use std::fmt;
use webrtc::dtls_transport::dtls_fingerprint::RTCDtlsFingerprint; use webrtc::dtls_transport::dtls_fingerprint::RTCDtlsFingerprint;
use std::fmt;
const SHA256: &str = "sha-256"; const SHA256: &str = "sha-256";
const MULTIHASH_SHA256_CODE: u64 = 0x12;
type Multihash = MultihashGeneric<64>;
/// A certificate fingerprint that is assumed to be created using the SHA256 hash algorithm. /// A certificate fingerprint that is assumed to be created using the SHA256 hash algorithm.
#[derive(Eq, PartialEq, Copy, Clone)] #[derive(Eq, PartialEq, Copy, Clone)]
@ -39,13 +42,7 @@ impl Fingerprint {
/// Creates a fingerprint from a raw certificate. /// Creates a fingerprint from a raw certificate.
pub fn from_certificate(bytes: &[u8]) -> Self { pub fn from_certificate(bytes: &[u8]) -> Self {
let mut h = multihash::Sha2_256::default(); Fingerprint(sha2::Sha256::digest(bytes).into())
h.update(bytes);
let mut bytes: [u8; 32] = [0; 32];
bytes.copy_from_slice(h.finalize());
Fingerprint(bytes)
} }
/// Converts [`RTCDtlsFingerprint`] to [`Fingerprint`]. /// Converts [`RTCDtlsFingerprint`] to [`Fingerprint`].
@ -60,9 +57,9 @@ impl Fingerprint {
Some(Self(buf)) Some(Self(buf))
} }
/// Converts [`type@Multihash`] to [`Fingerprint`]. /// Converts [`Multihash`](MultihashGeneric) to [`Fingerprint`].
pub fn try_from_multihash(hash: Multihash) -> Option<Self> { pub fn try_from_multihash(hash: Multihash) -> Option<Self> {
if hash.code() != u64::from(Code::Sha2_256) { if hash.code() != MULTIHASH_SHA256_CODE {
// Only support SHA256 for now. // Only support SHA256 for now.
return None; return None;
} }
@ -72,11 +69,9 @@ impl Fingerprint {
Some(Self(bytes)) Some(Self(bytes))
} }
/// Converts this fingerprint to [`type@Multihash`]. /// Converts this fingerprint to [`Multihash`](MultihashGeneric).
pub fn to_multihash(self) -> Multihash { pub fn to_multihash(self) -> Multihash {
Code::Sha2_256 Multihash::wrap(MULTIHASH_SHA256_CODE, &self.0).expect("fingerprint's len to be 32 bytes")
.wrap(&self.0)
.expect("fingerprint's len to be 32 bytes")
} }
/// Formats this fingerprint as uppercase hex, separated by colons (`:`). /// Formats this fingerprint as uppercase hex, separated by colons (`:`).