2 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
3 Copyright (C) 2016-2021 Sergey Matveev <stargrave@stargrave.org>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, version 3 of the License.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 "lukechampine.com/blake3"
29 MTHBlockSize = 128 * 1024
34 MTHLeafKey = blake3.Sum256([]byte("NNCP MTH LEAF"))
35 MTHNodeKey = blake3.Sum256([]byte("NNCP MTH NODE"))
38 type MTHEventType uint8
41 MTHEventAppend MTHEventType = iota
42 MTHEventPrepend MTHEventType = iota
43 MTHEventFold MTHEventType = iota
46 type MTHEvent struct {
59 hashes [][MTHSize]byte
66 func MTHNew(size, offset int64) *MTH {
68 hasher: blake3.New(MTHSize, MTHLeafKey[:]),
69 buf: bytes.NewBuffer(make([]byte, 0, 2*MTHBlockSize)),
74 prepends := int(offset / MTHBlockSize)
75 skip := MTHBlockSize - (offset - int64(prepends)*MTHBlockSize)
76 if skip == MTHBlockSize {
81 prependSize := int64(prepends * MTHBlockSize)
82 if prependSize > size {
85 if offset+skip > size {
89 mth.PrependSize = prependSize
91 mth.hashes = make([][MTHSize]byte, prepends, 1+size/MTHBlockSize)
95 func (mth *MTH) Reset() { panic("not implemented") }
97 func (mth *MTH) Size() int { return MTHSize }
99 func (mth *MTH) BlockSize() int { return MTHBlockSize }
101 func (mth *MTH) Write(data []byte) (int, error) {
103 return 0, errors.New("already Sum()ed")
105 n, err := mth.buf.Write(data)
109 if mth.skip > 0 && int64(mth.buf.Len()) >= mth.skip {
110 mth.buf.Next(int(mth.skip))
113 for mth.buf.Len() >= MTHBlockSize {
114 if _, err = mth.hasher.Write(mth.buf.Next(MTHBlockSize)); err != nil {
117 h := new([MTHSize]byte)
118 mth.hasher.Sum(h[:0])
120 mth.hashes = append(mth.hashes, *h)
121 if mth.Events != nil {
122 mth.Events <- MTHEvent{
124 0, len(mth.hashes) - 1,
125 mth.hashes[len(mth.hashes)-1][:],
132 func (mth *MTH) PrependFrom(r io.Reader) (int, error) {
134 return 0, errors.New("already Sum()ed")
137 buf := make([]byte, MTHBlockSize)
139 fullsize := mth.PrependSize
140 les := LEs{{"Pkt", mth.PktName}, {"FullSize", fullsize}, {"Size", 0}}
141 for mth.PrependSize >= MTHBlockSize {
142 n, err = io.ReadFull(r, buf)
144 mth.PrependSize -= MTHBlockSize
148 if _, err = mth.hasher.Write(buf); err != nil {
151 mth.hasher.Sum(mth.hashes[i][:0])
153 if mth.Events != nil {
154 mth.Events <- MTHEvent{MTHEventPrepend, 0, i, mth.hashes[i][:]}
156 if mth.PktName != "" {
157 les[len(les)-1].V = int64(read)
158 Progress("check", les)
162 if mth.PrependSize > 0 {
163 n, err = io.ReadFull(r, buf[:mth.PrependSize])
168 if _, err = mth.hasher.Write(buf[:mth.PrependSize]); err != nil {
171 mth.hasher.Sum(mth.hashes[i][:0])
173 if mth.Events != nil {
174 mth.Events <- MTHEvent{MTHEventPrepend, 0, i, mth.hashes[i][:]}
176 if mth.PktName != "" {
177 les[len(les)-1].V = fullsize
178 Progress("check", les)
184 func (mth *MTH) Sum(b []byte) []byte {
186 return append(b, mth.hashes[0][:]...)
188 if mth.buf.Len() > 0 {
189 b := mth.buf.Next(MTHBlockSize)
190 if _, err := mth.hasher.Write(b); err != nil {
193 h := new([MTHSize]byte)
194 mth.hasher.Sum(h[:0])
196 mth.hashes = append(mth.hashes, *h)
197 if mth.Events != nil {
198 mth.Events <- MTHEvent{
200 0, len(mth.hashes) - 1,
201 mth.hashes[len(mth.hashes)-1][:],
205 switch len(mth.hashes) {
207 h := new([MTHSize]byte)
208 if _, err := mth.hasher.Write(nil); err != nil {
211 mth.hasher.Sum(h[:0])
213 mth.hashes = append(mth.hashes, *h)
214 if mth.Events != nil {
215 mth.Events <- MTHEvent{MTHEventAppend, 0, 0, mth.hashes[0][:]}
219 mth.hashes = append(mth.hashes, mth.hashes[0])
220 if mth.Events != nil {
221 mth.Events <- MTHEvent{MTHEventAppend, 0, 1, mth.hashes[1][:]}
224 mth.hasher = blake3.New(MTHSize, MTHNodeKey[:])
226 for len(mth.hashes) != 1 {
227 hashesUp := make([][MTHSize]byte, 0, 1+len(mth.hashes)/2)
228 pairs := (len(mth.hashes) / 2) * 2
229 for i := 0; i < pairs; i += 2 {
230 if _, err := mth.hasher.Write(mth.hashes[i][:]); err != nil {
233 if _, err := mth.hasher.Write(mth.hashes[i+1][:]); err != nil {
236 h := new([MTHSize]byte)
237 mth.hasher.Sum(h[:0])
239 hashesUp = append(hashesUp, *h)
240 if mth.Events != nil {
241 mth.Events <- MTHEvent{
243 level, len(hashesUp) - 1,
244 hashesUp[len(hashesUp)-1][:],
248 if len(mth.hashes)%2 == 1 {
249 hashesUp = append(hashesUp, mth.hashes[len(mth.hashes)-1])
250 if mth.Events != nil {
251 mth.Events <- MTHEvent{
253 level, len(hashesUp) - 1,
254 hashesUp[len(hashesUp)-1][:],
258 mth.hashes = hashesUp
262 if mth.Events != nil {
265 return append(b, mth.hashes[0][:]...)