From d3b71c4e48680cf17e3c730761509e4f649ee7bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Mon, 21 Oct 2024 11:02:08 +0200 Subject: [PATCH 01/10] refactor: remove and --- go/ics23.go | 28 --------------- go/vectors_data_test.go | 76 ----------------------------------------- go/vectors_test.go | 36 ------------------- 3 files changed, 140 deletions(-) diff --git a/go/ics23.go b/go/ics23.go index 709094d6..0cb2a57b 100644 --- a/go/ics23.go +++ b/go/ics23.go @@ -61,34 +61,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. // diff --git a/go/vectors_data_test.go b/go/vectors_data_test.go index f6e453cc..5ad1e3cf 100644 --- a/go/vectors_data_test.go +++ b/go/vectors_data_test.go @@ -73,82 +73,6 @@ 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") diff --git a/go/vectors_test.go b/go/vectors_test.go index b6e0e909..9b6282a8 100644 --- a/go/vectors_test.go +++ b/go/vectors_test.go @@ -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 { From a1082ee66ce6bcbe1d7502a4b68834ca3b6f36fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Mon, 21 Oct 2024 11:04:34 +0200 Subject: [PATCH 02/10] chore: CHANGELOG --- go/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/go/CHANGELOG.md b/go/CHANGELOG.md index d49eff71..6c6b8b78 100644 --- a/go/CHANGELOG.md +++ b/go/CHANGELOG.md @@ -4,6 +4,7 @@ - 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` and `BatchVerifyNonMembership` have been removed. ([#390](https://github.com/cosmos/ics23/pull/390)) # v0.11.0 From 300714b621bd7f3f41a01f6a93ffff92e07ba567 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Mon, 21 Oct 2024 11:07:01 +0200 Subject: [PATCH 03/10] lint --- go/vectors_data_test.go | 33 +++++---------------------------- 1 file changed, 5 insertions(+), 28 deletions(-) diff --git a/go/vectors_data_test.go b/go/vectors_data_test.go index 5ad1e3cf..15a86ecc 100644 --- a/go/vectors_data_test.go +++ b/go/vectors_data_test.go @@ -79,9 +79,9 @@ func DecompressBatchVectorsTestData(t *testing.T) map[string]*CommitmentProof { 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, @@ -129,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) @@ -162,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 } From ebbb3bab0c5deb605b0dd81d9ad0c45220886251 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Mon, 21 Oct 2024 11:09:09 +0200 Subject: [PATCH 04/10] chore: changelog --- go/CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/go/CHANGELOG.md b/go/CHANGELOG.md index 6c6b8b78..eddb3ac8 100644 --- a/go/CHANGELOG.md +++ b/go/CHANGELOG.md @@ -4,7 +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` and `BatchVerifyNonMembership` have been removed. ([#390](https://github.com/cosmos/ics23/pull/390)) +- refactor: support for `BatchProof` and `CompressedBatchProof` is being dropped. + * The API's `BatchVerifyMembership` and `BatchVerifyNonMembership` have been removed. ([#390](https://github.com/cosmos/ics23/pull/390)) # v0.11.0 From fd4a2a1fd7c34f30a092f693cac531888b935cb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Mon, 21 Oct 2024 11:12:24 +0200 Subject: [PATCH 05/10] refactor: remove CombineProofs --- go/CHANGELOG.md | 2 +- go/fuzz_test.go | 34 ---------------------------------- go/ics23.go | 44 -------------------------------------------- 3 files changed, 1 insertion(+), 79 deletions(-) diff --git a/go/CHANGELOG.md b/go/CHANGELOG.md index eddb3ac8..984175e1 100644 --- a/go/CHANGELOG.md +++ b/go/CHANGELOG.md @@ -5,7 +5,7 @@ - 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` and `BatchVerifyNonMembership` have been removed. ([#390](https://github.com/cosmos/ics23/pull/390)) + * The API's `BatchVerifyMembership`, `BatchVerifyNonMembership`, and `CombineProofs` have been removed. ([#390](https://github.com/cosmos/ics23/pull/390)) # v0.11.0 diff --git a/go/fuzz_test.go b/go/fuzz_test.go index f972fde5..8ae45aa3 100644 --- a/go/fuzz_test.go +++ b/go/fuzz_test.go @@ -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) - }) -} diff --git a/go/ics23.go b/go/ics23.go index 0cb2a57b..db129753 100644 --- a/go/ics23.go +++ b/go/ics23.go @@ -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 @@ -61,49 +60,6 @@ func VerifyNonMembership(spec *ProofSpec, root CommitmentRoot, proof *Commitment return err == nil } -// 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 From c57484e14281647a7606b594146498c5a2d75432 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Mon, 21 Oct 2024 11:29:04 +0200 Subject: [PATCH 06/10] refactor: VerifyMembership and VerifyNonMembership api --- go/fuzz_test.go | 4 +-- go/ics23.go | 71 +++++++++++----------------------------------- go/vectors_test.go | 19 +++++++------ 3 files changed, 30 insertions(+), 64 deletions(-) diff --git a/go/fuzz_test.go b/go/fuzz_test.go index 8ae45aa3..5ff2e3ca 100644 --- a/go/fuzz_test.go +++ b/go/fuzz_test.go @@ -118,7 +118,7 @@ func FuzzVerifyNonMembership(f *testing.F) { return } // Otherwise now run VerifyNonMembership. - _ = VerifyNonMembership(bv.Spec, bv.Ref.RootHash, bv.Proof, bv.Ref.Key) + _ = VerifyNonMembership(bv.Spec, bv.Ref.RootHash, bv.Proof.GetNonexist(), bv.Ref.Key) }) } @@ -165,7 +165,7 @@ func FuzzVerifyMembership(f *testing.F) { if err := json.Unmarshal(input, &con); err != nil { return } - spec, ref, proof := con.Spec, con.Ref, con.Proof + spec, ref, proof := con.Spec, con.Ref, con.Proof.GetExist() if ref == nil { return } diff --git a/go/ics23.go b/go/ics23.go index db129753..35924469 100644 --- a/go/ics23.go +++ b/go/ics23.go @@ -25,23 +25,24 @@ 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 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 -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 ep == nil { - return false +// VerifyMembership returns successfully iff +// 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 *ExistenceProof, key []byte, value []byte) error { + if proof == nil { + return fmt.Errorf("proof cannot be empty") + } + if !bytes.Equal(proof.Key, key) { + return fmt.Errorf("proof key (%s) must equal given key (%s)", proof.Key, key) } - err := ep.Verify(spec, root, key, value) - return err == nil + + return proof.Verify(spec, root, key, value) } // VerifyNonMembership returns true iff @@ -49,53 +50,15 @@ func VerifyMembership(spec *ProofSpec, root CommitmentRoot, proof *CommitmentPro // both left and right sub-proofs are valid existence proofs (see above) or nil // 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 -} - -func getExistProofForKey(proof *CommitmentProof, key []byte) *ExistenceProof { +func VerifyNonMembership(spec *ProofSpec, root CommitmentRoot, proof *NonExistenceProof, key []byte) error { if proof == nil { - return nil + return fmt.Errorf("proof cannot be empty") } - - 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 - } - } + if !isLeft(spec, proof.Left, key) || !isRight(spec, proof.Right, key) { + return fmt.Errorf("provided existence proofs must be for left and right keys of non-existing key") } - 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 proof.Verify(spec, root, key) } func isLeft(spec *ProofSpec, left *ExistenceProof, key []byte) bool { diff --git a/go/vectors_test.go b/go/vectors_test.go index 9b6282a8..2c4d4188 100644 --- a/go/vectors_test.go +++ b/go/vectors_test.go @@ -12,9 +12,10 @@ func TestVectors(t *testing.T) { tc := tc name := fmt.Sprintf("%s/%s", tc.Dir, tc.Filename) t.Run(name, func(t *testing.T) { - proof, ref := LoadFile(t, tc.Dir, tc.Filename) + commitmentProof, ref := LoadFile(t, tc.Dir, tc.Filename) + // Test Calculate method - calculatedRoot, err := proof.Calculate() + calculatedRoot, err := commitmentProof.Calculate() if err != nil { t.Fatal("proof.Calculate() returned error") } @@ -23,15 +24,17 @@ func TestVectors(t *testing.T) { } // Test Verify method if ref.Value == nil { + proof := commitmentProof.GetNonexist() // non-existence - valid := VerifyNonMembership(tc.Spec, ref.RootHash, proof, ref.Key) - if !valid { - t.Fatal("Invalid proof") + err := VerifyNonMembership(tc.Spec, ref.RootHash, proof, ref.Key) + if err != nil { + t.Fatalf("Invalid proof: %v", err) } } else { - valid := VerifyMembership(tc.Spec, ref.RootHash, proof, ref.Key, ref.Value) - if !valid { - t.Fatal("Invalid proof") + proof := commitmentProof.GetExist() + err := VerifyMembership(tc.Spec, ref.RootHash, proof, ref.Key, ref.Value) + if err != nil { + t.Fatalf("Invalid proof: %v", err) } } }) From 9188852142969d5ea4e8a7b65f994223ddd618d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Mon, 21 Oct 2024 16:02:41 +0200 Subject: [PATCH 07/10] refactor: reset api --- go/fuzz_test.go | 4 ++-- go/ics23.go | 29 ++++++++++++++++++----------- go/vectors_test.go | 14 ++++++-------- 3 files changed, 26 insertions(+), 21 deletions(-) diff --git a/go/fuzz_test.go b/go/fuzz_test.go index 5ff2e3ca..8ae45aa3 100644 --- a/go/fuzz_test.go +++ b/go/fuzz_test.go @@ -118,7 +118,7 @@ func FuzzVerifyNonMembership(f *testing.F) { return } // Otherwise now run VerifyNonMembership. - _ = VerifyNonMembership(bv.Spec, bv.Ref.RootHash, bv.Proof.GetNonexist(), bv.Ref.Key) + _ = VerifyNonMembership(bv.Spec, bv.Ref.RootHash, bv.Proof, bv.Ref.Key) }) } @@ -165,7 +165,7 @@ func FuzzVerifyMembership(f *testing.F) { if err := json.Unmarshal(input, &con); err != nil { return } - spec, ref, proof := con.Spec, con.Ref, con.Proof.GetExist() + spec, ref, proof := con.Spec, con.Ref, con.Proof if ref == nil { return } diff --git a/go/ics23.go b/go/ics23.go index 35924469..8e7f8563 100644 --- a/go/ics23.go +++ b/go/ics23.go @@ -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 @@ -34,15 +33,17 @@ type CommitmentRoot []byte // VerifyMembership returns successfully iff // 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 *ExistenceProof, key []byte, value []byte) error { +func VerifyMembership(spec *ProofSpec, root CommitmentRoot, proof *CommitmentProof, key []byte, value []byte) bool { if proof == nil { - return fmt.Errorf("proof cannot be empty") + return false } - if !bytes.Equal(proof.Key, key) { - return fmt.Errorf("proof key (%s) must equal given key (%s)", proof.Key, key) + + ep := proof.GetExist() + if ep == nil { + return false } - return proof.Verify(spec, root, key, value) + return ep.Verify(spec, root, key, value) == nil } // VerifyNonMembership returns true iff @@ -50,15 +51,21 @@ func VerifyMembership(spec *ProofSpec, root CommitmentRoot, proof *ExistenceProo // both left and right sub-proofs are valid existence proofs (see above) or nil // 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 *NonExistenceProof, key []byte) error { +func VerifyNonMembership(spec *ProofSpec, root CommitmentRoot, proof *CommitmentProof, key []byte) bool { if proof == nil { - return fmt.Errorf("proof cannot be empty") + return false + } + + np := proof.GetNonexist() + if np == nil { + return false } - if !isLeft(spec, proof.Left, key) || !isRight(spec, proof.Right, key) { - return fmt.Errorf("provided existence proofs must be for left and right keys of non-existing key") + + if !isLeft(spec, np.Left, key) || !isRight(spec, np.Right, key) { + return false } - return proof.Verify(spec, root, key) + return np.Verify(spec, root, key) == nil } func isLeft(spec *ProofSpec, left *ExistenceProof, key []byte) bool { diff --git a/go/vectors_test.go b/go/vectors_test.go index 2c4d4188..425f9b5e 100644 --- a/go/vectors_test.go +++ b/go/vectors_test.go @@ -12,10 +12,10 @@ func TestVectors(t *testing.T) { tc := tc name := fmt.Sprintf("%s/%s", tc.Dir, tc.Filename) t.Run(name, func(t *testing.T) { - commitmentProof, ref := LoadFile(t, tc.Dir, tc.Filename) + proof, ref := LoadFile(t, tc.Dir, tc.Filename) // Test Calculate method - calculatedRoot, err := commitmentProof.Calculate() + calculatedRoot, err := proof.Calculate() if err != nil { t.Fatal("proof.Calculate() returned error") } @@ -24,16 +24,14 @@ func TestVectors(t *testing.T) { } // Test Verify method if ref.Value == nil { - proof := commitmentProof.GetNonexist() // non-existence - err := VerifyNonMembership(tc.Spec, ref.RootHash, proof, ref.Key) - if err != nil { + valid := VerifyNonMembership(tc.Spec, ref.RootHash, proof, ref.Key) + if !valid { t.Fatalf("Invalid proof: %v", err) } } else { - proof := commitmentProof.GetExist() - err := VerifyMembership(tc.Spec, ref.RootHash, proof, ref.Key, ref.Value) - if err != nil { + valid := VerifyMembership(tc.Spec, ref.RootHash, proof, ref.Key, ref.Value) + if !valid { t.Fatalf("Invalid proof: %v", err) } } From 718e9e24a6edc77a82c0b2d3a42e51ec8c04c920 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Mon, 21 Oct 2024 17:12:11 +0200 Subject: [PATCH 08/10] Update go/ics23.go --- go/ics23.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go/ics23.go b/go/ics23.go index 8e7f8563..b278cc3b 100644 --- a/go/ics23.go +++ b/go/ics23.go @@ -30,7 +30,7 @@ import ( // 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 successfully iff +// VerifyMembership returns true iff // 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 { From c08b737d9d35350ed81f030e8c58e29bc413aef4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Mon, 21 Oct 2024 17:44:34 +0200 Subject: [PATCH 09/10] refactor: remove unnecessary code --- go/ics23.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/go/ics23.go b/go/ics23.go index 8e7f8563..8995a324 100644 --- a/go/ics23.go +++ b/go/ics23.go @@ -61,10 +61,6 @@ func VerifyNonMembership(spec *ProofSpec, root CommitmentRoot, proof *Commitment return false } - if !isLeft(spec, np.Left, key) || !isRight(spec, np.Right, key) { - return false - } - return np.Verify(spec, root, key) == nil } From 2f768bef643deecedcfe7a03e0ccb49789537acc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Wed, 23 Oct 2024 11:37:33 +0200 Subject: [PATCH 10/10] lint: remove isLeft and isRight as they are unused now --- go/ics23.go | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/go/ics23.go b/go/ics23.go index ade9a319..51f23230 100644 --- a/go/ics23.go +++ b/go/ics23.go @@ -23,10 +23,6 @@ and determine neighbors */ package ics23 -import ( - "bytes" -) - // CommitmentRoot is a byte slice that represents the merkle root of a tree that can be used to validate proofs type CommitmentRoot []byte @@ -63,11 +59,3 @@ func VerifyNonMembership(spec *ProofSpec, root CommitmentRoot, proof *Commitment return np.Verify(spec, root, key) == nil } - -func isLeft(spec *ProofSpec, left *ExistenceProof, key []byte) bool { - return left == nil || bytes.Compare(keyForComparison(spec, left.Key), keyForComparison(spec, key)) < 0 -} - -func isRight(spec *ProofSpec, right *ExistenceProof, key []byte) bool { - return right == nil || bytes.Compare(keyForComparison(spec, right.Key), keyForComparison(spec, key)) > 0 -}