From e015cc604de04c7d6356be6440fbdcdca0f700e5 Mon Sep 17 00:00:00 2001 From: Aditya Sripal Date: Fri, 22 May 2020 07:24:56 +0530 Subject: [PATCH 1/3] Add Calculate method to CommitmentProof --- go/proof.go | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/go/proof.go b/go/proof.go index a9c819612..f9a122c17 100644 --- a/go/proof.go +++ b/go/proof.go @@ -40,6 +40,34 @@ var TendermintSpec = &ProofSpec{ }, } +// Calculate determines the root hash that matches a given Commitment proof +// by type switching and calculating root based on proof type +// NOTE: Calculate will return the first calculated root in the proof, +// you must validate that all other embedded ExistenceProofs commit to the same root. +// This can be done with the Verify method +func (p *CommitmentProof) Calculate() (CommitmentRoot, error) { + switch v := p.Proof.(type) { + case *CommitmentProof_Exist: + return v.Exist.Calculate() + case *CommitmentProof_Nonexist: + return v.Nonexist.Left.Calculate() + case *CommitmentProof_Batch: + if len(v.Batch.GetEntries()) == 0 || v.Batch.GetEntries()[0] == nil { + return nil, errors.New("batch proof has empty entry") + } + bexist := v.Batch.GetEntries()[0].GetExist() + if bexist == nil { + return nil, errors.New("batch proof is not an existence proof") + } + return bexist.Calculate() + case *CommitmentProof_Compressed: + proof := Decompress(p) + return proof.Calculate() + default: + return nil, errors.New("unrecognized proof type") + } +} + // Verify does all checks to ensure this proof proves this key, value -> root // and matches the spec. func (p *ExistenceProof) Verify(spec *ProofSpec, root CommitmentRoot, key []byte, value []byte) error { From f8b2605c8507694153a6fbb11a8a68e0f0efe413 Mon Sep 17 00:00:00 2001 From: Aditya Sripal Date: Wed, 3 Jun 2020 14:49:11 -0400 Subject: [PATCH 2/3] fix nonexistence proof calculate --- go/proof.go | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/go/proof.go b/go/proof.go index f9a122c17..41f6f40eb 100644 --- a/go/proof.go +++ b/go/proof.go @@ -50,16 +50,17 @@ func (p *CommitmentProof) Calculate() (CommitmentRoot, error) { case *CommitmentProof_Exist: return v.Exist.Calculate() case *CommitmentProof_Nonexist: - return v.Nonexist.Left.Calculate() + 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") } - bexist := v.Batch.GetEntries()[0].GetExist() - if bexist == nil { - return nil, errors.New("batch proof is not an existence proof") + if e := v.Batch.GetEntries()[0].GetExist(); e != nil { + return e.Calculate() + } + if n := v.Batch.GetEntries()[0].GetNonexist(); n != nil { + return n.Calculate() } - return bexist.Calculate() case *CommitmentProof_Compressed: proof := Decompress(p) return proof.Calculate() @@ -118,6 +119,21 @@ func (p *ExistenceProof) Calculate() (CommitmentRoot, error) { return res, nil } +// Calculate determines the root hash that matches the given nonexistence rpoog. +// You must validate the result is what you have in a header. +// Returns error if the calculations cannot be performed. +func (p *NonExistenceProof) Calculate() (CommitmentRoot, error) { + // A Nonexist proof may have left or right proof nil + switch { + case p.Left != nil: + return p.Left.Calculate() + case p.Right != nil: + return p.Right.Calculate() + default: + return nil, errors.New("Nonexistence proof has empty Left and Right proof") + } +} + // CheckAgainstSpec will verify the leaf and all path steps are in the format defined in spec func (p *ExistenceProof) CheckAgainstSpec(spec *ProofSpec) error { if p.GetLeaf() == nil { From 423d6575e4c1db41393174eb9fdd6760a4d63ff7 Mon Sep 17 00:00:00 2001 From: Aditya Sripal Date: Wed, 3 Jun 2020 16:49:38 -0400 Subject: [PATCH 3/3] add calculate tests --- go/proof.go | 1 + go/vectors_test.go | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/go/proof.go b/go/proof.go index 41f6f40eb..d1e258f65 100644 --- a/go/proof.go +++ b/go/proof.go @@ -67,6 +67,7 @@ func (p *CommitmentProof) Calculate() (CommitmentRoot, error) { 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 diff --git a/go/vectors_test.go b/go/vectors_test.go index 13716e417..acdd50944 100644 --- a/go/vectors_test.go +++ b/go/vectors_test.go @@ -49,9 +49,19 @@ func TestVectors(t *testing.T) { } for _, tc := range cases { + 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) + // Test Calculate method + calculatedRoot, err := proof.Calculate() + if err != nil { + t.Fatal("proof.Calculate() returned error") + } + if !bytes.Equal(ref.RootHash, calculatedRoot) { + t.Fatalf("calculated root: %X did not match expected root: %X", calculatedRoot, ref.RootHash) + } + // Test Verify method if ref.Value == nil { // non-existence valid := VerifyNonMembership(tc.spec, ref.RootHash, proof, ref.Key) @@ -218,6 +228,7 @@ func TestBatchVectors(t *testing.T) { } for name, tc := range cases { + tc := tc t.Run(name, func(t *testing.T) { // try one proof if tc.ref.Value == nil {