-
-
Notifications
You must be signed in to change notification settings - Fork 620
/
bep52.go
55 lines (51 loc) · 1.64 KB
/
bep52.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
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)
}