github.com/0chain/gosdk@v1.17.11/core/util/fixed_merkle_tree.go (about) 1 package util 2 3 import ( 4 "bytes" 5 "encoding/hex" 6 "hash" 7 "io" 8 "sync" 9 10 goError "errors" 11 12 "github.com/0chain/errors" 13 "github.com/minio/sha256-simd" 14 ) 15 16 const ( 17 // MerkleChunkSize is the size of a chunk of data that is hashed 18 MerkleChunkSize = 64 19 20 // MaxMerkleLeavesSize is the maximum size of the data that can be written to the merkle tree 21 MaxMerkleLeavesSize = 64 * 1024 22 23 // FixedMerkleLeaves is the number of leaves in the fixed merkle tree 24 FixedMerkleLeaves = 1024 25 26 // FixedMTDepth is the depth of the fixed merkle tree 27 FixedMTDepth = 11 28 ) 29 30 var ( 31 leafPool = sync.Pool{ 32 New: func() interface{} { 33 return &leaf{ 34 h: sha256.New(), 35 } 36 }, 37 } 38 ) 39 40 type leaf struct { 41 h hash.Hash 42 } 43 44 func (l *leaf) GetHashBytes() []byte { 45 return l.h.Sum(nil) 46 } 47 48 func (l *leaf) GetHash() string { 49 return hex.EncodeToString(l.h.Sum(nil)) 50 } 51 52 func (l *leaf) Write(b []byte) (int, error) { 53 return l.h.Write(b) 54 } 55 56 func getNewLeaf() *leaf { 57 l, ok := leafPool.Get().(*leaf) 58 if !ok { 59 return &leaf{ 60 h: sha256.New(), 61 } 62 } 63 l.h.Reset() 64 return l 65 } 66 67 // FixedMerkleTree A trusted mekerle tree for outsourcing attack protection. see section 1.8 on whitepager 68 // see detail on https://github.com/0chain/blobber/wiki/Protocols#what-is-fixedmerkletree 69 type FixedMerkleTree struct { 70 // Leaves will store hash digester that calculates sha256 hash of the leaf content 71 Leaves []Hashable `json:"leaves,omitempty"` 72 73 writeLock sync.Mutex 74 // isFinal is set to true once Finalize() is called. 75 // After it is set to true, there will be no any writes to writeBytes field 76 isFinal bool 77 // writeCount will track count of bytes written to writeBytes field 78 writeCount int 79 // writeBytes will store bytes upto MaxMerkleLeavesSize. For the last bytes that 80 // does not make upto MaxMerkleLeavesSize, it will be sliced with writeCount field. 81 writeBytes []byte 82 merkleRoot []byte 83 } 84 85 // Finalize will set isFinal to true and sends remaining bytes for leaf hash calculation 86 func (fmt *FixedMerkleTree) Finalize() error { 87 fmt.writeLock.Lock() 88 defer fmt.writeLock.Unlock() 89 90 if fmt.isFinal { 91 return goError.New("already finalized") 92 } 93 fmt.isFinal = true 94 if fmt.writeCount > 0 { 95 return fmt.writeToLeaves(fmt.writeBytes[:fmt.writeCount]) 96 } 97 return nil 98 } 99 100 // NewFixedMerkleTree create a FixedMerkleTree with specify hash method 101 func NewFixedMerkleTree() *FixedMerkleTree { 102 103 t := &FixedMerkleTree{ 104 writeBytes: make([]byte, MaxMerkleLeavesSize), 105 } 106 t.initLeaves() 107 108 return t 109 110 } 111 112 func (fmt *FixedMerkleTree) initLeaves() { 113 fmt.Leaves = make([]Hashable, FixedMerkleLeaves) 114 for i := 0; i < FixedMerkleLeaves; i++ { 115 fmt.Leaves[i] = getNewLeaf() 116 } 117 } 118 119 // writeToLeaves will divide the data with MerkleChunkSize(64 bytes) and write to 120 // each leaf hasher 121 func (fmt *FixedMerkleTree) writeToLeaves(b []byte) error { 122 if len(b) > MaxMerkleLeavesSize { 123 return goError.New("data size greater than maximum required size") 124 } 125 126 if len(b) < MaxMerkleLeavesSize && !fmt.isFinal { 127 return goError.New("invalid merkle leaf write") 128 } 129 130 leafInd := 0 131 for i := 0; i < len(b); i += MerkleChunkSize { 132 j := i + MerkleChunkSize 133 if j > len(b) { 134 j = len(b) 135 } 136 137 _, err := fmt.Leaves[leafInd].Write(b[i:j]) 138 if err != nil { 139 return err 140 } 141 leafInd++ 142 } 143 144 return nil 145 } 146 147 // Write will write data to the leaves once MaxMerkleLeavesSize(64 KB) is reached. 148 // Since each 64KB is divided into 1024 pieces with 64 bytes each, once data len reaches 149 // 64KB then it will be written to leaf hashes. The remaining data that is not multiple of 150 // 64KB will be written to leaf hashes by Finalize() function. 151 // This can be used to write stream of data as well. 152 // fmt.Finalize() is required after data write is complete. 153 func (fmt *FixedMerkleTree) Write(b []byte) (int, error) { 154 155 fmt.writeLock.Lock() 156 defer fmt.writeLock.Unlock() 157 if fmt.isFinal { 158 return 0, goError.New("cannot write. Tree is already finalized") 159 } 160 161 for i, j := 0, MaxMerkleLeavesSize-fmt.writeCount; i < len(b); i, j = j, j+MaxMerkleLeavesSize { 162 if j > len(b) { 163 j = len(b) 164 } 165 prevWriteCount := fmt.writeCount 166 fmt.writeCount += int(j - i) 167 copy(fmt.writeBytes[prevWriteCount:fmt.writeCount], b[i:j]) 168 169 if fmt.writeCount == MaxMerkleLeavesSize { 170 // data fragment reached 64KB, so send this slice to write to leaf hashes 171 err := fmt.writeToLeaves(fmt.writeBytes) 172 if err != nil { 173 return 0, err 174 } 175 fmt.writeCount = 0 // reset writeCount 176 } 177 } 178 return len(b), nil 179 } 180 181 // GetMerkleRoot is only for interface compliance. 182 func (fmt *FixedMerkleTree) GetMerkleTree() MerkleTreeI { 183 return nil 184 } 185 186 func (fmt *FixedMerkleTree) CalculateMerkleRoot() { 187 nodes := make([][]byte, len(fmt.Leaves)) 188 for i := 0; i < len(nodes); i++ { 189 nodes[i] = fmt.Leaves[i].GetHashBytes() 190 leafPool.Put(fmt.Leaves[i]) 191 } 192 193 for i := 0; i < FixedMTDepth; i++ { 194 195 newNodes := make([][]byte, (len(nodes)+1)/2) 196 nodeInd := 0 197 for j := 0; j < len(nodes); j += 2 { 198 newNodes[nodeInd] = MHashBytes(nodes[j], nodes[j+1]) 199 nodeInd++ 200 } 201 nodes = newNodes 202 if len(nodes) == 1 { 203 break 204 } 205 } 206 207 fmt.merkleRoot = nodes[0] 208 } 209 210 // FixedMerklePath is used to verify existence of leaf hash for fixed merkle tree 211 type FixedMerklePath struct { 212 LeafHash []byte `json:"leaf_hash"` 213 RootHash []byte `json:"root_hash"` 214 Nodes [][]byte `json:"nodes"` 215 LeafInd int 216 } 217 218 func (fp FixedMerklePath) VerifyMerklePath() bool { 219 leafInd := fp.LeafInd 220 hash := fp.LeafHash 221 for i := 0; i < len(fp.Nodes); i++ { 222 if leafInd&1 == 0 { 223 hash = MHashBytes(hash, fp.Nodes[i]) 224 } else { 225 hash = MHashBytes(fp.Nodes[i], hash) 226 } 227 leafInd = leafInd / 2 228 } 229 return bytes.Equal(hash, fp.RootHash) 230 } 231 232 // GetMerkleRoot get merkle root. 233 func (fmt *FixedMerkleTree) GetMerkleRoot() string { 234 if fmt.merkleRoot != nil { 235 return hex.EncodeToString(fmt.merkleRoot) 236 } 237 fmt.CalculateMerkleRoot() 238 return hex.EncodeToString(fmt.merkleRoot) 239 } 240 241 // Reload reset and reload leaves from io.Reader 242 func (fmt *FixedMerkleTree) Reload(reader io.Reader) error { 243 244 fmt.initLeaves() 245 246 bytesBuf := bytes.NewBuffer(make([]byte, 0, MaxMerkleLeavesSize)) 247 for i := 0; ; i++ { 248 written, err := io.CopyN(bytesBuf, reader, MaxMerkleLeavesSize) 249 250 if written > 0 { 251 _, err = fmt.Write(bytesBuf.Bytes()) 252 bytesBuf.Reset() 253 254 if err != nil { 255 return err 256 } 257 258 } 259 260 if err != nil { 261 if errors.Is(err, io.EOF) { 262 break 263 } 264 265 return err 266 } 267 268 } 269 270 return nil 271 }