github.com/celestiaorg/celestia-node@v0.15.0-beta.1/share/getter.go (about) 1 package share 2 3 import ( 4 "context" 5 "crypto/sha256" 6 "errors" 7 "fmt" 8 9 "github.com/celestiaorg/nmt" 10 "github.com/celestiaorg/rsmt2d" 11 12 "github.com/celestiaorg/celestia-node/header" 13 ) 14 15 var ( 16 // ErrNotFound is used to indicate that requested data could not be found. 17 ErrNotFound = errors.New("share: data not found") 18 // ErrOutOfBounds is used to indicate that a passed row or column index is out of bounds of the 19 // square size. 20 ErrOutOfBounds = errors.New("share: row or column index is larger than square size") 21 ) 22 23 // Getter interface provides a set of accessors for shares by the Root. 24 // Automatically verifies integrity of shares(exceptions possible depending on the implementation). 25 // 26 //go:generate mockgen -destination=mocks/getter.go -package=mocks . Getter 27 type Getter interface { 28 // GetShare gets a Share by coordinates in EDS. 29 GetShare(ctx context.Context, header *header.ExtendedHeader, row, col int) (Share, error) 30 31 // GetEDS gets the full EDS identified by the given extended header. 32 GetEDS(context.Context, *header.ExtendedHeader) (*rsmt2d.ExtendedDataSquare, error) 33 34 // GetSharesByNamespace gets all shares from an EDS within the given namespace. 35 // Shares are returned in a row-by-row order if the namespace spans multiple rows. 36 // Inclusion of returned data could be verified using Verify method on NamespacedShares. 37 // If no shares are found for target namespace non-inclusion could be also verified by calling 38 // Verify method. 39 GetSharesByNamespace(context.Context, *header.ExtendedHeader, Namespace) (NamespacedShares, error) 40 } 41 42 // NamespacedShares represents all shares with proofs within a specific namespace of an EDS. 43 type NamespacedShares []NamespacedRow 44 45 // Flatten returns the concatenated slice of all NamespacedRow shares. 46 func (ns NamespacedShares) Flatten() []Share { 47 shares := make([]Share, 0) 48 for _, row := range ns { 49 shares = append(shares, row.Shares...) 50 } 51 return shares 52 } 53 54 // NamespacedRow represents all shares with proofs within a specific namespace of a single EDS row. 55 type NamespacedRow struct { 56 Shares []Share `json:"shares"` 57 Proof *nmt.Proof `json:"proof"` 58 } 59 60 // Verify validates NamespacedShares by checking every row with nmt inclusion proof. 61 func (ns NamespacedShares) Verify(root *Root, namespace Namespace) error { 62 var originalRoots [][]byte 63 for _, row := range root.RowRoots { 64 if !namespace.IsOutsideRange(row, row) { 65 originalRoots = append(originalRoots, row) 66 } 67 } 68 69 if len(originalRoots) != len(ns) { 70 return fmt.Errorf("amount of rows differs between root and namespace shares: expected %d, got %d", 71 len(originalRoots), len(ns)) 72 } 73 74 for i, row := range ns { 75 // verify row data against row hash from original root 76 if !row.verify(originalRoots[i], namespace) { 77 return fmt.Errorf("row verification failed: row %d doesn't match original root: %s", i, root.String()) 78 } 79 } 80 return nil 81 } 82 83 // verify validates the row using nmt inclusion proof. 84 func (row *NamespacedRow) verify(rowRoot []byte, namespace Namespace) bool { 85 // construct nmt leaves from shares by prepending namespace 86 leaves := make([][]byte, 0, len(row.Shares)) 87 for _, shr := range row.Shares { 88 leaves = append(leaves, append(GetNamespace(shr), shr...)) 89 } 90 91 // verify namespace 92 return row.Proof.VerifyNamespace( 93 sha256.New(), 94 namespace.ToNMT(), 95 leaves, 96 rowRoot, 97 ) 98 }