-
Notifications
You must be signed in to change notification settings - Fork 899
/
share_proof.go
112 lines (98 loc) · 3.11 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
package byzantine
import (
"context"
"github.com/ipfs/go-blockservice"
"github.com/ipfs/go-cid"
logging "github.com/ipfs/go-log/v2"
"github.com/minio/sha256-simd"
"github.com/celestiaorg/celestia-node/share"
pb "github.com/celestiaorg/celestia-node/share/eds/byzantine/pb"
"github.com/celestiaorg/celestia-node/share/ipld"
"github.com/celestiaorg/nmt"
)
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(
sha256.New(), // TODO(@Wondertan): This should be defined somewhere globally
share.ID(s.Share),
[][]byte{share.Data(s.Share)},
ipld.NamespacedSha256FromCID(root),
)
}
func (s *ShareWithProof) ShareWithProofToProto() *pb.Share {
if s == nil {
return &pb.Share{}
}
return &pb.Share{
Data: s.Share,
Proof: &pb.MerkleProof{
Start: int64(s.Proof.Start()),
End: int64(s.Proof.End()),
Nodes: s.Proof.Nodes(),
LeafHash: s.Proof.LeafHash(),
},
}
}
// 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 := 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.
s, err := ipld.GetLeaf(ctx, bGetter, root, index, len(shares))
if err != nil {
return nil, err
}
proof, err = ipld.GetProof(ctx, bGetter, root, proof, index, len(shares))
if err != nil {
return nil, err
}
proofs[index] = NewShareWithProof(index, s.RawData(), proof)
}
}
return proofs, 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 *pb.MerkleProof) nmt.Proof {
return nmt.NewInclusionProof(int(protoProof.Start), int(protoProof.End), protoProof.Nodes, ipld.NMTIgnoreMaxNamespace)
}