Skip to content

Commit

Permalink
refactor: remove BatchVerifyMembership and `BatchVerifyNonMembershi…
Browse files Browse the repository at this point in the history
…p` (#390)

* refactor: remove  and

* chore: CHANGELOG

* lint

* chore: changelog

* refactor: remove CombineProofs
  • Loading branch information
colin-axner authored Oct 23, 2024
1 parent 5bb1b54 commit fa483bc
Show file tree
Hide file tree
Showing 5 changed files with 7 additions and 246 deletions.
2 changes: 2 additions & 0 deletions go/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

- 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))

# v0.11.0

Expand Down
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)
})
}
72 changes: 0 additions & 72 deletions go/ics23.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ package ics23

import (
"bytes"
"fmt"
)

// CommitmentRoot is a byte slice that represents the merkle root of a tree that can be used to validate proofs
Expand Down Expand Up @@ -61,77 +60,6 @@ func VerifyNonMembership(spec *ProofSpec, root CommitmentRoot, proof *Commitment
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
Expand Down
109 changes: 5 additions & 104 deletions go/vectors_data_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,91 +73,15 @@ type BatchVectorData struct {
Invalid bool // default is valid
}

func BatchVectorsTestData(t *testing.T) map[string]BatchVectorData {
t.Helper()
iavl := filepath.Join("..", "testdata", "iavl")
tendermint := filepath.Join("..", "testdata", "tendermint")
smt := filepath.Join("..", "testdata", "smt")
// Note that each item has a different commitment root,
// so maybe not ideal (cannot check multiple entries)
batchIAVL, refsIAVL := buildBatch(t, iavl, []string{
"exist_left.json",
"exist_right.json",
"exist_middle.json",
"nonexist_left.json",
"nonexist_right.json",
"nonexist_middle.json",
})
refsTML, refsTM := buildBatch(t, tendermint, []string{
"exist_left.json",
"exist_right.json",
"exist_middle.json",
"nonexist_left.json",
"nonexist_right.json",
"nonexist_middle.json",
})
batchSMT, refsSMT := buildBatch(t, smt, []string{
"exist_left.json",
"exist_right.json",
"exist_middle.json",
"nonexist_left.json",
"nonexist_right.json",
"nonexist_middle.json",
})

batchTMExist, refsTMExist := loadBatch(t, tendermint, "batch_exist.json")
batchTMNonexist, refsTMNonexist := loadBatch(t, tendermint, "batch_nonexist.json")
batchIAVLExist, refsIAVLExist := loadBatch(t, iavl, "batch_exist.json")
batchIAVLNonexist, refsIAVLNonexist := loadBatch(t, iavl, "batch_nonexist.json")
batchSMTexist, refsSMTexist := loadBatch(t, smt, "batch_exist.json")
batchSMTnonexist, refsSMTnonexist := loadBatch(t, smt, "batch_nonexist.json")

return map[string]BatchVectorData{
"iavl 0": {Spec: IavlSpec, Proof: batchIAVL, Ref: refsIAVL[0]},
"iavl 1": {Spec: IavlSpec, Proof: batchIAVL, Ref: refsIAVL[1]},
"iavl 2": {Spec: IavlSpec, Proof: batchIAVL, Ref: refsIAVL[2]},
"iavl 3": {Spec: IavlSpec, Proof: batchIAVL, Ref: refsIAVL[3]},
"iavl 4": {Spec: IavlSpec, Proof: batchIAVL, Ref: refsIAVL[4]},
"iavl 5": {Spec: IavlSpec, Proof: batchIAVL, Ref: refsIAVL[5]},
// Note this spec only differs for non-existence proofs
"iavl invalid 1": {Spec: TendermintSpec, Proof: batchIAVL, Ref: refsIAVL[4], Invalid: true},
"iavl invalid 2": {Spec: IavlSpec, Proof: batchIAVL, Ref: refsTM[0], Invalid: true},
"iavl batch exist": {Spec: IavlSpec, Proof: batchIAVLExist, Ref: refsIAVLExist[17]},
"iavl batch nonexist": {Spec: IavlSpec, Proof: batchIAVLNonexist, Ref: refsIAVLNonexist[7]},
"tm 0": {Spec: TendermintSpec, Proof: refsTML, Ref: refsTM[0]},
"tm 1": {Spec: TendermintSpec, Proof: refsTML, Ref: refsTM[1]},
"tm 2": {Spec: TendermintSpec, Proof: refsTML, Ref: refsTM[2]},
"tm 3": {Spec: TendermintSpec, Proof: refsTML, Ref: refsTM[3]},
"tm 4": {Spec: TendermintSpec, Proof: refsTML, Ref: refsTM[4]},
"tm 5": {Spec: TendermintSpec, Proof: refsTML, Ref: refsTM[5]},
// Note this spec only differs for non-existence proofs
"tm invalid 1": {Spec: IavlSpec, Proof: refsTML, Ref: refsTM[4], Invalid: true},
"tm invalid 2": {Spec: TendermintSpec, Proof: refsTML, Ref: refsIAVL[0], Invalid: true},
"tm batch exist": {Spec: TendermintSpec, Proof: batchTMExist, Ref: refsTMExist[10]},
"tm batch nonexist": {Spec: TendermintSpec, Proof: batchTMNonexist, Ref: refsTMNonexist[3]},
"smt 0": {Spec: SmtSpec, Proof: batchSMT, Ref: refsSMT[0]},
"smt 1": {Spec: SmtSpec, Proof: batchSMT, Ref: refsSMT[1]},
"smt 2": {Spec: SmtSpec, Proof: batchSMT, Ref: refsSMT[2]},
"smt 3": {Spec: SmtSpec, Proof: batchSMT, Ref: refsSMT[3]},
"smt 4": {Spec: SmtSpec, Proof: batchSMT, Ref: refsSMT[4]},
"smt 5": {Spec: SmtSpec, Proof: batchSMT, Ref: refsSMT[5]},
// Note this spec only differs for non-existence proofs
"smt invalid 1": {Spec: IavlSpec, Proof: batchSMT, Ref: refsSMT[4], Invalid: true},
"smt invalid 2": {Spec: SmtSpec, Proof: batchSMT, Ref: refsIAVL[0], Invalid: true},
"smt batch exist": {Spec: SmtSpec, Proof: batchSMTexist, Ref: refsSMTexist[10]},
"smt batch nonexist": {Spec: SmtSpec, Proof: batchSMTnonexist, Ref: refsSMTnonexist[3]},
}
}

func DecompressBatchVectorsTestData(t *testing.T) map[string]*CommitmentProof {
t.Helper()
iavl := filepath.Join("..", "testdata", "iavl")
tendermint := filepath.Join("..", "testdata", "tendermint")
smt := filepath.Join("..", "testdata", "smt")
// note that these batches are already compressed
batchIAVL, _ := loadBatch(t, iavl, "batch_exist.json")
batchTM, _ := loadBatch(t, tendermint, "batch_nonexist.json")
batchSMT, _ := loadBatch(t, smt, "batch_nonexist.json")
batchIAVL := loadBatch(t, iavl, "batch_exist.json")
batchTM := loadBatch(t, tendermint, "batch_nonexist.json")
batchSMT := loadBatch(t, smt, "batch_nonexist.json")
return map[string]*CommitmentProof{
"iavl": batchIAVL,
"tendermint": batchTM,
Expand Down Expand Up @@ -205,21 +129,7 @@ func mustHex(tb testing.TB, data string) []byte {
return res
}

func buildBatch(t *testing.T, dir string, filenames []string) (*CommitmentProof, []*RefData) {
t.Helper()
refs := make([]*RefData, len(filenames))
proofs := make([]*CommitmentProof, len(filenames))
for i, fn := range filenames {
proofs[i], refs[i] = LoadFile(t, dir, fn)
}
batch, err := CombineProofs(proofs)
if err != nil {
t.Fatalf("Generating batch: %v", err)
}
return batch, refs
}

func loadBatch(t *testing.T, dir string, filename string) (*CommitmentProof, []*RefData) {
func loadBatch(t *testing.T, dir string, filename string) *CommitmentProof {
t.Helper()
// load the file into a json struct
name := filepath.Join(dir, filename)
Expand All @@ -238,14 +148,5 @@ func loadBatch(t *testing.T, dir string, filename string) (*CommitmentProof, []*
if err != nil {
t.Fatalf("Unmarshal protobuf: %+v", err)
}
root := mustHex(t, data.RootHash)
refs := make([]*RefData, len(data.Items))
for i, item := range data.Items {
refs[i] = &RefData{
RootHash: root,
Key: mustHex(t, item.Key),
Value: mustHex(t, item.Value),
}
}
return &proof, refs
return &proof
}
36 changes: 0 additions & 36 deletions go/vectors_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,42 +38,6 @@ func TestVectors(t *testing.T) {
}
}

func TestBatchVectors(t *testing.T) {
cases := BatchVectorsTestData(t)
for name, tc := range cases {
tc := tc
t.Run(name, func(t *testing.T) {
// try one proof
if tc.Ref.Value == nil {
// non-existence
valid := VerifyNonMembership(tc.Spec, tc.Ref.RootHash, tc.Proof, tc.Ref.Key)
if valid == tc.Invalid {
t.Logf("name: %+v", name)
t.Logf("ref: %+v", tc.Ref)
t.Logf("spec: %+v", tc.Spec)
t.Errorf("Expected proof validity: %t", !tc.Invalid)
}
keys := [][]byte{tc.Ref.Key}
valid = BatchVerifyNonMembership(tc.Spec, tc.Ref.RootHash, tc.Proof, keys)
if valid == tc.Invalid {
t.Errorf("Expected batch proof validity: %t", !tc.Invalid)
}
} else {
valid := VerifyMembership(tc.Spec, tc.Ref.RootHash, tc.Proof, tc.Ref.Key, tc.Ref.Value)
if valid == tc.Invalid {
t.Errorf("Expected proof validity: %t", !tc.Invalid)
}
items := make(map[string][]byte)
items[string(tc.Ref.Key)] = tc.Ref.Value
valid = BatchVerifyMembership(tc.Spec, tc.Ref.RootHash, tc.Proof, items)
if valid == tc.Invalid {
t.Errorf("Expected batch proof validity: %t", !tc.Invalid)
}
}
})
}
}

func TestDecompressBatchVectors(t *testing.T) {
cases := DecompressBatchVectorsTestData(t)
for name, tc := range cases {
Expand Down

0 comments on commit fa483bc

Please sign in to comment.