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) (int, 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 := int(offset / MTHBlockSize)
84 skip := MTHBlockSize - (offset - int64(prepends)*MTHBlockSize)
85 if skip == MTHBlockSize {
90 prependSize := int64(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, len(mth.hashes) - 1,
143 mth.hashes[len(mth.hashes)-1][:],
150 func (mth *MTHFat) PrependFrom(r io.Reader) (int, error) {
152 return 0, errors.New("already Sum()ed")
155 buf := make([]byte, MTHBlockSize)
157 fullsize := mth.prependSize
158 les := LEs{{"Pkt", mth.pktName}, {"FullSize", fullsize}, {"Size", 0}}
159 for mth.prependSize >= MTHBlockSize {
160 n, err = io.ReadFull(r, buf)
162 mth.prependSize -= MTHBlockSize
166 if _, err = mth.hasher.Write(buf); err != nil {
169 mth.hasher.Sum(mth.hashes[i][:0])
171 if mth.events != nil {
172 mth.events <- MTHEvent{MTHEventPrepend, 0, i, mth.hashes[i][:]}
174 if mth.pktName != "" {
175 les[len(les)-1].V = int64(read)
176 Progress("check", les)
180 if mth.prependSize > 0 {
181 n, err = io.ReadFull(r, buf[:mth.prependSize])
186 if _, err = mth.hasher.Write(buf[:mth.prependSize]); err != nil {
189 mth.hasher.Sum(mth.hashes[i][:0])
191 if mth.events != nil {
192 mth.events <- MTHEvent{MTHEventPrepend, 0, i, mth.hashes[i][:]}
194 if mth.pktName != "" {
195 les[len(les)-1].V = fullsize
196 Progress("check", les)
202 func (mth *MTHFat) Sum(b []byte) []byte {
204 return append(b, mth.hashes[0][:]...)
206 if mth.buf.Len() > 0 {
207 b := mth.buf.Next(MTHBlockSize)
208 if _, err := mth.hasher.Write(b); err != nil {
211 h := new([MTHSize]byte)
212 mth.hasher.Sum(h[:0])
214 mth.hashes = append(mth.hashes, *h)
215 if mth.events != nil {
216 mth.events <- MTHEvent{
218 0, len(mth.hashes) - 1,
219 mth.hashes[len(mth.hashes)-1][:],
223 switch len(mth.hashes) {
225 h := new([MTHSize]byte)
226 if _, err := mth.hasher.Write(nil); err != nil {
229 mth.hasher.Sum(h[:0])
231 mth.hashes = append(mth.hashes, *h)
232 if mth.events != nil {
233 mth.events <- MTHEvent{MTHEventAppend, 0, 0, mth.hashes[0][:]}
237 mth.hashes = append(mth.hashes, mth.hashes[0])
238 if mth.events != nil {
239 mth.events <- MTHEvent{MTHEventAppend, 0, 1, mth.hashes[1][:]}
242 mth.hasher = blake3.New(MTHSize, MTHNodeKey[:])
244 for len(mth.hashes) != 1 {
245 hashesUp := make([][MTHSize]byte, 0, 1+len(mth.hashes)/2)
246 pairs := (len(mth.hashes) / 2) * 2
247 for i := 0; i < pairs; i += 2 {
248 if _, err := mth.hasher.Write(mth.hashes[i][:]); err != nil {
251 if _, err := mth.hasher.Write(mth.hashes[i+1][:]); err != nil {
254 h := new([MTHSize]byte)
255 mth.hasher.Sum(h[:0])
257 hashesUp = append(hashesUp, *h)
258 if mth.events != nil {
259 mth.events <- MTHEvent{
261 level, len(hashesUp) - 1,
262 hashesUp[len(hashesUp)-1][:],
266 if len(mth.hashes)%2 == 1 {
267 hashesUp = append(hashesUp, mth.hashes[len(mth.hashes)-1])
268 if mth.events != nil {
269 mth.events <- MTHEvent{
271 level, len(hashesUp) - 1,
272 hashesUp[len(hashesUp)-1][:],
276 mth.hashes = hashesUp
280 if mth.events != nil {
283 return append(b, mth.hashes[0][:]...)
286 type MTHSeqEnt struct {
292 hasherLeaf *blake3.Hasher
293 hasherNode *blake3.Hasher
301 func MTHSeqNew() *MTHSeq {
303 hasherLeaf: blake3.New(MTHSize, MTHLeafKey[:]),
304 hasherNode: blake3.New(MTHSize, MTHNodeKey[:]),
305 buf: bytes.NewBuffer(make([]byte, 0, 2*MTHBlockSize)),
306 ctrs: make([]int, 1, 2),
311 func (mth *MTHSeq) Reset() { panic("not implemented") }
313 func (mth *MTHSeq) Size() int { return MTHSize }
315 func (mth *MTHSeq) BlockSize() int { return MTHBlockSize }
317 func (mth *MTHSeq) PrependFrom(r io.Reader) (int, error) {
318 panic("must not reach that code")
321 func (mth *MTHSeq) Events() chan MTHEvent {
322 mth.events = make(chan MTHEvent)
326 func (mth *MTHSeq) SetPktName(pktName string) {}
328 func (mth *MTHSeq) PrependSize() int64 { return 0 }
330 func (mth *MTHSeq) leafAdd() {
331 ent := MTHSeqEnt{l: 0}
332 mth.hasherLeaf.Sum(ent.h[:0])
333 mth.hasherLeaf.Reset()
334 mth.hashes = append(mth.hashes, ent)
335 if mth.events != nil {
336 mth.events <- MTHEvent{
337 MTHEventAppend, 0, mth.ctrs[0],
338 mth.hashes[len(mth.hashes)-1].h[:],
344 func (mth *MTHSeq) incr(l int) {
345 if len(mth.ctrs) <= l {
346 mth.ctrs = append(mth.ctrs, 0)
352 func (mth *MTHSeq) fold() {
353 for len(mth.hashes) >= 2 {
354 if mth.hashes[len(mth.hashes)-2].l != mth.hashes[len(mth.hashes)-1].l {
357 if _, err := mth.hasherNode.Write(mth.hashes[len(mth.hashes)-2].h[:]); err != nil {
360 if _, err := mth.hasherNode.Write(mth.hashes[len(mth.hashes)-1].h[:]); err != nil {
363 mth.hashes = mth.hashes[:len(mth.hashes)-1]
364 end := &mth.hashes[len(mth.hashes)-1]
367 mth.hasherNode.Sum(end.h[:0])
368 mth.hasherNode.Reset()
369 if mth.events != nil {
370 mth.events <- MTHEvent{MTHEventFold, end.l, mth.ctrs[end.l], end.h[:]}
375 func (mth *MTHSeq) Write(data []byte) (int, error) {
377 return 0, errors.New("already Sum()ed")
379 n, err := mth.buf.Write(data)
383 for mth.buf.Len() >= MTHBlockSize {
384 if _, err = mth.hasherLeaf.Write(mth.buf.Next(MTHBlockSize)); err != nil {
393 func (mth *MTHSeq) Sum(b []byte) []byte {
395 return append(b, mth.hashes[0].h[:]...)
397 if mth.buf.Len() > 0 {
398 if _, err := mth.hasherLeaf.Write(mth.buf.Next(MTHBlockSize)); err != nil {
406 if _, err := mth.hasherLeaf.Write(nil); err != nil {
412 mth.hashes = append(mth.hashes, mth.hashes[0])
414 if mth.events != nil {
415 mth.events <- MTHEvent{
416 MTHEventAppend, 0, mth.ctrs[0],
417 mth.hashes[len(mth.hashes)-1].h[:],
422 for len(mth.hashes) >= 2 {
423 l := mth.hashes[len(mth.hashes)-2].l
425 mth.hashes[len(mth.hashes)-1].l = l
426 if mth.events != nil {
427 mth.events <- MTHEvent{
428 MTHEventAppend, l, mth.ctrs[l],
429 mth.hashes[len(mth.hashes)-1].h[:],
435 if mth.events != nil {
438 return append(b, mth.hashes[0].h[:]...)
441 func MTHNew(size, offset int64) MTH {
445 return MTHFatNew(size, offset)