bmt_r.go 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. // Copyright 2017 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. // simple nonconcurrent reference implementation for hashsize segment based
  17. // Binary Merkle tree hash on arbitrary but fixed maximum chunksize
  18. //
  19. // This implementation does not take advantage of any paralellisms and uses
  20. // far more memory than necessary, but it is easy to see that it is correct.
  21. // It can be used for generating test cases for optimized implementations.
  22. // see testBMTHasherCorrectness function in bmt_test.go
  23. package bmt
  24. import (
  25. "hash"
  26. )
  27. // RefHasher is the non-optimized easy to read reference implementation of BMT
  28. type RefHasher struct {
  29. span int
  30. section int
  31. cap int
  32. h hash.Hash
  33. }
  34. // NewRefHasher returns a new RefHasher
  35. func NewRefHasher(hasher BaseHasher, count int) *RefHasher {
  36. h := hasher()
  37. hashsize := h.Size()
  38. maxsize := hashsize * count
  39. c := 2
  40. for ; c < count; c *= 2 {
  41. }
  42. if c > 2 {
  43. c /= 2
  44. }
  45. return &RefHasher{
  46. section: 2 * hashsize,
  47. span: c * hashsize,
  48. cap: maxsize,
  49. h: h,
  50. }
  51. }
  52. // Hash returns the BMT hash of the byte slice
  53. // implements the SwarmHash interface
  54. func (rh *RefHasher) Hash(d []byte) []byte {
  55. if len(d) > rh.cap {
  56. d = d[:rh.cap]
  57. }
  58. return rh.hash(d, rh.span)
  59. }
  60. func (rh *RefHasher) hash(d []byte, s int) []byte {
  61. l := len(d)
  62. left := d
  63. var right []byte
  64. if l > rh.section {
  65. for ; s >= l; s /= 2 {
  66. }
  67. left = rh.hash(d[:s], s)
  68. right = d[s:]
  69. if l-s > rh.section/2 {
  70. right = rh.hash(right, s)
  71. }
  72. }
  73. defer rh.h.Reset()
  74. rh.h.Write(left)
  75. rh.h.Write(right)
  76. h := rh.h.Sum(nil)
  77. return h
  78. }