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  }