@cryptotaxi247 / kubo / commits / 4d08eb014

updated multihash (io)

Juan Batiz-Benet committed Dec 24, 2014 at 10:20 UTC 4d08eb0140c5d6536742adfffb0b8724aee6ad51
9 files changed +306 -63
Godeps/Godeps.json
+2 -2
@@ -131,8 +131,8 @@
131 },
132 {
133 "ImportPath": "github.com/jbenet/go-multihash",
134 - "Comment": "0.1.0-5-g1976046",
135 - "Rev": "1976046c2b0db0b668791b3e541d76a38b7c1af7"
134 + "Comment": "0.1.0-19-g8ce5cb1",
135 + "Rev": "8ce5cb1b82e1b4c1bea1fdf3cd467ef49301734e"
136 },
137 {
138 "ImportPath": "github.com/jbenet/go-peerstream",
Godeps/_workspace/src/github.com/jbenet/go-multihash/io.go new
+79
@@ -0,0 +1,79 @@
1 +package multihash
2 +
3 +import (
4 + "fmt"
5 + "io"
6 +)
7 +
8 +// Reader is an io.Reader wrapper that exposes a function
9 +// to read a whole multihash, parse it, and return it.
10 +type Reader interface {
11 + io.Reader
12 +
13 + ReadMultihash() (Multihash, error)
14 +}
15 +
16 +// Writer is an io.Writer wrapper that exposes a function
17 +// to write a whole multihash.
18 +type Writer interface {
19 + io.Writer
20 +
21 + WriteMultihash(Multihash) error
22 +}
23 +
24 +// NewReader wraps an io.Reader with a multihash.Reader
25 +func NewReader(r io.Reader) Reader {
26 + return &mhReader{r}
27 +}
28 +
29 +// NewWriter wraps an io.Writer with a multihash.Writer
30 +func NewWriter(w io.Writer) Writer {
31 + return &mhWriter{w}
32 +}
33 +
34 +type mhReader struct {
35 + r io.Reader
36 +}
37 +
38 +func (r *mhReader) Read(buf []byte) (n int, err error) {
39 + return r.r.Read(buf)
40 +}
41 +
42 +func (r *mhReader) ReadMultihash() (Multihash, error) {
43 + mhhdr := make([]byte, 2)
44 + if _, err := io.ReadFull(r.r, mhhdr); err != nil {
45 + return nil, err
46 + }
47 +
48 + // first byte is the algo, the second is the length.
49 +
50 + // (varints someday...)
51 + length := uint(mhhdr[1])
52 +
53 + if length > 127 {
54 + return nil, fmt.Errorf("varints not yet supported (length is %d)", length)
55 + }
56 +
57 + buf := make([]byte, length+2)
58 + buf[0] = mhhdr[0]
59 + buf[1] = mhhdr[1]
60 +
61 + if _, err := io.ReadFull(r.r, buf[2:]); err != nil {
62 + return nil, err
63 + }
64 +
65 + return Cast(buf)
66 +}
67 +
68 +type mhWriter struct {
69 + w io.Writer
70 +}
71 +
72 +func (w *mhWriter) Write(buf []byte) (n int, err error) {
73 + return w.w.Write(buf)
74 +}
75 +
76 +func (w *mhWriter) WriteMultihash(m Multihash) error {
77 + _, err := w.w.Write([]byte(m))
78 + return err
79 +}
Godeps/_workspace/src/github.com/jbenet/go-multihash/io_test.go new
+69
@@ -0,0 +1,69 @@
1 +package multihash
2 +
3 +import (
4 + "bytes"
5 + "io"
6 + "testing"
7 +)
8 +
9 +func TestReader(t *testing.T) {
10 +
11 + var buf bytes.Buffer
12 +
13 + for _, tc := range testCases {
14 + m, err := tc.Multihash()
15 + if err != nil {
16 + t.Fatal(err)
17 + }
18 +
19 + buf.Write([]byte(m))
20 + }
21 +
22 + r := NewReader(&buf)
23 +
24 + for _, tc := range testCases {
25 + h, err := tc.Multihash()
26 + if err != nil {
27 + t.Fatal(err)
28 + }
29 +
30 + h2, err := r.ReadMultihash()
31 + if err != nil {
32 + t.Error(err)
33 + continue
34 + }
35 +
36 + if !bytes.Equal(h, h2) {
37 + t.Error("h and h2 should be equal")
38 + }
39 + }
40 +}
41 +
42 +func TestWriter(t *testing.T) {
43 +
44 + var buf bytes.Buffer
45 + w := NewWriter(&buf)
46 +
47 + for _, tc := range testCases {
48 + m, err := tc.Multihash()
49 + if err != nil {
50 + t.Error(err)
51 + continue
52 + }
53 +
54 + if err := w.WriteMultihash(m); err != nil {
55 + t.Error(err)
56 + continue
57 + }
58 +
59 + buf2 := make([]byte, len(m))
60 + if _, err := io.ReadFull(&buf, buf2); err != nil {
61 + t.Error(err)
62 + continue
63 + }
64 +
65 + if !bytes.Equal(m, buf2) {
66 + t.Error("m and buf2 should be equal")
67 + }
68 + }
69 +}
Godeps/_workspace/src/github.com/jbenet/go-multihash/multihash.go
+64 -37
@@ -2,43 +2,67 @@ package multihash
2
3 import (
4 "encoding/hex"
5 + "errors"
6 "fmt"
7 +
8 b58 "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-base58"
9 )
10
11 +// errors
12 +var (
13 + ErrUnknownCode = errors.New("unknown multihash code")
14 + ErrTooShort = errors.New("multihash too short. must be > 3 bytes")
15 + ErrTooLong = errors.New("multihash too long. must be < 129 bytes")
16 + ErrLenNotSupported = errors.New("multihash does not yet support digests longer than 127 bytes")
17 +)
18 +
19 +// ErrInconsistentLen is returned when a decoded multihash has an inconsistent length
20 +type ErrInconsistentLen struct {
21 + dm *DecodedMultihash
22 +}
23 +
24 +func (e ErrInconsistentLen) Error() string {
25 + return fmt.Sprintf("multihash length inconsistent: %v", e.dm)
26 +}
27 +
28 // constants
10 -const SHA1 = 0x11
11 -const SHA2_256 = 0x12
12 -const SHA2_512 = 0x13
13 -const SHA3 = 0x14
14 -const BLAKE2B = 0x40
15 -const BLAKE2S = 0x41
29 +const (
30 + SHA1 = 0x11
31 + SHA2_256 = 0x12
32 + SHA2_512 = 0x13
33 + SHA3 = 0x14
34 + BLAKE2B = 0x40
35 + BLAKE2S = 0x41
36 +)
37
38 +// Names maps the name of a hash to the code
39 var Names = map[string]int{
18 - "sha1": 0x11,
19 - "sha2-256": 0x12,
20 - "sha2-512": 0x13,
21 - "sha3": 0x14,
22 - "blake2b": 0x40,
23 - "blake2s": 0x41,
40 + "sha1": SHA1,
41 + "sha2-256": SHA2_256,
42 + "sha2-512": SHA2_512,
43 + "sha3": SHA3,
44 + "blake2b": BLAKE2B,
45 + "blake2s": BLAKE2S,
46 }
47
48 +// Codes maps a hash code to it's name
49 var Codes = map[int]string{
27 - 0x11: "sha1",
28 - 0x12: "sha2-256",
29 - 0x13: "sha2-512",
30 - 0x14: "sha3",
31 - 0x40: "blake2b",
32 - 0x41: "blake2s",
50 + SHA1: "sha1",
51 + SHA2_256: "sha2-256",
52 + SHA2_512: "sha2-512",
53 + SHA3: "sha3",
54 + BLAKE2B: "blake2b",
55 + BLAKE2S: "blake2s",
56 }
57
58 +// DefaultLengths maps a hash code to it's default length
59 var DefaultLengths = map[int]int{
36 - 0x11: 20,
37 - 0x12: 32,
38 - 0x13: 64,
39 - 0x14: 64,
40 - 0x40: 64,
41 - 0x41: 32,
60 + SHA1: 20,
61 + SHA2_256: 32,
62 + SHA2_512: 64,
63 + SHA3: 64,
64 + BLAKE2B: 64,
65 + BLAKE2S: 32,
66 }
67
68 type DecodedMultihash struct {
@@ -50,8 +74,12 @@ type DecodedMultihash struct {
74
75 type Multihash []byte
76
53 -func (m Multihash) HexString() string {
54 - return hex.EncodeToString([]byte(m))
77 +func (m *Multihash) HexString() string {
78 + return hex.EncodeToString([]byte(*m))
79 +}
80 +
81 +func (m *Multihash) String() string {
82 + return m.HexString()
83 }
84
85 func FromHexString(s string) (Multihash, error) {
@@ -88,21 +116,21 @@ func Cast(buf []byte) (Multihash, error) {
116 }
117
118 if !ValidCode(dm.Code) {
91 - return Multihash{}, fmt.Errorf("unknown multihash code")
119 + return Multihash{}, ErrUnknownCode
120 }
121
122 return Multihash(buf), nil
123 }
124
97 -// Decodes a hash from the given Multihash.
125 +// Decode a hash from the given Multihash.
126 func Decode(buf []byte) (*DecodedMultihash, error) {
127
128 if len(buf) < 3 {
101 - return nil, fmt.Errorf("multihash too short. must be > 3 bytes.")
129 + return nil, ErrTooShort
130 }
131
132 if len(buf) > 129 {
105 - return nil, fmt.Errorf("multihash too long. must be < 129 bytes.")
133 + return nil, ErrTooLong
134 }
135
136 dm := &DecodedMultihash{
@@ -113,23 +141,22 @@ func Decode(buf []byte) (*DecodedMultihash, error) {
141 }
142
143 if len(dm.Digest) != dm.Length {
116 - return nil, fmt.Errorf("multihash length inconsistent: %v", dm)
144 + return nil, ErrInconsistentLen{dm}
145 }
146
147 return dm, nil
148 }
149
122 -// Encodes a hash digest along with the specified function code.
150 +// Encode a hash digest along with the specified function code.
151 // Note: the length is derived from the length of the digest itself.
152 func Encode(buf []byte, code int) ([]byte, error) {
153
154 if !ValidCode(code) {
127 - return nil, fmt.Errorf("unknown multihash code")
155 + return nil, ErrUnknownCode
156 }
157
158 if len(buf) > 127 {
131 - m := "multihash does not yet support digests longer than 127 bytes."
132 - return nil, fmt.Errorf(m)
159 + return nil, ErrLenNotSupported
160 }
161
162 pre := make([]byte, 2)
@@ -142,7 +169,7 @@ func EncodeName(buf []byte, name string) ([]byte, error) {
169 return Encode(buf, Names[name])
170 }
171
145 -// Checks whether a multihash code is valid.
172 +// ValidCode checks whether a multihash code is valid.
173 func ValidCode(code int) bool {
174 if AppCode(code) {
175 return true
@@ -155,7 +182,7 @@ func ValidCode(code int) bool {
182 return false
183 }
184
158 -// Checks whether a multihash code is part of the App range.
185 +// AppCode checks whether a multihash code is part of the App range.
186 func AppCode(code int) bool {
187 return code >= 0 && code < 0x10
188 }
Godeps/_workspace/src/github.com/jbenet/go-multihash/multihash_test.go
+79 -1
@@ -3,6 +3,7 @@ package multihash
3 import (
4 "bytes"
5 "encoding/hex"
6 + "fmt"
7 "testing"
8 )
9
@@ -31,6 +32,19 @@ var testCases = []TestCase{
32 TestCase{"0beec7b5ea3f0fdbc9", 0x40, "blake2b"},
33 }
34
35 +func (tc TestCase) Multihash() (Multihash, error) {
36 + ob, err := hex.DecodeString(tc.hex)
37 + if err != nil {
38 + return nil, err
39 + }
40 +
41 + b := make([]byte, 2+len(ob))
42 + b[0] = byte(uint8(tc.code))
43 + b[1] = byte(uint8(len(ob)))
44 + copy(b[2:], ob)
45 + return Cast(b)
46 +}
47 +
48 func TestEncode(t *testing.T) {
49 for _, tc := range testCases {
50 ob, err := hex.DecodeString(tc.hex)
@@ -63,9 +77,28 @@ func TestEncode(t *testing.T) {
77 if !bytes.Equal(encN, nb) {
78 t.Error("encoded byte mismatch: ", encN, nb)
79 }
80 +
81 + h, err := tc.Multihash()
82 + if err != nil {
83 + t.Error(err)
84 + }
85 + if !bytes.Equal(h, nb) {
86 + t.Error("Multihash func mismatch.")
87 + }
88 }
89 }
90
91 +func ExampleEncodeName() {
92 + // ignores errors for simplicity - don't do that at home.
93 + buf, _ := hex.DecodeString("0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33")
94 + mhbuf, _ := EncodeName(buf, "sha1")
95 + mhhex := hex.EncodeToString(mhbuf)
96 + fmt.Printf("hex: %v\n", mhhex)
97 +
98 + // Output:
99 + // hex: 11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33
100 +}
101 +
102 func TestDecode(t *testing.T) {
103 for _, tc := range testCases {
104 ob, err := hex.DecodeString(tc.hex)
@@ -114,6 +147,18 @@ func TestTable(t *testing.T) {
147 }
148 }
149
150 +func ExampleDecode() {
151 + // ignores errors for simplicity - don't do that at home.
152 + buf, _ := hex.DecodeString("0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33")
153 + mhbuf, _ := EncodeName(buf, "sha1")
154 + o, _ := Decode(mhbuf)
155 + mhhex := hex.EncodeToString(o.Digest)
156 + fmt.Printf("obj: %v 0x%x %d %s\n", o.Name, o.Code, o.Length, mhhex)
157 +
158 + // Output:
159 + // obj: sha1 0x11 20 0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33
160 +}
161 +
162 func TestValidCode(t *testing.T) {
163 for i := 0; i < 0xff; i++ {
164 _, ok := tCodes[i]
@@ -127,7 +172,7 @@ func TestValidCode(t *testing.T) {
172
173 func TestAppCode(t *testing.T) {
174 for i := 0; i < 0xff; i++ {
130 - b := i > 0 && i < 0x10
175 + b := i >= 0 && i < 0x10
176 if AppCode(i) != b {
177 t.Error("AppCode incorrect for: ", i)
178 }
@@ -190,3 +235,36 @@ func TestHex(t *testing.T) {
235 }
236 }
237 }
238 +
239 +func BenchmarkEncode(b *testing.B) {
240 + tc := testCases[0]
241 + ob, err := hex.DecodeString(tc.hex)
242 + if err != nil {
243 + b.Error(err)
244 + return
245 + }
246 +
247 + b.ResetTimer()
248 + for i := 0; i < b.N; i++ {
249 + Encode(ob, tc.code)
250 + }
251 +}
252 +
253 +func BenchmarkDecode(b *testing.B) {
254 + tc := testCases[0]
255 + ob, err := hex.DecodeString(tc.hex)
256 + if err != nil {
257 + b.Error(err)
258 + return
259 + }
260 +
261 + pre := make([]byte, 2)
262 + pre[0] = byte(uint8(tc.code))
263 + pre[1] = byte(uint8(len(ob)))
264 + nb := append(pre, ob...)
265 +
266 + b.ResetTimer()
267 + for i := 0; i < b.N; i++ {
268 + Decode(nb)
269 + }
270 +}
Godeps/_workspace/src/github.com/jbenet/go-multihash/sum.go
+6 -2
@@ -4,10 +4,14 @@ import (
4 "crypto/sha1"
5 "crypto/sha256"
6 "crypto/sha512"
7 + "errors"
8 "fmt"
9 +
10 sha3 "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.crypto/sha3"
11 )
12
13 +var ErrSumNotSupported = errors.New("Function not implemented. Complain to lib maintainer.")
14 +
15 func Sum(data []byte, code int, length int) (Multihash, error) {
16 m := Multihash{}
17 err := error(nil)
@@ -26,7 +30,7 @@ func Sum(data []byte, code int, length int) (Multihash, error) {
30 case SHA3:
31 d, err = sumSHA3(data)
32 default:
29 - return m, fmt.Errorf("Function not implemented. Complain to lib maintainer.")
33 + return m, ErrSumNotSupported
34 }
35
36 if err != nil {
@@ -60,7 +64,7 @@ func sumSHA512(data []byte) []byte {
64 }
65
66 func sumSHA3(data []byte) ([]byte, error) {
63 - h := sha3.NewKeccak512()
67 + h := sha3.New512()
68 if _, err := h.Write(data); err != nil {
69 return nil, err
70 }
Godeps/_workspace/src/github.com/jbenet/go-multihash/sum_test.go
+7
@@ -57,3 +57,10 @@ func TestSum(t *testing.T) {
57 }
58 }
59 }
60 +
61 +func BenchmarkSum(b *testing.B) {
62 + tc := sumTestCases[0]
63 + for i := 0; i < b.N; i++ {
64 + Sum([]byte(tc.input), tc.code, tc.length)
65 + }
66 +}
Godeps/_workspace/src/github.com/jbenet/go-multihash/test/foo.go deleted
-21
@@ -1,21 +0,0 @@
1 -package main
2 -
3 -import (
4 - "encoding/hex"
5 - "fmt"
6 - "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash"
7 -)
8 -
9 -func main() {
10 - // ignores errors for simplicity.
11 - // don't do that at home.
12 -
13 - buf, _ := hex.DecodeString("0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33")
14 - mhbuf, _ := multihash.EncodeName(buf, "sha1")
15 - mhhex := hex.EncodeToString(mhbuf)
16 - fmt.Printf("hex: %v\n", mhhex)
17 -
18 - o, _ := multihash.Decode(mhbuf)
19 - mhhex = hex.EncodeToString(o.Digest)
20 - fmt.Printf("obj: %v 0x%x %d %s\n", o.Name, o.Code, o.Length, mhhex)
21 -}
Godeps/_workspace/src/github.com/jbenet/go-multihash/test/test
Binary files /dev/null and b/Godeps/_workspace/src/github.com/jbenet/go-multihash/test/test differ