diff --git a/accounts/account_manager.go b/accounts/account_manager.go
new file mode 100644
index 0000000000000000000000000000000000000000..b5a0c4f873dc6656c2079dbd01fb6b63f8d12b72
--- /dev/null
+++ b/accounts/account_manager.go
@@ -0,0 +1,99 @@
+/*
+	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
+ *
+ */
+/*
+
+This abstracts part of a user's interaction with an account she controls.
+It's not an abstraction of core Ethereum accounts data type / logic -
+for that see the core processing code of blocks / txs.
+
+Currently this is pretty much a passthrough to the KeyStore2 interface,
+and accounts persistence is derived from stored keys' addresses
+
+*/
+package accounts
+
+import (
+	crand "crypto/rand"
+	"github.com/ethereum/go-ethereum/crypto"
+	"github.com/ethereum/go-ethereum/crypto/secp256k1"
+)
+
+// TODO: better name for this struct?
+type UserAccount struct {
+	Addr []byte
+}
+
+type AccountManager struct {
+	keyStore crypto.KeyStore2
+}
+
+// TODO: get key by addr - modify KeyStore2 GetKey to work with addr
+
+// TODO: pass through passphrase for APIs which require access to private key?
+func NewAccountManager(keyStore crypto.KeyStore2) AccountManager {
+	am := &AccountManager{
+		keyStore: keyStore,
+	}
+	return *am
+}
+
+func (am *AccountManager) Sign(fromAddr []byte, keyAuth string, toSign []byte) (signature []byte, err error) {
+	key, err := am.keyStore.GetKey(fromAddr, keyAuth)
+	if err != nil {
+		return nil, err
+	}
+	privKey := crypto.FromECDSA(key.PrivateKey)
+	// TODO: what is second value?
+	signature, err = secp256k1.Sign(toSign, privKey)
+	return signature, err
+}
+
+func (am AccountManager) NewAccount(auth string) (*UserAccount, error) {
+	key, err := am.keyStore.GenerateNewKey(crand.Reader, auth)
+	if err != nil {
+		return nil, err
+	}
+	ua := &UserAccount{
+		Addr: key.Address,
+	}
+	return ua, err
+}
+
+// set of accounts == set of keys in given key store
+// TODO: do we need persistence of accounts as well?
+func (am *AccountManager) Accounts() ([]UserAccount, error) {
+	addresses, err := am.keyStore.GetKeyAddresses()
+	if err != nil {
+		return nil, err
+	}
+
+	accounts := make([]UserAccount, len(addresses))
+
+	for i, addr := range addresses {
+		ua := &UserAccount{
+			Addr: addr,
+		}
+		accounts[i] = *ua
+	}
+	return accounts, err
+}
diff --git a/accounts/accounts_test.go b/accounts/accounts_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..3816577188331fae4141ad12b4057fe381289b63
--- /dev/null
+++ b/accounts/accounts_test.go
@@ -0,0 +1,19 @@
+package accounts
+
+import (
+	"github.com/ethereum/go-ethereum/crypto"
+	"testing"
+)
+
+func TestAccountManager(t *testing.T) {
+	ks := crypto.NewKeyStorePlain(crypto.DefaultDataDir())
+	am := NewAccountManager(ks)
+	pass := "" // not used but required by API
+	a1, err := am.NewAccount(pass)
+	toSign := make([]byte, 4, 4)
+	toSign = []byte{0, 1, 2, 3}
+	_, err = am.Sign(a1.Addr, pass, toSign)
+	if err != nil {
+		t.Fatal(err)
+	}
+}
diff --git a/crypto/crypto.go b/crypto/crypto.go
index 4b2cc7bb4a693a9be763f475130d173e6a1c3511..f8d6139a8628c9a65b778d80ff1f043ede2d3696 100644
--- a/crypto/crypto.go
+++ b/crypto/crypto.go
@@ -134,7 +134,7 @@ func ImportPreSaleKey(keyStore KeyStore2, keyJSON []byte, password string) (*Key
 		return nil, err
 	}
 	id := uuid.NewRandom()
-	key.Id = &id
+	key.Id = id
 	err = keyStore.StoreKey(key, password)
 	return key, err
 }
@@ -167,9 +167,10 @@ func decryptPreSaleKey(fileContent []byte, password string) (key *Key, err error
 	ecKey := ToECDSA(ethPriv)
 	key = &Key{
 		Id:         nil,
+		Address:    pubkeyToAddress(ecKey.PublicKey),
 		PrivateKey: ecKey,
 	}
-	derivedAddr := ethutil.Bytes2Hex(key.Address())
+	derivedAddr := ethutil.Bytes2Hex(key.Address)
 	expectedAddr := preSaleKeyStruct.EthAddr
 	if derivedAddr != expectedAddr {
 		err = errors.New("decrypted addr not equal to expected addr")
@@ -223,3 +224,8 @@ func PKCS7Unpad(in []byte) []byte {
 	}
 	return in[:len(in)-int(padding)]
 }
+
+func pubkeyToAddress(p ecdsa.PublicKey) []byte {
+	pubBytes := FromECDSAPub(&p)
+	return Sha3(pubBytes[1:])[12:]
+}
diff --git a/crypto/key.go b/crypto/key.go
index ca29b691ff0fc5b234bc0dfe9c78f542a1c8af53..f8f64c35c1c9c38ee1023b90be8918e01c4f5b96 100644
--- a/crypto/key.go
+++ b/crypto/key.go
@@ -33,7 +33,9 @@ import (
 )
 
 type Key struct {
-	Id *uuid.UUID // Version 4 "random" for unique id not derived from key data
+	Id uuid.UUID // Version 4 "random" for unique id not derived from key data
+	// to simplify lookups we also store the address
+	Address []byte
 	// we only store privkey as pubkey/address can be derived from it
 	// privkey in this struct is always in plaintext
 	PrivateKey *ecdsa.PrivateKey
@@ -41,6 +43,7 @@ type Key struct {
 
 type plainKeyJSON struct {
 	Id         []byte
+	Address    []byte
 	PrivateKey []byte
 }
 
@@ -51,18 +54,15 @@ type cipherJSON struct {
 }
 
 type encryptedKeyJSON struct {
-	Id     []byte
-	Crypto cipherJSON
-}
-
-func (k *Key) Address() []byte {
-	pubBytes := FromECDSAPub(&k.PrivateKey.PublicKey)
-	return Sha3(pubBytes[1:])[12:]
+	Id      []byte
+	Address []byte
+	Crypto  cipherJSON
 }
 
 func (k *Key) MarshalJSON() (j []byte, err error) {
 	jStruct := plainKeyJSON{
-		*k.Id,
+		k.Id,
+		k.Address,
 		FromECDSA(k.PrivateKey),
 	}
 	j, err = json.Marshal(jStruct)
@@ -78,8 +78,8 @@ func (k *Key) UnmarshalJSON(j []byte) (err error) {
 
 	u := new(uuid.UUID)
 	*u = keyJSON.Id
-	k.Id = u
-
+	k.Id = *u
+	k.Address = keyJSON.Address
 	k.PrivateKey = ToECDSA(keyJSON.PrivateKey)
 
 	return err
@@ -101,7 +101,8 @@ func NewKey(rand io.Reader) *Key {
 
 	id := uuid.NewRandom()
 	key := &Key{
-		Id:         &id,
+		Id:         id,
+		Address:    pubkeyToAddress(privateKeyECDSA.PublicKey),
 		PrivateKey: privateKeyECDSA,
 	}
 	return key
diff --git a/crypto/key_store_passphrase.go b/crypto/key_store_passphrase.go
index 80bf49d68a4846a997a5497846dfa8b2af37d2cf..807a91397f0309516c318323097970901632ae71 100644
--- a/crypto/key_store_passphrase.go
+++ b/crypto/key_store_passphrase.go
@@ -69,6 +69,7 @@ import (
 	"crypto/aes"
 	"crypto/cipher"
 	crand "crypto/rand"
+	"encoding/hex"
 	"encoding/json"
 	"errors"
 	"io"
@@ -96,18 +97,23 @@ func (ks keyStorePassphrase) GenerateNewKey(rand io.Reader, auth string) (key *K
 	return GenerateNewKeyDefault(ks, rand, auth)
 }
 
-func (ks keyStorePassphrase) GetKey(keyId *uuid.UUID, auth string) (key *Key, err error) {
-	keyBytes, err := DecryptKey(ks, keyId, auth)
+func (ks keyStorePassphrase) GetKey(keyAddr []byte, auth string) (key *Key, err error) {
+	keyBytes, keyId, err := DecryptKey(ks, keyAddr, auth)
 	if err != nil {
 		return nil, err
 	}
 	key = &Key{
-		Id:         keyId,
+		Id:         uuid.UUID(keyId),
+		Address:    keyAddr,
 		PrivateKey: ToECDSA(keyBytes),
 	}
 	return key, err
 }
 
+func (ks keyStorePassphrase) GetKeyAddresses() (addresses [][]byte, err error) {
+	return GetKeyAddresses(ks.keysDirPath)
+}
+
 func (ks keyStorePassphrase) StoreKey(key *Key, auth string) (err error) {
 	authArray := []byte(auth)
 	salt := getEntropyCSPRNG(32)
@@ -136,7 +142,8 @@ func (ks keyStorePassphrase) StoreKey(key *Key, auth string) (err error) {
 		cipherText,
 	}
 	keyStruct := encryptedKeyJSON{
-		*key.Id,
+		key.Id,
+		key.Address,
 		cipherStruct,
 	}
 	keyJSON, err := json.Marshal(keyStruct)
@@ -144,51 +151,50 @@ func (ks keyStorePassphrase) StoreKey(key *Key, auth string) (err error) {
 		return err
 	}
 
-	return WriteKeyFile(key.Id.String(), ks.keysDirPath, keyJSON)
+	return WriteKeyFile(key.Address, ks.keysDirPath, keyJSON)
 }
 
-func (ks keyStorePassphrase) DeleteKey(keyId *uuid.UUID, auth string) (err error) {
+func (ks keyStorePassphrase) DeleteKey(keyAddr []byte, auth string) (err error) {
 	// only delete if correct passphrase is given
-	_, err = DecryptKey(ks, keyId, auth)
+	_, _, err = DecryptKey(ks, keyAddr, auth)
 	if err != nil {
 		return err
 	}
 
-	keyDirPath := path.Join(ks.keysDirPath, keyId.String())
+	keyDirPath := path.Join(ks.keysDirPath, hex.EncodeToString(keyAddr))
 	return os.RemoveAll(keyDirPath)
 }
 
-func DecryptKey(ks keyStorePassphrase, keyId *uuid.UUID, auth string) (keyBytes []byte, err error) {
-	fileContent, err := GetKeyFile(ks.keysDirPath, keyId)
+func DecryptKey(ks keyStorePassphrase, keyAddr []byte, auth string) (keyBytes []byte, keyId []byte, err error) {
+	fileContent, err := GetKeyFile(ks.keysDirPath, keyAddr)
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 
 	keyProtected := new(encryptedKeyJSON)
 	err = json.Unmarshal(fileContent, keyProtected)
 
+	keyId = keyProtected.Id
 	salt := keyProtected.Crypto.Salt
-
 	iv := keyProtected.Crypto.IV
-
 	cipherText := keyProtected.Crypto.CipherText
 
 	authArray := []byte(auth)
 	derivedKey, err := scrypt.Key(authArray, salt, scryptN, scryptr, scryptp, scryptdkLen)
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 	plainText, err := aesCBCDecrypt(derivedKey, cipherText, iv)
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 	keyBytes = plainText[:len(plainText)-32]
 	keyBytesHash := plainText[len(plainText)-32:]
 	if !bytes.Equal(Sha3(keyBytes), keyBytesHash) {
 		err = errors.New("Decryption failed: checksum mismatch")
-		return nil, err
+		return nil, nil, err
 	}
-	return keyBytes, err
+	return keyBytes, keyId, err
 }
 
 func getEntropyCSPRNG(n int) []byte {
diff --git a/crypto/key_store_plain.go b/crypto/key_store_plain.go
index b6e2a309a9a37f3ba3c75d3a9c9740d36ab0e81d..6b76962a0b1438bda72d2079dd8189defc5b1fc1 100644
--- a/crypto/key_store_plain.go
+++ b/crypto/key_store_plain.go
@@ -24,7 +24,7 @@
 package crypto
 
 import (
-	"code.google.com/p/go-uuid/uuid"
+	"encoding/hex"
 	"encoding/json"
 	"fmt"
 	"io"
@@ -38,9 +38,10 @@ import (
 type KeyStore2 interface {
 	// create new key using io.Reader entropy source and optionally using auth string
 	GenerateNewKey(io.Reader, string) (*Key, error)
-	GetKey(*uuid.UUID, string) (*Key, error) // key from id and auth string
-	StoreKey(*Key, string) error             // store key optionally using auth string
-	DeleteKey(*uuid.UUID, string) error      // delete key by id and auth string
+	GetKey([]byte, string) (*Key, error) // key from addr and auth string
+	GetKeyAddresses() ([][]byte, error)  // get all addresses
+	StoreKey(*Key, string) error         // store key optionally using auth string
+	DeleteKey([]byte, string) error      // delete key by addr and auth string
 }
 
 type keyStorePlain struct {
@@ -72,8 +73,8 @@ func GenerateNewKeyDefault(ks KeyStore2, rand io.Reader, auth string) (key *Key,
 	return key, err
 }
 
-func (ks keyStorePlain) GetKey(keyId *uuid.UUID, auth string) (key *Key, err error) {
-	fileContent, err := GetKeyFile(ks.keysDirPath, keyId)
+func (ks keyStorePlain) GetKey(keyAddr []byte, auth string) (key *Key, err error) {
+	fileContent, err := GetKeyFile(ks.keysDirPath, keyAddr)
 	if err != nil {
 		return nil, err
 	}
@@ -83,32 +84,50 @@ func (ks keyStorePlain) GetKey(keyId *uuid.UUID, auth string) (key *Key, err err
 	return key, err
 }
 
+func (ks keyStorePlain) GetKeyAddresses() (addresses [][]byte, err error) {
+	return GetKeyAddresses(ks.keysDirPath)
+}
+
 func (ks keyStorePlain) StoreKey(key *Key, auth string) (err error) {
 	keyJSON, err := json.Marshal(key)
 	if err != nil {
 		return err
 	}
-	err = WriteKeyFile(key.Id.String(), ks.keysDirPath, keyJSON)
+	err = WriteKeyFile(key.Address, ks.keysDirPath, keyJSON)
 	return err
 }
 
-func (ks keyStorePlain) DeleteKey(keyId *uuid.UUID, auth string) (err error) {
-	keyDirPath := path.Join(ks.keysDirPath, keyId.String())
+func (ks keyStorePlain) DeleteKey(keyAddr []byte, auth string) (err error) {
+	keyDirPath := path.Join(ks.keysDirPath, hex.EncodeToString(keyAddr))
 	err = os.RemoveAll(keyDirPath)
 	return err
 }
 
-func GetKeyFile(keysDirPath string, keyId *uuid.UUID) (fileContent []byte, err error) {
-	id := keyId.String()
-	return ioutil.ReadFile(path.Join(keysDirPath, id, id))
+func GetKeyFile(keysDirPath string, keyAddr []byte) (fileContent []byte, err error) {
+	fileName := hex.EncodeToString(keyAddr)
+	return ioutil.ReadFile(path.Join(keysDirPath, fileName, fileName))
 }
 
-func WriteKeyFile(id string, keysDirPath string, content []byte) (err error) {
-	keyDirPath := path.Join(keysDirPath, id)
-	keyFilePath := path.Join(keyDirPath, id)
+func WriteKeyFile(addr []byte, keysDirPath string, content []byte) (err error) {
+	addrHex := hex.EncodeToString(addr)
+	keyDirPath := path.Join(keysDirPath, addrHex)
+	keyFilePath := path.Join(keyDirPath, addrHex)
 	err = os.MkdirAll(keyDirPath, 0700) // read, write and dir search for user
 	if err != nil {
 		return err
 	}
 	return ioutil.WriteFile(keyFilePath, content, 0600) // read, write for user
 }
+
+func GetKeyAddresses(keysDirPath string) (addresses [][]byte, err error) {
+	fileInfos, err := ioutil.ReadDir(keysDirPath)
+	if err != nil {
+		return nil, err
+	}
+	addresses = make([][]byte, len(fileInfos))
+	for i, fileInfo := range fileInfos {
+		addresses[i] = make([]byte, 40)
+		addresses[i] = []byte(fileInfo.Name())
+	}
+	return addresses, err
+}
diff --git a/crypto/key_store_test.go b/crypto/key_store_test.go
index 54efc739a2e036407ac6fcee0623c6da9d6bb016..0d229ab654f9333550ff42cf3421ff8899c7d60f 100644
--- a/crypto/key_store_test.go
+++ b/crypto/key_store_test.go
@@ -15,12 +15,12 @@ func TestKeyStorePlain(t *testing.T) {
 	}
 
 	k2 := new(Key)
-	k2, err = ks.GetKey(k1.Id, pass)
+	k2, err = ks.GetKey(k1.Address, pass)
 	if err != nil {
 		t.Fatal(err)
 	}
 
-	if !reflect.DeepEqual(k1.Id, k2.Id) {
+	if !reflect.DeepEqual(k1.Address, k2.Address) {
 		t.Fatal(err)
 	}
 
@@ -28,7 +28,7 @@ func TestKeyStorePlain(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	err = ks.DeleteKey(k2.Id, pass)
+	err = ks.DeleteKey(k2.Address, pass)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -42,11 +42,11 @@ func TestKeyStorePassphrase(t *testing.T) {
 		t.Fatal(err)
 	}
 	k2 := new(Key)
-	k2, err = ks.GetKey(k1.Id, pass)
+	k2, err = ks.GetKey(k1.Address, pass)
 	if err != nil {
 		t.Fatal(err)
 	}
-	if !reflect.DeepEqual(k1.Id, k2.Id) {
+	if !reflect.DeepEqual(k1.Address, k2.Address) {
 		t.Fatal(err)
 	}
 
@@ -54,7 +54,7 @@ func TestKeyStorePassphrase(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	err = ks.DeleteKey(k2.Id, pass) // also to clean up created files
+	err = ks.DeleteKey(k2.Address, pass) // also to clean up created files
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -68,17 +68,17 @@ func TestKeyStorePassphraseDecryptionFail(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	_, err = ks.GetKey(k1.Id, "bar") // wrong passphrase
+	_, err = ks.GetKey(k1.Address, "bar") // wrong passphrase
 	if err == nil {
 		t.Fatal(err)
 	}
 
-	err = ks.DeleteKey(k1.Id, "bar") // wrong passphrase
+	err = ks.DeleteKey(k1.Address, "bar") // wrong passphrase
 	if err == nil {
 		t.Fatal(err)
 	}
 
-	err = ks.DeleteKey(k1.Id, pass) // to clean up
+	err = ks.DeleteKey(k1.Address, pass) // to clean up
 	if err != nil {
 		t.Fatal(err)
 	}