@@ -117,10 +117,7 @@ func NewTreePool(hasher BaseHasherFunc, segmentCount, capacity int) *TreePool {
117117 zerohashes [0 ] = zeros
118118 h := hasher ()
119119 for i := 1 ; i < depth ; i ++ {
120- h .Reset ()
121- h .Write (zeros )
122- h .Write (zeros )
123- zeros = h .Sum (nil )
120+ zeros = doHash (h , nil , zeros , zeros )
124121 zerohashes [i ] = zeros
125122 }
126123 return & TreePool {
@@ -318,41 +315,19 @@ func (h *Hasher) Sum(b []byte) (r []byte) {
318315// * if sequential write is used (can read sections)
319316func (h * Hasher ) sum (b []byte , release , section bool ) (r []byte ) {
320317 t := h .bmt
321- h .finalise (section )
322- if t .offset > 0 { // get the last node (double segment)
323-
324- // padding the segment with zero
325- copy (t .segment [t .offset :], h .pool .zerohashes [0 ])
326- }
327- if section {
328- if t .cur % 2 == 1 {
329- // if just finished current segment, copy it to the right half of the chunk
330- copy (t .section [h .pool .SegmentSize :], t .segment )
331- } else {
332- // copy segment to front of section, zero pad the right half
333- copy (t .section , t .segment )
334- copy (t .section [h .pool .SegmentSize :], h .pool .zerohashes [0 ])
335- }
336- h .writeSection (t .cur , t .section )
337- } else {
338- // TODO: h.writeSegment(t.cur, t.segment)
339- panic ("SegmentWriter not implemented" )
340- }
318+ bh := h .pool .hasher ()
319+ go h .writeSection (t .cur , t .section , true )
341320 bmtHash := <- t .result
342321 span := t .span
343-
322+ // fmt.Println(t.draw(bmtHash))
344323 if release {
345324 h .releaseTree ()
346325 }
347- // sha3(span + BMT(pure_chunk))
326+ // b + sha3(span + BMT(pure_chunk))
348327 if span == nil {
349- return bmtHash
328+ return append ( b , bmtHash ... )
350329 }
351- bh := h .pool .hasher ()
352- bh .Reset ()
353- bh .Write (span )
354- bh .Write (bmtHash )
355- return bh .Sum (b )
330+ return doHash (bh , b , span , bmtHash )
356331}
357332
358333// Hasher implements the SwarmHash interface
@@ -367,37 +342,41 @@ func (h *Hasher) Write(b []byte) (int, error) {
367342 return 0 , nil
368343 }
369344 t := h .bmt
370- need := (h .pool .SegmentCount - t .cur ) * h .pool .SegmentSize
371- if l < need {
372- need = l
373- }
374- // calculate missing bit to complete current open segment
375- rest := h .pool .SegmentSize - t .offset
376- if need < rest {
377- rest = need
378- }
379- copy (t .segment [t .offset :], b [:rest ])
380- need -= rest
381- size := (t .offset + rest ) % h .pool .SegmentSize
382- // read full segments and the last possibly partial segment
383- for need > 0 {
384- // push all finished chunks we read
385- if t .cur % 2 == 0 {
386- copy (t .section , t .segment )
387- } else {
388- copy (t .section [h .pool .SegmentSize :], t .segment )
389- h .writeSection (t .cur , t .section )
345+ secsize := 2 * h .pool .SegmentSize
346+ // calculate length of missing bit to complete current open section
347+ smax := secsize - t .offset
348+ // if at the beginning of chunk or middle of the section
349+ if t .offset < secsize {
350+ // fill up current segment from buffer
351+ copy (t .section [t .offset :], b )
352+ // if input buffer consumed and open section not complete, then
353+ // advance offset and return
354+ if smax == 0 {
355+ smax = secsize
356+ }
357+ if l <= smax {
358+ t .offset += l
359+ return l , nil
390360 }
391- size = h . pool . SegmentSize
392- if need < size {
393- size = need
361+ } else {
362+ if t . cur == h . pool . SegmentCount * 2 {
363+ return 0 , nil
394364 }
395- copy (t .segment , b [rest :rest + size ])
396- need -= size
397- rest += size
365+ }
366+ // read full segments and the last possibly partial segment from the input buffer
367+ for smax < l {
368+ // section complete; push to tree asynchronously
369+ go h .writeSection (t .cur , t .section , false )
370+ // reset section
371+ t .section = make ([]byte , secsize )
372+ // copy from imput buffer at smax to right half of section
373+ copy (t .section , b [smax :])
374+ // advance cursor
398375 t .cur ++
376+ // smax here represents successive offsets in the input buffer
377+ smax += secsize
399378 }
400- t .offset = size % h . pool . SegmentSize
379+ t .offset = l - smax + secsize
401380 return l , nil
402381}
403382
@@ -426,6 +405,8 @@ func (h *Hasher) releaseTree() {
426405 t .span = nil
427406 t .hash = nil
428407 h .bmt = nil
408+ t .section = make ([]byte , h .pool .SegmentSize * 2 )
409+ t .segment = make ([]byte , h .pool .SegmentSize )
429410 h .pool .release (t )
430411 }
431412}
@@ -435,29 +416,37 @@ func (h *Hasher) releaseTree() {
435416// go h.run(h.bmt.leaves[i/2], h.pool.hasher(), i%2 == 0, s)
436417// }
437418
438- // writeSection writes the hash of i/2-th segction into right level 1 node of the BMT tree
439- func (h * Hasher ) writeSection (i int , section []byte ) {
440- n := h .bmt .leaves [i / 2 ]
419+ // writeSection writes the hash of i-th section into level 1 node of the BMT tree
420+ func (h * Hasher ) writeSection (i int , section []byte , final bool ) {
421+ // select the leaf node for the section
422+ n := h .bmt .leaves [i ]
441423 isLeft := n .isLeft
442424 n = n .parent
443425 bh := h .pool .hasher ()
444- bh . Write ( section )
445- go func () {
446- sum := bh . Sum ( nil )
447- if n == nil {
448- h . bmt . result <- sum
449- return
450- }
451- h .run (n , bh , isLeft , sum )
452- }()
426+ // hash the section
427+ s := doHash ( bh , nil , section )
428+ // write hash into parent node
429+ if final {
430+ // for the last segment use writeFinalNode
431+ h . writeFinalNode ( 1 , n , bh , isLeft , s )
432+ } else {
433+ h .writeNode (n , bh , isLeft , s )
434+ }
453435}
454436
455- // run pushes the data to the node
437+ // writeNode pushes the data to the node
456438// if it is the first of 2 sisters written the routine returns
457439// if it is the second, it calculates the hash and writes it
458440// to the parent node recursively
459- func (h * Hasher ) run (n * node , bh hash.Hash , isLeft bool , s []byte ) {
441+ func (h * Hasher ) writeNode (n * node , bh hash.Hash , isLeft bool , s []byte ) {
442+ level := 1
460443 for {
444+ // at the root of the bmt just write the result to the result channel
445+ if n == nil {
446+ h .bmt .result <- s
447+ return
448+ }
449+ // otherwise assign child hash to branc
461450 if isLeft {
462451 n .left = s
463452 } else {
@@ -467,44 +456,68 @@ func (h *Hasher) run(n *node, bh hash.Hash, isLeft bool, s []byte) {
467456 if n .toggle () {
468457 return
469458 }
470- // the second thread now can be sure both left and right children are written
471- // it calculates the hash of left|right and take it to the next level
472- bh .Reset ()
473- bh .Write (n .left )
474- bh .Write (n .right )
475- s = bh .Sum (nil )
476-
477- // at the root of the bmt just write the result to the result channel
478- if n .parent == nil {
479- h .bmt .result <- s
480- return
481- }
482-
483- // otherwise iterate on parent
459+ // the thread coming later now can be sure both left and right children are written
460+ // it calculates the hash of left|right and pushes it to the parent
461+ s = doHash (bh , nil , n .left , n .right )
484462 isLeft = n .isLeft
485463 n = n .parent
464+ level ++
486465 }
487466}
488467
489- // finalise is following the path starting from the final datasegment to the
468+ // writeFinalNode is following the path starting from the final datasegment to the
490469// BMT root via parents
491470// for unbalanced trees it fills in the missing right sister nodes using
492471// the pool's lookup table for BMT subtree root hashes for all-zero sections
493- func (h * Hasher ) finalise (skip bool ) {
494- t := h .bmt
495- isLeft := t .cur % 2 == 0
496- n := t .leaves [t .cur / 2 ]
497- for level := 0 ; n != nil ; level ++ {
498- // when the final segment's path is going via left child node
499- // we include an all-zero subtree hash for the right level and toggle the node.
500- // when the path is going through right child node, nothing to do
501- if isLeft && ! skip {
472+ // otherwise behaves like `writeNode`
473+ func (h * Hasher ) writeFinalNode (level int , n * node , bh hash.Hash , isLeft bool , s []byte ) {
474+
475+ for {
476+ // at the root of the bmt just write the result to the result channel
477+ if n == nil {
478+ if s != nil {
479+ h .bmt .result <- s
480+ }
481+ return
482+ }
483+ var noHash bool
484+ if isLeft {
485+ // coming from left sister branch
486+ // when the final section's path is going via left child node
487+ // we include an all-zero subtree hash for the right level and toggle the node.
488+ // when the path is going through right child node, nothing to do
502489 n .right = h .pool .zerohashes [level ]
503- n .toggle ()
490+ if s != nil {
491+ n .left = s
492+ // if a left final node carries a hash, it must be the first (and only thread)
493+ // so the toggle is already in passive state no need no call
494+ // yet thread needs to carry on pushing hash to parent
495+ } else {
496+ // if again first thread then propagate nil and calculate no hash
497+ noHash = n .toggle ()
498+ }
499+ } else {
500+ // right sister branch
501+ // if s is nil, then thread arrived first at previous node and here there will be two,
502+ // so no need to do anything
503+ if s != nil {
504+ n .right = s
505+ noHash = n .toggle ()
506+ } else {
507+ noHash = true
508+ }
509+ }
510+ // the child-thread first arriving will just continue resetting s to nil
511+ // the second thread now can be sure both left and right children are written
512+ // it calculates the hash of left|right and pushes it to the parent
513+ if noHash {
514+ s = nil
515+ } else {
516+ s = doHash (bh , nil , n .left , n .right )
504517 }
505- skip = false
506518 isLeft = n .isLeft
507519 n = n .parent
520+ level ++
508521 }
509522}
510523
@@ -525,6 +538,15 @@ func (n *node) toggle() bool {
525538 return atomic .AddInt32 (& n .state , 1 )% 2 == 1
526539}
527540
541+ // calculates the hash of the data using hash.Hash
542+ func doHash (h hash.Hash , b []byte , data ... []byte ) []byte {
543+ h .Reset ()
544+ for _ , v := range data {
545+ h .Write (v )
546+ }
547+ return h .Sum (b )
548+ }
549+
528550func hashstr (b []byte ) string {
529551 end := len (b )
530552 if end > 4 {
0 commit comments