github.com/bigzoro/my_simplechain@v0.0.0-20240315012955-8ad0a2a29bb9/core/access_contoller/crypto/hash/merkle.go (about) 1 /* 2 Copyright (C) BABEC. All rights reserved. 3 Copyright (C) THL A29 Limited, a Tencent company. All rights reserved. 4 5 SPDX-License-Identifier: Apache-2.0 6 */ 7 8 package hash 9 10 import ( 11 "crypto/sha256" 12 "github.com/bigzoro/my_simplechain/core/access_contoller/crypto" 13 "math" 14 ) 15 16 // nolint: deadcode,unused 17 var h = sha256.New() 18 19 func GetMerkleRoot(hashType string, hashes [][]byte) ([]byte, error) { 20 if len(hashes) == 0 { 21 return nil, nil 22 } 23 24 merkleTree, err := BuildMerkleTree(hashType, hashes) 25 if err != nil { 26 return nil, err 27 } 28 return merkleTree[len(merkleTree)-1], nil 29 } 30 31 // take leaf node hash array and build merkle tree 32 func BuildMerkleTree(hashType string, hashes [][]byte) ([][]byte, error) { 33 var hasher = Hash{ 34 hashType: crypto.HashAlgoMap[hashType], 35 } 36 37 var err error 38 if len(hashes) == 0 { 39 return nil, nil 40 } 41 42 // use array to store merkle tree entries 43 nextPowOfTwo := getNextPowerOfTwo(len(hashes)) 44 arraySize := nextPowOfTwo*2 - 1 45 merkelTree := make([][]byte, arraySize) 46 47 // 1. copy hashes first 48 copy(merkelTree[:len(hashes)], hashes[:]) 49 50 // 2. compute merkle step by step 51 offset := nextPowOfTwo 52 for i := 0; i < arraySize-1; i += 2 { 53 switch { 54 case merkelTree[i] == nil: 55 // parent node is nil if left is nil 56 merkelTree[offset] = nil 57 case merkelTree[i+1] == nil: 58 // hash(left, left) if right is nil 59 merkelTree[offset], err = hashMerkleBranches(hasher, merkelTree[i], merkelTree[i]) 60 if err != nil { 61 return nil, err 62 } 63 default: 64 // default hash(left||right) 65 merkelTree[offset], err = hashMerkleBranches(hasher, merkelTree[i], merkelTree[i+1]) 66 if err != nil { 67 return nil, err 68 } 69 } 70 offset++ 71 } 72 73 return merkelTree, nil 74 } 75 76 func GetMerklePath(hashType string, hash []byte, merkleTree [][]byte, 77 paths *[][]byte, withRoot bool) (brother []byte, parent []byte) { 78 brother, parent = getPath(hashType, hash, merkleTree, withRoot) 79 if brother != nil { 80 *paths = append(*paths, brother) 81 GetMerklePath(hashType, parent, merkleTree, paths, withRoot) 82 } 83 return brother, parent 84 } 85 86 func getPath(hashType string, hash []byte, merkleTree [][]byte, withRoot bool) (brother []byte, parent []byte) { 87 var hasher = Hash{ 88 hashType: crypto.HashAlgoMap[hashType], 89 } 90 91 for i, bytes := range merkleTree { 92 if isEqualStr(bytes, hash) { 93 if isEvenNum(i) { 94 return getEvenHashMerkleBranches(i, hasher, merkleTree, withRoot) 95 } 96 parent, _ = hashMerkleBranches(hasher, merkleTree[i-1], hash) 97 return merkleTree[i-1], parent 98 } 99 } 100 return nil, nil 101 } 102 103 func getEvenHashMerkleBranches(i int, hasher Hash, merkleTree [][]byte, withRoot bool) (brother []byte, parent []byte) { 104 if i+1 < len(merkleTree) { 105 parent, _ = hashMerkleBranches(hasher, merkleTree[i], merkleTree[i+1]) 106 return merkleTree[i+1], parent 107 } else if withRoot { //root 108 parent, _ = hashMerkleBranches(hasher, merkleTree[i], merkleTree[i]) 109 return merkleTree[i], parent 110 } 111 return brother, parent 112 } 113 114 func isEvenNum(num int) bool { 115 return num&'1' == 0 116 } 117 118 func isEqualStr(dst, src []byte) bool { 119 return string(dst) == string(src) 120 } 121 122 func getNextPowerOfTwo(n int) int { 123 if n&(n-1) == 0 { 124 return n 125 } 126 127 exponent := uint(math.Log2(float64(n))) + 1 128 return 1 << exponent 129 } 130 131 func hashMerkleBranches(hasher Hash, left []byte, right []byte) ([]byte, error) { 132 data := make([]byte, len(left)+len(right)) 133 copy(data[:len(left)], left) 134 copy(data[len(left):], right) 135 return hasher.Get(data) 136 } 137 138 func getNextPowerOfTen(n int) (int, int) { 139 //if n&(n-1) == 0 { 140 // return n, 0 141 //} 142 if n == 1 { 143 return 1, 0 144 } 145 146 exponent := int(math.Log10(float64(n-1))) + 1 147 rootsSize := 0 148 for i := 0; i < exponent; i++ { 149 rootsSize += int(math.Pow10(i)) 150 } 151 return int(math.Pow10(exponent)), rootsSize 152 }