func (proof MerkleProof) VerifyMembership(specs []*ics23.ProofSpec, root exported.Root, path exported.Path, value []byte) error {
	if err := proof.validateVerificationArgs(specs, root); err != nil {
		return err
	}
	mpath, ok := path.(MerklePath)
	if !ok {
		return sdkerrors.Wrapf(ErrInvalidProof, "path %v is not of type MerklePath", path)
	}
	if len(mpath.KeyPath) != len(specs) {
		return sdkerrors.Wrapf(
			ErrInvalidProof,
			"path length %d not same as proof %d",
			len(mpath.KeyPath), len(specs),
		)
	}
	if len(value) == 0 {
		return sdkerrors.Wrap(ErrInvalidProof, "empty value in membership proof")
	}
	if err := verifyChainedMembershipProof(root.GetHash(), specs, proof.Proofs, mpath, value, 0); err != nil {
		return err
	}
	return nil
}
VerifyMembership verifies the membership pf a merkle proof against the given root, path, and value.
package types
import (
	"bytes"
	"fmt"
	"net/url"
	ics23 "github.com/confio/ics23/go"
	"github.com/gogo/protobuf/proto"
	tmcrypto "github.com/tendermint/tendermint/proto/tendermint/crypto"
	sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
	"github.com/bianjieai/tibc-go/modules/tibc/core/exported"
)
var sdkSpecs = []*ics23.ProofSpec{ics23.IavlSpec, ics23.TendermintSpec}
var _ exported.Root = (*MerkleRoot)(nil)
func GetSDKSpecs() []*ics23.ProofSpec {
	return sdkSpecs
}
func NewMerkleRoot(hash []byte) MerkleRoot {
	return MerkleRoot{
		Hash: hash,
	}
}
func (mr MerkleRoot) GetHash() []byte {
	return mr.Hash
}
func (mr MerkleRoot) Empty() bool {
	return len(mr.GetHash()) == 0
}
var _ exported.Prefix = (*MerklePrefix)(nil)
func NewMerklePrefix(keyPrefix []byte) MerklePrefix {
	return MerklePrefix{
		KeyPrefix: keyPrefix,
	}
}
func (mp MerklePrefix) Bytes() []byte {
	return mp.KeyPrefix
}
func (mp MerklePrefix) Empty() bool {
	return len(mp.Bytes()) == 0
}
var _ exported.Path = (*MerklePath)(nil)
func NewMerklePath(keyPath ...string) MerklePath {
	return MerklePath{
		KeyPath: keyPath,
	}
}
func (mp MerklePath) String() string {
	pathStr := ""
	for _, k := range mp.KeyPath {
		pathStr += "/" + url.PathEscape(k)
	}
	return pathStr
}
func (mp MerklePath) Pretty() string {
	path, err := url.PathUnescape(mp.String())
	if err != nil {
		panic(err)
	}
	return path
}
func (mp MerklePath) GetKey(i uint64) ([]byte, error) {
	if i >= uint64(len(mp.KeyPath)) {
		return nil, fmt.Errorf("index out of range. %d (index) >= %d (len)", i, len(mp.KeyPath))
	}
	key, err := url.PathUnescape(mp.KeyPath[i])
	if err != nil {
		return nil, err
	}
	return []byte(key), nil
}
func (mp MerklePath) Empty() bool {
	return len(mp.KeyPath) == 0
}
func ApplyPrefix(prefix exported.Prefix, path MerklePath) (MerklePath, error) {
	if prefix == nil || prefix.Empty() {
		return MerklePath{}, sdkerrors.Wrap(ErrInvalidPrefix, "prefix can't be empty")
	}
	return NewMerklePath(append([]string{string(prefix.Bytes())}, path.KeyPath...)...), nil
}
var _ exported.Proof = (*MerkleProof)(nil)