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  }