mirror of
https://github.com/ipfs/kubo.git
synced 2025-06-27 16:07:42 +08:00
updated multihash (io)
This commit is contained in:
4
Godeps/Godeps.json
generated
4
Godeps/Godeps.json
generated
@ -131,8 +131,8 @@
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/jbenet/go-multihash",
|
||||
"Comment": "0.1.0-5-g1976046",
|
||||
"Rev": "1976046c2b0db0b668791b3e541d76a38b7c1af7"
|
||||
"Comment": "0.1.0-19-g8ce5cb1",
|
||||
"Rev": "8ce5cb1b82e1b4c1bea1fdf3cd467ef49301734e"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/jbenet/go-peerstream",
|
||||
|
79
Godeps/_workspace/src/github.com/jbenet/go-multihash/io.go
generated
vendored
Normal file
79
Godeps/_workspace/src/github.com/jbenet/go-multihash/io.go
generated
vendored
Normal file
@ -0,0 +1,79 @@
|
||||
package multihash
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
// Reader is an io.Reader wrapper that exposes a function
|
||||
// to read a whole multihash, parse it, and return it.
|
||||
type Reader interface {
|
||||
io.Reader
|
||||
|
||||
ReadMultihash() (Multihash, error)
|
||||
}
|
||||
|
||||
// Writer is an io.Writer wrapper that exposes a function
|
||||
// to write a whole multihash.
|
||||
type Writer interface {
|
||||
io.Writer
|
||||
|
||||
WriteMultihash(Multihash) error
|
||||
}
|
||||
|
||||
// NewReader wraps an io.Reader with a multihash.Reader
|
||||
func NewReader(r io.Reader) Reader {
|
||||
return &mhReader{r}
|
||||
}
|
||||
|
||||
// NewWriter wraps an io.Writer with a multihash.Writer
|
||||
func NewWriter(w io.Writer) Writer {
|
||||
return &mhWriter{w}
|
||||
}
|
||||
|
||||
type mhReader struct {
|
||||
r io.Reader
|
||||
}
|
||||
|
||||
func (r *mhReader) Read(buf []byte) (n int, err error) {
|
||||
return r.r.Read(buf)
|
||||
}
|
||||
|
||||
func (r *mhReader) ReadMultihash() (Multihash, error) {
|
||||
mhhdr := make([]byte, 2)
|
||||
if _, err := io.ReadFull(r.r, mhhdr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// first byte is the algo, the second is the length.
|
||||
|
||||
// (varints someday...)
|
||||
length := uint(mhhdr[1])
|
||||
|
||||
if length > 127 {
|
||||
return nil, fmt.Errorf("varints not yet supported (length is %d)", length)
|
||||
}
|
||||
|
||||
buf := make([]byte, length+2)
|
||||
buf[0] = mhhdr[0]
|
||||
buf[1] = mhhdr[1]
|
||||
|
||||
if _, err := io.ReadFull(r.r, buf[2:]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return Cast(buf)
|
||||
}
|
||||
|
||||
type mhWriter struct {
|
||||
w io.Writer
|
||||
}
|
||||
|
||||
func (w *mhWriter) Write(buf []byte) (n int, err error) {
|
||||
return w.w.Write(buf)
|
||||
}
|
||||
|
||||
func (w *mhWriter) WriteMultihash(m Multihash) error {
|
||||
_, err := w.w.Write([]byte(m))
|
||||
return err
|
||||
}
|
69
Godeps/_workspace/src/github.com/jbenet/go-multihash/io_test.go
generated
vendored
Normal file
69
Godeps/_workspace/src/github.com/jbenet/go-multihash/io_test.go
generated
vendored
Normal file
@ -0,0 +1,69 @@
|
||||
package multihash
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestReader(t *testing.T) {
|
||||
|
||||
var buf bytes.Buffer
|
||||
|
||||
for _, tc := range testCases {
|
||||
m, err := tc.Multihash()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
buf.Write([]byte(m))
|
||||
}
|
||||
|
||||
r := NewReader(&buf)
|
||||
|
||||
for _, tc := range testCases {
|
||||
h, err := tc.Multihash()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
h2, err := r.ReadMultihash()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !bytes.Equal(h, h2) {
|
||||
t.Error("h and h2 should be equal")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestWriter(t *testing.T) {
|
||||
|
||||
var buf bytes.Buffer
|
||||
w := NewWriter(&buf)
|
||||
|
||||
for _, tc := range testCases {
|
||||
m, err := tc.Multihash()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
if err := w.WriteMultihash(m); err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
buf2 := make([]byte, len(m))
|
||||
if _, err := io.ReadFull(&buf, buf2); err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !bytes.Equal(m, buf2) {
|
||||
t.Error("m and buf2 should be equal")
|
||||
}
|
||||
}
|
||||
}
|
101
Godeps/_workspace/src/github.com/jbenet/go-multihash/multihash.go
generated
vendored
101
Godeps/_workspace/src/github.com/jbenet/go-multihash/multihash.go
generated
vendored
@ -2,43 +2,67 @@ package multihash
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
b58 "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-base58"
|
||||
)
|
||||
|
||||
// errors
|
||||
var (
|
||||
ErrUnknownCode = errors.New("unknown multihash code")
|
||||
ErrTooShort = errors.New("multihash too short. must be > 3 bytes")
|
||||
ErrTooLong = errors.New("multihash too long. must be < 129 bytes")
|
||||
ErrLenNotSupported = errors.New("multihash does not yet support digests longer than 127 bytes")
|
||||
)
|
||||
|
||||
// ErrInconsistentLen is returned when a decoded multihash has an inconsistent length
|
||||
type ErrInconsistentLen struct {
|
||||
dm *DecodedMultihash
|
||||
}
|
||||
|
||||
func (e ErrInconsistentLen) Error() string {
|
||||
return fmt.Sprintf("multihash length inconsistent: %v", e.dm)
|
||||
}
|
||||
|
||||
// constants
|
||||
const SHA1 = 0x11
|
||||
const SHA2_256 = 0x12
|
||||
const SHA2_512 = 0x13
|
||||
const SHA3 = 0x14
|
||||
const BLAKE2B = 0x40
|
||||
const BLAKE2S = 0x41
|
||||
const (
|
||||
SHA1 = 0x11
|
||||
SHA2_256 = 0x12
|
||||
SHA2_512 = 0x13
|
||||
SHA3 = 0x14
|
||||
BLAKE2B = 0x40
|
||||
BLAKE2S = 0x41
|
||||
)
|
||||
|
||||
// Names maps the name of a hash to the code
|
||||
var Names = map[string]int{
|
||||
"sha1": 0x11,
|
||||
"sha2-256": 0x12,
|
||||
"sha2-512": 0x13,
|
||||
"sha3": 0x14,
|
||||
"blake2b": 0x40,
|
||||
"blake2s": 0x41,
|
||||
"sha1": SHA1,
|
||||
"sha2-256": SHA2_256,
|
||||
"sha2-512": SHA2_512,
|
||||
"sha3": SHA3,
|
||||
"blake2b": BLAKE2B,
|
||||
"blake2s": BLAKE2S,
|
||||
}
|
||||
|
||||
// Codes maps a hash code to it's name
|
||||
var Codes = map[int]string{
|
||||
0x11: "sha1",
|
||||
0x12: "sha2-256",
|
||||
0x13: "sha2-512",
|
||||
0x14: "sha3",
|
||||
0x40: "blake2b",
|
||||
0x41: "blake2s",
|
||||
SHA1: "sha1",
|
||||
SHA2_256: "sha2-256",
|
||||
SHA2_512: "sha2-512",
|
||||
SHA3: "sha3",
|
||||
BLAKE2B: "blake2b",
|
||||
BLAKE2S: "blake2s",
|
||||
}
|
||||
|
||||
// DefaultLengths maps a hash code to it's default length
|
||||
var DefaultLengths = map[int]int{
|
||||
0x11: 20,
|
||||
0x12: 32,
|
||||
0x13: 64,
|
||||
0x14: 64,
|
||||
0x40: 64,
|
||||
0x41: 32,
|
||||
SHA1: 20,
|
||||
SHA2_256: 32,
|
||||
SHA2_512: 64,
|
||||
SHA3: 64,
|
||||
BLAKE2B: 64,
|
||||
BLAKE2S: 32,
|
||||
}
|
||||
|
||||
type DecodedMultihash struct {
|
||||
@ -50,8 +74,12 @@ type DecodedMultihash struct {
|
||||
|
||||
type Multihash []byte
|
||||
|
||||
func (m Multihash) HexString() string {
|
||||
return hex.EncodeToString([]byte(m))
|
||||
func (m *Multihash) HexString() string {
|
||||
return hex.EncodeToString([]byte(*m))
|
||||
}
|
||||
|
||||
func (m *Multihash) String() string {
|
||||
return m.HexString()
|
||||
}
|
||||
|
||||
func FromHexString(s string) (Multihash, error) {
|
||||
@ -88,21 +116,21 @@ func Cast(buf []byte) (Multihash, error) {
|
||||
}
|
||||
|
||||
if !ValidCode(dm.Code) {
|
||||
return Multihash{}, fmt.Errorf("unknown multihash code")
|
||||
return Multihash{}, ErrUnknownCode
|
||||
}
|
||||
|
||||
return Multihash(buf), nil
|
||||
}
|
||||
|
||||
// Decodes a hash from the given Multihash.
|
||||
// Decode a hash from the given Multihash.
|
||||
func Decode(buf []byte) (*DecodedMultihash, error) {
|
||||
|
||||
if len(buf) < 3 {
|
||||
return nil, fmt.Errorf("multihash too short. must be > 3 bytes.")
|
||||
return nil, ErrTooShort
|
||||
}
|
||||
|
||||
if len(buf) > 129 {
|
||||
return nil, fmt.Errorf("multihash too long. must be < 129 bytes.")
|
||||
return nil, ErrTooLong
|
||||
}
|
||||
|
||||
dm := &DecodedMultihash{
|
||||
@ -113,23 +141,22 @@ func Decode(buf []byte) (*DecodedMultihash, error) {
|
||||
}
|
||||
|
||||
if len(dm.Digest) != dm.Length {
|
||||
return nil, fmt.Errorf("multihash length inconsistent: %v", dm)
|
||||
return nil, ErrInconsistentLen{dm}
|
||||
}
|
||||
|
||||
return dm, nil
|
||||
}
|
||||
|
||||
// Encodes a hash digest along with the specified function code.
|
||||
// Encode a hash digest along with the specified function code.
|
||||
// Note: the length is derived from the length of the digest itself.
|
||||
func Encode(buf []byte, code int) ([]byte, error) {
|
||||
|
||||
if !ValidCode(code) {
|
||||
return nil, fmt.Errorf("unknown multihash code")
|
||||
return nil, ErrUnknownCode
|
||||
}
|
||||
|
||||
if len(buf) > 127 {
|
||||
m := "multihash does not yet support digests longer than 127 bytes."
|
||||
return nil, fmt.Errorf(m)
|
||||
return nil, ErrLenNotSupported
|
||||
}
|
||||
|
||||
pre := make([]byte, 2)
|
||||
@ -142,7 +169,7 @@ func EncodeName(buf []byte, name string) ([]byte, error) {
|
||||
return Encode(buf, Names[name])
|
||||
}
|
||||
|
||||
// Checks whether a multihash code is valid.
|
||||
// ValidCode checks whether a multihash code is valid.
|
||||
func ValidCode(code int) bool {
|
||||
if AppCode(code) {
|
||||
return true
|
||||
@ -155,7 +182,7 @@ func ValidCode(code int) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Checks whether a multihash code is part of the App range.
|
||||
// AppCode checks whether a multihash code is part of the App range.
|
||||
func AppCode(code int) bool {
|
||||
return code >= 0 && code < 0x10
|
||||
}
|
||||
|
80
Godeps/_workspace/src/github.com/jbenet/go-multihash/multihash_test.go
generated
vendored
80
Godeps/_workspace/src/github.com/jbenet/go-multihash/multihash_test.go
generated
vendored
@ -3,6 +3,7 @@ package multihash
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@ -31,6 +32,19 @@ var testCases = []TestCase{
|
||||
TestCase{"0beec7b5ea3f0fdbc9", 0x40, "blake2b"},
|
||||
}
|
||||
|
||||
func (tc TestCase) Multihash() (Multihash, error) {
|
||||
ob, err := hex.DecodeString(tc.hex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
b := make([]byte, 2+len(ob))
|
||||
b[0] = byte(uint8(tc.code))
|
||||
b[1] = byte(uint8(len(ob)))
|
||||
copy(b[2:], ob)
|
||||
return Cast(b)
|
||||
}
|
||||
|
||||
func TestEncode(t *testing.T) {
|
||||
for _, tc := range testCases {
|
||||
ob, err := hex.DecodeString(tc.hex)
|
||||
@ -63,9 +77,28 @@ func TestEncode(t *testing.T) {
|
||||
if !bytes.Equal(encN, nb) {
|
||||
t.Error("encoded byte mismatch: ", encN, nb)
|
||||
}
|
||||
|
||||
h, err := tc.Multihash()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if !bytes.Equal(h, nb) {
|
||||
t.Error("Multihash func mismatch.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleEncodeName() {
|
||||
// ignores errors for simplicity - don't do that at home.
|
||||
buf, _ := hex.DecodeString("0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33")
|
||||
mhbuf, _ := EncodeName(buf, "sha1")
|
||||
mhhex := hex.EncodeToString(mhbuf)
|
||||
fmt.Printf("hex: %v\n", mhhex)
|
||||
|
||||
// Output:
|
||||
// hex: 11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33
|
||||
}
|
||||
|
||||
func TestDecode(t *testing.T) {
|
||||
for _, tc := range testCases {
|
||||
ob, err := hex.DecodeString(tc.hex)
|
||||
@ -114,6 +147,18 @@ func TestTable(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleDecode() {
|
||||
// ignores errors for simplicity - don't do that at home.
|
||||
buf, _ := hex.DecodeString("0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33")
|
||||
mhbuf, _ := EncodeName(buf, "sha1")
|
||||
o, _ := Decode(mhbuf)
|
||||
mhhex := hex.EncodeToString(o.Digest)
|
||||
fmt.Printf("obj: %v 0x%x %d %s\n", o.Name, o.Code, o.Length, mhhex)
|
||||
|
||||
// Output:
|
||||
// obj: sha1 0x11 20 0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33
|
||||
}
|
||||
|
||||
func TestValidCode(t *testing.T) {
|
||||
for i := 0; i < 0xff; i++ {
|
||||
_, ok := tCodes[i]
|
||||
@ -127,7 +172,7 @@ func TestValidCode(t *testing.T) {
|
||||
|
||||
func TestAppCode(t *testing.T) {
|
||||
for i := 0; i < 0xff; i++ {
|
||||
b := i > 0 && i < 0x10
|
||||
b := i >= 0 && i < 0x10
|
||||
if AppCode(i) != b {
|
||||
t.Error("AppCode incorrect for: ", i)
|
||||
}
|
||||
@ -190,3 +235,36 @@ func TestHex(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkEncode(b *testing.B) {
|
||||
tc := testCases[0]
|
||||
ob, err := hex.DecodeString(tc.hex)
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
Encode(ob, tc.code)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkDecode(b *testing.B) {
|
||||
tc := testCases[0]
|
||||
ob, err := hex.DecodeString(tc.hex)
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
pre := make([]byte, 2)
|
||||
pre[0] = byte(uint8(tc.code))
|
||||
pre[1] = byte(uint8(len(ob)))
|
||||
nb := append(pre, ob...)
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
Decode(nb)
|
||||
}
|
||||
}
|
||||
|
8
Godeps/_workspace/src/github.com/jbenet/go-multihash/sum.go
generated
vendored
8
Godeps/_workspace/src/github.com/jbenet/go-multihash/sum.go
generated
vendored
@ -4,10 +4,14 @@ import (
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"crypto/sha512"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
sha3 "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.crypto/sha3"
|
||||
)
|
||||
|
||||
var ErrSumNotSupported = errors.New("Function not implemented. Complain to lib maintainer.")
|
||||
|
||||
func Sum(data []byte, code int, length int) (Multihash, error) {
|
||||
m := Multihash{}
|
||||
err := error(nil)
|
||||
@ -26,7 +30,7 @@ func Sum(data []byte, code int, length int) (Multihash, error) {
|
||||
case SHA3:
|
||||
d, err = sumSHA3(data)
|
||||
default:
|
||||
return m, fmt.Errorf("Function not implemented. Complain to lib maintainer.")
|
||||
return m, ErrSumNotSupported
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
@ -60,7 +64,7 @@ func sumSHA512(data []byte) []byte {
|
||||
}
|
||||
|
||||
func sumSHA3(data []byte) ([]byte, error) {
|
||||
h := sha3.NewKeccak512()
|
||||
h := sha3.New512()
|
||||
if _, err := h.Write(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
7
Godeps/_workspace/src/github.com/jbenet/go-multihash/sum_test.go
generated
vendored
7
Godeps/_workspace/src/github.com/jbenet/go-multihash/sum_test.go
generated
vendored
@ -57,3 +57,10 @@ func TestSum(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSum(b *testing.B) {
|
||||
tc := sumTestCases[0]
|
||||
for i := 0; i < b.N; i++ {
|
||||
Sum([]byte(tc.input), tc.code, tc.length)
|
||||
}
|
||||
}
|
||||
|
21
Godeps/_workspace/src/github.com/jbenet/go-multihash/test/foo.go
generated
vendored
21
Godeps/_workspace/src/github.com/jbenet/go-multihash/test/foo.go
generated
vendored
@ -1,21 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// ignores errors for simplicity.
|
||||
// don't do that at home.
|
||||
|
||||
buf, _ := hex.DecodeString("0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33")
|
||||
mhbuf, _ := multihash.EncodeName(buf, "sha1")
|
||||
mhhex := hex.EncodeToString(mhbuf)
|
||||
fmt.Printf("hex: %v\n", mhhex)
|
||||
|
||||
o, _ := multihash.Decode(mhbuf)
|
||||
mhhex = hex.EncodeToString(o.Digest)
|
||||
fmt.Printf("obj: %v 0x%x %d %s\n", o.Name, o.Code, o.Length, mhhex)
|
||||
}
|
BIN
Godeps/_workspace/src/github.com/jbenet/go-multihash/test/test
generated
vendored
Normal file
BIN
Godeps/_workspace/src/github.com/jbenet/go-multihash/test/test
generated
vendored
Normal file
Binary file not shown.
Reference in New Issue
Block a user