1
1
use std:: convert:: TryFrom ;
2
2
use std:: { cmp, fmt, hash} ;
3
3
4
- use blake2b_simd:: { blake2b, Params as Blake2bVariable } ;
5
- use blake2s_simd:: { blake2s, Params as Blake2sVariable } ;
6
- use sha2:: Digest ;
7
- use tiny_keccak:: Keccak ;
8
- use unsigned_varint:: { decode, encode} ;
9
-
10
- use crate :: errors:: { DecodeError , DecodeOwnedError , EncodeError } ;
11
- use crate :: hashes:: Hash ;
12
- use crate :: storage:: Storage ;
13
-
14
- // Helper macro for encoding input into output using sha1, sha2, tiny_keccak, or blake2
15
- macro_rules! encode {
16
- ( sha1, Sha1 , $input: expr, $output: expr) => { {
17
- let mut hasher = sha1:: Sha1 :: new( ) ;
18
- hasher. update( $input) ;
19
- $output. copy_from_slice( & hasher. digest( ) . bytes( ) ) ;
20
- } } ;
21
- ( sha2, $algorithm: ident, $input: expr, $output: expr) => { {
22
- let mut hasher = sha2:: $algorithm:: default ( ) ;
23
- hasher. input( $input) ;
24
- $output. copy_from_slice( hasher. result( ) . as_ref( ) ) ;
25
- } } ;
26
- ( tiny, $constructor: ident, $input: expr, $output: expr) => { {
27
- let mut kec = Keccak :: $constructor( ) ;
28
- kec. update( $input) ;
29
- kec. finalize( $output) ;
30
- } } ;
31
- ( blake2, $algorithm: ident, $input: expr, $output: expr) => { {
32
- let hash = $algorithm( $input) ;
33
- $output. copy_from_slice( hash. as_ref( ) ) ;
34
- } } ;
35
- ( blake2_256, $constructor: ident, $input: expr, $output: expr) => { {
36
- let hash = $constructor:: new( )
37
- . hash_length( 32 )
38
- . to_state( )
39
- . update( $input)
40
- . finalize( ) ;
41
- $output. copy_from_slice( hash. as_ref( ) ) ;
42
- } } ;
43
- ( blake2_128, $constructor: ident, $input: expr, $output: expr) => { {
44
- let hash = $constructor:: new( )
45
- . hash_length( 16 )
46
- . to_state( )
47
- . update( $input)
48
- . finalize( ) ;
49
- $output. copy_from_slice( hash. as_ref( ) ) ;
50
- } } ;
51
- }
52
-
53
- // And another one to keep the matching DRY
54
- macro_rules! match_encoder {
55
- ( $hash: ident for ( $input: expr, $output: expr) {
56
- $( $hashtype: ident => $lib: ident :: $method: ident, ) *
57
- } ) => ( {
58
- match $hash {
59
- $(
60
- Hash :: $hashtype => encode!( $lib, $method, $input, $output) ,
61
- ) *
62
-
63
- _ => return Err ( EncodeError :: UnsupportedType )
64
- }
65
- } )
66
- }
67
-
68
- /// Encodes data into a multihash.
69
- ///
70
- /// # Errors
71
- ///
72
- /// Will return an error if the specified hash type is not supported. See the docs for `Hash`
73
- /// to see what is supported.
74
- ///
75
- /// # Examples
76
- ///
77
- /// ```
78
- /// use multihash::{encode, Hash};
79
- ///
80
- /// assert_eq!(
81
- /// encode(Hash::SHA2256, b"hello world").unwrap().to_vec(),
82
- /// vec![18, 32, 185, 77, 39, 185, 147, 77, 62, 8, 165, 46, 82, 215, 218, 125, 171, 250, 196,
83
- /// 132, 239, 227, 122, 83, 128, 238, 144, 136, 247, 172, 226, 239, 205, 233]
84
- /// );
85
- /// ```
86
- ///
87
- pub fn encode ( hash : Hash , input : & [ u8 ] ) -> Result < Multihash , EncodeError > {
88
- // Custom length encoding for the identity multihash
89
- if let Hash :: Identity = hash {
90
- if u64:: from ( std:: u32:: MAX ) < as_u64 ( input. len ( ) ) {
91
- return Err ( EncodeError :: UnsupportedInputLength ) ;
92
- }
93
- let mut buf = encode:: u16_buffer ( ) ;
94
- let code = encode:: u16 ( hash. code ( ) , & mut buf) ;
95
- let mut len_buf = encode:: u32_buffer ( ) ;
96
- let size = encode:: u32 ( input. len ( ) as u32 , & mut len_buf) ;
97
- Ok ( Multihash {
98
- storage : Storage :: from_slices ( & [ & code, & size, & input] ) ,
99
- } )
100
- } else {
101
- let ( offset, mut output) = encode_hash ( hash) ;
102
- match_encoder ! ( hash for ( input, & mut output[ offset ..] ) {
103
- SHA1 => sha1:: Sha1 ,
104
- SHA2256 => sha2:: Sha256 ,
105
- SHA2512 => sha2:: Sha512 ,
106
- SHA3224 => tiny:: new_sha3_224,
107
- SHA3256 => tiny:: new_sha3_256,
108
- SHA3384 => tiny:: new_sha3_384,
109
- SHA3512 => tiny:: new_sha3_512,
110
- Keccak224 => tiny:: new_keccak224,
111
- Keccak256 => tiny:: new_keccak256,
112
- Keccak384 => tiny:: new_keccak384,
113
- Keccak512 => tiny:: new_keccak512,
114
- Blake2b512 => blake2:: blake2b,
115
- Blake2b256 => blake2_256:: Blake2bVariable ,
116
- Blake2s256 => blake2:: blake2s,
117
- Blake2s128 => blake2_128:: Blake2sVariable ,
118
- } ) ;
119
-
120
- Ok ( Multihash {
121
- storage : Storage :: from_slice ( & output) ,
122
- } )
123
- }
124
- }
4
+ use unsigned_varint:: { decode as varint_decode, encode as varint_encode} ;
125
5
126
- // Encode the given [`Hash`] value and ensure the returned [`Vec<u8>`]
127
- // has enough capacity to hold the actual digest.
128
- fn encode_hash ( hash : Hash ) -> ( usize , Vec < u8 > ) {
129
- let mut buf = encode:: u16_buffer ( ) ;
130
- let code = encode:: u16 ( hash. code ( ) , & mut buf) ;
131
-
132
- let len = code. len ( ) + 1 + usize:: from ( hash. size ( ) ) ;
133
-
134
- let mut output = Vec :: with_capacity ( len) ;
135
- output. extend_from_slice ( code) ;
136
- output. push ( hash. size ( ) ) ;
137
- output. resize ( len, 0 ) ;
138
-
139
- ( code. len ( ) + 1 , output)
140
- }
6
+ use crate :: errors:: { DecodeError , DecodeOwnedError } ;
7
+ use crate :: hashes:: Code ;
8
+ use crate :: storage:: Storage ;
141
9
142
10
/// Represents a valid multihash.
143
11
#[ derive( Clone ) ]
@@ -202,7 +70,7 @@ impl Multihash {
202
70
}
203
71
204
72
/// Returns which hashing algorithm is used in this multihash.
205
- pub fn algorithm ( & self ) -> Hash {
73
+ pub fn algorithm ( & self ) -> Code {
206
74
self . as_ref ( ) . algorithm ( )
207
75
}
208
76
@@ -257,49 +125,31 @@ impl<'a> MultihashRef<'a> {
257
125
return Err ( DecodeError :: BadInputLength ) ;
258
126
}
259
127
260
- // Ensure `Hash::code` returns a `u16` so that our `decode::u16` here is correct.
261
- std:: convert:: identity :: < fn ( Hash ) -> u16 > ( Hash :: code) ;
262
- let ( code, bytes) = decode:: u16 ( & input) . map_err ( |_| DecodeError :: BadInputLength ) ?;
263
-
264
- let alg = Hash :: from_code ( code) . ok_or ( DecodeError :: UnknownCode ) ?;
128
+ let ( _code, bytes) = varint_decode:: u64 ( & input) . map_err ( |_| DecodeError :: BadInputLength ) ?;
265
129
266
- // handle the identity case
267
- if alg == Hash :: Identity {
268
- let ( hash_len, bytes) = decode:: u32 ( & bytes) . map_err ( |_| DecodeError :: BadInputLength ) ?;
269
- if as_u64 ( bytes. len ( ) ) != u64:: from ( hash_len) {
270
- return Err ( DecodeError :: BadInputLength ) ;
271
- }
272
- return Ok ( MultihashRef { bytes : input } ) ;
273
- }
274
-
275
- let hash_len = usize:: from ( alg. size ( ) ) ;
276
-
277
- // Length of input after hash code should be exactly hash_len + 1
278
- if bytes. len ( ) != hash_len + 1 {
279
- return Err ( DecodeError :: BadInputLength ) ;
280
- }
281
-
282
- if usize:: from ( bytes[ 0 ] ) != hash_len {
130
+ let ( hash_len, bytes) =
131
+ varint_decode:: u64 ( & bytes) . map_err ( |_| DecodeError :: BadInputLength ) ?;
132
+ if ( bytes. len ( ) as u64 ) != hash_len {
283
133
return Err ( DecodeError :: BadInputLength ) ;
284
134
}
285
135
286
136
Ok ( MultihashRef { bytes : input } )
287
137
}
288
138
289
139
/// Returns which hashing algorithm is used in this multihash.
290
- pub fn algorithm ( & self ) -> Hash {
291
- let code = decode:: u16 ( & self . bytes )
292
- . expect ( "multihash is known to be valid algorithm" )
293
- . 0 ;
294
- Hash :: from_code ( code) . expect ( "multihash is known to be valid" )
140
+ pub fn algorithm ( & self ) -> Code {
141
+ let ( code, _bytes) =
142
+ varint_decode:: u64 ( & self . bytes ) . expect ( "multihash is known to be valid algorithm" ) ;
143
+ Code :: from_u64 ( code)
295
144
}
296
145
297
146
/// Returns the hashed data.
298
147
pub fn digest ( & self ) -> & ' a [ u8 ] {
299
- let bytes = decode:: u16 ( & self . bytes )
300
- . expect ( "multihash is known to be valid digest" )
301
- . 1 ;
302
- & bytes[ 1 ..]
148
+ let ( _code, bytes) =
149
+ varint_decode:: u64 ( & self . bytes ) . expect ( "multihash is known to be valid digest" ) ;
150
+ let ( _hash_len, bytes) =
151
+ varint_decode:: u64 ( & bytes) . expect ( "multihash is known to be a valid digest" ) ;
152
+ & bytes[ ..]
303
153
}
304
154
305
155
/// Builds a `Multihash` that owns the data.
@@ -323,7 +173,31 @@ impl<'a> PartialEq<Multihash> for MultihashRef<'a> {
323
173
}
324
174
}
325
175
326
- #[ cfg( any( target_pointer_width = "32" , target_pointer_width = "64" ) ) ]
327
- fn as_u64 ( a : usize ) -> u64 {
328
- a as u64
176
+ /// The `MultihashDigest` trait specifies an interface common for all multihash functions.
177
+ pub trait MultihashDigest {
178
+ /// The Mutlihash byte value.
179
+ fn code ( & self ) -> Code ;
180
+
181
+ /// Hash some input and return the digest.
182
+ ///
183
+ /// # Panics
184
+ ///
185
+ /// Panics if the digest length is bigger than 2^32. This only happens for identity hasing.
186
+ fn digest ( & self , data : & [ u8 ] ) -> Multihash ;
187
+ }
188
+
189
+ /// Wraps a hash digest in Multihash with the given Mutlihash code.
190
+ ///
191
+ /// The size of the hash is determoned by the size of the input hash. If it should be truncated
192
+ /// the input data must already be the truncated hash.
193
+ pub fn wrap ( code : & Code , data : & [ u8 ] ) -> Multihash {
194
+ let mut code_buf = varint_encode:: u64_buffer ( ) ;
195
+ let code = varint_encode:: u64 ( code. to_u64 ( ) , & mut code_buf) ;
196
+
197
+ let mut size_buf = varint_encode:: u64_buffer ( ) ;
198
+ let size = varint_encode:: u64 ( data. len ( ) as u64 , & mut size_buf) ;
199
+
200
+ Multihash {
201
+ storage : Storage :: from_slices ( & [ code, & size, & data] ) ,
202
+ }
329
203
}
0 commit comments