| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455 |
- package metainfo
- import (
- "fmt"
- "github.com/anacrolix/torrent/merkle"
- )
- func ValidatePieceLayers(
- pieceLayers map[string]string,
- fileTree *FileTree,
- pieceLength int64,
- ) (err error) {
- fileTree.Walk(nil, func(path []string, ft *FileTree) {
- if err != nil {
- return
- }
- if ft.IsDir() {
- return
- }
- piecesRoot := ft.PiecesRootAsByteArray()
- if !piecesRoot.Ok {
- return
- }
- filePieceLayers, ok := pieceLayers[string(piecesRoot.Value[:])]
- if !ok {
- // BEP 52: "For each file in the file tree that is larger than the piece size it
- // contains one string value.". The reference torrent creator in
- // https://blog.libtorrent.org/2020/09/bittorrent-v2/ also has this. If a file is equal
- // to or smaller than the piece length, we can just use the pieces root instead of the
- // piece layer hash.
- if ft.File.Length > pieceLength {
- err = fmt.Errorf("no piece layers for file %q", path)
- }
- return
- }
- var layerHashes [][32]byte
- layerHashes, err = merkle.CompactLayerToSliceHashes(filePieceLayers)
- root := merkle.RootWithPadHash(layerHashes, HashForPiecePad(pieceLength))
- if root != piecesRoot.Value {
- err = fmt.Errorf("file %q: expected hash %x got %x", path, piecesRoot.Value, root)
- return
- }
- })
- return
- }
- // Returns the padding hash for the hash layer corresponding to a piece. It can't be zero because
- // that's the bottom-most layer (the hashes for the smallest blocks).
- func HashForPiecePad(pieceLength int64) (hash [32]byte) {
- // This should be a power of two, and probably checked elsewhere.
- blocksPerPiece := pieceLength / (1 << 14)
- blockHashes := make([][32]byte, blocksPerPiece)
- return merkle.Root(blockHashes)
- }
|