diff --git a/balloon/hyper2/proof.go b/balloon/hyper2/proof.go index 18e635e80..a26330672 100644 --- a/balloon/hyper2/proof.go +++ b/balloon/hyper2/proof.go @@ -17,7 +17,10 @@ package hyper2 import ( + "bytes" + "github.com/bbva/qed/balloon/hyper2/navigation" + "github.com/bbva/qed/balloon/hyper2/pruning2" "github.com/bbva/qed/hashing" "github.com/bbva/qed/log" ) @@ -44,11 +47,19 @@ func (p QueryProof) Verify(key []byte, expectedRootHash hashing.Digest) (valid b log.Debugf("Verifying query proof for key %d", p.Key) - // build a visitable pruned tree and the visit it to recompute the root hash - // visitor := pruning.NewComputeHashVisitor(p) - // recomputed := pruning.PruneToVerify(key, p.Value, p.hasher.Len()-len(p.AuditPath)).Accept(visitor) + if len(p.AuditPath) == 0 { + // an empty audit path (empty tree) shows non-membersip for any key + return false + } + + // build a stack of operations and then interpret it to recompute the root hash + ops := pruning2.PruneToVerify(key, p.Value, p.hasher.Len()-uint16(len(p.AuditPath))) + ctx := &pruning2.Context{ + Hasher: p.hasher, + AuditPath: p.AuditPath, + } + recomputed := ops.Pop().Interpret(ops, ctx) - // return bytes.Equal(key, p.Key) && bytes.Equal(recomputed, expectedRootHash) - return true + return bytes.Equal(key, p.Key) && bytes.Equal(recomputed, expectedRootHash) } diff --git a/balloon/hyper2/proof_test.go b/balloon/hyper2/proof_test.go new file mode 100644 index 000000000..4b6c99679 --- /dev/null +++ b/balloon/hyper2/proof_test.go @@ -0,0 +1,78 @@ +/* + Copyright 2018 Banco Bilbao Vizcaya Argentaria, S.A. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package hyper2 + +import ( + "testing" + + "github.com/bbva/qed/hashing" + "github.com/stretchr/testify/assert" + + "github.com/bbva/qed/balloon/hyper2/navigation" +) + +func TestProofVerify(t *testing.T) { + + testCases := []struct { + key, value []byte + auditPath navigation.AuditPath + rootHash hashing.Digest + verifyResult bool + }{ + { + // verify key=0 with empty audit path + key: []byte{0}, + value: []byte{0}, + auditPath: navigation.AuditPath{}, + rootHash: hashing.Digest{0x0}, + verifyResult: false, + }, + { + // verify key=0 with empty audit path + key: []byte{0}, + value: []byte{0}, + auditPath: navigation.AuditPath{ + "0x80|7": hashing.Digest{0x0}, + "0x40|6": hashing.Digest{0x0}, + "0x20|5": hashing.Digest{0x0}, + "0x10|4": hashing.Digest{0x0}, + }, + rootHash: hashing.Digest{0x0}, + verifyResult: true, + }, + { + // verify key=0 with empty audit path + key: []byte{0}, + value: []byte{0}, + auditPath: navigation.AuditPath{ + "0x80|7": hashing.Digest{0x0}, + "0x40|6": hashing.Digest{0x0}, + "0x20|5": hashing.Digest{0x0}, + "0x10|4": hashing.Digest{0x0}, + }, + rootHash: hashing.Digest{0x1}, + verifyResult: false, + }, + } + + for i, c := range testCases { + proof := NewQueryProof(c.key, c.value, c.auditPath, hashing.NewFakeXorHasher()) + correct := proof.Verify(c.key, c.rootHash) + assert.Equalf(t, c.verifyResult, correct, "The verification result should match for test case %d", i) + } + +}