This repository was archived by the owner on Jun 17, 2020. It is now read-only.
forked from lukechampine/merkle
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmerkle.go
102 lines (86 loc) · 1.54 KB
/
merkle.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
91
92
93
94
95
96
97
98
99
100
101
102
package main
import (
"crypto/sha256"
"fmt"
"hash"
"io"
"os"
)
const segSize = 64
type stack struct {
head *elem
hash hash.Hash
}
type elem struct {
height int
sum []byte
next *elem
}
func (s *stack) pop() (e *elem) {
e = s.head
s.head = s.head.next
return
}
func (s *stack) push(e *elem) {
e.next = s.head
s.head = e
for s.head.next != nil && s.head.height == s.head.next.height {
s.collapse()
}
}
func (s *stack) collapse() {
oldhead := s.pop()
s.hash.Reset()
s.hash.Write(s.head.sum)
s.hash.Write(oldhead.sum)
s.hash.Sum(s.head.sum[:0])
s.head.height++
}
func copySeg(dst io.Writer, src io.Reader, buf []byte) (written int, err error) {
n, err := io.ReadFull(src, buf)
if err != nil && err != io.ErrUnexpectedEOF {
return n, err
}
return dst.Write(buf[:n])
}
func (s *stack) ReadFrom(r io.Reader) (n int64, err error) {
buf := make([]byte, segSize)
for {
s.hash.Reset()
copied, err := copySeg(s.hash, r, buf)
n += int64(copied)
if err != nil && err != io.EOF {
return n, err
} else if copied == 0 {
break
}
s.push(&elem{0, s.hash.Sum(nil), nil})
}
return n, nil
}
func (s *stack) Root() []byte {
if s.head == nil {
return nil
}
for s.head.next != nil {
s.collapse()
}
return s.head.sum
}
func New(h hash.Hash) *stack {
return &stack{hash: h}
}
func main() {
file, err := os.Open("test.dat")
if err != nil {
fmt.Println(err)
return
}
stack := New(sha256.New())
_, err = stack.ReadFrom(file)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("%x\n", stack.Root())
}