OSDN Git Service

Merge branch 'master' into dev
[bytom/bytom.git] / protocol / bc / hash.go
1 package bc
2
3 import (
4         "bytes"
5         "database/sql/driver"
6         "encoding/binary"
7         "encoding/hex"
8         "encoding/json"
9         "fmt"
10         "io"
11
12         "golang.org/x/crypto/sha3"
13 )
14
15 // Hash represents a 256-bit hash.
16
17 var EmptyStringHash = NewHash(sha3.Sum256(nil))
18
19 func NewHash(b32 [32]byte) (h Hash) {
20         h.V0 = binary.BigEndian.Uint64(b32[0:8])
21         h.V1 = binary.BigEndian.Uint64(b32[8:16])
22         h.V2 = binary.BigEndian.Uint64(b32[16:24])
23         h.V3 = binary.BigEndian.Uint64(b32[24:32])
24         return h
25 }
26
27 func (h Hash) Byte32() (b32 [32]byte) {
28         binary.BigEndian.PutUint64(b32[0:8], h.V0)
29         binary.BigEndian.PutUint64(b32[8:16], h.V1)
30         binary.BigEndian.PutUint64(b32[16:24], h.V2)
31         binary.BigEndian.PutUint64(b32[24:32], h.V3)
32         return b32
33 }
34
35 // MarshalText satisfies the TextMarshaler interface.
36 // It returns the bytes of h encoded in hex,
37 // for formats that can't hold arbitrary binary data.
38 // It never returns an error.
39 func (h Hash) MarshalText() ([]byte, error) {
40         b := h.Byte32()
41         v := make([]byte, 64)
42         hex.Encode(v, b[:])
43         return v, nil
44 }
45
46 // UnmarshalText satisfies the TextUnmarshaler interface.
47 // It decodes hex data from b into h.
48 func (h *Hash) UnmarshalText(v []byte) error {
49         var b [32]byte
50         if len(v) != 64 {
51                 return fmt.Errorf("bad length hash string %d", len(v))
52         }
53         _, err := hex.Decode(b[:], v)
54         *h = NewHash(b)
55         return err
56 }
57
58 // UnmarshalJSON satisfies the json.Unmarshaler interface.
59 // If b is a JSON-encoded null, it copies the zero-value into h. Othwerwise, it
60 // decodes hex data from b into h.
61 func (h *Hash) UnmarshalJSON(b []byte) error {
62         if bytes.Equal(b, []byte("null")) {
63                 *h = Hash{}
64                 return nil
65         }
66         var s string
67         err := json.Unmarshal(b, &s)
68         if err != nil {
69                 return err
70         }
71         return h.UnmarshalText([]byte(s))
72 }
73
74 func (h Hash) Bytes() []byte {
75         b32 := h.Byte32()
76         return b32[:]
77 }
78
79 // Value satisfies the driver.Valuer interface
80 func (h Hash) Value() (driver.Value, error) {
81         return h.Bytes(), nil
82 }
83
84 // Scan satisfies the driver.Scanner interface
85 func (h *Hash) Scan(v interface{}) error {
86         var buf [32]byte
87         b, ok := v.([]byte)
88         if !ok {
89                 return fmt.Errorf("Hash.Scan received unsupported type %T", v)
90         }
91         copy(buf[:], b)
92         *h = NewHash(buf)
93         return nil
94 }
95
96 // WriteTo satisfies the io.WriterTo interface.
97 func (h Hash) WriteTo(w io.Writer) (int64, error) {
98         n, err := w.Write(h.Bytes())
99         return int64(n), err
100 }
101
102 // ReadFrom satisfies the io.ReaderFrom interface.
103 func (h *Hash) ReadFrom(r io.Reader) (int64, error) {
104         var b32 [32]byte
105         n, err := io.ReadFull(r, b32[:])
106         if err != nil {
107                 return int64(n), err
108         }
109         *h = NewHash(b32)
110         return int64(n), nil
111 }
112
113 // IsZero tells whether a Hash pointer is nil or points to an all-zero
114 // hash.
115 func (h *Hash) IsZero() bool {
116         if h == nil {
117                 return true
118         }
119         return *h == Hash{}
120 }