github.com/0chain/gosdk@v1.17.11/core/util/validation_tree.go (about) 1 package util 2 3 import ( 4 "bytes" 5 "encoding/hex" 6 "errors" 7 "fmt" 8 "hash" 9 "math" 10 "sync" 11 12 "github.com/minio/sha256-simd" 13 ) 14 15 const ( 16 // Left tree node chile 17 Left = iota 18 19 // Right tree node child 20 Right 21 ) 22 23 const ( 24 START_LENGTH = 64 25 ADD_LENGTH = 320 26 ) 27 28 // ValidationTree is a merkle tree that is used to validate the data 29 type ValidationTree struct { 30 writeLock sync.Mutex 31 writeCount int 32 dataSize int64 33 writtenSize int64 34 leafIndex int 35 leaves [][]byte 36 isFinalized bool 37 h hash.Hash 38 validationRoot []byte 39 } 40 41 // GetLeaves returns the leaves of the validation tree 42 func (v *ValidationTree) GetLeaves() [][]byte { 43 return v.leaves 44 } 45 46 // SetLeaves sets the leaves of the validation tree. 47 // - leaves: leaves of the validation tree, each leaf is in byte format 48 func (v *ValidationTree) SetLeaves(leaves [][]byte) { 49 v.leaves = leaves 50 } 51 52 // GetDataSize returns the data size of the validation tree 53 func (v *ValidationTree) GetDataSize() int64 { 54 return v.dataSize 55 } 56 57 // GetValidationRoot returns the validation root of the validation tree 58 func (v *ValidationTree) GetValidationRoot() []byte { 59 if len(v.validationRoot) > 0 { 60 return v.validationRoot 61 } 62 v.calculateRoot() 63 return v.validationRoot 64 } 65 66 // Write writes the data to the validation tree 67 func (v *ValidationTree) Write(b []byte) (int, error) { 68 v.writeLock.Lock() 69 defer v.writeLock.Unlock() 70 71 if v.isFinalized { 72 return 0, fmt.Errorf("tree is already finalized") 73 } 74 75 if len(b) == 0 { 76 return 0, nil 77 } 78 79 if v.dataSize > 0 && v.writtenSize+int64(len(b)) > v.dataSize { 80 return 0, fmt.Errorf("data size overflow. expected %d, got %d", v.dataSize, v.writtenSize+int64(len(b))) 81 } 82 83 byteLen := len(b) 84 shouldContinue := true 85 // j is initialized to MaxMerkleLeavesSize - writeCount so as to make up MaxMerkleLeavesSize with previously 86 // read bytes. If previously it had written MaxMerkleLeavesSize - 1, then j will be initialized to 1 so 87 // in first iteration it will only read 1 byte and write it to v.h after which hash of v.h will be calculated 88 // and stored in v.Leaves and v.h will be reset. 89 for i, j := 0, MaxMerkleLeavesSize-v.writeCount; shouldContinue; i, j = j, j+MaxMerkleLeavesSize { 90 if j > byteLen { 91 j = byteLen 92 shouldContinue = false 93 } 94 95 n, _ := v.h.Write(b[i:j]) 96 v.writeCount += n // update write count 97 if v.writeCount == MaxMerkleLeavesSize { 98 if v.leafIndex >= len(v.leaves) { 99 // increase leaves size 100 leaves := make([][]byte, len(v.leaves)+ADD_LENGTH) 101 copy(leaves, v.leaves) 102 v.leaves = leaves 103 } 104 v.leaves[v.leafIndex] = v.h.Sum(nil) 105 v.leafIndex++ 106 v.writeCount = 0 // reset writeCount 107 v.h.Reset() // reset hasher 108 } 109 } 110 v.writtenSize += int64(byteLen) 111 return byteLen, nil 112 } 113 114 // CalculateDepth calculates the depth of the validation tree 115 func (v *ValidationTree) CalculateDepth() int { 116 return int(math.Ceil(math.Log2(float64(len(v.leaves))))) + 1 117 } 118 119 func (v *ValidationTree) calculateRoot() { 120 totalLeaves := len(v.leaves) 121 depth := v.CalculateDepth() 122 nodes := make([][]byte, totalLeaves) 123 copy(nodes, v.leaves) 124 h := sha256.New() 125 126 for i := 0; i < depth; i++ { 127 if len(nodes) == 1 { 128 break 129 } 130 newNodes := make([][]byte, 0) 131 if len(nodes)%2 == 0 { 132 for j := 0; j < len(nodes); j += 2 { 133 h.Reset() 134 h.Write(nodes[j]) 135 h.Write(nodes[j+1]) 136 newNodes = append(newNodes, h.Sum(nil)) 137 } 138 } else { 139 for j := 0; j < len(nodes)-1; j += 2 { 140 h.Reset() 141 h.Write(nodes[j]) 142 h.Write(nodes[j+1]) 143 newNodes = append(newNodes, h.Sum(nil)) 144 } 145 h.Reset() 146 h.Write(nodes[len(nodes)-1]) 147 newNodes = append(newNodes, h.Sum(nil)) 148 } 149 nodes = newNodes 150 } 151 152 v.validationRoot = nodes[0] 153 } 154 155 // Finalize finalizes the validation tree, set isFinalized to true and calculate the root 156 func (v *ValidationTree) Finalize() error { 157 v.writeLock.Lock() 158 defer v.writeLock.Unlock() 159 160 if v.isFinalized { 161 return errors.New("already finalized") 162 } 163 if v.dataSize > 0 && v.writtenSize != v.dataSize { 164 return fmt.Errorf("invalid size. Expected %d got %d", v.dataSize, v.writtenSize) 165 } 166 167 v.isFinalized = true 168 169 if v.writeCount > 0 { 170 if v.leafIndex == len(v.leaves) { 171 // increase leaves size 172 leaves := make([][]byte, len(v.leaves)+1) 173 copy(leaves, v.leaves) 174 v.leaves = leaves 175 } 176 v.leaves[v.leafIndex] = v.h.Sum(nil) 177 } else { 178 v.leafIndex-- 179 } 180 if v.leafIndex < len(v.leaves) { 181 v.leaves = v.leaves[:v.leafIndex+1] 182 } 183 return nil 184 } 185 186 // NewValidationTree creates a new validation tree 187 // - dataSize is the size of the data 188 func NewValidationTree(dataSize int64) *ValidationTree { 189 totalLeaves := (dataSize + MaxMerkleLeavesSize - 1) / MaxMerkleLeavesSize 190 if totalLeaves == 0 { 191 totalLeaves = START_LENGTH 192 } 193 return &ValidationTree{ 194 dataSize: dataSize, 195 h: sha256.New(), 196 leaves: make([][]byte, totalLeaves), 197 } 198 } 199 200 // MerklePathForMultiLeafVerification is used to verify multiple blocks with single instance of 201 // merkle path. Usually client would request with counter incremented by 10. So if the block size 202 // is 64KB and counter is incremented by 10 then client is requesting 640 KB of data. Blobber can then 203 // provide sinlge merkle path instead of sending 10 merkle paths. 204 type MerklePathForMultiLeafVerification struct { 205 // RootHash that was signed by the client 206 RootHash []byte 207 // Nodes contains a slice for each merkle node level. Each slice contains hash that will 208 // be concatenated with the calculated hash from the level below. 209 // It is used together with field Index [][]int 210 // Length of Nodes will be according to number of blocks requested. If whole data is requested then 211 // blobber will send nil for Nodes i.e. length of Nodes will become zero. 212 Nodes [][][]byte `json:"nodes"` 213 // Index slice that determines whether to concatenate hash to left or right. 214 // It should have maximum of length 2 and minimum of 0. It is used together with field Nodes [][][]byte 215 Index [][]int `json:"index"` 216 // DataSize is size of data received by the blobber for the respective file. 217 // It is not same as actual file size 218 DataSize int64 219 totalLeaves int 220 requiredDepth int 221 } 222 223 /* 224 VerifyMultipleBlocks will verify merkle path for continuous data which is multiple of 64KB blocks 225 226 There can be at most 2 hashes in the input for each depth i.e. of the format below: 227 h1, data1, data2, data3, data4, h2 228 Note that data1, data2, data3,... should be continuous data 229 230 i#3 h14 231 i#2 h12 h13 232 i#1 h7 h8 h9 h10 233 i#0 h0, h1, h2, h3, h4, h5, h6 234 235 Consider there are 7 leaves(0...6) as shown above. Now if client wants data from 236 1-3 then blobber needs to provide: 237 238 1. One node from i#0, [h0]; data1 will generate h1,data2 will generate h2 and so on... 239 2. Zero node from i#1; h0 and h1 will generate h7 and h2 and h3 will generate h8 240 3. One node from i#2, h[13]; h7 and h8 will generate h12. Now to get h14, we need h13 241 which will be provided by blobber 242 243 i#5 h37 244 i#4 h35 h36 245 i#3 h32 h33 h34 246 i#2 h27 h28 h29 h30 h31 247 i#1 h18 h19 h20 h21 h22 h23 h24 h25, h26 248 i#0 h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11, h12, h13, h14, h15, h16, h17 249 250 Consider there are 16 leaves(0..15) with total data = 16*64KB as shown above. 251 If client wants data from 3-10 then blobber needs to provide: 252 1. Two nodes from i#0, [h2, h11] 253 2. One node from i#1, [h16] 254 3. One node from i#2, [h27] 255 256 If client had required data from 2-9 then blobber would have to provide: 257 1. Zero nodes from i#0 258 2. Two nodes from i#1, [h16, h21] 259 3. One node from i#2, [h27] 260 */ 261 func (m *MerklePathForMultiLeafVerification) VerifyMultipleBlocks(data []byte) error { 262 263 hashes := make([][]byte, 0) 264 h := sha256.New() 265 // Calculate hashes from the data responded from the blobber. 266 for i := 0; i < len(data); i += MaxMerkleLeavesSize { 267 endIndex := i + MaxMerkleLeavesSize 268 if endIndex > len(data) { 269 endIndex = len(data) 270 } 271 h.Reset() 272 h.Write(data[i:endIndex]) 273 hashes = append(hashes, h.Sum(nil)) 274 } 275 276 if m.requiredDepth == 0 { 277 m.calculateRequiredLevels() 278 } 279 for i := 0; i < m.requiredDepth-1; i++ { 280 if len(m.Nodes) > i { 281 if len(m.Index[i]) == 2 { // has both nodes to append for 282 hashes = append([][]byte{m.Nodes[i][0]}, hashes...) 283 hashes = append(hashes, m.Nodes[i][1]) 284 } else if len(m.Index[i]) == 1 { // hash single node to append for 285 if m.Index[i][0] == Right { // append to right 286 hashes = append(hashes, m.Nodes[i][0]) 287 } else { 288 hashes = append([][]byte{m.Nodes[i][0]}, hashes...) 289 } 290 } 291 } 292 293 hashes = m.calculateIntermediateHashes(hashes) 294 295 } 296 297 if len(hashes) == 0 { 298 return fmt.Errorf("no hashes to verify, data is empty") 299 } 300 301 if !bytes.Equal(m.RootHash, hashes[0]) { 302 return fmt.Errorf("calculated root %s; expected %s", 303 hex.EncodeToString(hashes[0]), 304 hex.EncodeToString(m.RootHash)) 305 } 306 return nil 307 } 308 309 func (m *MerklePathForMultiLeafVerification) calculateIntermediateHashes(hashes [][]byte) [][]byte { 310 newHashes := make([][]byte, 0) 311 h := sha256.New() 312 if len(hashes)%2 == 0 { 313 for i := 0; i < len(hashes); i += 2 { 314 h.Reset() 315 h.Write(hashes[i]) 316 h.Write(hashes[i+1]) 317 newHashes = append(newHashes, h.Sum(nil)) 318 } 319 } else { 320 for i := 0; i < len(hashes)-1; i += 2 { 321 h.Reset() 322 h.Write(hashes[i]) 323 h.Write(hashes[i+1]) 324 newHashes = append(newHashes, h.Sum(nil)) 325 } 326 h.Reset() 327 h.Write(hashes[len(hashes)-1]) 328 newHashes = append(newHashes, h.Sum(nil)) 329 } 330 return newHashes 331 } 332 333 func (m *MerklePathForMultiLeafVerification) calculateTotalLeaves() { 334 m.totalLeaves = int((m.DataSize + MaxMerkleLeavesSize - 1) / MaxMerkleLeavesSize) 335 } 336 337 func (m *MerklePathForMultiLeafVerification) calculateRequiredLevels() { 338 if m.totalLeaves == 0 { 339 m.calculateTotalLeaves() 340 } 341 m.requiredDepth = int(math.Ceil(math.Log2(float64(m.totalLeaves)))) + 1 // Add root hash to be a level 342 }