github.com/sixexorg/magnetic-ring@v0.0.0-20191119090307-31705a21e419/merkle/merkle_hasher.go (about)

     1  /*
     2   * Copyright (C) 2018 The ontology Authors
     3   * This file is part of The ontology library.
     4   *
     5   * The ontology is free software: you can redistribute it and/or modify
     6   * it under the terms of the GNU Lesser General Public License as published by
     7   * the Free Software Foundation, either version 3 of the License, or
     8   * (at your option) any later version.
     9   *
    10   * The ontology is distributed in the hope that it will be useful,
    11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13   * GNU Lesser General Public License for more details.
    14   *
    15   * You should have received a copy of the GNU Lesser General Public License
    16   * along with The ontology.  If not, see <http://www.gnu.org/licenses/>.
    17   */
    18  
    19  package merkle
    20  
    21  import (
    22  	"crypto/sha256"
    23  
    24  	"github.com/sixexorg/magnetic-ring/common"
    25  )
    26  
    27  type TreeHasher struct {
    28  }
    29  
    30  func (self TreeHasher) hash_empty() common.Hash {
    31  	return sha256.Sum256(nil)
    32  }
    33  
    34  func (self TreeHasher) hash_leaf(data []byte) common.Hash {
    35  	tmp := append([]byte{0}, data...)
    36  	return sha256.Sum256(tmp)
    37  }
    38  
    39  func (self TreeHasher) hash_children(left, right common.Hash) common.Hash {
    40  	data := append([]byte{1}, left[:]...)
    41  	data = append(data, right[:]...)
    42  	return sha256.Sum256(data)
    43  }
    44  
    45  func (self TreeHasher) HashFullTreeWithLeafHash(leaves []common.Hash) common.Hash {
    46  	length := uint64(len(leaves))
    47  	root_hash, hashes := self._hash_full(leaves, 0, length)
    48  
    49  	if uint(len(hashes)) != countBit(length) {
    50  		panic("assert failed in hash full tree")
    51  	}
    52  
    53  	// assert len(hashes) == countBit(len(leaves))
    54  	// assert self._hash_fold(hashes) == root_hash if hashes else root_hash == self.hash_empty()
    55  
    56  	return root_hash
    57  }
    58  
    59  func (self TreeHasher) HashFullTree(leaves [][]byte) common.Hash {
    60  	length := uint64(len(leaves))
    61  	leafhashes := make([]common.Hash, length, length)
    62  	for i := range leaves {
    63  		leafhashes[i] = self.hash_leaf(leaves[i])
    64  	}
    65  	root_hash, hashes := self._hash_full(leafhashes, 0, length)
    66  
    67  	if uint(len(hashes)) != countBit(length) {
    68  		panic("assert failed in hash full tree")
    69  	}
    70  
    71  	// assert len(hashes) == countBit(len(leaves))
    72  	// assert self._hash_fold(hashes) == root_hash if hashes else root_hash == self.hash_empty()
    73  
    74  	return root_hash
    75  }
    76  
    77  func (self TreeHasher) _hash_full(leaves []common.Hash, l_idx, r_idx uint64) (root_hash common.Hash, hashes []common.Hash) {
    78  	width := r_idx - l_idx
    79  	if width == 0 {
    80  		return self.hash_empty(), nil
    81  	} else if width == 1 {
    82  		leaf_hash := leaves[l_idx]
    83  		return leaf_hash, []common.Hash{leaf_hash}
    84  	} else {
    85  		var split_width uint64 = 1 << (countBit(width-1) - 1)
    86  		l_root, l_hashes := self._hash_full(leaves, l_idx, l_idx+split_width)
    87  		if len(l_hashes) != 1 {
    88  			panic("left tree always full")
    89  		}
    90  		r_root, r_hashes := self._hash_full(leaves, l_idx+split_width, r_idx)
    91  		root_hash = self.hash_children(l_root, r_root)
    92  		var hashes []common.Hash
    93  		if split_width*2 == width {
    94  			hashes = []common.Hash{root_hash}
    95  		} else {
    96  			hashes = append(l_hashes, r_hashes[:]...)
    97  		}
    98  		return root_hash, hashes
    99  	}
   100  }
   101  
   102  func (self TreeHasher) _hash_fold(hashes []common.Hash) common.Hash {
   103  	l := len(hashes)
   104  	accum := hashes[l-1]
   105  	for i := l - 2; i >= 0; i-- {
   106  		accum = self.hash_children(hashes[i], accum)
   107  	}
   108  
   109  	return accum
   110  }