Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: remove all batch and compress logic #392

Merged
merged 16 commits into from
Oct 23, 2024
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions go/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

- deps: bump golang to v1.22 ([#363](https://github.com/cosmos/ics23/pull/363)).
- fix: guarantee that `spec.InnerSpec.MaxPrefixLength` < `spec.InnerSpec.MinPrefixLength` + `spec.InnerSpec.ChildSize` ([#369](https://github.com/cosmos/ics23/pull/369))
- refactor: support for `BatchProof` and `CompressedBatchProof` is being dropped.
* The API's `BatchVerifyMembership`, `BatchVerifyNonMembership`, and `CombineProofs` have been removed. ([#390](https://github.com/cosmos/ics23/pull/390))
* The API's `IsCompressed`, `Compress`, and `Decompress` have been removed. ([#392](https://github.com/cosmos/ics23/pull/392))

# v0.11.0

Expand Down
159 changes: 0 additions & 159 deletions go/compress.go

This file was deleted.

34 changes: 0 additions & 34 deletions go/fuzz_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,37 +172,3 @@ func FuzzVerifyMembership(f *testing.F) {
_ = VerifyMembership(spec, ref.RootHash, proof, ref.Key, ref.Value)
})
}

func FuzzCombineProofs(f *testing.F) {
// 1. Load in the CommitmentProofs
baseDirs := []string{"iavl", "tendermint", "smt"}
filenames := []string{
"exist_left.json",
"exist_right.json",
"exist_middle.json",
"nonexist_left.json",
"nonexist_right.json",
"nonexist_middle.json",
}

for _, baseDir := range baseDirs {
dir := filepath.Join("..", "testdata", baseDir)
for _, filename := range filenames {
proofs, _ := LoadFile(new(testing.T), dir, filename)
blob, err := json.Marshal(proofs)
if err != nil {
f.Fatal(err)
}
f.Add(blob)
}
}

// 2. Now let's run the fuzzer.
f.Fuzz(func(t *testing.T, proofsJSON []byte) {
var proofs []*CommitmentProof
if err := json.Unmarshal(proofsJSON, &proofs); err != nil {
return
}
_, _ = CombineProofs(proofs)
})
}
134 changes: 14 additions & 120 deletions go/ics23.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,24 +25,25 @@

import (
"bytes"
"fmt"
)

// CommitmentRoot is a byte slice that represents the merkle root of a tree that can be used to validate proofs
type CommitmentRoot []byte

// VerifyMembership returns true iff
// proof is (contains) an ExistenceProof for the given key and value AND
// calculating the root for the ExistenceProof matches the provided CommitmentRoot
// proof is an ExistenceProof for the given key and value AND
// calculating the root for the ExistenceProof matches the provided CommitmentRoot.
func VerifyMembership(spec *ProofSpec, root CommitmentRoot, proof *CommitmentProof, key []byte, value []byte) bool {
// decompress it before running code (no-op if not compressed)
proof = Decompress(proof)
ep := getExistProofForKey(proof, key)
if proof == nil {
return false
}

ep := proof.GetExist()
if ep == nil {
return false
}
err := ep.Verify(spec, root, key, value)
return err == nil

return ep.Verify(spec, root, key, value) == nil
}

// VerifyNonMembership returns true iff
Expand All @@ -51,129 +52,22 @@
// left and right proofs are neighbors (or left/right most if one is nil)
// provided key is between the keys of the two proofs
func VerifyNonMembership(spec *ProofSpec, root CommitmentRoot, proof *CommitmentProof, key []byte) bool {
// decompress it before running code (no-op if not compressed)
proof = Decompress(proof)
np := getNonExistProofForKey(spec, proof, key)
if np == nil {
return false
}
err := np.Verify(spec, root, key)
return err == nil
}

// BatchVerifyMembership will ensure all items are also proven by the CommitmentProof (which should be a BatchProof,
// unless there is one item, when a ExistenceProof may work)
func BatchVerifyMembership(spec *ProofSpec, root CommitmentRoot, proof *CommitmentProof, items map[string][]byte) bool {
// decompress it before running code (no-op if not compressed) - once for batch
proof = Decompress(proof)
for k, v := range items {
valid := VerifyMembership(spec, root, proof, []byte(k), v)
if !valid {
return false
}
}
return true
}

// BatchVerifyNonMembership will ensure all items are also proven to not be in the Commitment by the CommitmentProof
// (which should be a BatchProof, unless there is one item, when a NonExistenceProof may work)
func BatchVerifyNonMembership(spec *ProofSpec, root CommitmentRoot, proof *CommitmentProof, keys [][]byte) bool {
// decompress it before running code (no-op if not compressed) - once for batch
proof = Decompress(proof)
for _, k := range keys {
valid := VerifyNonMembership(spec, root, proof, k)
if !valid {
return false
}
}
return true
}

// CombineProofs takes a number of commitment proofs (simple or batch) and
// converts them into a batch and compresses them.
//
// This is designed for proof generation libraries to create efficient batches
func CombineProofs(proofs []*CommitmentProof) (*CommitmentProof, error) {
var entries []*BatchEntry

for _, proof := range proofs {
if ex := proof.GetExist(); ex != nil {
entry := &BatchEntry{
Proof: &BatchEntry_Exist{
Exist: ex,
},
}
entries = append(entries, entry)
} else if non := proof.GetNonexist(); non != nil {
entry := &BatchEntry{
Proof: &BatchEntry_Nonexist{
Nonexist: non,
},
}
entries = append(entries, entry)
} else if batch := proof.GetBatch(); batch != nil {
entries = append(entries, batch.Entries...)
} else if comp := proof.GetCompressed(); comp != nil {
decomp := Decompress(proof)
entries = append(entries, decomp.GetBatch().Entries...)
} else {
return nil, fmt.Errorf("proof neither exist or nonexist: %#v", proof.GetProof())
}
}

batch := &CommitmentProof{
Proof: &CommitmentProof_Batch{
Batch: &BatchProof{
Entries: entries,
},
},
}

return Compress(batch), nil
}

func getExistProofForKey(proof *CommitmentProof, key []byte) *ExistenceProof {
if proof == nil {
return nil
return false
}

switch p := proof.Proof.(type) {
case *CommitmentProof_Exist:
ep := p.Exist
if bytes.Equal(ep.Key, key) {
return ep
}
case *CommitmentProof_Batch:
for _, sub := range p.Batch.Entries {
if ep := sub.GetExist(); ep != nil && bytes.Equal(ep.Key, key) {
return ep
}
}
np := proof.GetNonexist()
if np == nil {
return false
}
return nil
}

func getNonExistProofForKey(spec *ProofSpec, proof *CommitmentProof, key []byte) *NonExistenceProof {
switch p := proof.Proof.(type) {
case *CommitmentProof_Nonexist:
np := p.Nonexist
if isLeft(spec, np.Left, key) && isRight(spec, np.Right, key) {
return np
}
case *CommitmentProof_Batch:
for _, sub := range p.Batch.Entries {
if np := sub.GetNonexist(); np != nil && isLeft(spec, np.Left, key) && isRight(spec, np.Right, key) {
return np
}
}
}
return nil
return np.Verify(spec, root, key) == nil
}

func isLeft(spec *ProofSpec, left *ExistenceProof, key []byte) bool {

Check failure on line 67 in go/ics23.go

View workflow job for this annotation

GitHub Actions / Lint

func `isLeft` is unused (unused)
return left == nil || bytes.Compare(keyForComparison(spec, left.Key), keyForComparison(spec, key)) < 0
}

func isRight(spec *ProofSpec, right *ExistenceProof, key []byte) bool {

Check failure on line 71 in go/ics23.go

View workflow job for this annotation

GitHub Actions / Lint

func `isRight` is unused (unused)
return right == nil || bytes.Compare(keyForComparison(spec, right.Key), keyForComparison(spec, key)) > 0
}
14 changes: 0 additions & 14 deletions go/proof.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,23 +86,9 @@ func (p *CommitmentProof) Calculate() (CommitmentRoot, error) {
return v.Exist.Calculate()
case *CommitmentProof_Nonexist:
return v.Nonexist.Calculate()
case *CommitmentProof_Batch:
if len(v.Batch.GetEntries()) == 0 || v.Batch.GetEntries()[0] == nil {
return nil, errors.New("batch proof has empty entry")
}
if e := v.Batch.GetEntries()[0].GetExist(); e != nil {
return e.Calculate()
}
if n := v.Batch.GetEntries()[0].GetNonexist(); n != nil {
return n.Calculate()
}
case *CommitmentProof_Compressed:
proof := Decompress(p)
return proof.Calculate()
default:
return nil, errors.New("unrecognized proof type")
}
return nil, errors.New("unrecognized proof type")
}

// Verify does all checks to ensure this proof proves this key, value -> root
Expand Down
Loading
Loading