Skip to content

Commit

Permalink
Fix key proof serialization
Browse files Browse the repository at this point in the history
  • Loading branch information
cloudhead committed Dec 4, 2017
1 parent 3f47fc2 commit 19b2143
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 16 deletions.
38 changes: 32 additions & 6 deletions proof_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ type KeyProof interface {
Bytes() []byte
}

const (
// Used for serialization of proofs.
keyExistsMagicNumber = 0x50
keyAbsentMagicNumber = 0x51
)

// KeyExistsProof represents a proof of existence of a single key.
type KeyExistsProof struct {
RootHash data.Bytes `json:"root_hash"`
Expand All @@ -47,11 +53,11 @@ func (proof *KeyExistsProof) Verify(key []byte, value []byte, root []byte) error

// Bytes returns a go-wire binary serialization
func (proof *KeyExistsProof) Bytes() []byte {
return wire.BinaryBytes(proof)
return append([]byte{keyExistsMagicNumber}, wire.BinaryBytes(proof)...)
}

// ReadKeyExistsProof will deserialize a KeyExistsProof from bytes.
func ReadKeyExistsProof(data []byte) (*KeyExistsProof, error) {
// readKeyExistsProof will deserialize a KeyExistsProof from bytes.
func readKeyExistsProof(data []byte) (*KeyExistsProof, error) {
proof := new(KeyExistsProof)
err := wire.ReadBinaryBytes(data, &proof)
return proof, err
Expand Down Expand Up @@ -94,12 +100,32 @@ func (proof *KeyAbsentProof) Verify(key, value []byte, root []byte) error {

// Bytes returns a go-wire binary serialization
func (proof *KeyAbsentProof) Bytes() []byte {
return wire.BinaryBytes(proof)
return append([]byte{keyAbsentMagicNumber}, wire.BinaryBytes(proof)...)
}

// ReadKeyAbsentProof will deserialize a KeyAbsentProof from bytes.
func ReadKeyAbsentProof(data []byte) (*KeyAbsentProof, error) {
// readKeyAbsentProof will deserialize a KeyAbsentProof from bytes.
func readKeyAbsentProof(data []byte) (*KeyAbsentProof, error) {
proof := new(KeyAbsentProof)
err := wire.ReadBinaryBytes(data, &proof)
return proof, err
}

func ReadKeyProof(data []byte) (KeyProof, error) {
var err error
var n int

buf := bytes.NewBuffer(data)

b := wire.ReadByte(buf, &n, &err)
if err != nil {
return nil, err
}

switch b {
case keyExistsMagicNumber:
return readKeyExistsProof(buf.Bytes())
case keyAbsentMagicNumber:
return readKeyAbsentProof(buf.Bytes())
}
return nil, errors.New("unrecognized proof")
}
16 changes: 8 additions & 8 deletions proof_key_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,23 +23,23 @@ func TestSerializeProofs(t *testing.T) {
val, proof, err := tree.GetWithProof(key)
require.Nil(err, "%+v", err)
require.NotNil(val)

bin := proof.Bytes()
eproof, err := ReadKeyExistsProof(bin)
proof2, err := ReadKeyProof(bin)
require.Nil(err, "%+v", err)
require.NoError(eproof.Verify(key, val, root))
_, err = ReadKeyAbsentProof(bin)
require.NotNil(err)
require.NoError(proof2.Verify(key, val, root))

if _, ok := proof2.(*KeyExistsProof); !ok {
require.FailNow("Proof should be *KeyExistsProof")
}

// test with key absent
key = []byte{0x38}
val, proof, err = tree.GetWithProof(key)
require.Nil(err, "%+v", err)
require.Nil(val)
bin = proof.Bytes()
// I think this is ugly it works this way, but without type-bytes nothing we can do :(
// eproof, err = ReadKeyExistsProof(bin)
// require.NotNil(err)
aproof, err := ReadKeyAbsentProof(bin)
aproof, err := ReadKeyProof(bin)
require.Nil(err, "%+v", err)
require.NoError(aproof.Verify(key, val, root))
}
4 changes: 2 additions & 2 deletions testutils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,14 +125,14 @@ func testProof(t *testing.T, proof *KeyExistsProof, keyBytes, valueBytes, rootHa

// Write/Read then verify.
proofBytes := proof.Bytes()
proof2, err := ReadKeyExistsProof(proofBytes)
proof2, err := ReadKeyProof(proofBytes)
require.Nil(t, err, "Failed to read KeyExistsProof from bytes: %v", err)
require.NoError(t, proof2.Verify(keyBytes, valueBytes, proof.RootHash))

// Random mutations must not verify
for i := 0; i < 10; i++ {
badProofBytes := MutateByteSlice(proofBytes)
badProof, err := ReadKeyExistsProof(badProofBytes)
badProof, err := ReadKeyProof(badProofBytes)
// may be invalid... errors are okay
if err == nil {
assert.Error(t, badProof.Verify(keyBytes, valueBytes, rootHashBytes),
Expand Down

0 comments on commit 19b2143

Please sign in to comment.