consensus/monero/crypto/merkle.go

96 lines
2 KiB
Go

package crypto
import (
"git.gammaspectra.live/P2Pool/p2pool-observer/types"
"git.gammaspectra.live/P2Pool/p2pool-observer/utils"
"git.gammaspectra.live/P2Pool/sha3"
)
type BinaryTreeHash []types.Hash
func (t BinaryTreeHash) leafHash(hasher *sha3.HasherState) (rootHash types.Hash) {
switch len(t) {
case 0:
panic("unsupported length")
case 1:
return t[0]
default:
//only hash the next two items
hasher.Reset()
_, _ = hasher.Write(t[0][:])
_, _ = hasher.Write(t[1][:])
HashFastSum(hasher, rootHash[:])
return rootHash
}
}
func (t BinaryTreeHash) RootHash() (rootHash types.Hash) {
hasher := GetKeccak256Hasher()
defer PutKeccak256Hasher(hasher)
count := len(t)
if count <= 2 {
return t.leafHash(hasher)
}
pow2cnt := utils.PreviousPowerOfTwo(uint64(count))
offset := pow2cnt*2 - count
temporaryTree := make(BinaryTreeHash, pow2cnt)
copy(temporaryTree, t[:offset])
offsetTree := temporaryTree[offset:]
for i := range offsetTree {
offsetTree[i] = t[offset+i*2:].leafHash(hasher)
}
for pow2cnt >>= 1; pow2cnt > 1; pow2cnt >>= 1 {
for i := range temporaryTree[:pow2cnt] {
temporaryTree[i] = temporaryTree[i*2:].leafHash(hasher)
}
}
rootHash = temporaryTree.leafHash(hasher)
return
}
func (t BinaryTreeHash) MainBranch() (mainBranch []types.Hash) {
hasher := GetKeccak256Hasher()
defer PutKeccak256Hasher(hasher)
count := len(t)
if count <= 2 {
return nil
}
pow2cnt := utils.PreviousPowerOfTwo(uint64(count))
offset := pow2cnt*2 - count
temporaryTree := make(BinaryTreeHash, pow2cnt)
copy(temporaryTree, t[:offset])
offsetTree := temporaryTree[offset:]
for i := range offsetTree {
if (offset + i*2) == 0 {
mainBranch = append(mainBranch, t[1])
}
offsetTree[i] = t[offset+i*2:].leafHash(hasher)
}
for pow2cnt >>= 1; pow2cnt > 1; pow2cnt >>= 1 {
for i := range temporaryTree[:pow2cnt] {
if i == 0 {
mainBranch = append(mainBranch, temporaryTree[1])
}
temporaryTree[i] = temporaryTree[i*2:].leafHash(hasher)
}
}
mainBranch = append(mainBranch, temporaryTree[1])
return
}