-
Notifications
You must be signed in to change notification settings - Fork 301
/
Copy pathnmt_wrapper.go
74 lines (65 loc) · 3.06 KB
/
nmt_wrapper.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
package wrapper
import (
"fmt"
"github.com/celestiaorg/nmt"
"github.com/celestiaorg/rsmt2d"
"github.com/tendermint/tendermint/pkg/consts"
)
// Fulfills the rsmt2d.Tree interface and rsmt2d.TreeConstructorFn function
var _ rsmt2d.TreeConstructorFn = ErasuredNamespacedMerkleTree{}.Constructor
var _ rsmt2d.Tree = &ErasuredNamespacedMerkleTree{}
// ErasuredNamespacedMerkleTree wraps NamespaceMerkleTree to conform to the
// rsmt2d.Tree interface while also providing the correct namespaces to the
// underlying NamespaceMerkleTree. It does this by adding the already included
// namespace to the first half of the tree, and then uses the parity namespace
// ID for each share pushed to the second half of the tree. This allows for the
// namespaces to be included in the erasure data, while also keeping the nmt
// library sufficiently general
type ErasuredNamespacedMerkleTree struct {
squareSize uint64 // note: this refers to the width of the original square before erasure-coded
options []nmt.Option
tree *nmt.NamespacedMerkleTree
}
// NewErasuredNamespacedMerkleTree issues a new ErasuredNamespacedMerkleTree. squareSize must be greater than zero
func NewErasuredNamespacedMerkleTree(squareSize uint64, setters ...nmt.Option) ErasuredNamespacedMerkleTree {
if squareSize == 0 {
panic("cannot create a ErasuredNamespacedMerkleTree of squareSize == 0")
}
tree := nmt.New(consts.NewBaseHashFunc(), setters...)
return ErasuredNamespacedMerkleTree{squareSize: squareSize, options: setters, tree: tree}
}
// Constructor acts as the rsmt2d.TreeConstructorFn for
// ErasuredNamespacedMerkleTree
func (w ErasuredNamespacedMerkleTree) Constructor() rsmt2d.Tree {
newTree := NewErasuredNamespacedMerkleTree(w.squareSize, w.options...)
return &newTree
}
// Push adds the provided data to the underlying NamespaceMerkleTree, and
// automatically uses the first DefaultNamespaceIDLen number of bytes as the
// namespace unless the data pushed to the second half of the tree. Fulfills the
// rsmt.Tree interface. NOTE: panics if an error is encountered while pushing or
// if the tree size is exceeded.
func (w *ErasuredNamespacedMerkleTree) Push(data []byte, idx rsmt2d.SquareIndex) {
if idx.Axis+1 > 2*uint(w.squareSize) || idx.Cell+1 > 2*uint(w.squareSize) {
panic(fmt.Sprintf("pushed past predetermined square size: boundary at %d index at %+v", 2*w.squareSize, idx))
}
nidAndData := make([]byte, consts.NamespaceSize+len(data))
copy(nidAndData[consts.NamespaceSize:], data)
// use the parity namespace if the cell is not in Q0 of the extended data square
if idx.Axis+1 > uint(w.squareSize) || idx.Cell+1 > uint(w.squareSize) {
copy(nidAndData[:consts.NamespaceSize], consts.ParitySharesNamespaceID)
} else {
copy(nidAndData[:consts.NamespaceSize], data[:consts.NamespaceSize])
}
// push to the underlying tree
err := w.tree.Push(nidAndData)
// panic on error
if err != nil {
panic(err)
}
}
// Root fulfills the rsmt.Tree interface by generating and returning the
// underlying NamespaceMerkleTree Root.
func (w *ErasuredNamespacedMerkleTree) Root() []byte {
return w.tree.Root()
}