github.com/daragao/go-ethereum@v1.8.14-0.20180809141559-45eaef243198/swarm/bmt/bmt.go (about)

     1  // Copyright 2018 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library 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 Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  // Package bmt provides a binary merkle tree implementation used for swarm chunk hash
    18  package bmt
    19  
    20  import (
    21  	"fmt"
    22  	"hash"
    23  	"strings"
    24  	"sync"
    25  	"sync/atomic"
    26  )
    27  
    28  /*
    29  Binary Merkle Tree Hash is a hash function over arbitrary datachunks of limited size.
    30  It is defined as the root hash of the binary merkle tree built over fixed size segments
    31  of the underlying chunk using any base hash function (e.g., keccak 256 SHA3).
    32  Chunks with data shorter than the fixed size are hashed as if they had zero padding.
    33  
    34  BMT hash is used as the chunk hash function in swarm which in turn is the basis for the
    35  128 branching swarm hash http://swarm-guide.readthedocs.io/en/latest/architecture.html#swarm-hash
    36  
    37  The BMT is optimal for providing compact inclusion proofs, i.e. prove that a
    38  segment is a substring of a chunk starting at a particular offset.
    39  The size of the underlying segments is fixed to the size of the base hash (called the resolution
    40  of the BMT hash), Using Keccak256 SHA3 hash is 32 bytes, the EVM word size to optimize for on-chain BMT verification
    41  as well as the hash size optimal for inclusion proofs in the merkle tree of the swarm hash.
    42  
    43  Two implementations are provided:
    44  
    45  * RefHasher is optimized for code simplicity and meant as a reference implementation
    46    that is simple to understand
    47  * Hasher is optimized for speed taking advantage of concurrency with minimalistic
    48    control structure to coordinate the concurrent routines
    49  
    50    BMT Hasher implements the following interfaces
    51  	* standard golang hash.Hash - synchronous, reusable
    52  	* SwarmHash - SumWithSpan provided
    53  	* io.Writer - synchronous left-to-right datawriter
    54  	* AsyncWriter - concurrent section writes and asynchronous Sum call
    55  */
    56  
    57  const (
    58  	// SegmentCount is the maximum number of segments of the underlying chunk
    59  	// Should be equal to max-chunk-data-size / hash-size
    60  	SegmentCount = 128
    61  	// PoolSize is the maximum number of bmt trees used by the hashers, i.e,
    62  	// the maximum number of concurrent BMT hashing operations performed by the same hasher
    63  	PoolSize = 8
    64  )
    65  
    66  // BaseHasherFunc is a hash.Hash constructor function used for the base hash of the BMT.
    67  // implemented by Keccak256 SHA3 sha3.NewKeccak256
    68  type BaseHasherFunc func() hash.Hash
    69  
    70  // Hasher a reusable hasher for fixed maximum size chunks representing a BMT
    71  // - implements the hash.Hash interface
    72  // - reuses a pool of trees for amortised memory allocation and resource control
    73  // - supports order-agnostic concurrent segment writes and section (double segment) writes
    74  //   as well as sequential read and write
    75  // - the same hasher instance must not be called concurrently on more than one chunk
    76  // - the same hasher instance is synchronously reuseable
    77  // - Sum gives back the tree to the pool and guaranteed to leave
    78  //   the tree and itself in a state reusable for hashing a new chunk
    79  // - generates and verifies segment inclusion proofs (TODO:)
    80  type Hasher struct {
    81  	pool *TreePool // BMT resource pool
    82  	bmt  *tree     // prebuilt BMT resource for flowcontrol and proofs
    83  }
    84  
    85  // New creates a reusable BMT Hasher that
    86  // pulls a new tree from a resource pool for hashing each chunk
    87  func New(p *TreePool) *Hasher {
    88  	return &Hasher{
    89  		pool: p,
    90  	}
    91  }
    92  
    93  // TreePool provides a pool of trees used as resources by the BMT Hasher.
    94  // A tree popped from the pool is guaranteed to have a clean state ready
    95  // for hashing a new chunk.
    96  type TreePool struct {
    97  	lock         sync.Mutex
    98  	c            chan *tree     // the channel to obtain a resource from the pool
    99  	hasher       BaseHasherFunc // base hasher to use for the BMT levels
   100  	SegmentSize  int            // size of leaf segments, stipulated to be = hash size
   101  	SegmentCount int            // the number of segments on the base level of the BMT
   102  	Capacity     int            // pool capacity, controls concurrency
   103  	Depth        int            // depth of the bmt trees = int(log2(segmentCount))+1
   104  	Size         int            // the total length of the data (count * size)
   105  	count        int            // current count of (ever) allocated resources
   106  	zerohashes   [][]byte       // lookup table for predictable padding subtrees for all levels
   107  }
   108  
   109  // NewTreePool creates a tree pool with hasher, segment size, segment count and capacity
   110  // on Hasher.getTree it reuses free trees or creates a new one if capacity is not reached
   111  func NewTreePool(hasher BaseHasherFunc, segmentCount, capacity int) *TreePool {
   112  	// initialises the zerohashes lookup table
   113  	depth := calculateDepthFor(segmentCount)
   114  	segmentSize := hasher().Size()
   115  	zerohashes := make([][]byte, depth+1)
   116  	zeros := make([]byte, segmentSize)
   117  	zerohashes[0] = zeros
   118  	h := hasher()
   119  	for i := 1; i < depth+1; i++ {
   120  		zeros = doSum(h, nil, zeros, zeros)
   121  		zerohashes[i] = zeros
   122  	}
   123  	return &TreePool{
   124  		c:            make(chan *tree, capacity),
   125  		hasher:       hasher,
   126  		SegmentSize:  segmentSize,
   127  		SegmentCount: segmentCount,
   128  		Capacity:     capacity,
   129  		Size:         segmentCount * segmentSize,
   130  		Depth:        depth,
   131  		zerohashes:   zerohashes,
   132  	}
   133  }
   134  
   135  // Drain drains the pool until it has no more than n resources
   136  func (p *TreePool) Drain(n int) {
   137  	p.lock.Lock()
   138  	defer p.lock.Unlock()
   139  	for len(p.c) > n {
   140  		<-p.c
   141  		p.count--
   142  	}
   143  }
   144  
   145  // Reserve is blocking until it returns an available tree
   146  // it reuses free trees or creates a new one if size is not reached
   147  // TODO: should use a context here
   148  func (p *TreePool) reserve() *tree {
   149  	p.lock.Lock()
   150  	defer p.lock.Unlock()
   151  	var t *tree
   152  	if p.count == p.Capacity {
   153  		return <-p.c
   154  	}
   155  	select {
   156  	case t = <-p.c:
   157  	default:
   158  		t = newTree(p.SegmentSize, p.Depth, p.hasher)
   159  		p.count++
   160  	}
   161  	return t
   162  }
   163  
   164  // release gives back a tree to the pool.
   165  // this tree is guaranteed to be in reusable state
   166  func (p *TreePool) release(t *tree) {
   167  	p.c <- t // can never fail ...
   168  }
   169  
   170  // tree is a reusable control structure representing a BMT
   171  // organised in a binary tree
   172  // Hasher uses a TreePool to obtain a tree for each chunk hash
   173  // the tree is 'locked' while not in the pool
   174  type tree struct {
   175  	leaves  []*node     // leaf nodes of the tree, other nodes accessible via parent links
   176  	cursor  int         // index of rightmost currently open segment
   177  	offset  int         // offset (cursor position) within currently open segment
   178  	section []byte      // the rightmost open section (double segment)
   179  	result  chan []byte // result channel
   180  	span    []byte      // The span of the data subsumed under the chunk
   181  }
   182  
   183  // node is a reuseable segment hasher representing a node in a BMT
   184  type node struct {
   185  	isLeft      bool      // whether it is left side of the parent double segment
   186  	parent      *node     // pointer to parent node in the BMT
   187  	state       int32     // atomic increment impl concurrent boolean toggle
   188  	left, right []byte    // this is where the two children sections are written
   189  	hasher      hash.Hash // preconstructed hasher on nodes
   190  }
   191  
   192  // newNode constructs a segment hasher node in the BMT (used by newTree)
   193  func newNode(index int, parent *node, hasher hash.Hash) *node {
   194  	return &node{
   195  		parent: parent,
   196  		isLeft: index%2 == 0,
   197  		hasher: hasher,
   198  	}
   199  }
   200  
   201  // Draw draws the BMT (badly)
   202  func (t *tree) draw(hash []byte) string {
   203  	var left, right []string
   204  	var anc []*node
   205  	for i, n := range t.leaves {
   206  		left = append(left, fmt.Sprintf("%v", hashstr(n.left)))
   207  		if i%2 == 0 {
   208  			anc = append(anc, n.parent)
   209  		}
   210  		right = append(right, fmt.Sprintf("%v", hashstr(n.right)))
   211  	}
   212  	anc = t.leaves
   213  	var hashes [][]string
   214  	for l := 0; len(anc) > 0; l++ {
   215  		var nodes []*node
   216  		hash := []string{""}
   217  		for i, n := range anc {
   218  			hash = append(hash, fmt.Sprintf("%v|%v", hashstr(n.left), hashstr(n.right)))
   219  			if i%2 == 0 && n.parent != nil {
   220  				nodes = append(nodes, n.parent)
   221  			}
   222  		}
   223  		hash = append(hash, "")
   224  		hashes = append(hashes, hash)
   225  		anc = nodes
   226  	}
   227  	hashes = append(hashes, []string{"", fmt.Sprintf("%v", hashstr(hash)), ""})
   228  	total := 60
   229  	del := "                             "
   230  	var rows []string
   231  	for i := len(hashes) - 1; i >= 0; i-- {
   232  		var textlen int
   233  		hash := hashes[i]
   234  		for _, s := range hash {
   235  			textlen += len(s)
   236  		}
   237  		if total < textlen {
   238  			total = textlen + len(hash)
   239  		}
   240  		delsize := (total - textlen) / (len(hash) - 1)
   241  		if delsize > len(del) {
   242  			delsize = len(del)
   243  		}
   244  		row := fmt.Sprintf("%v: %v", len(hashes)-i-1, strings.Join(hash, del[:delsize]))
   245  		rows = append(rows, row)
   246  
   247  	}
   248  	rows = append(rows, strings.Join(left, "  "))
   249  	rows = append(rows, strings.Join(right, "  "))
   250  	return strings.Join(rows, "\n") + "\n"
   251  }
   252  
   253  // newTree initialises a tree by building up the nodes of a BMT
   254  // - segment size is stipulated to be the size of the hash
   255  func newTree(segmentSize, depth int, hashfunc func() hash.Hash) *tree {
   256  	n := newNode(0, nil, hashfunc())
   257  	prevlevel := []*node{n}
   258  	// iterate over levels and creates 2^(depth-level) nodes
   259  	// the 0 level is on double segment sections so we start at depth - 2 since
   260  	count := 2
   261  	for level := depth - 2; level >= 0; level-- {
   262  		nodes := make([]*node, count)
   263  		for i := 0; i < count; i++ {
   264  			parent := prevlevel[i/2]
   265  			var hasher hash.Hash
   266  			if level == 0 {
   267  				hasher = hashfunc()
   268  			}
   269  			nodes[i] = newNode(i, parent, hasher)
   270  		}
   271  		prevlevel = nodes
   272  		count *= 2
   273  	}
   274  	// the datanode level is the nodes on the last level
   275  	return &tree{
   276  		leaves:  prevlevel,
   277  		result:  make(chan []byte),
   278  		section: make([]byte, 2*segmentSize),
   279  	}
   280  }
   281  
   282  // methods needed to implement hash.Hash
   283  
   284  // Size returns the size
   285  func (h *Hasher) Size() int {
   286  	return h.pool.SegmentSize
   287  }
   288  
   289  // BlockSize returns the block size
   290  func (h *Hasher) BlockSize() int {
   291  	return 2 * h.pool.SegmentSize
   292  }
   293  
   294  // Sum returns the BMT root hash of the buffer
   295  // using Sum presupposes sequential synchronous writes (io.Writer interface)
   296  // hash.Hash interface Sum method appends the byte slice to the underlying
   297  // data before it calculates and returns the hash of the chunk
   298  // caller must make sure Sum is not called concurrently with Write, writeSection
   299  func (h *Hasher) Sum(b []byte) (s []byte) {
   300  	t := h.getTree()
   301  	// write the last section with final flag set to true
   302  	go h.writeSection(t.cursor, t.section, true, true)
   303  	// wait for the result
   304  	s = <-t.result
   305  	span := t.span
   306  	// release the tree resource back to the pool
   307  	h.releaseTree()
   308  	// b + sha3(span + BMT(pure_chunk))
   309  	if len(span) == 0 {
   310  		return append(b, s...)
   311  	}
   312  	return doSum(h.pool.hasher(), b, span, s)
   313  }
   314  
   315  // methods needed to implement the SwarmHash and the io.Writer interfaces
   316  
   317  // Write calls sequentially add to the buffer to be hashed,
   318  // with every full segment calls writeSection in a go routine
   319  func (h *Hasher) Write(b []byte) (int, error) {
   320  	l := len(b)
   321  	if l == 0 || l > 4096 {
   322  		return 0, nil
   323  	}
   324  	t := h.getTree()
   325  	secsize := 2 * h.pool.SegmentSize
   326  	// calculate length of missing bit to complete current open section
   327  	smax := secsize - t.offset
   328  	// if at the beginning of chunk or middle of the section
   329  	if t.offset < secsize {
   330  		// fill up current segment from buffer
   331  		copy(t.section[t.offset:], b)
   332  		// if input buffer consumed and open section not complete, then
   333  		// advance offset and return
   334  		if smax == 0 {
   335  			smax = secsize
   336  		}
   337  		if l <= smax {
   338  			t.offset += l
   339  			return l, nil
   340  		}
   341  	} else {
   342  		// if end of a section
   343  		if t.cursor == h.pool.SegmentCount*2 {
   344  			return 0, nil
   345  		}
   346  	}
   347  	// read full sections and the last possibly partial section from the input buffer
   348  	for smax < l {
   349  		// section complete; push to tree asynchronously
   350  		go h.writeSection(t.cursor, t.section, true, false)
   351  		// reset section
   352  		t.section = make([]byte, secsize)
   353  		// copy from input buffer at smax to right half of section
   354  		copy(t.section, b[smax:])
   355  		// advance cursor
   356  		t.cursor++
   357  		// smax here represents successive offsets in the input buffer
   358  		smax += secsize
   359  	}
   360  	t.offset = l - smax + secsize
   361  	return l, nil
   362  }
   363  
   364  // Reset needs to be called before writing to the hasher
   365  func (h *Hasher) Reset() {
   366  	h.releaseTree()
   367  }
   368  
   369  // methods needed to implement the SwarmHash interface
   370  
   371  // ResetWithLength needs to be called before writing to the hasher
   372  // the argument is supposed to be the byte slice binary representation of
   373  // the length of the data subsumed under the hash, i.e., span
   374  func (h *Hasher) ResetWithLength(span []byte) {
   375  	h.Reset()
   376  	h.getTree().span = span
   377  }
   378  
   379  // releaseTree gives back the Tree to the pool whereby it unlocks
   380  // it resets tree, segment and index
   381  func (h *Hasher) releaseTree() {
   382  	t := h.bmt
   383  	if t == nil {
   384  		return
   385  	}
   386  	h.bmt = nil
   387  	go func() {
   388  		t.cursor = 0
   389  		t.offset = 0
   390  		t.span = nil
   391  		t.section = make([]byte, h.pool.SegmentSize*2)
   392  		select {
   393  		case <-t.result:
   394  		default:
   395  		}
   396  		h.pool.release(t)
   397  	}()
   398  }
   399  
   400  // NewAsyncWriter extends Hasher with an interface for concurrent segment/section writes
   401  func (h *Hasher) NewAsyncWriter(double bool) *AsyncHasher {
   402  	secsize := h.pool.SegmentSize
   403  	if double {
   404  		secsize *= 2
   405  	}
   406  	write := func(i int, section []byte, final bool) {
   407  		h.writeSection(i, section, double, final)
   408  	}
   409  	return &AsyncHasher{
   410  		Hasher:  h,
   411  		double:  double,
   412  		secsize: secsize,
   413  		write:   write,
   414  	}
   415  }
   416  
   417  // SectionWriter is an asynchronous segment/section writer interface
   418  type SectionWriter interface {
   419  	Reset()                                       // standard init to be called before reuse
   420  	Write(index int, data []byte)                 // write into section of index
   421  	Sum(b []byte, length int, span []byte) []byte // returns the hash of the buffer
   422  	SectionSize() int                             // size of the async section unit to use
   423  }
   424  
   425  // AsyncHasher extends BMT Hasher with an asynchronous segment/section writer interface
   426  // AsyncHasher is unsafe and does not check indexes and section data lengths
   427  // it must be used with the right indexes and length and the right number of sections
   428  //
   429  // behaviour is undefined if
   430  // * non-final sections are shorter or longer than secsize
   431  // * if final section does not match length
   432  // * write a section with index that is higher than length/secsize
   433  // * set length in Sum call when length/secsize < maxsec
   434  //
   435  // * if Sum() is not called on a Hasher that is fully written
   436  //   a process will block, can be terminated with Reset
   437  // * it will not leak processes if not all sections are written but it blocks
   438  //   and keeps the resource which can be released calling Reset()
   439  type AsyncHasher struct {
   440  	*Hasher            // extends the Hasher
   441  	mtx     sync.Mutex // to lock the cursor access
   442  	double  bool       // whether to use double segments (call Hasher.writeSection)
   443  	secsize int        // size of base section (size of hash or double)
   444  	write   func(i int, section []byte, final bool)
   445  }
   446  
   447  // methods needed to implement AsyncWriter
   448  
   449  // SectionSize returns the size of async section unit to use
   450  func (sw *AsyncHasher) SectionSize() int {
   451  	return sw.secsize
   452  }
   453  
   454  // Write writes the i-th section of the BMT base
   455  // this function can and is meant to be called concurrently
   456  // it sets max segment threadsafely
   457  func (sw *AsyncHasher) Write(i int, section []byte) {
   458  	sw.mtx.Lock()
   459  	defer sw.mtx.Unlock()
   460  	t := sw.getTree()
   461  	// cursor keeps track of the rightmost section written so far
   462  	// if index is lower than cursor then just write non-final section as is
   463  	if i < t.cursor {
   464  		// if index is not the rightmost, safe to write section
   465  		go sw.write(i, section, false)
   466  		return
   467  	}
   468  	// if there is a previous rightmost section safe to write section
   469  	if t.offset > 0 {
   470  		if i == t.cursor {
   471  			// i==cursor implies cursor was set by Hash call so we can write section as final one
   472  			// since it can be shorter, first we copy it to the padded buffer
   473  			t.section = make([]byte, sw.secsize)
   474  			copy(t.section, section)
   475  			go sw.write(i, t.section, true)
   476  			return
   477  		}
   478  		// the rightmost section just changed, so we write the previous one as non-final
   479  		go sw.write(t.cursor, t.section, false)
   480  	}
   481  	// set i as the index of the righmost section written so far
   482  	// set t.offset to cursor*secsize+1
   483  	t.cursor = i
   484  	t.offset = i*sw.secsize + 1
   485  	t.section = make([]byte, sw.secsize)
   486  	copy(t.section, section)
   487  }
   488  
   489  // Sum can be called any time once the length and the span is known
   490  // potentially even before all segments have been written
   491  // in such cases Sum will block until all segments are present and
   492  // the hash for the length can be calculated.
   493  //
   494  // b: digest is appended to b
   495  // length: known length of the input (unsafe; undefined if out of range)
   496  // meta: metadata to hash together with BMT root for the final digest
   497  //   e.g., span for protection against existential forgery
   498  func (sw *AsyncHasher) Sum(b []byte, length int, meta []byte) (s []byte) {
   499  	sw.mtx.Lock()
   500  	t := sw.getTree()
   501  	if length == 0 {
   502  		sw.mtx.Unlock()
   503  		s = sw.pool.zerohashes[sw.pool.Depth]
   504  	} else {
   505  		// for non-zero input the rightmost section is written to the tree asynchronously
   506  		// if the actual last section has been written (t.cursor == length/t.secsize)
   507  		maxsec := (length - 1) / sw.secsize
   508  		if t.offset > 0 {
   509  			go sw.write(t.cursor, t.section, maxsec == t.cursor)
   510  		}
   511  		// set cursor to maxsec so final section is written when it arrives
   512  		t.cursor = maxsec
   513  		t.offset = length
   514  		result := t.result
   515  		sw.mtx.Unlock()
   516  		// wait for the result or reset
   517  		s = <-result
   518  	}
   519  	// relesase the tree back to the pool
   520  	sw.releaseTree()
   521  	// if no meta is given just append digest to b
   522  	if len(meta) == 0 {
   523  		return append(b, s...)
   524  	}
   525  	// hash together meta and BMT root hash using the pools
   526  	return doSum(sw.pool.hasher(), b, meta, s)
   527  }
   528  
   529  // writeSection writes the hash of i-th section into level 1 node of the BMT tree
   530  func (h *Hasher) writeSection(i int, section []byte, double bool, final bool) {
   531  	// select the leaf node for the section
   532  	var n *node
   533  	var isLeft bool
   534  	var hasher hash.Hash
   535  	var level int
   536  	t := h.getTree()
   537  	if double {
   538  		level++
   539  		n = t.leaves[i]
   540  		hasher = n.hasher
   541  		isLeft = n.isLeft
   542  		n = n.parent
   543  		// hash the section
   544  		section = doSum(hasher, nil, section)
   545  	} else {
   546  		n = t.leaves[i/2]
   547  		hasher = n.hasher
   548  		isLeft = i%2 == 0
   549  	}
   550  	// write hash into parent node
   551  	if final {
   552  		// for the last segment use writeFinalNode
   553  		h.writeFinalNode(level, n, hasher, isLeft, section)
   554  	} else {
   555  		h.writeNode(n, hasher, isLeft, section)
   556  	}
   557  }
   558  
   559  // writeNode pushes the data to the node
   560  // if it is the first of 2 sisters written, the routine terminates
   561  // if it is the second, it calculates the hash and writes it
   562  // to the parent node recursively
   563  // since hashing the parent is synchronous the same hasher can be used
   564  func (h *Hasher) writeNode(n *node, bh hash.Hash, isLeft bool, s []byte) {
   565  	level := 1
   566  	for {
   567  		// at the root of the bmt just write the result to the result channel
   568  		if n == nil {
   569  			h.getTree().result <- s
   570  			return
   571  		}
   572  		// otherwise assign child hash to left or right segment
   573  		if isLeft {
   574  			n.left = s
   575  		} else {
   576  			n.right = s
   577  		}
   578  		// the child-thread first arriving will terminate
   579  		if n.toggle() {
   580  			return
   581  		}
   582  		// the thread coming second now can be sure both left and right children are written
   583  		// so it calculates the hash of left|right and pushes it to the parent
   584  		s = doSum(bh, nil, n.left, n.right)
   585  		isLeft = n.isLeft
   586  		n = n.parent
   587  		level++
   588  	}
   589  }
   590  
   591  // writeFinalNode is following the path starting from the final datasegment to the
   592  // BMT root via parents
   593  // for unbalanced trees it fills in the missing right sister nodes using
   594  // the pool's lookup table for BMT subtree root hashes for all-zero sections
   595  // otherwise behaves like `writeNode`
   596  func (h *Hasher) writeFinalNode(level int, n *node, bh hash.Hash, isLeft bool, s []byte) {
   597  
   598  	for {
   599  		// at the root of the bmt just write the result to the result channel
   600  		if n == nil {
   601  			if s != nil {
   602  				h.getTree().result <- s
   603  			}
   604  			return
   605  		}
   606  		var noHash bool
   607  		if isLeft {
   608  			// coming from left sister branch
   609  			// when the final section's path is going via left child node
   610  			// we include an all-zero subtree hash for the right level and toggle the node.
   611  			n.right = h.pool.zerohashes[level]
   612  			if s != nil {
   613  				n.left = s
   614  				// if a left final node carries a hash, it must be the first (and only thread)
   615  				// so the toggle is already in passive state no need no call
   616  				// yet thread needs to carry on pushing hash to parent
   617  				noHash = false
   618  			} else {
   619  				// if again first thread then propagate nil and calculate no hash
   620  				noHash = n.toggle()
   621  			}
   622  		} else {
   623  			// right sister branch
   624  			if s != nil {
   625  				// if hash was pushed from right child node, write right segment change state
   626  				n.right = s
   627  				// if toggle is true, we arrived first so no hashing just push nil to parent
   628  				noHash = n.toggle()
   629  
   630  			} else {
   631  				// if s is nil, then thread arrived first at previous node and here there will be two,
   632  				// so no need to do anything and keep s = nil for parent
   633  				noHash = true
   634  			}
   635  		}
   636  		// the child-thread first arriving will just continue resetting s to nil
   637  		// the second thread now can be sure both left and right children are written
   638  		// it calculates the hash of left|right and pushes it to the parent
   639  		if noHash {
   640  			s = nil
   641  		} else {
   642  			s = doSum(bh, nil, n.left, n.right)
   643  		}
   644  		// iterate to parent
   645  		isLeft = n.isLeft
   646  		n = n.parent
   647  		level++
   648  	}
   649  }
   650  
   651  // getTree obtains a BMT resource by reserving one from the pool and assigns it to the bmt field
   652  func (h *Hasher) getTree() *tree {
   653  	if h.bmt != nil {
   654  		return h.bmt
   655  	}
   656  	t := h.pool.reserve()
   657  	h.bmt = t
   658  	return t
   659  }
   660  
   661  // atomic bool toggle implementing a concurrent reusable 2-state object
   662  // atomic addint with %2 implements atomic bool toggle
   663  // it returns true if the toggler just put it in the active/waiting state
   664  func (n *node) toggle() bool {
   665  	return atomic.AddInt32(&n.state, 1)%2 == 1
   666  }
   667  
   668  // calculates the hash of the data using hash.Hash
   669  func doSum(h hash.Hash, b []byte, data ...[]byte) []byte {
   670  	h.Reset()
   671  	for _, v := range data {
   672  		h.Write(v)
   673  	}
   674  	return h.Sum(b)
   675  }
   676  
   677  // hashstr is a pretty printer for bytes used in tree.draw
   678  func hashstr(b []byte) string {
   679  	end := len(b)
   680  	if end > 4 {
   681  		end = 4
   682  	}
   683  	return fmt.Sprintf("%x", b[:end])
   684  }
   685  
   686  // calculateDepthFor calculates the depth (number of levels) in the BMT tree
   687  func calculateDepthFor(n int) (d int) {
   688  	c := 2
   689  	for ; c < n; c *= 2 {
   690  		d++
   691  	}
   692  	return d + 1
   693  }