diff --git a/cmd/blocktest/main.go b/cmd/blocktest/main.go
deleted file mode 100644
index acbadee773cf52c1b0f86a8fe639b7b1f576f9a2..0000000000000000000000000000000000000000
--- a/cmd/blocktest/main.go
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
-	This file is part of go-ethereum
-
-	go-ethereum is free software: you can redistribute it and/or modify
-	it under the terms of the GNU Lesser General Public License as published by
-	the Free Software Foundation, either version 3 of the License, or
-	(at your option) any later version.
-
-	go-ethereum is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU Lesser General Public License
-	along with go-ethereum.  If not, see <http://www.gnu.org/licenses/>.
-*/
-/**
- * @authors
- * 	Gustav Simonsson <gustav.simonsson@gmail.com>
- * @date 2015
- *
- */
-
-package main
-
-import (
-	"bytes"
-	"encoding/hex"
-	"encoding/json"
-	"flag"
-	"fmt"
-	"io/ioutil"
-	"log"
-	"math/big"
-	"os"
-	"runtime"
-	"strings"
-
-	"github.com/ethereum/go-ethereum/cmd/utils"
-	"github.com/ethereum/go-ethereum/core"
-	types "github.com/ethereum/go-ethereum/core/types"
-	"github.com/ethereum/go-ethereum/ethdb"
-	"github.com/ethereum/go-ethereum/event"
-	"github.com/ethereum/go-ethereum/logger"
-	"github.com/ethereum/go-ethereum/rlp"
-)
-
-type Account struct {
-	Balance string
-	Code    string
-	Nonce   string
-	Storage map[string]string
-}
-
-type BlockHeader struct {
-	Bloom            string
-	Coinbase         string
-	Difficulty       string
-	ExtraData        string
-	GasLimit         string
-	GasUsed          string
-	MixHash          string
-	Nonce            string
-	Number           string
-	ParentHash       string
-	ReceiptTrie      string
-	SeedHash         string
-	StateRoot        string
-	Timestamp        string
-	TransactionsTrie string
-	UncleHash        string
-}
-
-type Tx struct {
-	Data     string
-	GasLimit string
-	GasPrice string
-	Nonce    string
-	R        string
-	S        string
-	To       string
-	V        string
-	Value    string
-}
-
-type Block struct {
-	BlockHeader  BlockHeader
-	Rlp          string
-	Transactions []Tx
-	UncleHeaders []string
-}
-
-type Test struct {
-	Blocks             []Block
-	GenesisBlockHeader BlockHeader
-	Pre                map[string]Account
-}
-
-func main() {
-	flag.Usage = func() {
-		fmt.Fprintf(os.Stderr, "%s <testfile>\n", os.Args[0])
-		flag.PrintDefaults()
-	}
-	flag.Parse()
-
-	runtime.GOMAXPROCS(runtime.NumCPU())
-	logger.AddLogSystem(logger.NewStdLogSystem(os.Stderr, log.LstdFlags, logger.DebugDetailLevel))
-	defer func() { logger.Flush() }()
-
-	if len(os.Args) < 2 {
-		utils.Fatalf("Please specify a test file as the first argument.")
-	}
-	blocks, err := loadBlocksFromTestFile(os.Args[1])
-	if err != nil {
-		utils.Fatalf("Could not load blocks: %v", err)
-	}
-
-	chain := memchain()
-	chain.ResetWithGenesisBlock(blocks[0])
-	if err = chain.InsertChain(types.Blocks{blocks[1]}); err != nil {
-		utils.Fatalf("Error: %v", err)
-	} else {
-		fmt.Println("PASS")
-	}
-}
-
-func memchain() *core.ChainManager {
-	blockdb, err := ethdb.NewMemDatabase()
-	if err != nil {
-		utils.Fatalf("Could not create in-memory database: %v", err)
-	}
-	statedb, err := ethdb.NewMemDatabase()
-	if err != nil {
-		utils.Fatalf("Could not create in-memory database: %v", err)
-	}
-	return core.NewChainManager(blockdb, statedb, new(event.TypeMux))
-}
-
-func loadBlocksFromTestFile(filePath string) (blocks types.Blocks, err error) {
-	fileContent, err := ioutil.ReadFile(filePath)
-	if err != nil {
-		return
-	}
-	bt := make(map[string]Test)
-	if err = json.Unmarshal(fileContent, &bt); err != nil {
-		return
-	}
-
-	// TODO: support multiple blocks; loop over all blocks
-	gbh := new(types.Header)
-
-	// Let's use slighlty different namings for the same things, because that's awesome.
-	gbh.ParentHash, err = hex_decode(bt["SimpleTx"].GenesisBlockHeader.ParentHash)
-	gbh.UncleHash, err = hex_decode(bt["SimpleTx"].GenesisBlockHeader.UncleHash)
-	gbh.Coinbase, err = hex_decode(bt["SimpleTx"].GenesisBlockHeader.Coinbase)
-	gbh.Root, err = hex_decode(bt["SimpleTx"].GenesisBlockHeader.StateRoot)
-	gbh.TxHash, err = hex_decode(bt["SimpleTx"].GenesisBlockHeader.TransactionsTrie)
-	gbh.ReceiptHash, err = hex_decode(bt["SimpleTx"].GenesisBlockHeader.ReceiptTrie)
-	gbh.Bloom, err = hex_decode(bt["SimpleTx"].GenesisBlockHeader.Bloom)
-
-	gbh.MixDigest, err = hex_decode(bt["SimpleTx"].GenesisBlockHeader.MixHash)
-	//gbh.SeedHash, err = hex_decode(bt["SimpleTx"].GenesisBlockHeader.SeedHash)
-
-	d, _ := new(big.Int).SetString(bt["SimpleTx"].GenesisBlockHeader.Difficulty, 10)
-	gbh.Difficulty = d
-
-	n, _ := new(big.Int).SetString(bt["SimpleTx"].GenesisBlockHeader.Number, 10)
-	gbh.Number = n
-
-	gl, _ := new(big.Int).SetString(bt["SimpleTx"].GenesisBlockHeader.GasLimit, 10)
-	gbh.GasLimit = gl
-
-	gu, _ := new(big.Int).SetString(bt["SimpleTx"].GenesisBlockHeader.GasUsed, 10)
-	gbh.GasUsed = gu
-
-	ts, _ := new(big.Int).SetString(bt["SimpleTx"].GenesisBlockHeader.Timestamp, 0)
-	gbh.Time = ts.Uint64()
-
-	extra, err := hex_decode(bt["SimpleTx"].GenesisBlockHeader.ExtraData)
-	gbh.Extra = string(extra) // TODO: change ExtraData to byte array
-
-	nonce, _ := hex_decode(bt["SimpleTx"].GenesisBlockHeader.Nonce)
-	gbh.Nonce = nonce
-
-	if err != nil {
-		return
-	}
-
-	gb := types.NewBlockWithHeader(gbh)
-	//gb.uncles = *new([]*types.Header)
-	//gb.transactions = *new(types.Transactions)
-	gb.Td = new(big.Int)
-	gb.Reward = new(big.Int)
-
-	testBlock := new(types.Block)
-
-	rlpBytes, err := hex_decode(bt["SimpleTx"].Blocks[0].Rlp)
-	err = rlp.Decode(bytes.NewReader(rlpBytes), &testBlock)
-	if err != nil {
-		return
-	}
-
-	blocks = types.Blocks{
-		gb,
-		testBlock,
-	}
-
-	return
-}
-
-func hex_decode(s string) (res []byte, err error) {
-	return hex.DecodeString(strings.TrimPrefix(s, "0x"))
-}
diff --git a/common/rlp.go b/common/rlp.go
index 602f13202381594bd16de8a2fde7318aa3672dd7..06ac410e95d4af16abd18e969aed5599b58c064b 100644
--- a/common/rlp.go
+++ b/common/rlp.go
@@ -112,7 +112,7 @@ func Encode(object interface{}) []byte {
 	if object != nil {
 		switch t := object.(type) {
 		case *Value:
-			buff.Write(Encode(t.Raw()))
+			buff.Write(Encode(t.Val))
 		case RlpEncodable:
 			buff.Write(Encode(t.RlpData()))
 		// Code dup :-/
diff --git a/common/rlp_test.go b/common/rlp_test.go
index 16a3553d753bf390b3e89168467dbe97675ab02a..2a55da92858f33a7072f3c02562bcfca0b86407a 100644
--- a/common/rlp_test.go
+++ b/common/rlp_test.go
@@ -5,6 +5,8 @@ import (
 	"math/big"
 	"reflect"
 	"testing"
+
+	"github.com/ethereum/go-ethereum/rlp"
 )
 
 func TestNonInterfaceSlice(t *testing.T) {
@@ -19,13 +21,16 @@ func TestNonInterfaceSlice(t *testing.T) {
 
 func TestRlpValueEncoding(t *testing.T) {
 	val := EmptyValue()
-	val.AppendList().Append(1).Append(2).Append(3)
-	val.Append("4").AppendList().Append(5)
+	val.AppendList().Append(byte(1)).Append(byte(2)).Append(byte(3))
+	val.Append("4").AppendList().Append(byte(5))
 
-	res := val.Encode()
+	res, err := rlp.EncodeToBytes(val)
+	if err != nil {
+		t.Fatalf("encode error: %v", err)
+	}
 	exp := Encode([]interface{}{[]interface{}{1, 2, 3}, "4", []interface{}{5}})
 	if bytes.Compare(res, exp) != 0 {
-		t.Errorf("expected %q, got %q", res, exp)
+		t.Errorf("expected %x, got %x", exp, res)
 	}
 }
 
@@ -57,9 +62,7 @@ func TestValueSlice(t *testing.T) {
 func TestLargeData(t *testing.T) {
 	data := make([]byte, 100000)
 	enc := Encode(data)
-	value := NewValue(enc)
-	value.Decode()
-
+	value := NewValueFromBytes(enc)
 	if value.Len() != len(data) {
 		t.Error("Expected data to be", len(data), "got", value.Len())
 	}
@@ -133,15 +136,16 @@ func TestEncodeDecodeBigInt(t *testing.T) {
 }
 
 func TestEncodeDecodeBytes(t *testing.T) {
-	b := NewValue([]interface{}{[]byte{1, 2, 3, 4, 5}, byte(6)})
-	val := NewValueFromBytes(b.Encode())
-	if !b.Cmp(val) {
-		t.Errorf("Expected %v, got %v", val, b)
+	bv := NewValue([]interface{}{[]byte{1, 2, 3, 4, 5}, []byte{6}})
+	b, _ := rlp.EncodeToBytes(bv)
+	val := NewValueFromBytes(b)
+	if !bv.Cmp(val) {
+		t.Errorf("Expected %#v, got %#v", bv, val)
 	}
 }
 
 func TestEncodeZero(t *testing.T) {
-	b := NewValue(0).Encode()
+	b, _ := rlp.EncodeToBytes(NewValue(0))
 	exp := []byte{0xc0}
 	if bytes.Compare(b, exp) == 0 {
 		t.Error("Expected", exp, "got", b)
diff --git a/common/value.go b/common/value.go
index 72a123772cc6063b5a70bb9319d562d162ee381f..c3893d565de3505a787dacde3a12c1ac4b2f83f1 100644
--- a/common/value.go
+++ b/common/value.go
@@ -3,18 +3,30 @@ package common
 import (
 	"bytes"
 	"fmt"
+	"io"
 	"math/big"
 	"reflect"
 	"strconv"
+
+	"github.com/ethereum/go-ethereum/rlp"
 )
 
-// Data values are returned by the rlp decoder. The data values represents
-// one item within the rlp data structure. It's responsible for all the casting
-// It always returns something valid
-type Value struct {
-	Val  interface{}
-	kind reflect.Value
-}
+// Value can hold values of certain basic types and provides ways to
+// convert between types without bothering to check whether the
+// conversion is actually meaningful.
+//
+// It currently supports the following types:
+//
+//    - int{,8,16,32,64}
+//    - uint{,8,16,32,64}
+//    - *big.Int
+//    - []byte, string
+//    - []interface{}
+//
+// Value is useful whenever you feel that Go's types limit your
+// ability to express yourself. In these situations, use Value and
+// forget about this strong typing nonsense.
+type Value struct{ Val interface{} }
 
 func (val *Value) String() string {
 	return fmt.Sprintf("%x", val.Val)
@@ -38,7 +50,6 @@ func (val *Value) IsNil() bool {
 }
 
 func (val *Value) Len() int {
-	//return val.kind.Len()
 	if data, ok := val.Val.([]interface{}); ok {
 		return len(data)
 	}
@@ -46,14 +57,6 @@ func (val *Value) Len() int {
 	return len(val.Bytes())
 }
 
-func (val *Value) Raw() interface{} {
-	return val.Val
-}
-
-func (val *Value) Interface() interface{} {
-	return val.Val
-}
-
 func (val *Value) Uint() uint64 {
 	if Val, ok := val.Val.(uint8); ok {
 		return uint64(Val)
@@ -260,26 +263,34 @@ func (self *Value) DeepCmp(o *Value) bool {
 	return bytes.Compare(self.Bytes(), o.Bytes()) == 0
 }
 
-func (val *Value) Encode() []byte {
-	return Encode(val.Val)
+func (self *Value) DecodeRLP(s *rlp.Stream) error {
+	var v interface{}
+	if err := s.Decode(&v); err != nil {
+		return err
+	}
+	self.Val = v
+	return nil
 }
 
-// Assume that the data we have is encoded
-func (self *Value) Decode() {
-	v, _ := Decode(self.Bytes(), 0)
-	self.Val = v
-	//self.Val = DecodeWithReader(bytes.NewBuffer(self.Bytes()))
+func (self *Value) EncodeRLP(w io.Writer) error {
+	if self == nil {
+		w.Write(rlp.EmptyList)
+		return nil
+	} else {
+		return rlp.Encode(w, self.Val)
+	}
 }
 
+// NewValueFromBytes decodes RLP data.
+// The contained value will be nil if data contains invalid RLP.
 func NewValueFromBytes(data []byte) *Value {
+	v := new(Value)
 	if len(data) != 0 {
-		value := NewValue(data)
-		value.Decode()
-
-		return value
+		if err := rlp.DecodeBytes(data, v); err != nil {
+			v.Val = nil
+		}
 	}
-
-	return NewValue(nil)
+	return v
 }
 
 // Value setters
diff --git a/common/value_test.go b/common/value_test.go
index 09d37802d52a98984c384d620d98f7c707892240..38a0e98434100d598153ae0c37c9cfd4e601c7fe 100644
--- a/common/value_test.go
+++ b/common/value_test.go
@@ -35,7 +35,7 @@ func (s *ValueSuite) TestValueTypes(c *checker.C) {
 
 	c.Assert(str.Str(), checker.Equals, strExp)
 	c.Assert(num.Uint(), checker.Equals, numExp)
-	c.Assert(NewValue(inter.Interface()).Cmp(NewValue(interExp)), checker.Equals, true)
+	c.Assert(NewValue(inter.Val).Cmp(NewValue(interExp)), checker.Equals, true)
 	c.Assert(byt.Bytes(), checker.DeepEquals, bytExp)
 	c.Assert(bigInt.BigInt(), checker.DeepEquals, bigExp)
 }
diff --git a/crypto/keypair.go b/crypto/keypair.go
index 6702e6595e063b1f4e779205959d71858ca3ea78..cc17328cb0411914896634ab7d5bfd691ad10be8 100644
--- a/crypto/keypair.go
+++ b/crypto/keypair.go
@@ -3,8 +3,8 @@ package crypto
 import (
 	"strings"
 
-	"github.com/ethereum/go-ethereum/crypto/secp256k1"
 	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/crypto/secp256k1"
 )
 
 type KeyPair struct {
@@ -48,11 +48,3 @@ func (k *KeyPair) Mnemonic() string {
 func (k *KeyPair) AsStrings() (string, string, string, string) {
 	return k.Mnemonic(), common.Bytes2Hex(k.Address()), common.Bytes2Hex(k.PrivateKey), common.Bytes2Hex(k.PublicKey)
 }
-
-func (k *KeyPair) RlpEncode() []byte {
-	return k.RlpValue().Encode()
-}
-
-func (k *KeyPair) RlpValue() *common.Value {
-	return common.NewValue(k.PrivateKey)
-}
diff --git a/eth/backend.go b/eth/backend.go
index b086d6a562f10141326a5d71361199ade555871f..141c6c6055abd11b18d2d9442c37706d7b0cdec6 100644
--- a/eth/backend.go
+++ b/eth/backend.go
@@ -206,7 +206,7 @@ func New(config *Config) (*Ethereum, error) {
 	ethProto := EthProtocol(config.ProtocolVersion, config.NetworkId, eth.txPool, eth.chainManager, eth.blockPool)
 	protocols := []p2p.Protocol{ethProto}
 	if config.Shh {
-		//protocols = append(protocols, eth.whisper.Protocol())
+		protocols = append(protocols, eth.whisper.Protocol())
 	}
 
 	eth.net = &p2p.Server{
diff --git a/ethdb/memory_database.go b/ethdb/memory_database.go
index d914f47f89d2ea42069c232758ec10eb35faa6ea..d4988d0d8ec69f7760bcc4e43c21fffeb1299c86 100644
--- a/ethdb/memory_database.go
+++ b/ethdb/memory_database.go
@@ -49,7 +49,7 @@ func (db *MemDatabase) Print() {
 	for key, val := range db.db {
 		fmt.Printf("%x(%d): ", key, len(key))
 		node := common.NewValueFromBytes(val)
-		fmt.Printf("%q\n", node.Interface())
+		fmt.Printf("%q\n", node.Val)
 	}
 }
 
diff --git a/rlp/decode.go b/rlp/decode.go
index 6d7e670c24ad8a26fe9e23eed585e21dc146acbe..0fde0a947373f95634240e821d41d12b3ee11ca7 100644
--- a/rlp/decode.go
+++ b/rlp/decode.go
@@ -367,7 +367,12 @@ func makePtrDecoder(typ reflect.Type) (decoder, error) {
 	dec := func(s *Stream, val reflect.Value) (err error) {
 		_, size, err := s.Kind()
 		if err != nil || size == 0 && s.byteval == 0 {
-			val.Set(reflect.Zero(typ)) // set to nil
+			// rearm s.Kind. This is important because the input
+			// position must advance to the next value even though
+			// we don't read anything.
+			s.kind = -1
+			// set the pointer to nil.
+			val.Set(reflect.Zero(typ))
 			return err
 		}
 		newval := val
@@ -535,6 +540,31 @@ func (s *Stream) Bytes() ([]byte, error) {
 	}
 }
 
+// Raw reads a raw encoded value including RLP type information.
+func (s *Stream) Raw() ([]byte, error) {
+	kind, size, err := s.Kind()
+	if err != nil {
+		return nil, err
+	}
+	if kind == Byte {
+		s.kind = -1 // rearm Kind
+		return []byte{s.byteval}, nil
+	}
+	// the original header has already been read and is no longer
+	// available. read content and put a new header in front of it.
+	start := headsize(size)
+	buf := make([]byte, uint64(start)+size)
+	if err := s.readFull(buf[start:]); err != nil {
+		return nil, err
+	}
+	if kind == String {
+		puthead(buf, 0x80, 0xB8, size)
+	} else {
+		puthead(buf, 0xC0, 0xF7, size)
+	}
+	return buf, nil
+}
+
 var errUintOverflow = errors.New("rlp: uint overflow")
 
 // Uint reads an RLP string of up to 8 bytes and returns its contents
diff --git a/rlp/decode_test.go b/rlp/decode_test.go
index 9f66840b19396163189c9e7f567bd1b56a2bd426..a18ff1d080dfb43193a0785f7fa41aa0f18a8afe 100644
--- a/rlp/decode_test.go
+++ b/rlp/decode_test.go
@@ -39,7 +39,7 @@ func TestStreamKind(t *testing.T) {
 		s := NewStream(bytes.NewReader(unhex(test.input)))
 		kind, len, err := s.Kind()
 		if err != nil {
-			t.Errorf("test %d: Type returned error: %v", i, err)
+			t.Errorf("test %d: Kind returned error: %v", i, err)
 			continue
 		}
 		if kind != test.wantKind {
@@ -93,6 +93,23 @@ func TestStreamErrors(t *testing.T) {
 		{"C3C2010201", calls{"List", "List", "Uint", "Uint", "ListEnd", "Uint"}, EOL},
 		{"00", calls{"ListEnd"}, errNotInList},
 		{"C40102", calls{"List", "Uint", "ListEnd"}, errNotAtEOL},
+
+		// This test verifies that the input position is advanced
+		// correctly when calling Bytes for empty strings. Kind can be called
+		// any number of times in between and doesn't advance.
+		{"C3808080", calls{
+			"List",  // enter the list
+			"Bytes", // past first element
+
+			"Kind", "Kind", "Kind", // this shouldn't advance
+
+			"Bytes", // past second element
+
+			"Kind", "Kind", // can't hurt to try
+
+			"Bytes", // past final element
+			"Bytes", // this one should fail
+		}, EOL},
 	}
 
 testfor:
@@ -148,6 +165,20 @@ func TestStreamList(t *testing.T) {
 	}
 }
 
+func TestStreamRaw(t *testing.T) {
+	s := NewStream(bytes.NewReader(unhex("C58401010101")))
+	s.List()
+
+	want := unhex("8401010101")
+	raw, err := s.Raw()
+	if err != nil {
+		t.Fatal(err)
+	}
+	if !bytes.Equal(want, raw) {
+		t.Errorf("raw mismatch: got %x, want %x", raw, want)
+	}
+}
+
 func TestDecodeErrors(t *testing.T) {
 	r := bytes.NewReader(nil)
 
@@ -314,6 +345,9 @@ var decodeTests = []decodeTest{
 	{input: "C109", ptr: new(*[]uint), value: &[]uint{9}},
 	{input: "C58403030303", ptr: new(*[][]byte), value: &[][]byte{{3, 3, 3, 3}}},
 
+	// check that input position is advanced also for empty values.
+	{input: "C3808005", ptr: new([]*uint), value: []*uint{nil, nil, uintp(5)}},
+
 	// pointer should be reset to nil
 	{input: "05", ptr: sharedPtr, value: uintp(5)},
 	{input: "80", ptr: sharedPtr, value: (*uint)(nil)},
diff --git a/rlp/encode.go b/rlp/encode.go
index 7ac74d8fb92f39e92b7d66ad5d1bbccad7ed9f28..289bc4eaaa1e0bcd8b41af158b2662cb2010c2d6 100644
--- a/rlp/encode.go
+++ b/rlp/encode.go
@@ -70,7 +70,7 @@ func (e flatenc) EncodeRLP(out io.Writer) error {
 	newhead := eb.lheads[prevnheads]
 	copy(eb.lheads[prevnheads:], eb.lheads[prevnheads+1:])
 	eb.lheads = eb.lheads[:len(eb.lheads)-1]
-	eb.lhsize -= newhead.tagsize()
+	eb.lhsize -= headsize(uint64(newhead.size))
 	return nil
 }
 
@@ -155,21 +155,29 @@ type listhead struct {
 // encode writes head to the given buffer, which must be at least
 // 9 bytes long. It returns the encoded bytes.
 func (head *listhead) encode(buf []byte) []byte {
-	if head.size < 56 {
-		buf[0] = 0xC0 + byte(head.size)
-		return buf[:1]
-	} else {
-		sizesize := putint(buf[1:], uint64(head.size))
-		buf[0] = 0xF7 + byte(sizesize)
-		return buf[:sizesize+1]
+	return buf[:puthead(buf, 0xC0, 0xF7, uint64(head.size))]
+}
+
+// headsize returns the size of a list or string header
+// for a value of the given size.
+func headsize(size uint64) int {
+	if size < 56 {
+		return 1
 	}
+	return 1 + intsize(size)
 }
 
-func (head *listhead) tagsize() int {
-	if head.size < 56 {
+// puthead writes a list or string header to buf.
+// buf must be at least 9 bytes long.
+func puthead(buf []byte, smalltag, largetag byte, size uint64) int {
+	if size < 56 {
+		buf[0] = smalltag + byte(size)
 		return 1
+	} else {
+		sizesize := putint(buf[1:], size)
+		buf[0] = largetag + byte(sizesize)
+		return sizesize + 1
 	}
-	return 1 + intsize(uint64(head.size))
 }
 
 func newencbuf() *encbuf {
diff --git a/whisper/envelope.go b/whisper/envelope.go
index 9ec9fc31857c340f456222eb85c4bf7b0ebcd5b0..20e3e6d395060f52cc890befdc13fca9c74942b1 100644
--- a/whisper/envelope.go
+++ b/whisper/envelope.go
@@ -18,26 +18,31 @@ const (
 
 type Envelope struct {
 	Expiry uint32 // Whisper protocol specifies int32, really should be int64
-	Ttl    uint32 // ^^^^^^
+	TTL    uint32 // ^^^^^^
 	Topics [][]byte
 	Data   []byte
 	Nonce  uint32
 
-	hash Hash
+	hash common.Hash
 }
 
-func (self *Envelope) Hash() Hash {
-	if self.hash == EmptyHash {
-		self.hash = H(crypto.Sha3(common.Encode(self)))
+func (self *Envelope) Hash() common.Hash {
+	if (self.hash == common.Hash{}) {
+		enc, _ := rlp.EncodeToBytes(self)
+		self.hash = crypto.Sha3Hash(enc)
 	}
-
 	return self.hash
 }
 
 func NewEnvelope(ttl time.Duration, topics [][]byte, data *Message) *Envelope {
 	exp := time.Now().Add(ttl)
-
-	return &Envelope{uint32(exp.Unix()), uint32(ttl.Seconds()), topics, data.Bytes(), 0, Hash{}}
+	return &Envelope{
+		Expiry: uint32(exp.Unix()),
+		TTL:    uint32(ttl.Seconds()),
+		Topics: topics,
+		Data:   data.Bytes(),
+		Nonce:  0,
+	}
 }
 
 func (self *Envelope) Seal(pow time.Duration) {
@@ -76,7 +81,8 @@ func (self *Envelope) Open(prv *ecdsa.PrivateKey) (msg *Message, err error) {
 func (self *Envelope) proveWork(dura time.Duration) {
 	var bestBit int
 	d := make([]byte, 64)
-	copy(d[:32], common.Encode(self.withoutNonce()))
+	enc, _ := rlp.EncodeToBytes(self.withoutNonce())
+	copy(d[:32], enc)
 
 	then := time.Now().Add(dura).UnixNano()
 	for n := uint32(0); time.Now().UnixNano() < then; {
@@ -96,39 +102,28 @@ func (self *Envelope) proveWork(dura time.Duration) {
 
 func (self *Envelope) valid() bool {
 	d := make([]byte, 64)
-	copy(d[:32], common.Encode(self.withoutNonce()))
+	enc, _ := rlp.EncodeToBytes(self.withoutNonce())
+	copy(d[:32], enc)
 	binary.BigEndian.PutUint32(d[60:], self.Nonce)
 	return common.FirstBitSet(common.BigD(crypto.Sha3(d))) > 0
 }
 
 func (self *Envelope) withoutNonce() interface{} {
-	return []interface{}{self.Expiry, self.Ttl, common.ByteSliceToInterface(self.Topics), self.Data}
+	return []interface{}{self.Expiry, self.TTL, self.Topics, self.Data}
 }
 
-func (self *Envelope) RlpData() interface{} {
-	return []interface{}{self.Expiry, self.Ttl, common.ByteSliceToInterface(self.Topics), self.Data, self.Nonce}
-}
+// rlpenv is an Envelope but is not an rlp.Decoder.
+// It is used for decoding because we need to
+type rlpenv Envelope
 
 func (self *Envelope) DecodeRLP(s *rlp.Stream) error {
-	var extenv struct {
-		Expiry uint32
-		Ttl    uint32
-		Topics [][]byte
-		Data   []byte
-		Nonce  uint32
+	raw, err := s.Raw()
+	if err != nil {
+		return err
 	}
-	if err := s.Decode(&extenv); err != nil {
+	if err := rlp.DecodeBytes(raw, (*rlpenv)(self)); err != nil {
 		return err
 	}
-
-	self.Expiry = extenv.Expiry
-	self.Ttl = extenv.Ttl
-	self.Topics = extenv.Topics
-	self.Data = extenv.Data
-	self.Nonce = extenv.Nonce
-
-	// TODO We should use the stream directly here.
-	self.hash = H(crypto.Sha3(common.Encode(self)))
-
+	self.hash = crypto.Sha3Hash(raw)
 	return nil
 }
diff --git a/whisper/peer.go b/whisper/peer.go
index ee5bffd0bdae3ce3ed327628bc8ce3c33c09e938..338166c25f3fe9e5d5d4b944e3ce68c1d347c2d0 100644
--- a/whisper/peer.go
+++ b/whisper/peer.go
@@ -10,7 +10,7 @@ import (
 )
 
 const (
-	protocolVersion = 0x02
+	protocolVersion uint64 = 0x02
 )
 
 type peer struct {
@@ -66,21 +66,18 @@ out:
 }
 
 func (self *peer) broadcast(envelopes []*Envelope) error {
-	envs := make([]interface{}, len(envelopes))
-	i := 0
-	for _, envelope := range envelopes {
-		if !self.known.Has(envelope.Hash()) {
-			envs[i] = envelope
-			self.known.Add(envelope.Hash())
-			i++
+	envs := make([]*Envelope, 0, len(envelopes))
+	for _, env := range envelopes {
+		if !self.known.Has(env.Hash()) {
+			envs = append(envs, env)
+			self.known.Add(env.Hash())
 		}
 	}
-
-	if i > 0 {
-		if err := p2p.Send(self.ws, envelopesMsg, envs[:i]); err != nil {
+	if len(envs) > 0 {
+		if err := p2p.Send(self.ws, envelopesMsg, envs); err != nil {
 			return err
 		}
-		self.peer.DebugDetailln("broadcasted", i, "message(s)")
+		self.peer.DebugDetailln("broadcasted", len(envs), "message(s)")
 	}
 	return nil
 }
diff --git a/whisper/sort.go b/whisper/sort.go
index 8c5b46e9e3437a9e69bea122043d6f07d1858263..313ba5ac0a63650b3d1ac863c93de808742a04f8 100644
--- a/whisper/sort.go
+++ b/whisper/sort.go
@@ -1,6 +1,10 @@
 package whisper
 
-import "sort"
+import (
+	"sort"
+
+	"github.com/ethereum/go-ethereum/common"
+)
 
 type sortedKeys struct {
 	k []int32
@@ -10,7 +14,7 @@ func (self *sortedKeys) Len() int           { return len(self.k) }
 func (self *sortedKeys) Less(i, j int) bool { return self.k[i] < self.k[j] }
 func (self *sortedKeys) Swap(i, j int)      { self.k[i], self.k[j] = self.k[j], self.k[i] }
 
-func sortKeys(m map[int32]Hash) []int32 {
+func sortKeys(m map[int32]common.Hash) []int32 {
 	sorted := new(sortedKeys)
 	sorted.k = make([]int32, len(m))
 	i := 0
diff --git a/whisper/sort_test.go b/whisper/sort_test.go
index 5d8177d4101441582575ac3b1ba2f77c61fd32ee..a61fde4c2d41656dae2ae9c4f25aadaece40fd01 100644
--- a/whisper/sort_test.go
+++ b/whisper/sort_test.go
@@ -1,13 +1,17 @@
 package whisper
 
-import "testing"
+import (
+	"testing"
+
+	"github.com/ethereum/go-ethereum/common"
+)
 
 func TestSorting(t *testing.T) {
-	m := map[int32]Hash{
-		1: HS("1"),
-		3: HS("3"),
-		2: HS("2"),
-		5: HS("5"),
+	m := map[int32]common.Hash{
+		1: {1},
+		3: {3},
+		2: {2},
+		5: {5},
 	}
 	exp := []int32{1, 2, 3, 5}
 	res := sortKeys(m)
diff --git a/whisper/whisper.go b/whisper/whisper.go
index 908df973c0f5e0b464a2a9c32a99a8733a627f68..dbd4fc85fd453e9ba41c0061c5e470d6e11aab84 100644
--- a/whisper/whisper.go
+++ b/whisper/whisper.go
@@ -1,12 +1,12 @@
 package whisper
 
 import (
-	"bytes"
 	"crypto/ecdsa"
 	"errors"
 	"sync"
 	"time"
 
+	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/crypto"
 	"github.com/ethereum/go-ethereum/crypto/ecies"
 	"github.com/ethereum/go-ethereum/event/filter"
@@ -15,26 +15,6 @@ import (
 	"gopkg.in/fatih/set.v0"
 )
 
-// MOVE ME
-type Hash struct {
-	hash string
-}
-
-var EmptyHash Hash
-
-func H(hash []byte) Hash {
-	return Hash{string(hash)}
-}
-func HS(hash string) Hash {
-	return Hash{hash}
-}
-
-func (self Hash) Compare(other Hash) int {
-	return bytes.Compare([]byte(self.hash), []byte(other.hash))
-}
-
-// MOVE ME END
-
 const (
 	statusMsg    = 0x0
 	envelopesMsg = 0x01
@@ -55,7 +35,7 @@ type Whisper struct {
 	filters  *filter.Filters
 
 	mmu      sync.RWMutex
-	messages map[Hash]*Envelope
+	messages map[common.Hash]*Envelope
 	expiry   map[uint32]*set.SetNonTS
 
 	quit chan struct{}
@@ -65,7 +45,7 @@ type Whisper struct {
 
 func New() *Whisper {
 	whisper := &Whisper{
-		messages: make(map[Hash]*Envelope),
+		messages: make(map[common.Hash]*Envelope),
 		filters:  filter.New(),
 		expiry:   make(map[uint32]*set.SetNonTS),
 		quit:     make(chan struct{}),
@@ -239,7 +219,7 @@ func (self *Whisper) expire() {
 		}
 
 		hashSet.Each(func(v interface{}) bool {
-			delete(self.messages, v.(Hash))
+			delete(self.messages, v.(common.Hash))
 			return true
 		})
 		self.expiry[then].Clear()