Skip to content

Commit 5fb6bc7

Browse files
tomakavmx
authored andcommitted
Add peer id inlining for small public keys (#1237)
* Add peer id inlining for small public keys * Apply @twittner suggestions * Restore hashing Originally from libp2p/rust-libp2p@c6e8e63.
1 parent 4c22240 commit 5fb6bc7

File tree

3 files changed

+67
-20
lines changed

3 files changed

+67
-20
lines changed

src/errors.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,19 @@ use std::{error, fmt};
55
pub enum EncodeError {
66
/// The requested hash algorithm isn't supported by this library.
77
UnsupportedType,
8+
/// The input length is too large for the hash algorithm.
9+
UnsupportedInputLength,
810
}
911

1012
impl fmt::Display for EncodeError {
1113
#[inline]
1214
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1315
match *self {
1416
EncodeError::UnsupportedType => write!(f, "This type is not supported yet"),
17+
EncodeError::UnsupportedInputLength => write!(
18+
f,
19+
"The length of the input for the given hash is not yet supported"
20+
),
1521
}
1622
}
1723
}

src/hashes.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
/// Not all hash types are supported by this library.
44
#[derive(PartialEq, Eq, Clone, Debug, Copy, Hash)]
55
pub enum Hash {
6+
/// Identity (Raw binary )
7+
Identity,
68
/// SHA-1 (20-byte hash size)
79
SHA1,
810
/// SHA-256 (32-byte hash size)
@@ -39,6 +41,7 @@ impl Hash {
3941
/// Get the corresponding hash code.
4042
pub fn code(self) -> u16 {
4143
match self {
44+
Hash::Identity => 0x00,
4245
Hash::SHA1 => 0x11,
4346
Hash::SHA2256 => 0x12,
4447
Hash::SHA2512 => 0x13,
@@ -60,6 +63,7 @@ impl Hash {
6063
/// Get the hash length in bytes.
6164
pub fn size(self) -> u8 {
6265
match self {
66+
Hash::Identity => 42,
6367
Hash::SHA1 => 20,
6468
Hash::SHA2256 => 32,
6569
Hash::SHA2512 => 64,
@@ -81,6 +85,7 @@ impl Hash {
8185
/// Returns the algorithm corresponding to a code, or `None` if no algorithm is matching.
8286
pub fn from_code(code: u16) -> Option<Hash> {
8387
Some(match code {
88+
0x00 => Hash::Identity,
8489
0x11 => Hash::SHA1,
8590
0x12 => Hash::SHA2256,
8691
0x13 => Hash::SHA2512,

src/lib.rs

Lines changed: 56 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -79,26 +79,47 @@ macro_rules! match_encoder {
7979
/// ```
8080
///
8181
pub fn encode(hash: Hash, input: &[u8]) -> Result<Multihash, EncodeError> {
82-
let (offset, mut output) = encode_hash(hash);
83-
match_encoder!(hash for (input, &mut output[offset ..]) {
84-
SHA1 => sha1::Sha1,
85-
SHA2256 => sha2::Sha256,
86-
SHA2512 => sha2::Sha512,
87-
SHA3224 => tiny::new_sha3_224,
88-
SHA3256 => tiny::new_sha3_256,
89-
SHA3384 => tiny::new_sha3_384,
90-
SHA3512 => tiny::new_sha3_512,
91-
Keccak224 => tiny::new_keccak224,
92-
Keccak256 => tiny::new_keccak256,
93-
Keccak384 => tiny::new_keccak384,
94-
Keccak512 => tiny::new_keccak512,
95-
Blake2b512 => blake2::blake2b,
96-
Blake2s256 => blake2::blake2s,
97-
});
98-
99-
Ok(Multihash {
100-
bytes: output.freeze(),
101-
})
82+
// Custom length encoding for the identity multihash
83+
if let Hash::Identity = hash {
84+
if u64::from(std::u32::MAX) < as_u64(input.len()) {
85+
return Err(EncodeError::UnsupportedInputLength);
86+
}
87+
let mut buf = encode::u16_buffer();
88+
let code = encode::u16(hash.code(), &mut buf);
89+
let mut len_buf = encode::u32_buffer();
90+
let size = encode::u32(input.len() as u32, &mut len_buf);
91+
92+
let total_len = code.len() + size.len() + input.len();
93+
94+
let mut output = BytesMut::with_capacity(total_len);
95+
output.put_slice(code);
96+
output.put_slice(size);
97+
output.put_slice(input);
98+
Ok(Multihash {
99+
bytes: output.freeze(),
100+
})
101+
} else {
102+
let (offset, mut output) = encode_hash(hash);
103+
match_encoder!(hash for (input, &mut output[offset ..]) {
104+
SHA1 => sha1::Sha1,
105+
SHA2256 => sha2::Sha256,
106+
SHA2512 => sha2::Sha512,
107+
SHA3224 => tiny::new_sha3_224,
108+
SHA3256 => tiny::new_sha3_256,
109+
SHA3384 => tiny::new_sha3_384,
110+
SHA3512 => tiny::new_sha3_512,
111+
Keccak224 => tiny::new_keccak224,
112+
Keccak256 => tiny::new_keccak256,
113+
Keccak384 => tiny::new_keccak384,
114+
Keccak512 => tiny::new_keccak512,
115+
Blake2b512 => blake2::blake2b,
116+
Blake2s256 => blake2::blake2s,
117+
});
118+
119+
Ok(Multihash {
120+
bytes: output.freeze(),
121+
})
122+
}
102123
}
103124

104125
// Encode the given [`Hash`] value and ensure the returned [`BytesMut`]
@@ -206,6 +227,16 @@ impl<'a> MultihashRef<'a> {
206227
let (code, bytes) = decode::u16(&input).map_err(|_| DecodeError::BadInputLength)?;
207228

208229
let alg = Hash::from_code(code).ok_or(DecodeError::UnknownCode)?;
230+
231+
// handle the identity case
232+
if alg == Hash::Identity {
233+
let (hash_len, bytes) = decode::u32(&bytes).map_err(|_| DecodeError::BadInputLength)?;
234+
if as_u64(bytes.len()) != u64::from(hash_len) {
235+
return Err(DecodeError::BadInputLength);
236+
}
237+
return Ok(MultihashRef { bytes: input });
238+
}
239+
209240
let hash_len = usize::from(alg.size());
210241

211242
// Length of input after hash code should be exactly hash_len + 1
@@ -256,3 +287,8 @@ impl<'a> PartialEq<Multihash> for MultihashRef<'a> {
256287
self.bytes == &*other.bytes
257288
}
258289
}
290+
291+
#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
292+
fn as_u64(a: usize) -> u64 {
293+
a as u64
294+
}

0 commit comments

Comments
 (0)