Skip to content

Commit

Permalink
Introduced skip pointers in merkletree2 (keybase#20218)
Browse files Browse the repository at this point in the history
* Introduced skip pointers in merkletree2, as well as MerkleExtensionProof and MerkleInclusionExtensionProof to check that those pointers.

* minor

* minor rename

* Added RootVersion and AddOnsHash fields and removed EncodingType in RootMetadata. Added some inline comments to clarify how extension proofs are verified

* readded encoding type

* allow nil proof when initialSeqno=finalSeqno in extension proofs and clarified a test
  • Loading branch information
AMarcedone authored Oct 15, 2019
1 parent d2c50b0 commit 2f525f3
Show file tree
Hide file tree
Showing 12 changed files with 1,132 additions and 108 deletions.
19 changes: 19 additions & 0 deletions go/libkb/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -2700,6 +2700,25 @@ func (c ChainLinkBadUnstubError) Error() string {

//============================================================================

// AppOutdatedError indicates that an operation failed because the client does
// not support some necessary feature and needs to be updated.
type AppOutdatedError struct {
cause error
}

func NewAppOutdatedError(cause error) AppOutdatedError {
return AppOutdatedError{cause: cause}
}

func (e AppOutdatedError) Error() string {
if e.cause != nil {
return fmt.Sprintf("AppOutdatedError: %v", e.cause.Error())
}
return fmt.Sprintf("AppOutdatedError")
}

//============================================================================

type PushSecretWithoutPasswordError struct {
msg string
}
Expand Down
2 changes: 2 additions & 0 deletions go/merkletree2/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,6 @@ type Encoder interface {

HashKeyValuePairWithKeySpecificSecret(KeyValuePair, KeySpecificSecret) (Hash, error)
HashKeyEncodedValuePairWithKeySpecificSecret(KeyEncodedValuePair, KeySpecificSecret) (Hash, error)

GetEncodingType() EncodingType
}
62 changes: 29 additions & 33 deletions go/merkletree2/encoders.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,17 @@ import (
type EncodingType uint8

const (
// For KeyValuePairs, the hash of the pair (k, v) is p(p(k, s), (k,v) ))
// where p = HMAC-SHA512-256 and s is a secret unique per Merkle seqno. For
// generic data structures, use SHA512-256 to hash the msgpack canonical
// encoding.
// For KeyValuePairs, the hash of the pair (k, v) is p(p(k, s), v )) where p
// = HMAC-SHA512-256 and s is a secret unique per Merkle seqno. Note that
// users learn k, v and p(k,s) but not s itself, so the hash is a commitment
// to the value only and not the key. However, the key is written and hashed
// as part of the merkle tree leaf node, so keybase cannot equivocate that.
// For generic data structures, this encoder uses SHA512-256 to hash the
// msgpack canonical encoding.
EncodingTypeBlindedSHA512_256v1 EncodingType = 1

// Simple messagepack encoding and SHA256_512 hashing. Used for testing.
EncodingTypeSHA512_256ForTesting EncodingType = 127
// Generic testing encoding.
EncodingTypeForTesting EncodingType = 127
)

func (e EncodingType) GetEncoder() Encoder {
Expand All @@ -36,9 +39,9 @@ type BlindedSHA512_256v1Encoder struct {
dec *codec.Decoder
}

var _ Encoder = BlindedSHA512_256v1Encoder{}
var _ Encoder = &BlindedSHA512_256v1Encoder{}

func NewBlindedSHA512_256v1Encoder() BlindedSHA512_256v1Encoder {
func NewBlindedSHA512_256v1Encoder() *BlindedSHA512_256v1Encoder {
var mh codec.MsgpackHandle
mh.WriteExt = true
mh.Canonical = true
Expand All @@ -47,65 +50,58 @@ func NewBlindedSHA512_256v1Encoder() BlindedSHA512_256v1Encoder {
mh2.WriteExt = true
mh2.Canonical = true

return BlindedSHA512_256v1Encoder{enc: codec.NewEncoderBytes(nil, &mh), dec: codec.NewDecoderBytes(nil, &mh2)}
return &BlindedSHA512_256v1Encoder{enc: codec.NewEncoderBytes(nil, &mh), dec: codec.NewDecoderBytes(nil, &mh2)}
}

func (e BlindedSHA512_256v1Encoder) Encode(o interface{}) (out []byte, err error) {
func (e *BlindedSHA512_256v1Encoder) Encode(o interface{}) (out []byte, err error) {
e.enc.ResetBytes(&out)
return out, e.enc.Encode(o)
}

func (e BlindedSHA512_256v1Encoder) Decode(dest interface{}, src []byte) error {
func (e *BlindedSHA512_256v1Encoder) Decode(dest interface{}, src []byte) error {
e.dec.ResetBytes(src)
return e.dec.Decode(dest)
}

func (e BlindedSHA512_256v1Encoder) EncodeAndHashGeneric(o interface{}) ([]byte, Hash, error) {
func (e *BlindedSHA512_256v1Encoder) EncodeAndHashGeneric(o interface{}) ([]byte, Hash, error) {
enc, err := e.Encode(o)
if err != nil {
return nil, nil, err
}
hasher := sha512.New512_256()
_, err = hasher.Write(enc)
if err != nil {
return nil, nil, err
}
// hasher.Write never errors.
_, _ = hasher.Write(enc)
return enc, hasher.Sum(nil), nil
}

func (e BlindedSHA512_256v1Encoder) HashKeyValuePairWithKeySpecificSecret(kvp KeyValuePair, kss KeySpecificSecret) (Hash, error) {
func (e *BlindedSHA512_256v1Encoder) HashKeyValuePairWithKeySpecificSecret(kvp KeyValuePair, kss KeySpecificSecret) (Hash, error) {
encVal, err := e.Encode(kvp.Value)
if err != nil {
return nil, err
}
return e.HashKeyEncodedValuePairWithKeySpecificSecret(KeyEncodedValuePair{Key: kvp.Key, Value: encVal}, kss)
}

func (e BlindedSHA512_256v1Encoder) HashKeyEncodedValuePairWithKeySpecificSecret(kevp KeyEncodedValuePair, kss KeySpecificSecret) (Hash, error) {
// TODO this double encoding is unnecessary. Consider removing.
enc, err := e.Encode(kevp)
if err != nil {
return nil, err
}
func (e *BlindedSHA512_256v1Encoder) HashKeyEncodedValuePairWithKeySpecificSecret(kevp KeyEncodedValuePair, kss KeySpecificSecret) (Hash, error) {
hasher := hmac.New(sha512.New512_256, kss)
_, err = hasher.Write(enc)
if err != nil {
return nil, err
}
// hasher.Write never errors.
_, _ = hasher.Write(kevp.Value)
return hasher.Sum(nil), nil
}

func (e BlindedSHA512_256v1Encoder) GenerateMasterSecret(Seqno) (MasterSecret, error) {
func (e *BlindedSHA512_256v1Encoder) GenerateMasterSecret(Seqno) (MasterSecret, error) {
secret := make([]byte, 32)
_, err := cryptorand.Read(secret)
return MasterSecret(secret), err
}

func (e BlindedSHA512_256v1Encoder) ComputeKeySpecificSecret(ms MasterSecret, k Key) KeySpecificSecret {
func (e *BlindedSHA512_256v1Encoder) ComputeKeySpecificSecret(ms MasterSecret, k Key) KeySpecificSecret {
hasher := hmac.New(sha512.New512_256, ms)
_, err := hasher.Write(k)
if err != nil {
panic("Error hashing")
}
// hasher.Write never errors.
_, _ = hasher.Write(k)
return hasher.Sum(nil)
}

func (e *BlindedSHA512_256v1Encoder) GetEncodingType() EncodingType {
return EncodingTypeBlindedSHA512_256v1
}
4 changes: 2 additions & 2 deletions go/merkletree2/encoders_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,9 +141,9 @@ func TestBlindedSHA512_256v1EncoderHardcodedValues(t *testing.T) {

h, err := encoder.HashKeyEncodedValuePairWithKeySpecificSecret(KeyEncodedValuePair{Key: Key([]byte{0x00, 0x01}), Value: encValue}, ks)
require.NoError(t, err)
require.EqualValues(t, []byte{0xab, 0x6c, 0xfe, 0x18, 0xda, 0x5f, 0x43, 0x52, 0x66, 0x6f, 0x1e, 0x56, 0xbe, 0x64, 0x1b, 0xd3, 0xf, 0x7, 0xa6, 0x32, 0x1b, 0xbd, 0xfa, 0x6f, 0xd2, 0xa1, 0x5a, 0xfd, 0xcb, 0xd5, 0xd3, 0xd3}, h)
require.EqualValues(t, []byte{0xc, 0x43, 0x55, 0x10, 0x67, 0xc3, 0x0, 0x13, 0x70, 0xfc, 0xab, 0x9e, 0xdd, 0x33, 0x70, 0x9a, 0x65, 0xb9, 0x8c, 0x34, 0xcc, 0xf0, 0x5, 0x23, 0x1d, 0x39, 0x2c, 0x0, 0x5d, 0xd4, 0xe9, 0x1d}, h)

h, err = encoder.HashKeyValuePairWithKeySpecificSecret(KeyValuePair{Key: Key([]byte{0x00, 0x01}), Value: value}, ks)
require.NoError(t, err)
require.EqualValues(t, []byte{0xab, 0x6c, 0xfe, 0x18, 0xda, 0x5f, 0x43, 0x52, 0x66, 0x6f, 0x1e, 0x56, 0xbe, 0x64, 0x1b, 0xd3, 0xf, 0x7, 0xa6, 0x32, 0x1b, 0xbd, 0xfa, 0x6f, 0xd2, 0xa1, 0x5a, 0xfd, 0xcb, 0xd5, 0xd3, 0xd3}, h)
require.EqualValues(t, []byte{0xc, 0x43, 0x55, 0x10, 0x67, 0xc3, 0x0, 0x13, 0x70, 0xfc, 0xab, 0x9e, 0xdd, 0x33, 0x70, 0x9a, 0x65, 0xb9, 0x8c, 0x34, 0xcc, 0xf0, 0x5, 0x23, 0x1d, 0x39, 0x2c, 0x0, 0x5d, 0xd4, 0xe9, 0x1d}, h)
}
8 changes: 8 additions & 0 deletions go/merkletree2/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ type StorageEngine interface {
// If there is no root for the specified Seqno, an InvalidSeqnoError is returned.
LookupRoot(logger.ContextInterface, Transaction, Seqno) (RootMetadata, error)

// LookupRoots returns the RootMetadata objects in the tree at the
// supplied Seqnos, ordered by seqno.
LookupRoots(logger.ContextInterface, Transaction, []Seqno) ([]RootMetadata, error)

// LookupRootHashes returns hashes of the RootMetadata in the tree at the
// corresponding Seqnos, ordered by seqno.
LookupRootHashes(logger.ContextInterface, Transaction, []Seqno) ([]Hash, error)

// LookupNode returns, for any position, the hash of the node with the
// highest Seqno s' <= s which was stored at position p. For example, if
// StoreNode(ctx, t, 5, p, hash5) and StoreNode(ctx, 6, p, hash6) and
Expand Down
Loading

0 comments on commit 2f525f3

Please sign in to comment.