Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gx/lastpubver
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.0.8: QmPnFwZ2JXKnXgMw8CdBPxn7FWh6LLdjUjxV1fKHuJnkr8
1.2.0: QmVxufDv6HhtP927fpS1bJsWLeF2t1iT7p8b315wehX5du
8 changes: 4 additions & 4 deletions io.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@ import (
type Reader interface {
io.Reader

ReadMultihash() (Multihash, error)
ReadMultihash() (MultihashBytes, error)
}

// Writer is an io.Writer wrapper that exposes a function
// to write a whole multihash.
type Writer interface {
io.Writer

WriteMultihash(Multihash) error
WriteMultihash(MultihashBytes) error
}

// NewReader wraps an io.Reader with a multihash.Reader
Expand Down Expand Up @@ -59,7 +59,7 @@ func (r *mhReader) ReadByte() (byte, error) {
return 0, err
}

func (r *mhReader) ReadMultihash() (Multihash, error) {
func (r *mhReader) ReadMultihash() (MultihashBytes, error) {
code, err := binary.ReadUvarint(r)
if err != nil {
return nil, err
Expand Down Expand Up @@ -97,7 +97,7 @@ func (w *mhWriter) Write(buf []byte) (n int, err error) {
return w.w.Write(buf)
}

func (w *mhWriter) WriteMultihash(m Multihash) error {
func (w *mhWriter) WriteMultihash(m MultihashBytes) error {
_, err := w.w.Write([]byte(m))
return err
}
134 changes: 110 additions & 24 deletions multihash.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import (
"fmt"
"math"

strbinary "github.com/multiformats/go-multihash/strbinary"

b58 "github.com/mr-tron/base58/base58"
)

Expand Down Expand Up @@ -144,17 +146,8 @@ var DefaultLengths = map[uint64]int{
SHAKE_256: 64,
}

func uvarint(buf []byte) (uint64, []byte, error) {
n, c := binary.Uvarint(buf)

if c == 0 {
return n, buf, ErrVarintBufferShort
} else if c < 0 {
return n, buf[-c:], ErrVarintTooLong
} else {
return n, buf[c:], nil
}
}
// Multihash is the cannoical representation of a Multihash
type Multihash struct{ str string }

// DecodedMultihash represents a parsed multihash and allows
// easy access to the different parts of a multihash.
Expand All @@ -168,56 +161,137 @@ type DecodedMultihash struct {
// Multihash is byte slice with the following form:
// <hash function code><digest size><hash function output>.
// See the spec for more information.
type Multihash []byte
type MultihashBytes []byte

// Builder contains a Sum method to create multihashes
type Builder struct {
Type uint64
Length int
}

// FromBinary creates a new multihash from the binary representation. The
// string is assumed to be a valid multihash. It will panic if it is
// unable to parse the string.
func FromBinary(v string) Multihash {
// Sanity check that the string can be parsed.
if len(v) < 2 {
panic(ErrTooShort)
}
i := strbinary.UvarintLen(v)
digestLen, l := strbinary.Uvarint(v[i:])
i += l
if len(v[i:]) != int(digestLen) {
panic(ErrInvalidMultihash)
}
return Multihash{v}
}

// IsNil checkes in the multihash is the zero value
func (m Multihash) IsNil() bool {
return m.str == ""
}

// String returns the hex string for debugging
func (m Multihash) String() string {
return hex.EncodeToString([]byte(m.str))
}

// B58String returns the B58-encoded representation of a multihash.
func (m Multihash) B58String() string {
return b58.Encode([]byte(m.str))
}

// Parts returns the components of the Multihash (Code, Name, Digest)
func (m Multihash) Parts() (uint64, int, string) {
// Note: no need to check for errors as the New method guarantees
// the string can be parsed
i := 0
codec, l := strbinary.Uvarint(m.str)
i += l
digestLen, l := strbinary.Uvarint(m.str[i:])
i += l
return codec, int(digestLen), m.str[i:]
}

func (b Builder) Sum(data []byte) (Multihash, error) {
len := b.Length
if len <= 0 {
len = -1
}
hash, err := Sum(data, b.Type, len)
if err != nil {
return Multihash{}, err
}
return Multihash{string(hash)}, nil
}

// AsBytes converts the multihash to the MultihashBytes type
func (m Multihash) AsBytes() MultihashBytes {
return MultihashBytes(m.str)
}

// Bytes returns the binary representation
func (m Multihash) Bytes() []byte {
return []byte(m.str)
}

// Binary returns the binary representation as a string
func (m Multihash) Binary() string {
return m.str
}

func (m MultihashBytes) Cast() Multihash {
return FromBinary(string(m))
}

// HexString returns the hex-encoded representation of a multihash.
func (m *Multihash) HexString() string {
return hex.EncodeToString([]byte(*m))
func (m MultihashBytes) HexString() string {
return hex.EncodeToString([]byte(m))
}

// String is an alias to HexString().
func (m *Multihash) String() string {
func (m MultihashBytes) String() string {
return m.HexString()
}

// FromHexString parses a hex-encoded multihash.
func FromHexString(s string) (Multihash, error) {
func FromHexString(s string) (MultihashBytes, error) {
b, err := hex.DecodeString(s)
if err != nil {
return Multihash{}, err
return MultihashBytes{}, err
}

return Cast(b)
}

// B58String returns the B58-encoded representation of a multihash.
func (m Multihash) B58String() string {
func (m MultihashBytes) B58String() string {
return b58.Encode([]byte(m))
}

// FromB58String parses a B58-encoded multihash.
func FromB58String(s string) (m Multihash, err error) {
func FromB58String(s string) (m MultihashBytes, err error) {
b, err := b58.Decode(s)
if err != nil {
return Multihash{}, ErrInvalidMultihash
return MultihashBytes{}, ErrInvalidMultihash
}

return Cast(b)
}

// Cast casts a buffer onto a multihash, and returns an error
// if it does not work.
func Cast(buf []byte) (Multihash, error) {
func Cast(buf []byte) (MultihashBytes, error) {
dm, err := Decode(buf)
if err != nil {
return Multihash{}, err
return MultihashBytes{}, err
}

if !ValidCode(dm.Code) {
return Multihash{}, ErrUnknownCode
return MultihashBytes{}, ErrUnknownCode
}

return Multihash(buf), nil
return MultihashBytes(buf), nil
}

// Decode parses multihash bytes into a DecodedMultihash.
Expand Down Expand Up @@ -298,3 +372,15 @@ func ValidCode(code uint64) bool {
func AppCode(code uint64) bool {
return code >= 0 && code < 0x10
}

func uvarint(buf []byte) (uint64, []byte, error) {
n, c := binary.Uvarint(buf)

if c == 0 {
return n, buf, ErrVarintBufferShort
} else if c < 0 {
return n, buf[-c:], ErrVarintTooLong
} else {
return n, buf[c:], nil
}
}
2 changes: 1 addition & 1 deletion multihash/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Options:
// flags
var opts *mhopts.Options
var checkRaw string
var checkMh mh.Multihash
var checkMh mh.MultihashBytes
var inputFilename string
var quiet bool
var help bool
Expand Down
2 changes: 1 addition & 1 deletion multihash_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ var testCases = []TestCase{
TestCase{"4bca2b137edc580fe50a88983ef860ebaca36c857b1f492839d6d7392452a63c82cbebc68e3b70a2a1480b4bb5d437a7cba6ecf9d89f9ff3ccd14cd6146ea7e7", 0x14, "sha3-512"},
}

func (tc TestCase) Multihash() (Multihash, error) {
func (tc TestCase) Multihash() (MultihashBytes, error) {
ob, err := hex.DecodeString(tc.hex)
if err != nil {
return nil, err
Expand Down
4 changes: 2 additions & 2 deletions opts/coding.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
mh "github.com/multiformats/go-multihash"
)

func Decode(encoding, digest string) (mh.Multihash, error) {
func Decode(encoding, digest string) (mh.MultihashBytes, error) {
switch encoding {
case "raw":
return mh.Cast([]byte(digest))
Expand All @@ -24,7 +24,7 @@ func Decode(encoding, digest string) (mh.Multihash, error) {
}
}

func Encode(encoding string, hash mh.Multihash) (string, error) {
func Encode(encoding string, hash mh.MultihashBytes) (string, error) {
switch encoding {
case "raw":
return string(hash), nil
Expand Down
4 changes: 2 additions & 2 deletions opts/opts.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ func strIn(a string, set []string) bool {

// Check reads all the data in r, calculates its multihash,
// and checks it matches h1
func (o *Options) Check(r io.Reader, h1 mh.Multihash) error {
func (o *Options) Check(r io.Reader, h1 mh.MultihashBytes) error {
h2, err := o.Multihash(r)
if err != nil {
return err
Expand All @@ -121,7 +121,7 @@ func (o *Options) Check(r io.Reader, h1 mh.Multihash) error {
}

// Multihash reads all the data in r and calculates its multihash.
func (o *Options) Multihash(r io.Reader) (mh.Multihash, error) {
func (o *Options) Multihash(r io.Reader) (mh.MultihashBytes, error) {
b, err := ioutil.ReadAll(r)
if err != nil {
return nil, err
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,6 @@
"license": "MIT",
"name": "go-multihash",
"releaseCmd": "git commit -a -m \"gx release $VERSION\"",
"version": "1.0.8"
"version": "1.2.0"
}

42 changes: 42 additions & 0 deletions strbinary/uvarint.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package strbinary

// Version of varint function that work with a string rather than
// []byte to avoid unnecessary allocation

// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license as given at https://golang.org/LICENSE

// Uvarint decodes a uint64 from buf and returns that value and the
// number of characters read (> 0). If an error occurred, the value is 0
// and the number of bytes n is <= 0 meaning:
//
// n == 0: buf too small
// n < 0: value larger than 64 bits (overflow)
// and -n is the number of bytes read
//
func Uvarint(buf string) (uint64, int) {
var x uint64
var s uint
for i, b := range buf {
if b < 0x80 {
if i > 9 || i == 9 && b > 1 {
return 0, -(i + 1) // overflow
}
return x | uint64(b)<<s, i + 1
}
x |= uint64(b&0x7f) << s
s += 7
}
return 0, 0
}

// Ulen returns the length of an varint in bytes
func UvarintLen(buf string) int {
for i, b := range buf {
if b < 0x80 {
return i + 1
}
}
return 0
}
4 changes: 2 additions & 2 deletions sum.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ var ErrSumNotSupported = errors.New("Function not implemented. Complain to lib m
// Sum obtains the cryptographic sum of a given buffer. The length parameter
// indicates the length of the resulting digest and passing a negative value
// use default length values for the selected hash function.
func Sum(data []byte, code uint64, length int) (Multihash, error) {
m := Multihash{}
func Sum(data []byte, code uint64, length int) (MultihashBytes, error) {
m := MultihashBytes{}
err := error(nil)
if !ValidCode(code) {
return m, fmt.Errorf("invalid multihash code %d", code)
Expand Down