github.com/evdatsion/aphelion-dpos-bft@v0.32.1/crypto/merkle/simple_proof.go (about)

     1  package merkle
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"fmt"
     7  
     8  	cmn "github.com/evdatsion/aphelion-dpos-bft/libs/common"
     9  )
    10  
    11  // SimpleProof represents a simple Merkle proof.
    12  // NOTE: The convention for proofs is to include leaf hashes but to
    13  // exclude the root hash.
    14  // This convention is implemented across IAVL range proofs as well.
    15  // Keep this consistent unless there's a very good reason to change
    16  // everything.  This also affects the generalized proof system as
    17  // well.
    18  type SimpleProof struct {
    19  	Total    int      `json:"total"`     // Total number of items.
    20  	Index    int      `json:"index"`     // Index of item to prove.
    21  	LeafHash []byte   `json:"leaf_hash"` // Hash of item value.
    22  	Aunts    [][]byte `json:"aunts"`     // Hashes from leaf's sibling to a root's child.
    23  }
    24  
    25  // SimpleProofsFromByteSlices computes inclusion proof for given items.
    26  // proofs[0] is the proof for items[0].
    27  func SimpleProofsFromByteSlices(items [][]byte) (rootHash []byte, proofs []*SimpleProof) {
    28  	trails, rootSPN := trailsFromByteSlices(items)
    29  	rootHash = rootSPN.Hash
    30  	proofs = make([]*SimpleProof, len(items))
    31  	for i, trail := range trails {
    32  		proofs[i] = &SimpleProof{
    33  			Total:    len(items),
    34  			Index:    i,
    35  			LeafHash: trail.Hash,
    36  			Aunts:    trail.FlattenAunts(),
    37  		}
    38  	}
    39  	return
    40  }
    41  
    42  // SimpleProofsFromMap generates proofs from a map. The keys/values of the map will be used as the keys/values
    43  // in the underlying key-value pairs.
    44  // The keys are sorted before the proofs are computed.
    45  func SimpleProofsFromMap(m map[string][]byte) (rootHash []byte, proofs map[string]*SimpleProof, keys []string) {
    46  	sm := newSimpleMap()
    47  	for k, v := range m {
    48  		sm.Set(k, v)
    49  	}
    50  	sm.Sort()
    51  	kvs := sm.kvs
    52  	kvsBytes := make([][]byte, len(kvs))
    53  	for i, kvp := range kvs {
    54  		kvsBytes[i] = KVPair(kvp).Bytes()
    55  	}
    56  
    57  	rootHash, proofList := SimpleProofsFromByteSlices(kvsBytes)
    58  	proofs = make(map[string]*SimpleProof)
    59  	keys = make([]string, len(proofList))
    60  	for i, kvp := range kvs {
    61  		proofs[string(kvp.Key)] = proofList[i]
    62  		keys[i] = string(kvp.Key)
    63  	}
    64  	return
    65  }
    66  
    67  // Verify that the SimpleProof proves the root hash.
    68  // Check sp.Index/sp.Total manually if needed
    69  func (sp *SimpleProof) Verify(rootHash []byte, leaf []byte) error {
    70  	leafHash := leafHash(leaf)
    71  	if sp.Total < 0 {
    72  		return errors.New("Proof total must be positive")
    73  	}
    74  	if sp.Index < 0 {
    75  		return errors.New("Proof index cannot be negative")
    76  	}
    77  	if !bytes.Equal(sp.LeafHash, leafHash) {
    78  		return cmn.NewError("invalid leaf hash: wanted %X got %X", leafHash, sp.LeafHash)
    79  	}
    80  	computedHash := sp.ComputeRootHash()
    81  	if !bytes.Equal(computedHash, rootHash) {
    82  		return cmn.NewError("invalid root hash: wanted %X got %X", rootHash, computedHash)
    83  	}
    84  	return nil
    85  }
    86  
    87  // Compute the root hash given a leaf hash.  Does not verify the result.
    88  func (sp *SimpleProof) ComputeRootHash() []byte {
    89  	return computeHashFromAunts(
    90  		sp.Index,
    91  		sp.Total,
    92  		sp.LeafHash,
    93  		sp.Aunts,
    94  	)
    95  }
    96  
    97  // String implements the stringer interface for SimpleProof.
    98  // It is a wrapper around StringIndented.
    99  func (sp *SimpleProof) String() string {
   100  	return sp.StringIndented("")
   101  }
   102  
   103  // StringIndented generates a canonical string representation of a SimpleProof.
   104  func (sp *SimpleProof) StringIndented(indent string) string {
   105  	return fmt.Sprintf(`SimpleProof{
   106  %s  Aunts: %X
   107  %s}`,
   108  		indent, sp.Aunts,
   109  		indent)
   110  }
   111  
   112  // Use the leafHash and innerHashes to get the root merkle hash.
   113  // If the length of the innerHashes slice isn't exactly correct, the result is nil.
   114  // Recursive impl.
   115  func computeHashFromAunts(index int, total int, leafHash []byte, innerHashes [][]byte) []byte {
   116  	if index >= total || index < 0 || total <= 0 {
   117  		return nil
   118  	}
   119  	switch total {
   120  	case 0:
   121  		panic("Cannot call computeHashFromAunts() with 0 total")
   122  	case 1:
   123  		if len(innerHashes) != 0 {
   124  			return nil
   125  		}
   126  		return leafHash
   127  	default:
   128  		if len(innerHashes) == 0 {
   129  			return nil
   130  		}
   131  		numLeft := getSplitPoint(total)
   132  		if index < numLeft {
   133  			leftHash := computeHashFromAunts(index, numLeft, leafHash, innerHashes[:len(innerHashes)-1])
   134  			if leftHash == nil {
   135  				return nil
   136  			}
   137  			return innerHash(leftHash, innerHashes[len(innerHashes)-1])
   138  		}
   139  		rightHash := computeHashFromAunts(index-numLeft, total-numLeft, leafHash, innerHashes[:len(innerHashes)-1])
   140  		if rightHash == nil {
   141  			return nil
   142  		}
   143  		return innerHash(innerHashes[len(innerHashes)-1], rightHash)
   144  	}
   145  }
   146  
   147  // SimpleProofNode is a helper structure to construct merkle proof.
   148  // The node and the tree is thrown away afterwards.
   149  // Exactly one of node.Left and node.Right is nil, unless node is the root, in which case both are nil.
   150  // node.Parent.Hash = hash(node.Hash, node.Right.Hash) or
   151  // hash(node.Left.Hash, node.Hash), depending on whether node is a left/right child.
   152  type SimpleProofNode struct {
   153  	Hash   []byte
   154  	Parent *SimpleProofNode
   155  	Left   *SimpleProofNode // Left sibling  (only one of Left,Right is set)
   156  	Right  *SimpleProofNode // Right sibling (only one of Left,Right is set)
   157  }
   158  
   159  // FlattenAunts will return the inner hashes for the item corresponding to the leaf,
   160  // starting from a leaf SimpleProofNode.
   161  func (spn *SimpleProofNode) FlattenAunts() [][]byte {
   162  	// Nonrecursive impl.
   163  	innerHashes := [][]byte{}
   164  	for spn != nil {
   165  		if spn.Left != nil {
   166  			innerHashes = append(innerHashes, spn.Left.Hash)
   167  		} else if spn.Right != nil {
   168  			innerHashes = append(innerHashes, spn.Right.Hash)
   169  		} else {
   170  			break
   171  		}
   172  		spn = spn.Parent
   173  	}
   174  	return innerHashes
   175  }
   176  
   177  // trails[0].Hash is the leaf hash for items[0].
   178  // trails[i].Parent.Parent....Parent == root for all i.
   179  func trailsFromByteSlices(items [][]byte) (trails []*SimpleProofNode, root *SimpleProofNode) {
   180  	// Recursive impl.
   181  	switch len(items) {
   182  	case 0:
   183  		return nil, nil
   184  	case 1:
   185  		trail := &SimpleProofNode{leafHash(items[0]), nil, nil, nil}
   186  		return []*SimpleProofNode{trail}, trail
   187  	default:
   188  		k := getSplitPoint(len(items))
   189  		lefts, leftRoot := trailsFromByteSlices(items[:k])
   190  		rights, rightRoot := trailsFromByteSlices(items[k:])
   191  		rootHash := innerHash(leftRoot.Hash, rightRoot.Hash)
   192  		root := &SimpleProofNode{rootHash, nil, nil, nil}
   193  		leftRoot.Parent = root
   194  		leftRoot.Right = rightRoot
   195  		rightRoot.Parent = root
   196  		rightRoot.Left = leftRoot
   197  		return append(lefts, rights...), root
   198  	}
   199  }