1 // NNCP -- Node to Node copy, utilities for store-and-forward data exchange
2 // Copyright (C) 2016-2024 Sergey Matveev <stargrave@stargrave.org>
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, version 3 of the License.
8 // This program is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 // GNU General Public License for more details.
13 // You should have received a copy of the GNU General Public License
14 // 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 MTHSeqEnt struct {
45 func (ent *MTHSeqEnt) String() string {
46 return fmt.Sprintf("%03d\t%06d\t%s", ent.l, ent.c, hex.EncodeToString(ent.h[:]))
49 type MTHEventType string
52 MTHEventAdd MTHEventType = "Add"
53 MTHEventPreadd MTHEventType = "Pre"
54 MTHEventFold MTHEventType = "Fold"
57 type MTHEvent struct {
62 func (e MTHEvent) String() string {
63 return fmt.Sprintf("%s\t%s", e.Type, e.Ent.String())
68 PreaddFrom(r io.Reader, pktName string, showPrgrs bool) (int64, error)
70 Events() chan MTHEvent
74 hasherLeaf *blake3.Hasher
75 hasherNode *blake3.Hasher
86 func MTHSeqNew(size, offset int64) *MTHSeq {
88 hasherLeaf: blake3.New(MTHSize, MTHLeafKey[:]),
89 hasherNode: blake3.New(MTHSize, MTHNodeKey[:]),
90 buf: bytes.NewBuffer(make([]byte, 0, 2*MTHBlockSize)),
95 prepends := offset / MTHBlockSize
96 toSkip := MTHBlockSize - (offset - prepends*MTHBlockSize)
97 if toSkip == MTHBlockSize {
99 } else if toSkip > 0 {
102 prependSize := prepends * MTHBlockSize
104 if prependSize > size {
107 if offset+toSkip > size {
108 toSkip = size - offset
111 mth.prependSize = prependSize
116 func (mth *MTHSeq) Reset() { panic("not implemented") }
118 func (mth *MTHSeq) Size() int { return MTHSize }
120 func (mth *MTHSeq) BlockSize() int { return MTHBlockSize }
122 func (mth *MTHSeq) PreaddFrom(r io.Reader, pktName string, showPrgrs bool) (int64, error) {
124 return 0, errors.New("already Sum()ed")
126 if mth.buf.Len() > 0 {
127 if _, err := mth.hasherLeaf.Write(mth.buf.Next(MTHBlockSize)); err != nil {
133 prevHashes := mth.hashes
137 lr := io.LimitedReader{R: r, N: mth.prependSize}
138 les := LEs{{"Pkt", pktName}, {"FullSize", mth.prependSize}}
139 n, err := CopyProgressed(mth, &lr, "prehash", les, showPrgrs)
140 for _, ent := range prevHashes {
141 mth.hashes = append(mth.hashes, ent)
144 if mth.buf.Len() > 0 {
145 mth.ctr = prevCtr - 1
152 func (mth *MTHSeq) Events() chan MTHEvent {
153 mth.events = make(chan MTHEvent)
157 func (mth *MTHSeq) PreaddSize() int64 { return mth.prependSize }
159 func (mth *MTHSeq) leafAdd() {
160 ent := MTHSeqEnt{c: mth.ctr}
161 mth.hasherLeaf.Sum(ent.h[:0])
162 mth.hasherLeaf.Reset()
163 mth.hashes = append(mth.hashes, ent)
165 if mth.events != nil {
166 mth.events <- MTHEvent{MTHEventAdd, &ent}
170 func (mth *MTHSeq) fold() {
171 for len(mth.hashes) >= 2 {
172 hlen := len(mth.hashes)
173 end1 := &mth.hashes[hlen-2]
174 end0 := &mth.hashes[hlen-1]
178 if end1.l != end0.l {
181 if _, err := mth.hasherNode.Write(end1.h[:]); err != nil {
184 if _, err := mth.hasherNode.Write(end0.h[:]); err != nil {
187 mth.hashes = mth.hashes[:hlen-1]
190 mth.hasherNode.Sum(end1.h[:0])
191 mth.hasherNode.Reset()
192 if mth.events != nil {
193 mth.events <- MTHEvent{MTHEventFold, end1}
198 func (mth *MTHSeq) Write(data []byte) (int, error) {
200 return 0, errors.New("already Sum()ed")
202 n, err := mth.buf.Write(data)
207 if int64(mth.buf.Len()) < mth.toSkip {
210 mth.buf.Next(int(mth.toSkip))
213 for mth.buf.Len() >= MTHBlockSize {
214 if _, err = mth.hasherLeaf.Write(mth.buf.Next(MTHBlockSize)); err != nil {
223 func (mth *MTHSeq) Sum(b []byte) []byte {
225 return append(b, mth.hashes[0].h[:]...)
227 if mth.buf.Len() > 0 {
228 if _, err := mth.hasherLeaf.Write(mth.buf.Next(MTHBlockSize)); err != nil {
236 if _, err := mth.hasherLeaf.Write(nil); err != nil {
242 ent := MTHSeqEnt{c: 1}
243 copy(ent.h[:], mth.hashes[0].h[:])
245 mth.hashes = append(mth.hashes, ent)
246 if mth.events != nil {
247 mth.events <- MTHEvent{MTHEventAdd, &ent}
251 for len(mth.hashes) >= 2 {
252 hlen := len(mth.hashes)
253 end1 := &mth.hashes[hlen-2]
254 end0 := &mth.hashes[hlen-1]
257 if mth.events != nil {
258 mth.events <- MTHEvent{MTHEventAdd, end0}
263 if mth.events != nil {
266 return append(b, mth.hashes[0].h[:]...)
269 func MTHNew(size, offset int64) MTH {
270 return MTHSeqNew(size, offset)
273 // Some kind of reference implementation (fat, because eats memory)
276 hasher *blake3.Hasher
277 hashes [][MTHSize]byte
282 func MTHFatNew() *MTHFat {
284 hasher: blake3.New(MTHSize, MTHLeafKey[:]),
285 buf: bytes.NewBuffer(make([]byte, 0, 2*MTHBlockSize)),
289 func (mth *MTHFat) Events() chan MTHEvent {
290 mth.events = make(chan MTHEvent)
294 func (mth *MTHFat) Write(data []byte) (int, error) {
295 n, err := mth.buf.Write(data)
299 for mth.buf.Len() >= MTHBlockSize {
300 if _, err = mth.hasher.Write(mth.buf.Next(MTHBlockSize)); err != nil {
303 h := new([MTHSize]byte)
304 mth.hasher.Sum(h[:0])
306 mth.hashes = append(mth.hashes, *h)
307 if mth.events != nil {
308 mth.events <- MTHEvent{
311 0, int64(len(mth.hashes) - 1),
312 mth.hashes[len(mth.hashes)-1],
320 func (mth *MTHFat) Sum(b []byte) []byte {
321 if mth.buf.Len() > 0 {
322 b := mth.buf.Next(MTHBlockSize)
323 if _, err := mth.hasher.Write(b); err != nil {
326 h := new([MTHSize]byte)
327 mth.hasher.Sum(h[:0])
329 mth.hashes = append(mth.hashes, *h)
330 if mth.events != nil {
331 mth.events <- MTHEvent{
334 0, int64(len(mth.hashes) - 1),
335 mth.hashes[len(mth.hashes)-1],
340 switch len(mth.hashes) {
342 h := new([MTHSize]byte)
343 if _, err := mth.hasher.Write(nil); err != nil {
346 mth.hasher.Sum(h[:0])
348 mth.hashes = append(mth.hashes, *h)
349 if mth.events != nil {
350 mth.events <- MTHEvent{MTHEventAdd, &MTHSeqEnt{0, 0, mth.hashes[0]}}
354 mth.hashes = append(mth.hashes, mth.hashes[0])
355 if mth.events != nil {
356 mth.events <- MTHEvent{MTHEventAdd, &MTHSeqEnt{0, 1, mth.hashes[1]}}
359 mth.hasher = blake3.New(MTHSize, MTHNodeKey[:])
361 for len(mth.hashes) != 1 {
362 hashesUp := make([][MTHSize]byte, 0, 1+len(mth.hashes)/2)
363 pairs := (len(mth.hashes) / 2) * 2
364 for i := 0; i < pairs; i += 2 {
365 if _, err := mth.hasher.Write(mth.hashes[i][:]); err != nil {
368 if _, err := mth.hasher.Write(mth.hashes[i+1][:]); err != nil {
371 h := new([MTHSize]byte)
372 mth.hasher.Sum(h[:0])
374 hashesUp = append(hashesUp, *h)
375 if mth.events != nil {
376 mth.events <- MTHEvent{
379 level, int64(len(hashesUp) - 1),
380 hashesUp[len(hashesUp)-1],
385 if len(mth.hashes)%2 == 1 {
386 hashesUp = append(hashesUp, mth.hashes[len(mth.hashes)-1])
387 if mth.events != nil {
388 mth.events <- MTHEvent{
391 level, int64(len(hashesUp) - 1),
392 hashesUp[len(hashesUp)-1],
397 mth.hashes = hashesUp
400 if mth.events != nil {
403 return append(b, mth.hashes[0][:]...)