-
Notifications
You must be signed in to change notification settings - Fork 270
Expand file tree
/
Copy pathhashing.go
More file actions
126 lines (108 loc) · 2.93 KB
/
Copy pathhashing.go
File metadata and controls
126 lines (108 loc) · 2.93 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
package types
import (
"crypto/sha256"
"errors"
"hash"
)
var (
leafPrefix = []byte{0}
)
// HashSlim returns the SHA256 hash of the header using the slim (current) binary encoding.
func (h *Header) HashSlim() (Hash, error) {
if h == nil {
return nil, errors.New("header is nil")
}
bytes, err := h.MarshalBinary()
if err != nil {
return nil, err
}
hash := sha256.Sum256(bytes)
return hash[:], nil
}
// HashLegacy returns the SHA256 hash of the header using the legacy binary encoding that
// includes the deprecated fields.
func (h *Header) HashLegacy() (Hash, error) {
if h == nil {
return nil, errors.New("header is nil")
}
bytes, err := h.MarshalBinaryLegacy()
if err != nil {
return nil, err
}
hash := sha256.Sum256(bytes)
return hash[:], nil
}
// Hash returns the header hash. It reuses a memoized value if one has already
// been prepared via MemoizeHash, but it does not write to the header itself.
func (h *Header) Hash() Hash {
if h == nil {
return nil
}
if h.cachedHash != nil {
return h.cachedHash
}
return h.computeHash()
}
// MemoizeHash computes the header hash and stores it on the header for future
// Hash() calls. Call this before publishing the header to shared goroutines or
// caches.
//
// If a Header struct is reused (e.g. overwritten via FromProto or field
// assignment), call InvalidateHash() first to clear the cached value before
// calling MemoizeHash again. Failure to do so will return the stale cached hash.
func (h *Header) MemoizeHash() Hash {
if h == nil {
return nil
}
if h.cachedHash != nil {
return h.cachedHash
}
hash := h.computeHash()
if hash != nil {
h.cachedHash = hash
}
return hash
}
func (h *Header) computeHash() Hash {
// Legacy hash takes precedence when legacy fields are present (backwards
// compatibility). Slim hash is the canonical hash for all other headers.
if h.Legacy != nil && !h.Legacy.IsZero() {
if legacyHash, err := h.HashLegacy(); err == nil {
return legacyHash
}
}
slimHash, err := h.HashSlim()
if err != nil {
return nil
}
return slimHash
}
// InvalidateHash clears the memoized hash, forcing recomputation on the next
// Hash() call. Must be called after any mutation of Header fields.
func (h *Header) InvalidateHash() {
if h != nil {
h.cachedHash = nil
}
}
// Hash returns hash of the Data
func (d *Data) Hash() Hash {
// Ignoring the marshal error for now to satisfy the go-header interface
// Later on the usage of Hash should be replaced with DA commitment
dBytes, _ := d.MarshalBinary()
return leafHashOpt(sha256.New(), dBytes)
}
// DACommitment returns the DA commitment of the Data excluding the Metadata
func (d *Data) DACommitment() Hash {
// Prune the Data to only include the Txs
prunedData := &Data{
Txs: d.Txs,
}
dBytes, _ := prunedData.MarshalBinary()
return leafHashOpt(sha256.New(), dBytes)
}
func leafHashOpt(s hash.Hash, leaf []byte) []byte {
s.Reset()
s.Write(leafPrefix)
s.Write(leaf)
return s.Sum(nil)
}