diff --git a/account/account.go b/account/account.go
index b050c9079a16cd61c8153be3129cfbdbdadb3b2b..3aec5db87403458036df2a8d44e60411bf0b198f 100644
--- a/account/account.go
+++ b/account/account.go
@@ -14,19 +14,14 @@
 
 package account
 
-// TODO: [ben] Account and PrivateAccount need to become a pure interface
-// and then move the implementation to the manager types.
-// Eg, Geth has its accounts, different from BurrowMint
-
 import (
 	"bytes"
+	"encoding/json"
 	"fmt"
 	"io"
 
-	"github.com/hyperledger/burrow/common/sanity"
+	"github.com/hyperledger/burrow/binary"
 	ptypes "github.com/hyperledger/burrow/permission/types"
-
-	"github.com/tendermint/go-crypto"
 	"github.com/tendermint/go-wire"
 )
 
@@ -41,64 +36,319 @@ func SignBytes(chainID string, o Signable) []byte {
 	buf, n, err := new(bytes.Buffer), new(int), new(error)
 	o.WriteSignBytes(chainID, buf, n, err)
 	if *err != nil {
-		sanity.PanicCrisis(err)
+		panic(fmt.Sprintf("could not write sign bytes for a signable: %s", *err))
 	}
-
 	return buf.Bytes()
 }
 
-//-----------------------------------------------------------------------------
+type Addressable interface {
+	// Get the 20 byte EVM address of this account
+	Address() Address
+	// Public key from which the Address is derived
+	PublicKey() PublicKey
+}
 
-// Account resides in the application state, and is mutated by transactions
-// on the blockchain.
-// Serialized by wire.[read|write]Reflect
-type Account struct {
-	Address     []byte        `json:"address"`
-	PubKey      crypto.PubKey `json:"pub_key"`
-	Sequence    int           `json:"sequence"`
-	Balance     int64         `json:"balance"`
-	Code        []byte        `json:"code"`         // VM code
-	StorageRoot []byte        `json:"storage_root"` // VM storage merkle root.
+// The default immutable interface to an account
+type Account interface {
+	Addressable
+	// The value held by this account in terms of the chain-native token
+	Balance() uint64
+	// The EVM byte code held by this account (or equivalently, this contract)
+	Code() Bytecode
+	// The sequence number (or nonce) of this account, incremented each time a mutation of the
+	// Account is persisted to the blockchain state
+	Sequence() uint64
+	// The hash of all the values in this accounts storage (typically the root of some subtree
+	// in the merkle tree of global storage state)
+	StorageRoot() []byte
+	// The permission flags and roles for this account
+	Permissions() ptypes.AccountPermissions
+	// Obtain a deterministic serialisation of this account
+	// (i.e. update order and Go runtime independent)
+	Encode() []byte
+}
 
-	Permissions ptypes.AccountPermissions `json:"permissions"`
+type MutableAccount interface {
+	Account
+	// Set public key (needed for lazy initialisation), should also set the dependent address
+	SetPublicKey(pubKey PublicKey) MutableAccount
+	// Subtract amount from account balance (will panic if amount is greater than balance)
+	SubtractFromBalance(amount uint64) MutableAccount
+	// Add amount to balance (will panic if amount plus balance is a uint64 overflow)
+	AddToBalance(amount uint64) MutableAccount
+	// Set EVM byte code associated with account
+	SetCode(code []byte) MutableAccount
+	// Increment Sequence number by 1 (capturing the current Sequence number as the index for any pending mutations)
+	IncSequence() MutableAccount
+	// Set the storage root hash
+	SetStorageRoot(storageRoot []byte) MutableAccount
+	// Set account permissions
+	SetPermissions(permissions ptypes.AccountPermissions) MutableAccount
+	// Get a pointer this account's AccountPermissions in order to mutate them
+	MutablePermissions() *ptypes.AccountPermissions
+	// Create a complete copy of this MutableAccount that is itself mutable
+	Copy() MutableAccount
+}
+
+// -------------------------------------------------
+// ConcreteAccount
+
+// ConcreteAccount is the canonical serialisation and bash-in-place object for an Account
+type ConcreteAccount struct {
+	Address     Address
+	PublicKey   PublicKey
+	Balance     uint64
+	Code        Bytecode
+	Sequence    uint64
+	StorageRoot []byte
+	Permissions ptypes.AccountPermissions
+}
+
+func NewConcreteAccount(pubKey PublicKey) ConcreteAccount {
+	return ConcreteAccount{
+		Address:   pubKey.Address(),
+		PublicKey: pubKey,
+		// Since nil slices and maps compare differently to empty ones
+		Code:        Bytecode{},
+		StorageRoot: []byte{},
+		Permissions: ptypes.AccountPermissions{
+			Roles: []string{},
+		},
+	}
 }
 
-func (acc *Account) Copy() *Account {
+func NewConcreteAccountFromSecret(secret string) ConcreteAccount {
+	return NewConcreteAccount(PublicKeyFromPubKey(PrivateKeyFromSecret(secret).PubKey()))
+}
+
+// Return as immutable Account
+func (acc ConcreteAccount) Account() Account {
+	return concreteAccountWrapper{&acc}
+}
+
+// Return as mutable MutableAccount
+func (acc ConcreteAccount) MutableAccount() MutableAccount {
+	return concreteAccountWrapper{&acc}
+}
+
+func (acc *ConcreteAccount) Encode() []byte {
+	return wire.BinaryBytes(acc)
+}
+
+func (acc *ConcreteAccount) Copy() *ConcreteAccount {
 	accCopy := *acc
 	return &accCopy
 }
 
-func (acc *Account) String() string {
+func (acc *ConcreteAccount) String() string {
 	if acc == nil {
-		return "nil-Account"
+		return "Account{nil}"
 	}
-	return fmt.Sprintf("Account{%X:%v B:%v C:%v S:%X P:%s}", acc.Address, acc.PubKey, acc.Balance, len(acc.Code), acc.StorageRoot, acc.Permissions)
+
+	return fmt.Sprintf("Account{Address: %s; PublicKey: %v Balance: %v; CodeBytes: %v; StorageRoot: 0x%X; Permissions: %s}",
+		acc.Address, acc.PublicKey, acc.Balance, len(acc.Code), acc.StorageRoot, acc.Permissions)
 }
 
-func AccountEncoder(o interface{}, w io.Writer, n *int, err *error) {
-	wire.WriteBinary(o.(*Account), w, n, err)
+// ConcreteAccount
+// -------------------------------------------------
+// Conversions
+//
+// Using the naming convention is this package of 'As<Type>' being
+// a conversion from Account to <Type> and 'From<Type>' being conversion
+// from <Type> to Account. Conversions are done by copying
+
+// Returns a mutable, serialisable ConcreteAccount by copying from account
+func AsConcreteAccount(account Account) *ConcreteAccount {
+	if account == nil {
+		return nil
+	}
+	if ca, ok := account.(concreteAccountWrapper); ok {
+		return ca.ConcreteAccount
+	}
+	return &ConcreteAccount{
+		Address:     account.Address(),
+		PublicKey:   account.PublicKey(),
+		Balance:     account.Balance(),
+		Code:        account.Code(),
+		Sequence:    account.Sequence(),
+		StorageRoot: account.StorageRoot(),
+		Permissions: account.Permissions(),
+	}
+}
+
+// Creates an otherwise zeroed Account from an Addressable and returns it as MutableAccount
+func FromAddressable(addressable Addressable) MutableAccount {
+	return ConcreteAccount{
+		Address:   addressable.Address(),
+		PublicKey: addressable.PublicKey(),
+		// Since nil slices and maps compare differently to empty ones
+		Code:        Bytecode{},
+		StorageRoot: []byte{},
+		Permissions: ptypes.AccountPermissions{
+			Roles: []string{},
+		},
+	}.MutableAccount()
+}
+
+// Returns an immutable account by copying from account
+func AsAccount(account Account) Account {
+	if account == nil {
+		return nil
+	}
+	return AsConcreteAccount(account).Account()
+}
+
+// Returns a MutableAccount by copying from account
+func AsMutableAccount(account Account) MutableAccount {
+	if account == nil {
+		return nil
+	}
+	return AsConcreteAccount(account).MutableAccount()
+}
+
+func GetMutableAccount(getter Getter, address Address) (MutableAccount, error) {
+	acc, err := getter.GetAccount(address)
+	if err != nil {
+		return nil, err
+	}
+	// If we get get our own concreteAccountWrapper back we can save an unnecessary copy and just
+	// return since ConcreteAccount.Account() will have been used to produce it which will already
+	// have copied
+	caw, ok := acc.(concreteAccountWrapper)
+	if ok {
+		return caw, nil
+	}
+	return AsMutableAccount(acc), nil
 }
 
-func AccountDecoder(r io.Reader, n *int, err *error) interface{} {
-	return wire.ReadBinary(&Account{}, r, 0, n, err)
+//----------------------------------------------
+// concreteAccount Wrapper
+
+// concreteAccountWrapper wraps ConcreteAccount to provide a immutable read-only view
+// via its implementation of Account and a mutable implementation via its implementation of
+// MutableAccount
+type concreteAccountWrapper struct {
+	*ConcreteAccount `json:"unwrap"`
+}
+
+var _ Account = concreteAccountWrapper{}
+
+func (caw concreteAccountWrapper) Address() Address {
+	return caw.ConcreteAccount.Address
 }
 
-var AccountCodec = wire.Codec{
-	Encode: AccountEncoder,
-	Decode: AccountDecoder,
+func (caw concreteAccountWrapper) PublicKey() PublicKey {
+	return caw.ConcreteAccount.PublicKey
 }
 
-func EncodeAccount(acc *Account) []byte {
-	w := new(bytes.Buffer)
-	var n int
-	var err error
-	AccountEncoder(acc, w, &n, &err)
-	return w.Bytes()
+func (caw concreteAccountWrapper) Balance() uint64 {
+	return caw.ConcreteAccount.Balance
 }
 
-func DecodeAccount(accBytes []byte) *Account {
-	var n int
-	var err error
-	acc := AccountDecoder(bytes.NewBuffer(accBytes), &n, &err)
-	return acc.(*Account)
+func (caw concreteAccountWrapper) Code() Bytecode {
+	return caw.ConcreteAccount.Code
+}
+
+func (caw concreteAccountWrapper) Sequence() uint64 {
+	return caw.ConcreteAccount.Sequence
+}
+
+func (caw concreteAccountWrapper) StorageRoot() []byte {
+	return caw.ConcreteAccount.StorageRoot
+}
+
+func (caw concreteAccountWrapper) Permissions() ptypes.AccountPermissions {
+	return caw.ConcreteAccount.Permissions
+}
+
+func (caw concreteAccountWrapper) Encode() []byte {
+	return caw.ConcreteAccount.Encode()
+}
+
+func (caw concreteAccountWrapper) MarshalJSON() ([]byte, error) {
+	return json.Marshal(caw.ConcreteAccount)
+}
+
+// Account mutation via MutableAccount interface
+var _ MutableAccount = concreteAccountWrapper{}
+
+func (caw concreteAccountWrapper) SetPublicKey(pubKey PublicKey) MutableAccount {
+	caw.ConcreteAccount.PublicKey = pubKey
+	addressFromPubKey := pubKey.Address()
+	// We don't want the wrong public key to take control of an account so we panic here
+	if caw.ConcreteAccount.Address != addressFromPubKey {
+		panic(fmt.Errorf("attempt to set public key of account %s to %v, "+
+			"but that public key has address %s",
+			caw.ConcreteAccount.Address, pubKey, addressFromPubKey))
+	}
+	return caw
+}
+
+func (caw concreteAccountWrapper) SubtractFromBalance(amount uint64) MutableAccount {
+	if amount > caw.Balance() {
+		panic(fmt.Errorf("insufficient funds: attempt to subtract %v from the balance of %s",
+			amount, caw.ConcreteAccount))
+	}
+	caw.ConcreteAccount.Balance -= amount
+	return caw
+}
+
+func (caw concreteAccountWrapper) AddToBalance(amount uint64) MutableAccount {
+	if binary.IsUint64SumOverflow(caw.Balance(), amount) {
+		panic(fmt.Errorf("uint64 overflow: attempt to add %v to the balance of %s",
+			amount, caw.ConcreteAccount))
+	}
+	caw.ConcreteAccount.Balance += amount
+	return caw
+}
+
+func (caw concreteAccountWrapper) SetCode(code []byte) MutableAccount {
+	caw.ConcreteAccount.Code = code
+	return caw
+}
+
+func (caw concreteAccountWrapper) IncSequence() MutableAccount {
+	caw.ConcreteAccount.Sequence += 1
+	return caw
+}
+
+func (caw concreteAccountWrapper) SetStorageRoot(storageRoot []byte) MutableAccount {
+	caw.ConcreteAccount.StorageRoot = storageRoot
+	return caw
+}
+
+func (caw concreteAccountWrapper) SetPermissions(permissions ptypes.AccountPermissions) MutableAccount {
+	caw.ConcreteAccount.Permissions = permissions
+	return caw
+}
+
+func (caw concreteAccountWrapper) MutablePermissions() *ptypes.AccountPermissions {
+	return &caw.ConcreteAccount.Permissions
+}
+
+func (caw concreteAccountWrapper) Copy() MutableAccount {
+	return concreteAccountWrapper{caw.ConcreteAccount.Copy()}
+}
+
+var _ = wire.RegisterInterface(struct{ Account }{}, wire.ConcreteType{concreteAccountWrapper{}, 0x01})
+
+// concreteAccount Wrapper
+//----------------------------------------------
+// Encoding/decoding
+
+func Decode(accBytes []byte) (Account, error) {
+	ca, err := DecodeConcrete(accBytes)
+	if err != nil {
+		return nil, err
+	}
+	return ca.Account(), nil
+}
+
+func DecodeConcrete(accBytes []byte) (*ConcreteAccount, error) {
+	ca := new(concreteAccountWrapper)
+	err := wire.ReadBinaryBytes(accBytes, ca)
+	if err != nil {
+		return nil, fmt.Errorf("could not convert decoded account to *ConcreteAccount: %v", err)
+	}
+	return ca.ConcreteAccount, nil
 }
diff --git a/account/account_test.go b/account/account_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..07c30618ee9a195a012913e486e606eefa2db82c
--- /dev/null
+++ b/account/account_test.go
@@ -0,0 +1,105 @@
+// Copyright 2017 Monax Industries Limited
+//
+// 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 account
+
+import (
+	"testing"
+
+	"encoding/json"
+
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+	"github.com/tendermint/go-wire"
+)
+
+func TestAddress(t *testing.T) {
+	bs := []byte{
+		1, 2, 3, 4, 5,
+		1, 2, 3, 4, 5,
+		1, 2, 3, 4, 5,
+		1, 2, 3, 4, 5,
+	}
+	addr, err := AddressFromBytes(bs)
+	assert.NoError(t, err)
+	word256 := addr.Word256()
+	leadingZeroes := []byte{
+		0, 0, 0, 0,
+		0, 0, 0, 0,
+		0, 0, 0, 0,
+	}
+	assert.Equal(t, leadingZeroes, word256[:12])
+	addrFromWord256 := AddressFromWord256(word256)
+	assert.Equal(t, bs, addrFromWord256[:])
+	assert.Equal(t, addr, addrFromWord256)
+}
+
+func TestAccountSerialise(t *testing.T) {
+	type AccountContainingStruct struct {
+		Account Account
+		ChainID string
+	}
+
+	// This test is really testing this go wire declaration in account.go
+
+	acc := NewConcreteAccountFromSecret("Super Semi Secret")
+
+	// Go wire cannot serialise a top-level interface type it needs to be a field or sub-field of a struct
+	// at some depth. i.e. you MUST wrap an interface if you want it to be decoded (they do not document this)
+	var accStruct = AccountContainingStruct{
+		Account: acc.Account(),
+		ChainID: "TestChain",
+	}
+
+	// We will write into this
+	accStructOut := AccountContainingStruct{}
+
+	// We must pass in a value type to read from (accStruct), but provide a pointer type to write into (accStructout
+	wire.ReadBinaryBytes(wire.BinaryBytes(accStruct), &accStructOut)
+
+	assert.Equal(t, accStruct, accStructOut)
+}
+
+func TestDecodeConcrete(t *testing.T) {
+	concreteAcc := NewConcreteAccountFromSecret("Super Semi Secret")
+	acc := concreteAcc.Account()
+	encodedAcc := acc.Encode()
+	concreteAccOut, err := DecodeConcrete(encodedAcc)
+	require.NoError(t, err)
+	assert.Equal(t, concreteAcc, *concreteAccOut)
+	concreteAccOut, err = DecodeConcrete([]byte("flungepliffery munknut tolopops"))
+	assert.Error(t, err)
+}
+
+func TestDecode(t *testing.T) {
+	concreteAcc := NewConcreteAccountFromSecret("Super Semi Secret")
+	acc := concreteAcc.Account()
+	accOut, err := Decode(acc.Encode())
+	assert.NoError(t, err)
+	assert.Equal(t, concreteAcc, *AsConcreteAccount(accOut))
+
+	accOut, err = Decode([]byte("flungepliffery munknut tolopops"))
+	assert.Error(t, err)
+	assert.Nil(t, accOut)
+}
+
+func TestMarshalJSON(t *testing.T) {
+	concreteAcc := NewConcreteAccountFromSecret("Super Semi Secret")
+	concreteAcc.Code = []byte{60, 23, 45}
+	acc := concreteAcc.Account()
+	bs, err := json.Marshal(acc)
+	assert.Equal(t, `{"Address":"745BD6BE33020146E04FA0F293A41E389887DE86","PublicKey":{"type":"ed25519","data":"8CEBC16C166A0614AD7C8E330318E774E1A039321F17274DF12ABA3B1BFC773C"},"Balance":0,"Code":"3C172D","Sequence":0,"StorageRoot":"","Permissions":{"Base":{"Perms":0,"SetBit":0},"Roles":[]}}`,
+		string(bs))
+	assert.NoError(t, err)
+}
diff --git a/account/address.go b/account/address.go
new file mode 100644
index 0000000000000000000000000000000000000000..5b011e657d65de1d31fff8c1c09aaadd1f220da6
--- /dev/null
+++ b/account/address.go
@@ -0,0 +1,95 @@
+package account
+
+import (
+	"encoding/json"
+	"fmt"
+
+	"github.com/hyperledger/burrow/binary"
+	"github.com/tmthrgd/go-hex"
+	"golang.org/x/crypto/ripemd160"
+)
+
+type Address binary.Word160
+
+var ZeroAddress = Address{}
+
+func AddressFromBytes(addr []byte) (address Address, err error) {
+	if len(addr) != binary.Word160Length {
+		err = fmt.Errorf("slice passed as address '%X' has %d bytes but should have %d bytes",
+			addr, len(addr), binary.Word160Length)
+		// It is caller's responsibility to check for errors. If they ignore the error we'll assume they want the
+		// best-effort mapping of the bytes passed to an  address so we don't return here
+	}
+	copy(address[:], addr)
+	return
+}
+
+func AddressFromHexString(str string) (Address, error) {
+	bs, err := hex.DecodeString(str)
+	if err != nil {
+		return ZeroAddress, err
+	}
+	return AddressFromBytes(bs)
+}
+
+func MustAddressFromBytes(addr []byte) Address {
+	address, err := AddressFromBytes(addr)
+	if err != nil {
+		panic(fmt.Errorf("error reading address from bytes that caller does not expect: %s", err))
+	}
+	return address
+}
+
+func AddressFromWord256(addr binary.Word256) Address {
+	return Address(addr.Word160())
+}
+
+func (address Address) Word256() binary.Word256 {
+	return binary.Word160(address).Word256()
+}
+
+// Copy address and return a slice onto the copy
+func (address Address) Bytes() []byte {
+	addressCopy := address
+	return addressCopy[:]
+}
+
+func (address Address) String() string {
+	return hex.EncodeUpperToString(address[:])
+}
+
+func (address *Address) UnmarshalJSON(data []byte) error {
+	str := new(string)
+	err := json.Unmarshal(data, str)
+	if err != nil {
+		return err
+	}
+	_, err = hex.Decode(address[:], []byte(*str))
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func (address Address) MarshalJSON() ([]byte, error) {
+	return json.Marshal(hex.EncodeUpperToString(address[:]))
+}
+
+func (address *Address) UnmarshalText(text []byte) error {
+	_, err := hex.Decode(address[:], text)
+	return err
+}
+
+func (address Address) MarshalText() ([]byte, error) {
+	return ([]byte)(hex.EncodeUpperToString(address[:])), nil
+}
+
+func NewContractAddress(caller Address, sequence uint64) (newAddr Address) {
+	temp := make([]byte, 32+8)
+	copy(temp, caller[:])
+	binary.PutUint64BE(temp[32:], uint64(sequence))
+	hasher := ripemd160.New()
+	hasher.Write(temp) // does not error
+	copy(newAddr[:], hasher.Sum(nil))
+	return
+}
diff --git a/account/address_test.go b/account/address_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..25c572c6146b9ddc84e50b49502cdbf6dc26a2db
--- /dev/null
+++ b/account/address_test.go
@@ -0,0 +1,59 @@
+package account
+
+import (
+	"testing"
+
+	"encoding/json"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestNewContractAddress(t *testing.T) {
+	addr := NewContractAddress(Address{
+		233, 181, 216, 115, 19,
+		53, 100, 101, 250, 227,
+		60, 64, 108, 226, 194,
+		151, 157, 230, 11, 203,
+	}, 1)
+
+	assert.Equal(t, Address{
+		73, 234, 48, 252, 174,
+		115, 27, 222, 54, 116,
+		47, 133, 144, 21, 73,
+		245, 21, 234, 26, 50,
+	}, addr)
+}
+
+func TestAddress_MarshalJSON(t *testing.T) {
+	addr := Address{
+		73, 234, 48, 252, 174,
+		115, 27, 222, 54, 116,
+		47, 133, 144, 21, 73,
+		245, 21, 234, 26, 50,
+	}
+
+	bs, err := json.Marshal(addr)
+	assert.NoError(t, err)
+
+	addrOut := new(Address)
+	err = json.Unmarshal(bs, addrOut)
+
+	assert.Equal(t, addr, *addrOut)
+}
+
+func TestAddress_MarshalText(t *testing.T) {
+	addr := Address{
+		73, 234, 48, 252, 174,
+		115, 27, 222, 54, 116,
+		47, 133, 144, 21, 73,
+		245, 21, 234, 26, 50,
+	}
+
+	bs, err := addr.MarshalText()
+	assert.NoError(t, err)
+
+	addrOut := new(Address)
+	err = addrOut.UnmarshalText(bs)
+
+	assert.Equal(t, addr, *addrOut)
+}
diff --git a/account/bytecode.go b/account/bytecode.go
new file mode 100644
index 0000000000000000000000000000000000000000..76a49f970e7b37c09dc7036b5199ecd2ccf33325
--- /dev/null
+++ b/account/bytecode.go
@@ -0,0 +1,36 @@
+package account
+
+import (
+	"encoding/json"
+
+	"github.com/tmthrgd/go-hex"
+)
+
+// TODO: write a simple lexer that prints the opcodes. Each byte is either an OpCode or part of the Word256 argument
+// to Push[1...32]
+type Bytecode []byte
+
+func (bc Bytecode) Bytes() []byte {
+	return bc[:]
+}
+
+func (bc Bytecode) String() string {
+	return hex.EncodeToString(bc[:])
+
+}
+func (bc Bytecode) MarshalJSON() ([]byte, error) {
+	return json.Marshal(hex.EncodeUpperToString(bc[:]))
+}
+
+func (bc Bytecode) UnmarshalJSON(data []byte) error {
+	str := new(string)
+	err := json.Unmarshal(data, str)
+	if err != nil {
+		return err
+	}
+	_, err = hex.Decode(bc[:], []byte(*str))
+	if err != nil {
+		return err
+	}
+	return nil
+}
diff --git a/account/keys.go b/account/keys.go
new file mode 100644
index 0000000000000000000000000000000000000000..189a9b318e3882b6209a4beefc83d2d2501d57b2
--- /dev/null
+++ b/account/keys.go
@@ -0,0 +1,61 @@
+package account
+
+import "github.com/tendermint/go-crypto"
+
+// This allows us to control serialisation
+
+type PublicKey struct {
+	crypto.PubKey `json:"unwrap"`
+}
+
+func PublicKeyFromPubKey(pubKey crypto.PubKey) PublicKey {
+	return PublicKey{PubKey: pubKey}
+}
+
+func PrivateKeyFromPrivKey(privKey crypto.PrivKey) PrivateKey {
+	return PrivateKey{PrivKey: privKey}
+}
+
+func (pk PublicKey) Address() Address {
+	return MustAddressFromBytes(pk.PubKey.Address())
+}
+
+func (pk PublicKey) MarshalJSON() ([]byte, error) {
+	return pk.PubKey.MarshalJSON()
+}
+
+func (pk *PublicKey) UnmarshalJSON(data []byte) error {
+	return pk.PubKey.UnmarshalJSON(data)
+}
+
+func (pk PublicKey) MarshalText() ([]byte, error) {
+	return pk.MarshalJSON()
+}
+
+func (pk *PublicKey) UnmarshalText(text []byte) error {
+	return pk.UnmarshalJSON(text)
+}
+
+type PrivateKey struct {
+	crypto.PrivKey
+}
+
+func (pk PrivateKey) PublicKey() PublicKey {
+	return PublicKeyFromPubKey(pk.PubKey())
+}
+
+func (pk PrivateKey) MarshalJSON() ([]byte, error) {
+	return pk.PrivKey.MarshalJSON()
+}
+
+func (pk *PrivateKey) UnmarshalJSON(data []byte) error {
+	return pk.PrivKey.UnmarshalJSON(data)
+}
+
+func (pk PrivateKey) MarshalText() ([]byte, error) {
+	return pk.MarshalJSON()
+}
+
+func (pk *PrivateKey) UnmarshalText(text []byte) error {
+	return pk.UnmarshalJSON(text)
+}
diff --git a/account/priv_account.go b/account/priv_account.go
deleted file mode 100644
index e2fa762fff0e62ce9162ea68e5dcbd4f6f07def5..0000000000000000000000000000000000000000
--- a/account/priv_account.go
+++ /dev/null
@@ -1,106 +0,0 @@
-// Copyright 2017 Monax Industries Limited
-//
-// 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 account
-
-// TODO: [ben] Account and PrivateAccount need to become a pure interface
-// and then move the implementation to the manager types.
-// Eg, Geth has its accounts, different from BurrowMint
-
-import (
-	"fmt"
-
-	"github.com/hyperledger/burrow/common/sanity"
-
-	"github.com/tendermint/ed25519"
-	"github.com/tendermint/go-crypto"
-	"github.com/tendermint/go-wire"
-)
-
-type PrivAccount struct {
-	Address []byte         `json:"address"`
-	PubKey  crypto.PubKey  `json:"pub_key"`
-	PrivKey crypto.PrivKey `json:"priv_key"`
-}
-
-func (pA *PrivAccount) Generate(index int) *PrivAccount {
-	newPrivKey := pA.PrivKey.(crypto.PrivKeyEd25519).Generate(index)
-	newPubKey := newPrivKey.PubKey()
-	newAddress := newPubKey.Address()
-	return &PrivAccount{
-		Address: newAddress,
-		PubKey:  newPubKey,
-		PrivKey: newPrivKey,
-	}
-}
-
-func (pA *PrivAccount) Sign(chainID string, o Signable) crypto.Signature {
-	return pA.PrivKey.Sign(SignBytes(chainID, o))
-}
-
-func (pA *PrivAccount) String() string {
-	return fmt.Sprintf("PrivAccount{%X}", pA.Address)
-}
-
-//----------------------------------------
-
-// Generates a new account with private key.
-func GenPrivAccount() *PrivAccount {
-	privKeyBytes := new([64]byte)
-	copy(privKeyBytes[:32], crypto.CRandBytes(32))
-	pubKeyBytes := ed25519.MakePublicKey(privKeyBytes)
-	pubKey := crypto.PubKeyEd25519(*pubKeyBytes)
-	privKey := crypto.PrivKeyEd25519(*privKeyBytes)
-	return &PrivAccount{
-		Address: pubKey.Address(),
-		PubKey:  pubKey,
-		PrivKey: privKey,
-	}
-}
-
-// Generates 32 priv key bytes from secret
-func GenPrivKeyBytesFromSecret(secret string) []byte {
-	return wire.BinarySha256(secret) // Not Ripemd160 because we want 32 bytes.
-}
-
-// Generates a new account with private key from SHA256 hash of a secret
-func GenPrivAccountFromSecret(secret string) *PrivAccount {
-	privKey32 := GenPrivKeyBytesFromSecret(secret)
-	privKeyBytes := new([64]byte)
-	copy(privKeyBytes[:32], privKey32)
-	pubKeyBytes := ed25519.MakePublicKey(privKeyBytes)
-	pubKey := crypto.PubKeyEd25519(*pubKeyBytes)
-	privKey := crypto.PrivKeyEd25519(*privKeyBytes)
-	return &PrivAccount{
-		Address: pubKey.Address(),
-		PubKey:  pubKey,
-		PrivKey: privKey,
-	}
-}
-
-func GenPrivAccountFromPrivKeyBytes(privKeyBytes []byte) *PrivAccount {
-	if len(privKeyBytes) != 64 {
-		sanity.PanicSanity(fmt.Sprintf("Expected 64 bytes but got %v", len(privKeyBytes)))
-	}
-	var privKeyArray [64]byte
-	copy(privKeyArray[:], privKeyBytes)
-	pubKeyBytes := ed25519.MakePublicKey(&privKeyArray)
-	pubKey := crypto.PubKeyEd25519(*pubKeyBytes)
-	privKey := crypto.PrivKeyEd25519(privKeyArray)
-	return &PrivAccount{
-		Address: pubKey.Address(),
-		PubKey:  pubKey,
-		PrivKey: privKey,
-	}
-}
diff --git a/account/private_account.go b/account/private_account.go
new file mode 100644
index 0000000000000000000000000000000000000000..9dc73dbb30e7ec47a3f48ef320b4f30ea460c62f
--- /dev/null
+++ b/account/private_account.go
@@ -0,0 +1,136 @@
+// Copyright 2017 Monax Industries Limited
+//
+// 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 account
+
+import (
+	"fmt"
+
+	"github.com/tendermint/ed25519"
+	"github.com/tendermint/go-crypto"
+	"github.com/tendermint/go-wire"
+)
+
+type Signer interface {
+	Sign(msg []byte) (crypto.Signature, error)
+}
+
+type PrivateAccount interface {
+	Addressable
+	PrivateKey() PrivateKey
+	Signer
+}
+
+type ConcretePrivateAccount struct {
+	Address    Address
+	PublicKey  PublicKey
+	PrivateKey PrivateKey
+}
+
+type concretePrivateAccountWrapper struct {
+	*ConcretePrivateAccount `json:"unwrap"`
+}
+
+var _ PrivateAccount = concretePrivateAccountWrapper{}
+
+var _ = wire.RegisterInterface(struct{ PrivateAccount }{}, wire.ConcreteType{concretePrivateAccountWrapper{}, 0x01})
+
+func (cpaw concretePrivateAccountWrapper) Address() Address {
+	return cpaw.ConcretePrivateAccount.Address
+}
+
+func (cpaw concretePrivateAccountWrapper) PublicKey() PublicKey {
+	return cpaw.ConcretePrivateAccount.PublicKey
+}
+
+func (cpaw concretePrivateAccountWrapper) PrivateKey() PrivateKey {
+	return cpaw.ConcretePrivateAccount.PrivateKey
+}
+
+func (pa ConcretePrivateAccount) PrivateAccount() concretePrivateAccountWrapper {
+	return concretePrivateAccountWrapper{&pa}
+}
+
+func (pa ConcretePrivateAccount) Sign(msg []byte) (crypto.Signature, error) {
+	return pa.PrivateKey.Sign(msg), nil
+}
+
+func ChainSign(pa PrivateAccount, chainID string, o Signable) crypto.Signature {
+	sig, _ := pa.Sign(SignBytes(chainID, o))
+	return sig
+}
+
+func (pa *ConcretePrivateAccount) Generate(index int) concretePrivateAccountWrapper {
+	newPrivKey := PrivateKeyFromPrivKey(pa.PrivateKey.Unwrap().(crypto.PrivKeyEd25519).Generate(index).Wrap())
+	newPubKey := PublicKeyFromPubKey(newPrivKey.PubKey())
+	newAddress := newPubKey.Address()
+	return ConcretePrivateAccount{
+		Address:    newAddress,
+		PublicKey:  newPubKey,
+		PrivateKey: newPrivKey,
+	}.PrivateAccount()
+}
+
+func (pa *ConcretePrivateAccount) String() string {
+	return fmt.Sprintf("ConcretePrivateAccount{%s}", pa.Address)
+}
+
+//----------------------------------------
+
+// Generates a new account with private key.
+func GeneratePrivateAccount() concretePrivateAccountWrapper {
+	privKeyBytes := new([64]byte)
+	copy(privKeyBytes[:32], crypto.CRandBytes(32))
+	pubKeyBytes := ed25519.MakePublicKey(privKeyBytes)
+	publicKey := PublicKeyFromPubKey(crypto.PubKeyEd25519(*pubKeyBytes).Wrap())
+	address := publicKey.Address()
+	privateKey := PrivateKeyFromPrivKey(crypto.PrivKeyEd25519(*privKeyBytes).Wrap())
+	return ConcretePrivateAccount{
+		Address:    address,
+		PublicKey:  publicKey,
+		PrivateKey: privateKey,
+	}.PrivateAccount()
+}
+
+func PrivateKeyFromSecret(secret string) PrivateKey {
+	return PrivateKeyFromPrivKey(crypto.GenPrivKeyEd25519FromSecret(wire.BinarySha256(secret)).Wrap())
+}
+
+// Generates a new account with private key from SHA256 hash of a secret
+func GeneratePrivateAccountFromSecret(secret string) concretePrivateAccountWrapper {
+	privKey := PrivateKeyFromSecret(secret)
+	pubKey := PublicKeyFromPubKey(privKey.PubKey())
+	return ConcretePrivateAccount{
+		Address:    pubKey.Address(),
+		PublicKey:  pubKey,
+		PrivateKey: privKey,
+	}.PrivateAccount()
+}
+
+func GeneratePrivateAccountFromPrivateKeyBytes(privKeyBytes []byte) concretePrivateAccountWrapper {
+	if len(privKeyBytes) != 64 {
+		panic(fmt.Sprintf("Expected 64 bytes but got %v", len(privKeyBytes)))
+	}
+	var privKeyArray [64]byte
+	copy(privKeyArray[:], privKeyBytes)
+	pubKeyBytes := ed25519.MakePublicKey(&privKeyArray)
+	publicKey := PublicKeyFromPubKey(crypto.PubKeyEd25519(*pubKeyBytes).Wrap())
+	address := publicKey.Address()
+	privateKey := PrivateKeyFromPrivKey(crypto.PrivKeyEd25519(privKeyArray).Wrap())
+	return ConcretePrivateAccount{
+		Address:    address,
+		PublicKey:  publicKey,
+		PrivateKey: privateKey,
+	}.PrivateAccount()
+}
diff --git a/account/private_account_test.go b/account/private_account_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..b08a244e0ffef413a2c5ab729fb088c377c73d0a
--- /dev/null
+++ b/account/private_account_test.go
@@ -0,0 +1,48 @@
+// Copyright 2017 Monax Industries Limited
+//
+// 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 account
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	"github.com/tendermint/go-wire"
+	"github.com/stretchr/testify/require"
+)
+
+func TestPrivateAccountSerialise(t *testing.T) {
+	type PrivateAccountContainingStruct struct {
+		PrivateAccount PrivateAccount
+		ChainID        string
+	}
+	// This test is really testing this go wire declaration in private_account.go
+	acc := GeneratePrivateAccountFromSecret("Super Secret Secret")
+
+	// Go wire cannot serialise a top-level interface type it needs to be a field or sub-field of a struct
+	// at some depth. i.e. you MUST wrap an interface if you want it to be decoded (they do not document this)
+	var accStruct = PrivateAccountContainingStruct{
+		PrivateAccount: acc,
+		ChainID:        "TestChain",
+	}
+
+	// We will write into this
+	accStructOut := PrivateAccountContainingStruct{}
+
+	// We must pass in a value type to read from (accStruct), but provide a pointer type to write into (accStructout
+	err := wire.ReadBinaryBytes(wire.BinaryBytes(accStruct), &accStructOut)
+	require.NoError(t, err)
+
+	assert.Equal(t, accStruct, accStructOut)
+}
diff --git a/account/state.go b/account/state.go
new file mode 100644
index 0000000000000000000000000000000000000000..dcbba2424d1ba3227682e5d8a564bdb9998845c9
--- /dev/null
+++ b/account/state.go
@@ -0,0 +1,65 @@
+package account
+
+import (
+	"github.com/hyperledger/burrow/binary"
+)
+
+type Getter interface {
+	// Get an account by its address return nil if it does not exist (which should not be an error)
+	GetAccount(address Address) (Account, error)
+}
+
+type Iterable interface {
+	// Iterates through accounts calling passed function once per account, if the consumer
+	// returns true the iteration breaks and returns true to indicate it iteration
+	// was escaped
+	IterateAccounts(consumer func(Account) (stop bool)) (stopped bool, err error)
+}
+
+type Updater interface {
+	// Updates the fields of updatedAccount by address, creating the account
+	// if it does not exist
+	UpdateAccount(updatedAccount Account) error
+	// Remove the account at address
+	RemoveAccount(address Address) error
+}
+
+type StorageGetter interface {
+	// Retrieve a 32-byte value stored at key for the account at address, return Zero256 if key does not exist but
+	// error if address does not
+	GetStorage(address Address, key binary.Word256) (value binary.Word256, err error)
+}
+
+type StorageSetter interface {
+	// Store a 32-byte value at key for the account at address
+	SetStorage(address Address, key, value binary.Word256) error
+}
+
+type StorageIterable interface {
+	// Iterates through the storage of account ad address calling the passed function once per account,
+	// if the iterator function returns true the iteration breaks and returns true to indicate it iteration
+	// was escaped
+	IterateStorage(address Address, consumer func(key, value binary.Word256) (stop bool)) (stopped bool, err error)
+}
+
+// Compositions
+
+// Read-only account and storage state
+type StateReader interface {
+	Getter
+	StorageGetter
+}
+
+// Read and list account and storage state
+type StateIterable interface {
+	StateReader
+	Iterable
+	StorageIterable
+}
+
+// Read and write account and storage state
+type StateWriter interface {
+	StateReader
+	Updater
+	StorageSetter
+}
diff --git a/account/validator.go b/account/validator.go
new file mode 100644
index 0000000000000000000000000000000000000000..5271a2f4a01cdba71280175ff4fde479fb80576e
--- /dev/null
+++ b/account/validator.go
@@ -0,0 +1,93 @@
+package account
+
+import (
+	"encoding/json"
+)
+
+type Validator interface {
+	Addressable
+	// The validator's voting power
+	Power() uint64
+	// Alter the validator's voting power by amount that can be negative or positive.
+	// A power of 0 effectively unbonds the validator
+	WithNewPower(uint64) Validator
+}
+
+// Neither abci_types or tm_types has quite the representation we want
+type ConcreteValidator struct {
+	Address   Address
+	PublicKey PublicKey
+	Power     uint64
+}
+
+type concreteValidatorWrapper struct {
+	*ConcreteValidator `json:"unwrap"`
+}
+
+var _ Validator = concreteValidatorWrapper{}
+
+func AsValidator(account Account) Validator {
+	return ConcreteValidator{
+		Address:   account.Address(),
+		PublicKey: account.PublicKey(),
+		Power:     account.Balance(),
+	}.Validator()
+}
+
+func AsConcreteValidator(validator Validator) *ConcreteValidator {
+	if validator == nil {
+		return nil
+	}
+	if ca, ok := validator.(concreteValidatorWrapper); ok {
+		return ca.ConcreteValidator
+	}
+	return &ConcreteValidator{
+		Address:   validator.Address(),
+		PublicKey: validator.PublicKey(),
+		Power:     validator.Power(),
+	}
+}
+
+func (cvw concreteValidatorWrapper) Address() Address {
+	return cvw.ConcreteValidator.Address
+}
+
+func (cvw concreteValidatorWrapper) PublicKey() PublicKey {
+	return cvw.ConcreteValidator.PublicKey
+}
+
+func (cvw concreteValidatorWrapper) Power() uint64 {
+	return cvw.ConcreteValidator.Power
+}
+
+func (cvw concreteValidatorWrapper) WithNewPower(power uint64) Validator {
+	cv := cvw.Copy()
+	cv.Power = power
+	return concreteValidatorWrapper{
+		ConcreteValidator: cv,
+	}
+}
+
+func (cv ConcreteValidator) Validator() Validator {
+	return concreteValidatorWrapper{
+		ConcreteValidator: &cv,
+	}
+}
+
+func (cv *ConcreteValidator) Copy() *ConcreteValidator {
+	cvCopy := *cv
+	return &cvCopy
+}
+
+func (cv *ConcreteValidator) String() string {
+	if cv == nil {
+		return "Nil Validator"
+	}
+
+	bs, err := json.Marshal(cv)
+	if err != nil {
+		return "error serialising Validator"
+	}
+
+	return string(bs)
+}
diff --git a/account/validator_test.go b/account/validator_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..ff660300316d650d7e3ab64ff89ae4b88effecd4
--- /dev/null
+++ b/account/validator_test.go
@@ -0,0 +1,14 @@
+package account
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestAlterPower(t *testing.T) {
+	val := AsValidator(NewConcreteAccountFromSecret("seeeeecret").Account())
+	valInc := val.WithNewPower(2442132)
+	assert.Equal(t, uint64(0), val.Power())
+	assert.Equal(t, uint64(2442132), valInc.Power())
+}
diff --git a/binary/byteslice.go b/binary/byteslice.go
new file mode 100644
index 0000000000000000000000000000000000000000..286280b32e37647c050ecffa36379e63e46a6038
--- /dev/null
+++ b/binary/byteslice.go
@@ -0,0 +1,48 @@
+// Copyright 2017 Monax Industries Limited
+//
+// 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 binary
+
+func Fingerprint(slice []byte) []byte {
+	fingerprint := make([]byte, 6)
+	copy(fingerprint, slice)
+	return fingerprint
+}
+
+func IsZeros(slice []byte) bool {
+	for _, byt := range slice {
+		if byt != byte(0) {
+			return false
+		}
+	}
+	return true
+}
+
+func RightPadBytes(slice []byte, l int) []byte {
+	if l < len(slice) {
+		return slice
+	}
+	padded := make([]byte, l)
+	copy(padded[0:len(slice)], slice)
+	return padded
+}
+
+func LeftPadBytes(slice []byte, l int) []byte {
+	if l < len(slice) {
+		return slice
+	}
+	padded := make([]byte, l)
+	copy(padded[l-len(slice):], slice)
+	return padded
+}
diff --git a/binary/integer.go b/binary/integer.go
new file mode 100644
index 0000000000000000000000000000000000000000..f865148400b866d4b071f469c934d1fb297c2f7b
--- /dev/null
+++ b/binary/integer.go
@@ -0,0 +1,77 @@
+// Copyright 2017 Monax Industries Limited
+//
+// 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 binary
+
+import (
+	"encoding/binary"
+	"math"
+	"sort"
+)
+
+const Uint64TopBitMask = 1 << 63
+
+// Sort for []uint64
+
+type Uint64Slice []uint64
+
+func (p Uint64Slice) Len() int           { return len(p) }
+func (p Uint64Slice) Less(i, j int) bool { return p[i] < p[j] }
+func (p Uint64Slice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
+func (p Uint64Slice) Sort()              { sort.Sort(p) }
+
+func SearchUint64s(a []uint64, x uint64) int {
+	return sort.Search(len(a), func(i int) bool { return a[i] >= x })
+}
+
+func (p Uint64Slice) Search(x uint64) int { return SearchUint64s(p, x) }
+
+//--------------------------------------------------------------------------------
+
+func PutUint64LE(dest []byte, i uint64) {
+	binary.LittleEndian.PutUint64(dest, i)
+}
+
+func GetUint64LE(src []byte) uint64 {
+	return binary.LittleEndian.Uint64(src)
+}
+
+func PutUint64BE(dest []byte, i uint64) {
+	binary.BigEndian.PutUint64(dest, i)
+}
+
+func GetUint64BE(src []byte) uint64 {
+	return binary.BigEndian.Uint64(src)
+}
+
+func PutInt64LE(dest []byte, i int64) {
+	binary.LittleEndian.PutUint64(dest, uint64(i))
+}
+
+func GetInt64LE(src []byte) int64 {
+	return int64(binary.LittleEndian.Uint64(src))
+}
+
+func PutInt64BE(dest []byte, i int64) {
+	binary.BigEndian.PutUint64(dest, uint64(i))
+}
+
+func GetInt64BE(src []byte) int64 {
+	return int64(binary.BigEndian.Uint64(src))
+}
+
+// Returns whether a + b would be a uint64 overflow
+func IsUint64SumOverflow(a, b uint64) bool {
+	return math.MaxUint64-a < b
+}
diff --git a/binary/integer_test.go b/binary/integer_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..e530c5a7bb6b312fb2e8777796889b1629cb4a45
--- /dev/null
+++ b/binary/integer_test.go
@@ -0,0 +1,19 @@
+package binary
+
+import (
+	"math"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestIsUint64SumOverflow(t *testing.T) {
+	var b uint64 = 0xdeadbeef
+	var a uint64 = math.MaxUint64 - b
+	assert.False(t, IsUint64SumOverflow(a-b, b))
+	assert.False(t, IsUint64SumOverflow(a, b))
+	assert.False(t, IsUint64SumOverflow(a+b, 0))
+	assert.True(t, IsUint64SumOverflow(a, b+1))
+	assert.True(t, IsUint64SumOverflow(a+b, 1))
+	assert.True(t, IsUint64SumOverflow(a+1, b+1))
+}
diff --git a/binary/word160.go b/binary/word160.go
new file mode 100644
index 0000000000000000000000000000000000000000..991cbee7731d6c9eac7dd683f9648f6fb8e5f98a
--- /dev/null
+++ b/binary/word160.go
@@ -0,0 +1,14 @@
+package binary
+
+const Word160Length = 20
+const Word256Word160Delta = 12
+
+var Zero160 = Word160{}
+
+type Word160 [Word160Length]byte
+
+// Pad a Word160 on the left and embed it in a Word256 (as it is for account addresses in EVM)
+func (w Word160) Word256() (word256 Word256) {
+	copy(word256[Word256Word160Delta:], w[:])
+	return
+}
diff --git a/binary/word160_test.go b/binary/word160_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..86af40b5a542c589de91410239b230beb792d8e7
--- /dev/null
+++ b/binary/word160_test.go
@@ -0,0 +1,26 @@
+package binary
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestWord160_Word256(t *testing.T) {
+	word256 := Word256{
+		0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0,
+		1, 2, 3, 4, 5,
+		6, 7, 8, 9, 10,
+		11, 12, 13, 14, 15,
+		16, 17, 18, 19, 20,
+	}
+	word160 := Word160{
+		1, 2, 3, 4, 5,
+		6, 7, 8, 9, 10,
+		11, 12, 13, 14, 15,
+		16, 17, 18, 19, 20,
+	}
+	assert.Equal(t, word256, word160.Word256())
+	assert.Equal(t, word160, word256.Word160())
+}
diff --git a/binary/word256.go b/binary/word256.go
new file mode 100644
index 0000000000000000000000000000000000000000..6d11fe9aa27538f0ea21b4f94b8183edcfb4f13b
--- /dev/null
+++ b/binary/word256.go
@@ -0,0 +1,139 @@
+// Copyright 2017 Monax Industries Limited
+//
+// 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 binary
+
+import (
+	"bytes"
+	"sort"
+)
+
+var (
+	Zero256 = Word256{}
+	One256  = Word256{1}
+)
+
+const Word256Length = 32
+
+var trimCutSet = string([]byte{0})
+
+type Word256 [Word256Length]byte
+
+func (w Word256) String() string {
+	return string(w[:])
+}
+
+func (w Word256) Copy() Word256 {
+	return w
+}
+
+func (w Word256) Bytes() []byte {
+	return w[:]
+}
+
+// copied.
+func (w Word256) Prefix(n int) []byte {
+	return w[:n]
+}
+
+func (w Word256) Postfix(n int) []byte {
+	return w[32-n:]
+}
+
+// Get a Word160 embedded a Word256 and padded on the left (as it is for account addresses in EVM)
+func (w Word256) Word160() (w160 Word160) {
+	copy(w160[:], w[Word256Word160Delta:])
+	return
+}
+
+func (w Word256) IsZero() bool {
+	accum := byte(0)
+	for _, byt := range w {
+		accum |= byt
+	}
+	return accum == 0
+}
+
+func (w Word256) Compare(other Word256) int {
+	return bytes.Compare(w[:], other[:])
+}
+
+func (w Word256) UnpadLeft() []byte {
+	return bytes.TrimLeft(w[:], trimCutSet)
+}
+
+func (w Word256) UnpadRight() []byte {
+	return bytes.TrimRight(w[:], trimCutSet)
+}
+
+func Uint64ToWord256(i uint64) Word256 {
+	buf := [8]byte{}
+	PutUint64BE(buf[:], i)
+	return LeftPadWord256(buf[:])
+}
+
+func Int64ToWord256(i int64) Word256 {
+	buf := [8]byte{}
+	PutInt64BE(buf[:], i)
+	return LeftPadWord256(buf[:])
+}
+
+func RightPadWord256(bz []byte) (word Word256) {
+	copy(word[:], bz)
+	return
+}
+
+func LeftPadWord256(bz []byte) (word Word256) {
+	copy(word[32-len(bz):], bz)
+	return
+}
+
+func Uint64FromWord256(word Word256) uint64 {
+	buf := word.Postfix(8)
+	return GetUint64BE(buf)
+}
+
+func Int64FromWord256(word Word256) int64 {
+	buf := word.Postfix(8)
+	return GetInt64BE(buf)
+}
+
+//-------------------------------------
+
+type Tuple256 struct {
+	First  Word256
+	Second Word256
+}
+
+func (tuple Tuple256) Compare(other Tuple256) int {
+	firstCompare := tuple.First.Compare(other.First)
+	if firstCompare == 0 {
+		return tuple.Second.Compare(other.Second)
+	} else {
+		return firstCompare
+	}
+}
+
+func Tuple256Split(t Tuple256) (Word256, Word256) {
+	return t.First, t.Second
+}
+
+type Tuple256Slice []Tuple256
+
+func (p Tuple256Slice) Len() int { return len(p) }
+func (p Tuple256Slice) Less(i, j int) bool {
+	return p[i].Compare(p[j]) < 0
+}
+func (p Tuple256Slice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
+func (p Tuple256Slice) Sort()         { sort.Sort(p) }
diff --git a/binary/word256_test.go b/binary/word256_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..055d39109e6e3cdbc249948b2071837ba3a9c87d
--- /dev/null
+++ b/binary/word256_test.go
@@ -0,0 +1,39 @@
+package binary
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestWord256_UnpadLeft(t *testing.T) {
+	bs := []byte{0x45, 0x12}
+	w := LeftPadWord256(bs)
+	wExpected := Word256{}
+	wExpected[30] = bs[0]
+	wExpected[31] = bs[1]
+	assert.Equal(t, wExpected, w)
+	assert.Equal(t, bs, w.UnpadLeft())
+}
+
+func TestWord256_UnpadRight(t *testing.T) {
+	bs := []byte{0x45, 0x12}
+	w := RightPadWord256(bs)
+	wExpected := Word256{}
+	wExpected[0] = bs[0]
+	wExpected[1] = bs[1]
+	assert.Equal(t, wExpected, w)
+	assert.Equal(t, bs, w.UnpadRight())
+}
+
+func TestLeftPadWord256(t *testing.T) {
+	assert.Equal(t, Zero256, LeftPadWord256(nil))
+	assert.Equal(t,
+		Word256{
+			0, 0, 0, 0, 0, 0, 0, 0,
+			0, 0, 0, 0, 0, 0, 0, 0,
+			0, 0, 0, 0, 0, 0, 0, 0,
+			0, 0, 0, 0, 0, 1, 2, 3,
+		},
+		LeftPadWord256([]byte{1, 2, 3}))
+}