-
Notifications
You must be signed in to change notification settings - Fork 893
/
share_proof.go
133 lines (117 loc) · 3.46 KB
/
share_proof.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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
package byzantine
import (
"context"
"github.com/ipfs/boxo/blockservice"
"github.com/ipfs/go-cid"
logging "github.com/ipfs/go-log/v2"
"github.com/celestiaorg/nmt"
nmt_pb "github.com/celestiaorg/nmt/pb"
"github.com/celestiaorg/celestia-node/share"
pb "github.com/celestiaorg/celestia-node/share/eds/byzantine/pb"
"github.com/celestiaorg/celestia-node/share/ipld"
)
var log = logging.Logger("share/byzantine")
// ShareWithProof contains data with corresponding Merkle Proof
type ShareWithProof struct {
// Share is a full data including namespace
share.Share
// Proof is a Merkle Proof of current share
Proof *nmt.Proof
}
// NewShareWithProof takes the given leaf and its path, starting from the tree root,
// and computes the nmt.Proof for it.
func NewShareWithProof(index int, share share.Share, pathToLeaf []cid.Cid) *ShareWithProof {
rangeProofs := make([][]byte, 0, len(pathToLeaf))
for i := len(pathToLeaf) - 1; i >= 0; i-- {
node := ipld.NamespacedSha256FromCID(pathToLeaf[i])
rangeProofs = append(rangeProofs, node)
}
proof := nmt.NewInclusionProof(index, index+1, rangeProofs, true)
return &ShareWithProof{
share,
&proof,
}
}
// Validate validates inclusion of the share under the given root CID.
func (s *ShareWithProof) Validate(root cid.Cid) bool {
return s.Proof.VerifyInclusion(
share.NewSHA256Hasher(),
share.GetNamespace(s.Share).ToNMT(),
[][]byte{share.GetData(s.Share)},
ipld.NamespacedSha256FromCID(root),
)
}
func (s *ShareWithProof) ShareWithProofToProto() *pb.Share {
if s == nil {
return &pb.Share{}
}
return &pb.Share{
Data: s.Share,
Proof: &nmt_pb.Proof{
Start: int64(s.Proof.Start()),
End: int64(s.Proof.End()),
Nodes: s.Proof.Nodes(),
LeafHash: s.Proof.LeafHash(),
IsMaxNamespaceIgnored: s.Proof.IsMaxNamespaceIDIgnored(),
},
}
}
// GetProofsForShares fetches Merkle proofs for the given shares
// and returns the result as an array of ShareWithProof.
func GetProofsForShares(
ctx context.Context,
bGetter blockservice.BlockGetter,
root cid.Cid,
shares [][]byte,
) ([]*ShareWithProof, error) {
proofs := make([]*ShareWithProof, len(shares))
for index, share := range shares {
if share != nil {
proof, err := getProofsAt(ctx, bGetter, root, index, len(shares))
if err != nil {
return nil, err
}
proofs[index] = proof
}
}
return proofs, nil
}
func getProofsAt(
ctx context.Context,
bGetter blockservice.BlockGetter,
root cid.Cid,
index,
total int,
) (*ShareWithProof, error) {
proof := make([]cid.Cid, 0)
// TODO(@vgonkivs): Combine GetLeafData and GetProof in one function as the are traversing the same
// tree. Add options that will control what data will be fetched.
node, err := ipld.GetLeaf(ctx, bGetter, root, index, total)
if err != nil {
return nil, err
}
proof, err = ipld.GetProof(ctx, bGetter, root, proof, index, total)
if err != nil {
return nil, err
}
return NewShareWithProof(index, node.RawData(), proof), nil
}
func ProtoToShare(protoShares []*pb.Share) []*ShareWithProof {
shares := make([]*ShareWithProof, len(protoShares))
for i, share := range protoShares {
if share.Proof == nil {
continue
}
proof := ProtoToProof(share.Proof)
shares[i] = &ShareWithProof{share.Data, &proof}
}
return shares
}
func ProtoToProof(protoProof *nmt_pb.Proof) nmt.Proof {
return nmt.NewInclusionProof(
int(protoProof.Start),
int(protoProof.End),
protoProof.Nodes,
protoProof.IsMaxNamespaceIgnored,
)
}