Skip to content

Commit

Permalink
Fix AP verification
Browse files Browse the repository at this point in the history
  • Loading branch information
vqhuy committed Nov 28, 2016
1 parent 5420200 commit 75cf9d7
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 52 deletions.
76 changes: 44 additions & 32 deletions merkletree/proof.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,24 @@ package merkletree

import (
"bytes"
"errors"

"github.com/coniks-sys/coniks-go/crypto"
"github.com/coniks-sys/coniks-go/utils"
)

var (
// ErrBindingsDiffer indicates that the value included in the proof
// is different from the expected value.
ErrBindingsDiffer = errors.New("[merkletree] The values included in the bindings are different")
// ErrIndicesMismatch indicates that there is a mismatch
// between the lookup index and the leaf index.
ErrIndicesMismatch = errors.New("[merkletree] The lookup index is inconsistent with the index of the proof node")
// ErrUnequalTreeHashes indicates that the hash computed from the authentication path
// and the hash taken from the signed tree root are different.
ErrUnequalTreeHashes = errors.New("[merkletree] The hashes computed from the authentication path and the STR are unequal")
)

// ProofNode can be a user node or an empty node,
// which is included in the returned AuthenticationPath
// of a given index. The type of that node can be determined
Expand Down Expand Up @@ -80,42 +93,41 @@ func (ap *AuthenticationPath) authPathHash() []byte {
return hash
}

// VerifyBinding verifies the value of the proof node
// of the authentication path. It also verifies the commitment
// of the proof node if ap is a proof of inclusion.
func (ap *AuthenticationPath) VerifyBinding(key, value []byte) bool {
return (ap.ProofType() == ProofOfAbsence && ap.Leaf.Value == nil) ||
(bytes.Equal(ap.Leaf.Value, value) && ap.Leaf.Commitment.Verify(key, value))
}

// VerifyIndex verifies the private index of the proof node.
//
// If the proof is a proof of absence, it checks if the index
// of the proof node and the lookup index match in the first
// l bits with l is the Level of the proof node.
// Verify first compares the lookup index with the leaf index.
// It expects the lookup index and the leaf index match in the
// first l bits with l is the Level of the proof node if ap is
// a proof of absence. It also verifies the value and
// the commitment (in case of the proof of inclusion).
// Finally, it recomputes the tree's root node from ap,
// and compares it to treeHash, which is taken from a STR.
// Specifically, treeHash has to come from the STR whose tree returns ap.
//
// If the proof is a proof of inclusion, it returns true immediately.
func (ap *AuthenticationPath) VerifyIndex() bool {
if ap.ProofType() == ProofOfInclusion {
return true
}
// Check if i and j match in the first l bits
indexBits := utils.ToBits(ap.Leaf.Index)
lookupIndexBits := utils.ToBits(ap.LookupIndex)
for i := 0; i < int(ap.Leaf.Level); i++ {
if indexBits[i] != lookupIndexBits[i] {
return false
// This should be called after the VRF index is verified successfully.
func (ap *AuthenticationPath) Verify(key, value, treeHash []byte) error {
if ap.ProofType() == ProofOfAbsence {
// Check if i and j match in the first l bits
indexBits := utils.ToBits(ap.Leaf.Index)
lookupIndexBits := utils.ToBits(ap.LookupIndex)
for i := 0; i < int(ap.Leaf.Level); i++ {
if indexBits[i] != lookupIndexBits[i] {
return ErrIndicesMismatch
}
}
if ap.Leaf.Value != nil {
return ErrBindingsDiffer
}
} else {
// Verify the key-value binding returned in the ProofNode
if !bytes.Equal(ap.Leaf.Value, value) ||
!ap.Leaf.Commitment.Verify(key, value) {
return ErrBindingsDiffer
}
}
return true
}

// VerifySTR recomputes the tree's root node from the authentication path,
// and compares it to treeHash, which is taken from a STR.
// Specifically, treeHash has to come from the STR whose tree returns
// the authentication path.
func (ap *AuthenticationPath) VerifySTR(treeHash []byte) bool {
return bytes.Equal(treeHash, ap.authPathHash())
if !bytes.Equal(treeHash, ap.authPathHash()) {
return ErrUnequalTreeHashes
}
return nil
}

func (ap *AuthenticationPath) ProofType() ProofType {
Expand Down
18 changes: 4 additions & 14 deletions merkletree/proof_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,6 @@ import (
"github.com/coniks-sys/coniks-go/utils"
)

func verifyAuthPath(ap *AuthenticationPath, key, value []byte, treehash []byte) bool {
if !ap.VerifyIndex() {
return false
}
if !ap.VerifyBinding(key, value) {
return false
}
return ap.VerifySTR(treehash)
}

func TestVerifyProof(t *testing.T) {
m, err := NewMerkleTree()
if err != nil {
Expand Down Expand Up @@ -73,7 +63,7 @@ func TestVerifyProof(t *testing.T) {
t.Fatal("Expect a proof of inclusion")
}
// verify auth path
if !verifyAuthPath(proof, []byte(key3), val3, m.hash) {
if proof.Verify([]byte(key3), val3, m.hash) != nil {
t.Error("Proof of inclusion verification failed.")
}

Expand All @@ -88,7 +78,7 @@ func TestVerifyProof(t *testing.T) {
!bytes.Equal(vrfPrivKey1.Compute([]byte("123")), proof.LookupIndex) {
t.Fatal("Expect a proof of absence")
}
if !verifyAuthPath(proof, []byte("123"), nil, m.hash) {
if proof.Verify([]byte("123"), nil, m.hash) != nil {
t.Error("Proof of absence verification failed.")
}
}
Expand Down Expand Up @@ -121,7 +111,7 @@ func TestVerifyProofSamePrefix(t *testing.T) {
utils.ToBytes(utils.ToBits(absentIndex)[:proof.Leaf.Level])) {
t.Fatal("Expect these indices share the same prefix in the first bit")
}
if !verifyAuthPath(proof, []byte("a"), nil, m.hash) {
if proof.Verify([]byte("a"), nil, m.hash) != nil {
t.Error("Proof of absence verification failed.")
}

Expand All @@ -138,7 +128,7 @@ func TestVerifyProofSamePrefix(t *testing.T) {
t.Fatal("Expect a proof of inclusion")
}
// step 2. verify auth path
if !verifyAuthPath(proof, []byte(key1), val1, m.hash) {
if proof.Verify([]byte(key1), val1, m.hash) != nil {
t.Error("Proof of inclusion verification failed.")
}
}
18 changes: 12 additions & 6 deletions protocol/consistencychecks.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,16 +218,22 @@ func verifyAuthPath(uname string, key []byte,
return CheckBadVRFProof
}

if !ap.VerifyIndex() {
return CheckBadLookupIndex
if key == nil {
// key is nil when the user does lookup for the first time.
// Accept the received key as TOFU
key = ap.Leaf.Value
}
if key != nil && !ap.VerifyBinding([]byte(uname), key) {

switch ap.Verify([]byte(uname), key, str.TreeHash) {
case m.ErrBindingsDiffer:
return CheckBindingsDiffer
}
if !ap.VerifySTR(str.TreeHash) {
case m.ErrIndicesMismatch:
return CheckBadLookupIndex
case m.ErrUnequalTreeHashes:
return CheckBadAuthPath
default:
return nil
}
return nil
}

func (cc *ConsistencyChecks) updateTBs(requestType int, msg *Response,
Expand Down

0 comments on commit 75cf9d7

Please sign in to comment.