forked from NebulousLabs/merkletree
-
Notifications
You must be signed in to change notification settings - Fork 0
/
cachedtree.go
71 lines (62 loc) · 2.6 KB
/
cachedtree.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
package merkletree
import (
"errors"
"hash"
)
// A CachedTree can be used to build Merkle roots and proofs from the cached
// Merkle roots of smaller blocks of data. Each CachedTree has a height,
// meaning every element added to the CachedTree is the root of a full Merkle
// tree containing 2^height leaves.
type CachedTree struct {
cachedNodeHeight uint64
trueProofIndex uint64
Tree
}
// NewCachedTree initializes a CachedTree with a hash object, which will be
// used when hashing the input.
func NewCachedTree(h hash.Hash, cachedNodeHeight uint64) *CachedTree {
return &CachedTree{
cachedNodeHeight: cachedNodeHeight,
Tree: Tree{
hash: h,
cachedTree: true,
},
}
}
// Prove will create a proof that the leaf at the indicated index is a part of
// the data represented by the Merkle root of the Cached Tree. The CachedTree
// needs the proof set proving that the index is an element of the cached
// element in order to create a correct proof. After proof is called, the
// CachedTree is unchanged, and can receive more elements.
func (ct *CachedTree) Prove(cachedProofSet [][]byte) (merkleRoot []byte, proofSet [][]byte, proofIndex uint64, numLeaves uint64) {
// Determine the proof index within the full tree, and the number of leaves
// within the full tree.
leavesPerCachedNode := uint64(1) << ct.cachedNodeHeight
numLeaves = leavesPerCachedNode * ct.currentIndex
// Get the proof set tail, which is generated based entirely on cached
// nodes.
merkleRoot, proofSetTail, _, _ := ct.Tree.Prove()
if len(proofSetTail) < 1 {
// The proof was invalid, return 'nil' for the proof set but accurate
// values for everything else.
return merkleRoot, nil, ct.trueProofIndex, numLeaves
}
// The full proof set is going to be the input cachedProofSet combined with
// the tail proof set. The one caveat is that the tail proof set has an
// extra piece of data at the first element - the verifier will assume that
// this data exists and therefore it needs to be omitted from the proof
// set.
proofSet = append(cachedProofSet, proofSetTail[1:]...)
return merkleRoot, proofSet, ct.trueProofIndex, numLeaves
}
// SetIndex will inform the CachedTree of the index of the leaf for which a
// storage proof is being created. The index should be the index of the actual
// leaf, and not the index of the cached element containing the leaf. SetIndex
// must be called on empty CachedTree.
func (ct *CachedTree) SetIndex(i uint64) error {
if ct.head != nil {
return errors.New("cannot call SetIndex on Tree if Tree has not been reset")
}
ct.trueProofIndex = i
return ct.Tree.SetIndex(i / (1 << ct.cachedNodeHeight))
}