github.com/sunrise-zone/sunrise-node@v0.13.1-sr2/share/eds/byzantine/share_proof.go (about) 1 package byzantine 2 3 import ( 4 "context" 5 "crypto/sha256" 6 7 "github.com/ipfs/boxo/blockservice" 8 "github.com/ipfs/go-cid" 9 logging "github.com/ipfs/go-log/v2" 10 11 "github.com/celestiaorg/nmt" 12 nmt_pb "github.com/celestiaorg/nmt/pb" 13 14 "github.com/sunrise-zone/sunrise-node/share" 15 pb "github.com/sunrise-zone/sunrise-node/share/eds/byzantine/pb" 16 "github.com/sunrise-zone/sunrise-node/share/ipld" 17 ) 18 19 var log = logging.Logger("share/byzantine") 20 21 // ShareWithProof contains data with corresponding Merkle Proof 22 type ShareWithProof struct { 23 // Share is a full data including namespace 24 share.Share 25 // Proof is a Merkle Proof of current share 26 Proof *nmt.Proof 27 } 28 29 // NewShareWithProof takes the given leaf and its path, starting from the tree root, 30 // and computes the nmt.Proof for it. 31 func NewShareWithProof(index int, share share.Share, pathToLeaf []cid.Cid) *ShareWithProof { 32 rangeProofs := make([][]byte, 0, len(pathToLeaf)) 33 for i := len(pathToLeaf) - 1; i >= 0; i-- { 34 node := ipld.NamespacedSha256FromCID(pathToLeaf[i]) 35 rangeProofs = append(rangeProofs, node) 36 } 37 38 proof := nmt.NewInclusionProof(index, index+1, rangeProofs, true) 39 return &ShareWithProof{ 40 share, 41 &proof, 42 } 43 } 44 45 // Validate validates inclusion of the share under the given root CID. 46 func (s *ShareWithProof) Validate(root cid.Cid) bool { 47 return s.Proof.VerifyInclusion( 48 sha256.New(), // TODO(@Wondertan): This should be defined somewhere globally 49 share.GetNamespace(s.Share).ToNMT(), 50 [][]byte{share.GetData(s.Share)}, 51 ipld.NamespacedSha256FromCID(root), 52 ) 53 } 54 55 func (s *ShareWithProof) ShareWithProofToProto() *pb.Share { 56 if s == nil { 57 return &pb.Share{} 58 } 59 60 return &pb.Share{ 61 Data: s.Share, 62 Proof: &nmt_pb.Proof{ 63 Start: int64(s.Proof.Start()), 64 End: int64(s.Proof.End()), 65 Nodes: s.Proof.Nodes(), 66 LeafHash: s.Proof.LeafHash(), 67 IsMaxNamespaceIgnored: s.Proof.IsMaxNamespaceIDIgnored(), 68 }, 69 } 70 } 71 72 // GetProofsForShares fetches Merkle proofs for the given shares 73 // and returns the result as an array of ShareWithProof. 74 func GetProofsForShares( 75 ctx context.Context, 76 bGetter blockservice.BlockGetter, 77 root cid.Cid, 78 shares [][]byte, 79 ) ([]*ShareWithProof, error) { 80 proofs := make([]*ShareWithProof, len(shares)) 81 for index, share := range shares { 82 if share != nil { 83 proof, err := getProofsAt(ctx, bGetter, root, index, len(shares)) 84 if err != nil { 85 return nil, err 86 } 87 proofs[index] = proof 88 } 89 } 90 return proofs, nil 91 } 92 93 func getProofsAt( 94 ctx context.Context, 95 bGetter blockservice.BlockGetter, 96 root cid.Cid, 97 index, 98 total int, 99 ) (*ShareWithProof, error) { 100 proof := make([]cid.Cid, 0) 101 // TODO(@vgonkivs): Combine GetLeafData and GetProof in one function as the are traversing the same 102 // tree. Add options that will control what data will be fetched. 103 node, err := ipld.GetLeaf(ctx, bGetter, root, index, total) 104 if err != nil { 105 return nil, err 106 } 107 108 proof, err = ipld.GetProof(ctx, bGetter, root, proof, index, total) 109 if err != nil { 110 return nil, err 111 } 112 return NewShareWithProof(index, node.RawData(), proof), nil 113 } 114 115 func ProtoToShare(protoShares []*pb.Share) []*ShareWithProof { 116 shares := make([]*ShareWithProof, len(protoShares)) 117 for i, share := range protoShares { 118 if share.Proof == nil { 119 continue 120 } 121 proof := ProtoToProof(share.Proof) 122 shares[i] = &ShareWithProof{share.Data, &proof} 123 } 124 return shares 125 } 126 127 func ProtoToProof(protoProof *nmt_pb.Proof) nmt.Proof { 128 return nmt.NewInclusionProof( 129 int(protoProof.Start), 130 int(protoProof.End), 131 protoProof.Nodes, 132 protoProof.IsMaxNamespaceIgnored, 133 ) 134 }