forked from DNAProject/DNA
-
Notifications
You must be signed in to change notification settings - Fork 1
/
merkle_hasher.go
115 lines (96 loc) · 3.12 KB
/
merkle_hasher.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
115
/*
* Copyright (C) 2018 The DNA Authors
* This file is part of The DNA library.
*
* The DNA is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The DNA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with The DNA. If not, see <http://www.gnu.org/licenses/>.
*/
package merkle
import (
"crypto/sha256"
"github.com/dnaproject2/DNA/common"
)
var debugCheck = false
type TreeHasher struct {
}
func (self TreeHasher) hash_empty() common.Uint256 {
return sha256.Sum256(nil)
}
func (self TreeHasher) hash_leaf(data []byte) common.Uint256 {
tmp := append([]byte{0}, data...)
return sha256.Sum256(tmp)
}
func (self TreeHasher) hash_children(left, right common.Uint256) common.Uint256 {
data := append([]byte{1}, left[:]...)
data = append(data, right[:]...)
return sha256.Sum256(data)
}
func (self TreeHasher) HashFullTreeWithLeafHash(leaves []common.Uint256) common.Uint256 {
length := uint32(len(leaves))
root_hash, hashes := self._hash_full(leaves, 0, length)
if uint(len(hashes)) != countBit(length) {
panic("hashes length mismatch")
}
if debugCheck {
root2 := self.hash_empty()
if len(hashes) != 0 {
root2 = self._hash_fold(hashes)
}
if root_hash != root2 {
panic("root hash mismatch")
}
}
// assert len(hashes) == countBit(len(leaves))
// assert self._hash_fold(hashes) == root_hash if hashes else root_hash == self.hash_empty()
return root_hash
}
func (self TreeHasher) HashFullTree(leaves [][]byte) common.Uint256 {
length := uint32(len(leaves))
leafhashes := make([]common.Uint256, length, length)
for i := range leaves {
leafhashes[i] = self.hash_leaf(leaves[i])
}
return self.HashFullTreeWithLeafHash(leafhashes)
}
func (self TreeHasher) _hash_full(leaves []common.Uint256, l_idx, r_idx uint32) (root_hash common.Uint256, hashes []common.Uint256) {
width := r_idx - l_idx
if width == 0 {
return self.hash_empty(), nil
} else if width == 1 {
leaf_hash := leaves[l_idx]
return leaf_hash, []common.Uint256{leaf_hash}
} else {
var split_width uint32 = 1 << (highBit(width-1) - 1)
l_root, l_hashes := self._hash_full(leaves, l_idx, l_idx+split_width)
if len(l_hashes) != 1 {
panic("left tree always full")
}
r_root, r_hashes := self._hash_full(leaves, l_idx+split_width, r_idx)
root_hash = self.hash_children(l_root, r_root)
var hashes []common.Uint256
if split_width*2 == width {
hashes = []common.Uint256{root_hash}
} else {
hashes = append(l_hashes, r_hashes[:]...)
}
return root_hash, hashes
}
}
func (self TreeHasher) _hash_fold(hashes []common.Uint256) common.Uint256 {
l := len(hashes)
accum := hashes[l-1]
for i := l - 2; i >= 0; i-- {
accum = self.hash_children(hashes[i], accum)
}
return accum
}