github.com/aergoio/aergo@v1.3.1/pkg/trie/trie_merkle_proof.go (about)

     1  /**
     2   *  @file
     3   *  @copyright defined in aergo/LICENSE.txt
     4   */
     5  
     6  package trie
     7  
     8  import (
     9  	"bytes"
    10  )
    11  
    12  // MerkleProof generates a Merke proof of inclusion or non-inclusion
    13  // for the current trie root
    14  // returns the audit path, bool (key included), key, value, error
    15  // (key,value) can be 1- (nil, value), value of the included key, 2- the kv of a LeafNode
    16  // on the path of the non-included key, 3- (nil, nil) for a non-included key
    17  // with a DefaultLeaf on the path
    18  func (s *Trie) MerkleProof(key []byte) ([][]byte, bool, []byte, []byte, error) {
    19  	s.lock.RLock()
    20  	defer s.lock.RUnlock()
    21  	s.atomicUpdate = false // so loadChildren doesnt return a copy
    22  	return s.merkleProof(s.Root, key, nil, s.TrieHeight, 0)
    23  }
    24  
    25  // MerkleProofPast generates a Merke proof of inclusion or non-inclusion
    26  // for a given past trie root
    27  // returns the audit path, bool (key included), key, value, error
    28  // (key,value) can be 1- (nil, value), value of the included key, 2- the kv of a LeafNode
    29  // on the path of the non-included key, 3- (nil, nil) for a non-included key
    30  // with a DefaultLeaf on the path
    31  func (s *Trie) MerkleProofR(key, root []byte) ([][]byte, bool, []byte, []byte, error) {
    32  	s.lock.RLock()
    33  	defer s.lock.RUnlock()
    34  	s.atomicUpdate = false // so loadChildren doesnt return a copy
    35  	return s.merkleProof(root, key, nil, s.TrieHeight, 0)
    36  }
    37  
    38  // MerkleProofCompressed returns a compressed merkle proof in the given trie
    39  func (s *Trie) MerkleProofCompressedR(key, root []byte) ([]byte, [][]byte, int, bool, []byte, []byte, error) {
    40  	return s.merkleProofCompressed(key, root)
    41  }
    42  
    43  // MerkleProofCompressed returns a compressed merkle proof
    44  func (s *Trie) MerkleProofCompressed(key []byte) ([]byte, [][]byte, int, bool, []byte, []byte, error) {
    45  	return s.merkleProofCompressed(key, s.Root)
    46  }
    47  
    48  func (s *Trie) merkleProofCompressed(key, root []byte) ([]byte, [][]byte, int, bool, []byte, []byte, error) {
    49  	s.lock.RLock()
    50  	defer s.lock.RUnlock()
    51  	s.atomicUpdate = false // so loadChildren doesnt return a copy
    52  	// create a regular merkle proof and then compress it
    53  	mpFull, included, proofKey, proofVal, err := s.merkleProof(root, key, nil, s.TrieHeight, 0)
    54  	if err != nil {
    55  		return nil, nil, 0, true, nil, nil, err
    56  	}
    57  	// the height of the shortcut in the tree will be needed for the proof verification
    58  	height := len(mpFull)
    59  	var mp [][]byte
    60  	bitmap := make([]byte, len(mpFull)/8+1)
    61  	for i, node := range mpFull {
    62  		if !bytes.Equal(node, DefaultLeaf) {
    63  			bitSet(bitmap, i)
    64  			mp = append(mp, node)
    65  		}
    66  	}
    67  	return bitmap, mp, height, included, proofKey, proofVal, nil
    68  }
    69  
    70  // merkleProof generates a Merke proof of inclusion or non-inclusion
    71  // for a given trie root.
    72  // returns the audit path, bool (key included), key, value, error
    73  // (key,value) can be 1- (nil, value), value of the included key, 2- the kv of a LeafNode
    74  // on the path of the non-included key, 3- (nil, nil) for a non-included key
    75  // with a DefaultLeaf on the path
    76  func (s *Trie) merkleProof(root, key []byte, batch [][]byte, height, iBatch int) ([][]byte, bool, []byte, []byte, error) {
    77  	if len(root) == 0 {
    78  		// proove that an empty subtree is on the path of the key
    79  		return nil, false, nil, nil, nil
    80  	}
    81  	// Fetch the children of the node
    82  	batch, iBatch, lnode, rnode, isShortcut, err := s.loadChildren(root, height, iBatch, batch)
    83  	if err != nil {
    84  		return nil, false, nil, nil, err
    85  	}
    86  	if isShortcut || height == 0 {
    87  		if bytes.Equal(lnode[:HashLength], key) {
    88  			// return the value so a call to trie.Get() is not needed.
    89  			return nil, true, nil, rnode[:HashLength], nil
    90  		}
    91  		// Return the proof of the leaf key that is on the path of the non included key
    92  		return nil, false, lnode[:HashLength], rnode[:HashLength], nil
    93  	}
    94  
    95  	// append the left or right node to the proof
    96  	if bitIsSet(key, s.TrieHeight-height) {
    97  		mp, included, proofKey, proofValue, err := s.merkleProof(rnode, key, batch, height-1, 2*iBatch+2)
    98  		if err != nil {
    99  			return nil, false, nil, nil, err
   100  		}
   101  		if len(lnode) != 0 {
   102  			return append(mp, lnode[:HashLength]), included, proofKey, proofValue, nil
   103  		} else {
   104  			return append(mp, DefaultLeaf), included, proofKey, proofValue, nil
   105  		}
   106  
   107  	}
   108  	mp, included, proofKey, proofValue, err := s.merkleProof(lnode, key, batch, height-1, 2*iBatch+1)
   109  	if err != nil {
   110  		return nil, false, nil, nil, err
   111  	}
   112  	if len(rnode) != 0 {
   113  		return append(mp, rnode[:HashLength]), included, proofKey, proofValue, nil
   114  	} else {
   115  		return append(mp, DefaultLeaf), included, proofKey, proofValue, nil
   116  	}
   117  }
   118  
   119  // VerifyInclusion verifies that key/value is included in the trie with latest root
   120  func (s *Trie) VerifyInclusion(ap [][]byte, key, value []byte) bool {
   121  	leafHash := s.hash(key, value, []byte{byte(s.TrieHeight - len(ap))})
   122  	return bytes.Equal(s.Root, s.verifyInclusion(ap, 0, key, leafHash))
   123  }
   124  
   125  // verifyInclusion returns the merkle root by hashing the merkle proof items
   126  func (s *Trie) verifyInclusion(ap [][]byte, keyIndex int, key, leafHash []byte) []byte {
   127  	if keyIndex == len(ap) {
   128  		return leafHash
   129  	}
   130  	if bitIsSet(key, keyIndex) {
   131  		return s.hash(ap[len(ap)-keyIndex-1], s.verifyInclusion(ap, keyIndex+1, key, leafHash))
   132  	}
   133  	return s.hash(s.verifyInclusion(ap, keyIndex+1, key, leafHash), ap[len(ap)-keyIndex-1])
   134  }
   135  
   136  // VerifyNonInclusion verifies a proof of non inclusion,
   137  // Returns true if the non-inclusion is verified
   138  func (s *Trie) VerifyNonInclusion(ap [][]byte, key, value, proofKey []byte) bool {
   139  	// Check if an empty subtree is on the key path
   140  	if len(proofKey) == 0 {
   141  		// return true if a DefaultLeaf in the key path is included in the trie
   142  		return bytes.Equal(s.Root, s.verifyInclusion(ap, 0, key, DefaultLeaf))
   143  	}
   144  	// Check if another kv leaf is on the key path in 2 steps
   145  	// 1- Check the proof leaf exists
   146  	if !s.VerifyInclusion(ap, proofKey, value) {
   147  		// the proof leaf is not included in the trie
   148  		return false
   149  	}
   150  	// 2- Check the proof leaf is on the key path
   151  	var b int
   152  	for b = 0; b < len(ap); b++ {
   153  		if bitIsSet(key, b) != bitIsSet(proofKey, b) {
   154  			// the proofKey leaf node is not on the path of the key
   155  			return false
   156  		}
   157  	}
   158  	// return true because we verified another leaf is on the key path
   159  	return true
   160  }
   161  
   162  // VerifyInclusionC verifies that key/value is included in the trie with latest root
   163  func (s *Trie) VerifyInclusionC(bitmap, key, value []byte, ap [][]byte, length int) bool {
   164  	leafHash := s.hash(key, value, []byte{byte(s.TrieHeight - length)})
   165  	return bytes.Equal(s.Root, s.verifyInclusionC(bitmap, key, leafHash, ap, length, 0, 0))
   166  }
   167  
   168  // verifyInclusionC returns the merkle root by hashing the merkle proof items
   169  func (s *Trie) verifyInclusionC(bitmap, key, leafHash []byte, ap [][]byte, length, keyIndex, apIndex int) []byte {
   170  	if keyIndex == length {
   171  		return leafHash
   172  	}
   173  	if bitIsSet(key, keyIndex) {
   174  		if bitIsSet(bitmap, length-keyIndex-1) {
   175  			return s.hash(ap[len(ap)-apIndex-1], s.verifyInclusionC(bitmap, key, leafHash, ap, length, keyIndex+1, apIndex+1))
   176  		}
   177  		return s.hash(DefaultLeaf, s.verifyInclusionC(bitmap, key, leafHash, ap, length, keyIndex+1, apIndex))
   178  
   179  	}
   180  	if bitIsSet(bitmap, length-keyIndex-1) {
   181  		return s.hash(s.verifyInclusionC(bitmap, key, leafHash, ap, length, keyIndex+1, apIndex+1), ap[len(ap)-apIndex-1])
   182  	}
   183  	return s.hash(s.verifyInclusionC(bitmap, key, leafHash, ap, length, keyIndex+1, apIndex), DefaultLeaf)
   184  }
   185  
   186  // VerifyNonInclusionC verifies a proof of non inclusion,
   187  // Returns true if the non-inclusion is verified
   188  func (s *Trie) VerifyNonInclusionC(ap [][]byte, length int, bitmap, key, value, proofKey []byte) bool {
   189  	// Check if an empty subtree is on the key path
   190  	if len(proofKey) == 0 {
   191  		// return true if a DefaultLeaf in the key path is included in the trie
   192  		return bytes.Equal(s.Root, s.verifyInclusionC(bitmap, key, DefaultLeaf, ap, length, 0, 0))
   193  	}
   194  	// Check if another kv leaf is on the key path in 2 steps
   195  	// 1- Check the proof leaf exists
   196  	if !s.VerifyInclusionC(bitmap, proofKey, value, ap, length) {
   197  		// the proof leaf is not included in the trie
   198  		return false
   199  	}
   200  	// 2- Check the proof leaf is on the key path
   201  	var b int
   202  	for b = 0; b < length; b++ {
   203  		if bitIsSet(key, b) != bitIsSet(proofKey, b) {
   204  			// the proofKey leaf node is not on the path of the key
   205  			return false
   206  		}
   207  	}
   208  	// return true because we verified another leaf is on the key path
   209  	return true
   210  }