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