forked from anacrolix/torrent
-
Notifications
You must be signed in to change notification settings - Fork 0
/
hash.go
90 lines (77 loc) · 1.81 KB
/
hash.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
package merkle
import (
"crypto/sha256"
"hash"
"unsafe"
)
func NewHash() *Hash {
h := &Hash{
nextBlock: sha256.New(),
}
return h
}
type Hash struct {
blocks [][32]byte
nextBlock hash.Hash
// How many bytes have been written to nextBlock so far.
nextBlockWritten int
}
func (h *Hash) remaining() int {
return BlockSize - h.nextBlockWritten
}
func (h *Hash) Write(p []byte) (n int, err error) {
for len(p) > 0 {
var n1 int
n1, err = h.nextBlock.Write(p[:min(len(p), h.remaining())])
n += n1
h.nextBlockWritten += n1
p = p[n1:]
if h.remaining() == 0 {
h.blocks = append(h.blocks, h.nextBlockSum())
h.nextBlock.Reset()
h.nextBlockWritten = 0
}
if err != nil {
break
}
}
return
}
func (h *Hash) nextBlockSum() (sum [32]byte) {
if unsafe.SliceData(h.nextBlock.Sum(sum[:0])) != unsafe.SliceData(sum[:]) {
panic("go sux")
}
return
}
func (h *Hash) curBlocks() [][32]byte {
blocks := h.blocks
if h.nextBlockWritten != 0 {
blocks = append(blocks, h.nextBlockSum())
}
return blocks
}
func (h *Hash) Sum(b []byte) []byte {
sum := RootWithPadHash(h.curBlocks(), [32]byte{})
return append(b, sum[:]...)
}
// Sums by extending with zero hashes for blocks missing to meet the given length. Necessary for
// piece layers hashes for file tail blocks that don't pad to the piece length.
func (h *Hash) SumMinLength(b []byte, length int) []byte {
blocks := h.curBlocks()
minBlocks := (length + BlockSize - 1) / BlockSize
blocks = append(blocks, make([][32]byte, minBlocks-len(blocks))...)
sum := RootWithPadHash(blocks, [32]byte{})
return append(b, sum[:]...)
}
func (h *Hash) Reset() {
h.blocks = h.blocks[:0]
h.nextBlock.Reset()
h.nextBlockWritten = 0
}
func (h *Hash) Size() int {
return 32
}
func (h *Hash) BlockSize() int {
return h.nextBlock.BlockSize()
}
var _ hash.Hash = (*Hash)(nil)