]> Sergey Matveev's repositories - btrtrc.git/blob - merkle/hash.go
Misc improvements
[btrtrc.git] / merkle / hash.go
1 package merkle
2
3 import (
4         "crypto/sha256"
5         "hash"
6         "unsafe"
7 )
8
9 func NewHash() *Hash {
10         h := &Hash{
11                 nextBlock: sha256.New(),
12         }
13         return h
14 }
15
16 type Hash struct {
17         blocks    [][32]byte
18         nextBlock hash.Hash
19         written   int
20 }
21
22 func (h *Hash) remaining() int {
23         return BlockSize - h.written
24 }
25
26 func (h *Hash) Write(p []byte) (n int, err error) {
27         for len(p) > 0 {
28                 var n1 int
29                 n1, err = h.nextBlock.Write(p[:min(len(p), h.remaining())])
30                 n += n1
31                 h.written += n1
32                 p = p[n1:]
33                 if h.remaining() == 0 {
34                         h.blocks = append(h.blocks, h.nextBlockSum())
35                         h.nextBlock.Reset()
36                         h.written = 0
37                 }
38                 if err != nil {
39                         break
40                 }
41         }
42         return
43 }
44
45 func (h *Hash) nextBlockSum() (sum [32]byte) {
46         if unsafe.SliceData(h.nextBlock.Sum(sum[:0])) != unsafe.SliceData(sum[:]) {
47                 panic("go sux")
48         }
49         return
50 }
51
52 func (h *Hash) Sum(b []byte) []byte {
53         blocks := h.blocks
54         if h.written != 0 {
55                 blocks = append(blocks, h.nextBlockSum())
56         }
57         sum := RootWithPadHash(blocks, [32]byte{})
58         return append(b, sum[:]...)
59 }
60
61 func (h *Hash) Reset() {
62         h.blocks = h.blocks[:0]
63         h.nextBlock.Reset()
64         h.written = 0
65 }
66
67 func (h *Hash) Size() int {
68         return 32
69 }
70
71 func (h *Hash) BlockSize() int {
72         return h.nextBlock.BlockSize()
73 }
74
75 var _ hash.Hash = (*Hash)(nil)