2018-07-04 10:51:47 +00:00
package multihash
import (
"fmt"
2022-08-19 16:34:07 +00:00
"hash"
"io"
2018-07-04 10:51:47 +00:00
2021-06-28 06:53:50 +00:00
mhreg "github.com/multiformats/go-multihash/core"
2018-07-04 10:51:47 +00:00
)
// ErrSumNotSupported is returned when the Sum function code is not implemented
2021-06-28 06:53:50 +00:00
var ErrSumNotSupported = mhreg . ErrSumNotSupported
2018-07-04 10:51:47 +00:00
2022-11-04 13:57:20 +00:00
var ErrLenTooLarge = mhreg . ErrLenTooLarge
2021-06-16 20:19:45 +00:00
2018-07-04 10:51:47 +00:00
// Sum obtains the cryptographic sum of a given buffer. The length parameter
2022-08-19 16:34:07 +00:00
// indicates the length of the resulting digest. Passing a negative value uses
// default length values for the selected hash function.
2018-07-04 10:51:47 +00:00
func Sum ( data [ ] byte , code uint64 , length int ) ( Multihash , error ) {
2021-06-28 06:53:50 +00:00
// Get the algorithm.
2022-11-04 13:57:20 +00:00
hasher , err := mhreg . GetVariableHasher ( code , length )
2018-07-04 10:51:47 +00:00
if err != nil {
2019-06-09 07:24:20 +00:00
return nil , err
2018-07-04 10:51:47 +00:00
}
2021-06-28 06:53:50 +00:00
// Feed data in.
2023-06-30 13:41:32 +00:00
if _ , err := hasher . Write ( data ) ; err != nil {
return nil , err
}
2018-07-04 10:51:47 +00:00
2022-08-19 16:34:07 +00:00
return encodeHash ( hasher , code , length )
}
// SumStream obtains the cryptographic sum of a given stream. The length
// parameter indicates the length of the resulting digest. Passing a negative
// value uses default length values for the selected hash function.
func SumStream ( r io . Reader , code uint64 , length int ) ( Multihash , error ) {
// Get the algorithm.
2022-11-04 13:57:20 +00:00
hasher , err := mhreg . GetVariableHasher ( code , length )
2022-08-19 16:34:07 +00:00
if err != nil {
return nil , err
}
// Feed data in.
if _ , err = io . Copy ( hasher , r ) ; err != nil {
return nil , err
}
return encodeHash ( hasher , code , length )
}
func encodeHash ( hasher hash . Hash , code uint64 , length int ) ( Multihash , error ) {
2021-06-28 06:53:50 +00:00
// Compute final hash.
// A new slice is allocated. FUTURE: see other comment below about allocation, and review together with this line to try to improve.
sum := hasher . Sum ( nil )
2018-07-04 10:51:47 +00:00
2021-06-28 06:53:50 +00:00
// Deal with any truncation.
// Unless it's an identity multihash. Those have different rules.
if length < 0 {
length = hasher . Size ( )
2019-06-09 07:24:20 +00:00
}
2021-06-28 06:53:50 +00:00
if len ( sum ) < length {
return nil , ErrLenTooLarge
2019-06-09 07:24:20 +00:00
}
2021-06-28 06:53:50 +00:00
if length >= 0 {
if code == IDENTITY {
if length != len ( sum ) {
return nil , fmt . Errorf ( "the length of the identity hash (%d) must be equal to the length of the data (%d)" , length , len ( sum ) )
}
}
sum = sum [ : length ]
2019-06-09 07:24:20 +00:00
}
2021-06-28 06:53:50 +00:00
// Put the multihash metainfo bytes at the front of the buffer.
// FUTURE: try to improve allocations here. Encode does several which are probably avoidable, but it's the shape of the Encode method arguments that forces this.
return Encode ( sum , code )
2018-07-04 10:51:47 +00:00
}