bmt.go 22 KB

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