git.gammaspectra.live/P2Pool/consensus@v0.0.0-20240403173234-a039820b20c9/monero/crypto/merkle.go (about)

     1  package crypto
     2  
     3  import (
     4  	"git.gammaspectra.live/P2Pool/consensus/types"
     5  	"git.gammaspectra.live/P2Pool/consensus/utils"
     6  	"git.gammaspectra.live/P2Pool/sha3"
     7  )
     8  
     9  type BinaryTreeHash []types.Hash
    10  
    11  func (t BinaryTreeHash) leafHash(hasher *sha3.HasherState) (rootHash types.Hash) {
    12  	switch len(t) {
    13  	case 0:
    14  		panic("unsupported length")
    15  	case 1:
    16  		return t[0]
    17  	default:
    18  		//only hash the next two items
    19  		hasher.Reset()
    20  		_, _ = hasher.Write(t[0][:])
    21  		_, _ = hasher.Write(t[1][:])
    22  		HashFastSum(hasher, rootHash[:])
    23  		return rootHash
    24  	}
    25  }
    26  
    27  func (t BinaryTreeHash) RootHash() (rootHash types.Hash) {
    28  
    29  	hasher := GetKeccak256Hasher()
    30  	defer PutKeccak256Hasher(hasher)
    31  	count := len(t)
    32  	if count <= 2 {
    33  		return t.leafHash(hasher)
    34  	}
    35  
    36  	pow2cnt := utils.PreviousPowerOfTwo(uint64(count))
    37  	offset := pow2cnt*2 - count
    38  
    39  	temporaryTree := make(BinaryTreeHash, pow2cnt)
    40  	copy(temporaryTree, t[:offset])
    41  
    42  	offsetTree := temporaryTree[offset:]
    43  	for i := range offsetTree {
    44  		offsetTree[i] = t[offset+i*2:].leafHash(hasher)
    45  	}
    46  
    47  	for pow2cnt >>= 1; pow2cnt > 1; pow2cnt >>= 1 {
    48  		for i := range temporaryTree[:pow2cnt] {
    49  			temporaryTree[i] = temporaryTree[i*2:].leafHash(hasher)
    50  		}
    51  	}
    52  
    53  	rootHash = temporaryTree.leafHash(hasher)
    54  
    55  	return
    56  }
    57  
    58  func (t BinaryTreeHash) MainBranch() (mainBranch []types.Hash) {
    59  
    60  	hasher := GetKeccak256Hasher()
    61  	defer PutKeccak256Hasher(hasher)
    62  	count := len(t)
    63  	if count <= 2 {
    64  		return nil
    65  	}
    66  
    67  	pow2cnt := utils.PreviousPowerOfTwo(uint64(count))
    68  	offset := pow2cnt*2 - count
    69  
    70  	temporaryTree := make(BinaryTreeHash, pow2cnt)
    71  	copy(temporaryTree, t[:offset])
    72  
    73  	offsetTree := temporaryTree[offset:]
    74  
    75  	for i := range offsetTree {
    76  		if (offset + i*2) == 0 {
    77  			mainBranch = append(mainBranch, t[1])
    78  		}
    79  		offsetTree[i] = t[offset+i*2:].leafHash(hasher)
    80  	}
    81  
    82  	for pow2cnt >>= 1; pow2cnt > 1; pow2cnt >>= 1 {
    83  		for i := range temporaryTree[:pow2cnt] {
    84  			if i == 0 {
    85  				mainBranch = append(mainBranch, temporaryTree[1])
    86  			}
    87  
    88  			temporaryTree[i] = temporaryTree[i*2:].leafHash(hasher)
    89  		}
    90  	}
    91  
    92  	mainBranch = append(mainBranch, temporaryTree[1])
    93  
    94  	return
    95  }