sum.go 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. package multihash
  2. import (
  3. "fmt"
  4. "hash"
  5. "io"
  6. mhreg "github.com/multiformats/go-multihash/core"
  7. )
  8. // ErrSumNotSupported is returned when the Sum function code is not implemented
  9. var ErrSumNotSupported = mhreg.ErrSumNotSupported
  10. var ErrLenTooLarge = mhreg.ErrLenTooLarge
  11. // Sum obtains the cryptographic sum of a given buffer. The length parameter
  12. // indicates the length of the resulting digest. Passing a negative value uses
  13. // default length values for the selected hash function.
  14. func Sum(data []byte, code uint64, length int) (Multihash, error) {
  15. // Get the algorithm.
  16. hasher, err := mhreg.GetVariableHasher(code, length)
  17. if err != nil {
  18. return nil, err
  19. }
  20. // Feed data in.
  21. if _, err := hasher.Write(data); err != nil {
  22. return nil, err
  23. }
  24. return encodeHash(hasher, code, length)
  25. }
  26. // SumStream obtains the cryptographic sum of a given stream. The length
  27. // parameter indicates the length of the resulting digest. Passing a negative
  28. // value uses default length values for the selected hash function.
  29. func SumStream(r io.Reader, code uint64, length int) (Multihash, error) {
  30. // Get the algorithm.
  31. hasher, err := mhreg.GetVariableHasher(code, length)
  32. if err != nil {
  33. return nil, err
  34. }
  35. // Feed data in.
  36. if _, err = io.Copy(hasher, r); err != nil {
  37. return nil, err
  38. }
  39. return encodeHash(hasher, code, length)
  40. }
  41. func encodeHash(hasher hash.Hash, code uint64, length int) (Multihash, error) {
  42. // Compute final hash.
  43. // A new slice is allocated. FUTURE: see other comment below about allocation, and review together with this line to try to improve.
  44. sum := hasher.Sum(nil)
  45. // Deal with any truncation.
  46. // Unless it's an identity multihash. Those have different rules.
  47. if length < 0 {
  48. length = hasher.Size()
  49. }
  50. if len(sum) < length {
  51. return nil, ErrLenTooLarge
  52. }
  53. if length >= 0 {
  54. if code == IDENTITY {
  55. if length != len(sum) {
  56. return nil, fmt.Errorf("the length of the identity hash (%d) must be equal to the length of the data (%d)", length, len(sum))
  57. }
  58. }
  59. sum = sum[:length]
  60. }
  61. // Put the multihash metainfo bytes at the front of the buffer.
  62. // 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.
  63. return Encode(sum, code)
  64. }