forked from NebulousLabs/Sia
-
Notifications
You must be signed in to change notification settings - Fork 0
/
merkle.go
114 lines (100 loc) · 3.29 KB
/
merkle.go
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
package crypto
import (
"io"
"github.com/NebulousLabs/Sia/encoding"
"github.com/NebulousLabs/merkletree"
)
const (
SegmentSize = 64 // number of bytes that are hashed to form each base leaf of the Merkle tree
)
type MerkleTree struct {
*merkletree.Tree
}
// NewTree returns a tree object that can be used to get the merkle root of a
// dataset.
func NewTree() MerkleTree {
return MerkleTree{merkletree.New(NewHash())}
}
// PushObject encodes and adds the hash of the encoded object to the tree as a
// leaf.
func (t MerkleTree) PushObject(obj interface{}) {
t.Push(encoding.Marshal(obj))
}
// ReadSegments reads segments from r into the tree. If EOF is encountered
// mid-segment, the zero-padded segment is added to the tree and no error is
// returned.
func (t MerkleTree) ReadSegments(r io.Reader) error {
buf := make([]byte, SegmentSize)
for {
_, err := io.ReadFull(r, buf)
if err == io.EOF {
break
} else if err != nil && err != io.ErrUnexpectedEOF {
return err
}
t.Push(buf)
}
return nil
}
// Root returns the Merkle root of all the objects pushed to the tree.
func (t MerkleTree) Root() (h Hash) {
copy(h[:], t.Tree.Root())
return
}
// MerkleRoot calculates the "root hash" formed by repeatedly concatenating
// and hashing a binary tree of hashes. If the number of leaves is not a
// power of 2, the orphan hash(es) are not rehashed. Examples:
//
// ┌───┴──┐ ┌────┴───┐ ┌─────┴─────┐
// ┌──┴──┐ │ ┌──┴──┐ │ ┌──┴──┐ ┌──┴──┐
// ┌─┴─┐ ┌─┴─┐ │ ┌─┴─┐ ┌─┴─┐ ┌─┴─┐ ┌─┴─┐ ┌─┴─┐ ┌─┴─┐ │
// (5-leaf) (6-leaf) (7-leaf)
func MerkleRoot(leaves [][]byte) (h Hash) {
tree := NewTree()
for _, leaf := range leaves {
tree.Push(leaf)
}
return tree.Root()
}
// Calculates the number of leaves in the file when building a Merkle tree.
func CalculateLeaves(fileSize uint64) uint64 {
numSegments := fileSize / SegmentSize
if fileSize == 0 || fileSize%SegmentSize != 0 {
numSegments++
}
return numSegments
}
// ReaderMerkleRoot returns the merkle root of a reader.
func ReaderMerkleRoot(r io.Reader) (h Hash, err error) {
root, err := merkletree.ReaderRoot(r, NewHash(), SegmentSize)
if err != nil {
return
}
copy(h[:], root)
return
}
// BuildReaderProof will build a storage proof when given a reader.
func BuildReaderProof(r io.Reader, proofIndex uint64) (base []byte, hashSet []Hash, err error) {
_, proofSet, _, err := merkletree.BuildReaderProof(r, NewHash(), SegmentSize, proofIndex)
if err != nil {
return
}
// convert proofSet to base and hashSet
base = proofSet[0]
hashSet = make([]Hash, len(proofSet)-1)
for i, proof := range proofSet[1:] {
copy(hashSet[i][:], proof)
}
return
}
// VerifySegment will verify that a segment, given the proof, is a part of a
// merkle root.
func VerifySegment(base []byte, hashSet []Hash, numSegments, proofIndex uint64, root Hash) bool {
// convert base and hashSet to proofSet
proofSet := make([][]byte, len(hashSet)+1)
proofSet[0] = base
for i := range hashSet {
proofSet[i+1] = hashSet[i][:]
}
return merkletree.VerifyProof(NewHash(), root[:], proofSet, proofIndex, numSegments)
}