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/>.
26 "lukechampine.com/blake3"
30 MTHBlockSize = 128 * 1024
35 MTHLeafKey = blake3.Sum256([]byte("NNCP MTH LEAF"))
36 MTHNodeKey = blake3.Sum256([]byte("NNCP MTH NODE"))
39 type MTHEventType uint8
42 MTHEventAppend MTHEventType = iota
43 MTHEventPrepend MTHEventType = iota
44 MTHEventFold MTHEventType = iota
47 type MTHEvent struct {
56 PrependFrom(r io.Reader) (int64, error)
59 Events() chan MTHEvent
68 hashes [][MTHSize]byte
75 func MTHFatNew(size, offset int64) MTH {
77 hasher: blake3.New(MTHSize, MTHLeafKey[:]),
78 buf: bytes.NewBuffer(make([]byte, 0, 2*MTHBlockSize)),
83 prepends := offset / MTHBlockSize
84 skip := MTHBlockSize - (offset - prepends*MTHBlockSize)
85 if skip == MTHBlockSize {
90 prependSize := prepends * MTHBlockSize
91 if prependSize > size {
94 if offset+skip > size {
98 mth.prependSize = prependSize
100 mth.hashes = make([][MTHSize]byte, prepends, 1+size/MTHBlockSize)
104 func (mth *MTHFat) Events() chan MTHEvent {
105 mth.events = make(chan MTHEvent)
109 func (mth *MTHFat) SetPktName(pktName string) { mth.pktName = pktName }
111 func (mth *MTHFat) PrependSize() int64 { return mth.prependSize }
113 func (mth *MTHFat) Reset() { panic("not implemented") }
115 func (mth *MTHFat) Size() int { return MTHSize }
117 func (mth *MTHFat) BlockSize() int { return MTHBlockSize }
119 func (mth *MTHFat) Write(data []byte) (int, error) {
121 return 0, errors.New("already Sum()ed")
123 n, err := mth.buf.Write(data)
127 if mth.skip > 0 && int64(mth.buf.Len()) >= mth.skip {
128 mth.buf.Next(int(mth.skip))
131 for mth.buf.Len() >= MTHBlockSize {
132 if _, err = mth.hasher.Write(mth.buf.Next(MTHBlockSize)); err != nil {
135 h := new([MTHSize]byte)
136 mth.hasher.Sum(h[:0])
138 mth.hashes = append(mth.hashes, *h)
139 if mth.events != nil {
140 mth.events <- MTHEvent{
142 0, int64(len(mth.hashes) - 1),
143 mth.hashes[len(mth.hashes)-1][:],
150 func (mth *MTHFat) PrependFrom(r io.Reader) (int64, error) {
152 return 0, errors.New("already Sum()ed")
155 buf := make([]byte, MTHBlockSize)
158 fullsize := mth.prependSize
159 les := LEs{{"Pkt", mth.pktName}, {"FullSize", fullsize}, {"Size", 0}}
160 for mth.prependSize >= MTHBlockSize {
161 n, err = io.ReadFull(r, buf)
163 mth.prependSize -= MTHBlockSize
167 if _, err = mth.hasher.Write(buf); err != nil {
170 mth.hasher.Sum(mth.hashes[i][:0])
172 if mth.events != nil {
173 mth.events <- MTHEvent{MTHEventPrepend, 0, i, mth.hashes[i][:]}
175 if mth.pktName != "" {
176 les[len(les)-1].V = read
177 Progress("check", les)
181 if mth.prependSize > 0 {
182 n, err = io.ReadFull(r, buf[:mth.prependSize])
187 if _, err = mth.hasher.Write(buf[:mth.prependSize]); err != nil {
190 mth.hasher.Sum(mth.hashes[i][:0])
192 if mth.events != nil {
193 mth.events <- MTHEvent{MTHEventPrepend, 0, i, mth.hashes[i][:]}
195 if mth.pktName != "" {
196 les[len(les)-1].V = fullsize
197 Progress("check", les)
203 func (mth *MTHFat) Sum(b []byte) []byte {
205 return append(b, mth.hashes[0][:]...)
207 if mth.buf.Len() > 0 {
208 b := mth.buf.Next(MTHBlockSize)
209 if _, err := mth.hasher.Write(b); err != nil {
212 h := new([MTHSize]byte)
213 mth.hasher.Sum(h[:0])
215 mth.hashes = append(mth.hashes, *h)
216 if mth.events != nil {
217 mth.events <- MTHEvent{
219 0, int64(len(mth.hashes) - 1),
220 mth.hashes[len(mth.hashes)-1][:],
224 switch len(mth.hashes) {
226 h := new([MTHSize]byte)
227 if _, err := mth.hasher.Write(nil); err != nil {
230 mth.hasher.Sum(h[:0])
232 mth.hashes = append(mth.hashes, *h)
233 if mth.events != nil {
234 mth.events <- MTHEvent{MTHEventAppend, 0, 0, mth.hashes[0][:]}
238 mth.hashes = append(mth.hashes, mth.hashes[0])
239 if mth.events != nil {
240 mth.events <- MTHEvent{MTHEventAppend, 0, 1, mth.hashes[1][:]}
243 mth.hasher = blake3.New(MTHSize, MTHNodeKey[:])
245 for len(mth.hashes) != 1 {
246 hashesUp := make([][MTHSize]byte, 0, 1+len(mth.hashes)/2)
247 pairs := (len(mth.hashes) / 2) * 2
248 for i := 0; i < pairs; i += 2 {
249 if _, err := mth.hasher.Write(mth.hashes[i][:]); err != nil {
252 if _, err := mth.hasher.Write(mth.hashes[i+1][:]); err != nil {
255 h := new([MTHSize]byte)
256 mth.hasher.Sum(h[:0])
258 hashesUp = append(hashesUp, *h)
259 if mth.events != nil {
260 mth.events <- MTHEvent{
262 level, int64(len(hashesUp) - 1),
263 hashesUp[len(hashesUp)-1][:],
267 if len(mth.hashes)%2 == 1 {
268 hashesUp = append(hashesUp, mth.hashes[len(mth.hashes)-1])
269 if mth.events != nil {
270 mth.events <- MTHEvent{
272 level, int64(len(hashesUp) - 1),
273 hashesUp[len(hashesUp)-1][:],
277 mth.hashes = hashesUp
281 if mth.events != nil {
284 return append(b, mth.hashes[0][:]...)
287 type MTHSeqEnt struct {
293 hasherLeaf *blake3.Hasher
294 hasherNode *blake3.Hasher
302 func MTHSeqNew() *MTHSeq {
304 hasherLeaf: blake3.New(MTHSize, MTHLeafKey[:]),
305 hasherNode: blake3.New(MTHSize, MTHNodeKey[:]),
306 buf: bytes.NewBuffer(make([]byte, 0, 2*MTHBlockSize)),
307 ctrs: make([]int64, 1, 2),
312 func (mth *MTHSeq) Reset() { panic("not implemented") }
314 func (mth *MTHSeq) Size() int { return MTHSize }
316 func (mth *MTHSeq) BlockSize() int { return MTHBlockSize }
318 func (mth *MTHSeq) PrependFrom(r io.Reader) (int64, error) {
319 panic("must not reach that code")
322 func (mth *MTHSeq) Events() chan MTHEvent {
323 mth.events = make(chan MTHEvent)
327 func (mth *MTHSeq) SetPktName(pktName string) {}
329 func (mth *MTHSeq) PrependSize() int64 { return 0 }
331 func (mth *MTHSeq) leafAdd() {
332 ent := MTHSeqEnt{l: 0}
333 mth.hasherLeaf.Sum(ent.h[:0])
334 mth.hasherLeaf.Reset()
335 mth.hashes = append(mth.hashes, ent)
336 if mth.events != nil {
337 mth.events <- MTHEvent{
338 MTHEventAppend, 0, mth.ctrs[0],
339 mth.hashes[len(mth.hashes)-1].h[:],
345 func (mth *MTHSeq) incr(l int64) {
346 if int64(len(mth.ctrs)) <= l {
347 mth.ctrs = append(mth.ctrs, 0)
353 func (mth *MTHSeq) fold() {
354 for len(mth.hashes) >= 2 {
355 if mth.hashes[len(mth.hashes)-2].l != mth.hashes[len(mth.hashes)-1].l {
358 if _, err := mth.hasherNode.Write(mth.hashes[len(mth.hashes)-2].h[:]); err != nil {
361 if _, err := mth.hasherNode.Write(mth.hashes[len(mth.hashes)-1].h[:]); err != nil {
364 mth.hashes = mth.hashes[:len(mth.hashes)-1]
365 end := &mth.hashes[len(mth.hashes)-1]
368 mth.hasherNode.Sum(end.h[:0])
369 mth.hasherNode.Reset()
370 if mth.events != nil {
371 mth.events <- MTHEvent{MTHEventFold, end.l, mth.ctrs[end.l], end.h[:]}
376 func (mth *MTHSeq) Write(data []byte) (int, error) {
378 return 0, errors.New("already Sum()ed")
380 n, err := mth.buf.Write(data)
384 for mth.buf.Len() >= MTHBlockSize {
385 if _, err = mth.hasherLeaf.Write(mth.buf.Next(MTHBlockSize)); err != nil {
394 func (mth *MTHSeq) Sum(b []byte) []byte {
396 return append(b, mth.hashes[0].h[:]...)
398 if mth.buf.Len() > 0 {
399 if _, err := mth.hasherLeaf.Write(mth.buf.Next(MTHBlockSize)); err != nil {
407 if _, err := mth.hasherLeaf.Write(nil); err != nil {
413 mth.hashes = append(mth.hashes, mth.hashes[0])
415 if mth.events != nil {
416 mth.events <- MTHEvent{
417 MTHEventAppend, 0, mth.ctrs[0],
418 mth.hashes[len(mth.hashes)-1].h[:],
423 for len(mth.hashes) >= 2 {
424 l := mth.hashes[len(mth.hashes)-2].l
426 mth.hashes[len(mth.hashes)-1].l = l
427 if mth.events != nil {
428 mth.events <- MTHEvent{
429 MTHEventAppend, l, mth.ctrs[l],
430 mth.hashes[len(mth.hashes)-1].h[:],
436 if mth.events != nil {
439 return append(b, mth.hashes[0].h[:]...)
442 func MTHNew(size, offset int64) MTH {
446 return MTHFatNew(size, offset)