diff --git a/Makefile b/Makefile
index 913a5d25da21868ca810efa834d8a77ea8cf7252..649eb0996a05b3c240751e5e99f8da386b1a8a18 100644
--- a/Makefile
+++ b/Makefile
@@ -156,8 +156,12 @@ docker_build: check commit_hash
 test: check
 	@go test ${PACKAGES_NOVENDOR}
 
+.PHONY: test_keys
+test_keys: build_db
+	burrow_bin="${REPO}/bin/burrow" keys/test.sh
+
 .PHONY: test_integration
-test_integration:
+test_integration: test_keys
 	@go test -tags integration ./rpc/v0/integration
 	@go test -tags integration ./rpc/tm/integration
 
diff --git a/client/methods/call.go b/client/methods/call.go
index c613ff489f089c14d0a8286127ad47c2abecea3b..38271439ae27955983272440f640df28c6eeebde 100644
--- a/client/methods/call.go
+++ b/client/methods/call.go
@@ -29,7 +29,10 @@ func Call(do *client.Do) error {
 	if err != nil {
 		return fmt.Errorf("Could not generate logging config from Do: %s", err)
 	}
-	burrowKeyClient := keys.NewKeyClient(do.SignAddrFlag, logger)
+	burrowKeyClient, err := keys.NewRemoteKeyClient(do.SignAddrFlag, logger)
+	if err != nil {
+		return fmt.Errorf("Could not create remote key client: %s", err)
+	}
 	burrowNodeClient := client.NewBurrowNodeClient(do.NodeAddrFlag, logger)
 	// form the call transaction
 	callTransaction, err := rpc.Call(burrowNodeClient, burrowKeyClient,
diff --git a/client/methods/send.go b/client/methods/send.go
index b9736d5065816f1ec43a69c9479288c99a0cffcf..e04771e185b358a22c0e8fcb53b99adb47504bc9 100644
--- a/client/methods/send.go
+++ b/client/methods/send.go
@@ -29,7 +29,10 @@ func Send(do *client.Do) error {
 	if err != nil {
 		return fmt.Errorf("Could not generate logging config from Do: %s", err)
 	}
-	burrowKeyClient := keys.NewKeyClient(do.SignAddrFlag, logger)
+	burrowKeyClient, err := keys.NewRemoteKeyClient(do.SignAddrFlag, logger)
+	if err != nil {
+		return fmt.Errorf("Could not create remote key client: %s", err)
+	}
 	burrowNodeClient := client.NewBurrowNodeClient(do.NodeAddrFlag, logger)
 	// form the send transaction
 	sendTransaction, err := rpc.Send(burrowNodeClient, burrowKeyClient,
diff --git a/cmd/burrow/commands/configure.go b/cmd/burrow/commands/configure.go
index 97c64432f120452f7db6e5c8004081e235687f7c..a964e2f9eb86b330eb34327ccfb8d31bbdc43c1b 100644
--- a/cmd/burrow/commands/configure.go
+++ b/cmd/burrow/commands/configure.go
@@ -12,7 +12,6 @@ import (
 	"github.com/hyperledger/burrow/genesis"
 	"github.com/hyperledger/burrow/genesis/spec"
 	"github.com/hyperledger/burrow/keys"
-	"github.com/hyperledger/burrow/keys/mock"
 	"github.com/hyperledger/burrow/logging"
 	logging_config "github.com/hyperledger/burrow/logging/config"
 	"github.com/hyperledger/burrow/logging/config/presets"
@@ -27,8 +26,8 @@ func Configure(output Output) func(cmd *cli.Cmd) {
 		jsonOutOpt := cmd.BoolOpt("j json", false, "Emit config in JSON rather than TOML "+
 			"suitable for further processing")
 
-		keysUrlOpt := cmd.StringOpt("k keys-url", "", fmt.Sprintf("Provide keys URL, default: %s",
-			keys.DefaultKeysConfig().URL))
+		keysUrlOpt := cmd.StringOpt("k keys-url", "", fmt.Sprintf("Provide keys GRPC address, default: %s",
+			keys.DefaultKeysConfig().RemoteAddress))
 
 		configOpt := cmd.StringOpt("c base-config", "", "Use the a specified burrow config file as a base")
 
@@ -85,7 +84,7 @@ func Configure(output Output) func(cmd *cli.Cmd) {
 			}
 
 			if *keysUrlOpt != "" {
-				conf.Keys.URL = *keysUrlOpt
+				conf.Keys.RemoteAddress = *keysUrlOpt
 			}
 
 			// Genesis Spec
@@ -95,14 +94,22 @@ func Configure(output Output) func(cmd *cli.Cmd) {
 				if err != nil {
 					output.Fatalf("Could not read GenesisSpec: %v", err)
 				}
+				keyStore := keys.NewKeyStore(conf.Keys.KeysDirectory)
 				if *generateKeysOpt != "" {
-					keyClient := mock.NewKeyClient()
+					keyClient := keys.NewLocalKeyClient(keyStore, logging.NewNoopLogger())
 					conf.GenesisDoc, err = genesisSpec.GenesisDoc(keyClient)
 					if err != nil {
 						output.Fatalf("Could not generate GenesisDoc from GenesisSpec using MockKeyClient: %v", err)
 					}
 
-					pkg := deployment.Package{Keys: keyClient.Keys()}
+					allKeys, err := keyStore.AllKeys()
+					if err != nil {
+						output.Fatalf("could get all keys: %v", err)
+					}
+					pkg := deployment.Package{Keys: allKeys}
+					if err != nil {
+						output.Fatalf("Could not dump keys: %v", err)
+					}
 					secretKeysString, err := pkg.Dump(*keysTemplateOpt)
 					if err != nil {
 						output.Fatalf("Could not dump keys: %v", err)
@@ -112,8 +119,18 @@ func Configure(output Output) func(cmd *cli.Cmd) {
 						output.Fatalf("Could not write secret keys: %v", err)
 					}
 				} else {
-					conf.GenesisDoc, err = genesisSpec.GenesisDoc(keys.NewKeyClient(conf.Keys.URL, logging.NewNoopLogger()))
+					var keyClient keys.KeyClient
+					if conf.Keys.RemoteAddress != "" {
+						keyClient, err = keys.NewRemoteKeyClient(conf.Keys.RemoteAddress, logging.NewNoopLogger())
+						if err != nil {
+							output.Fatalf("Could not create remote key client: %v", err)
+						}
+					} else {
+						keyClient = keys.NewLocalKeyClient(keyStore, logging.NewNoopLogger())
+					}
+					conf.GenesisDoc, err = genesisSpec.GenesisDoc(keyClient)
 				}
+
 				if err != nil {
 					output.Fatalf("could not realise GenesisSpec: %v", err)
 				}
diff --git a/cmd/burrow/commands/keys.go b/cmd/burrow/commands/keys.go
index 4b9408c6f60f0915fc62c054b703cbe3019b7eb8..10b3c4fe240425a8b1fb8d48252af480befe306e 100644
--- a/cmd/burrow/commands/keys.go
+++ b/cmd/burrow/commands/keys.go
@@ -4,11 +4,12 @@ import (
 	"context"
 	"encoding/hex"
 	"fmt"
-	"io/ioutil"
 	"os"
 
 	"time"
 
+	"io/ioutil"
+
 	"github.com/howeyc/gopass"
 	"github.com/hyperledger/burrow/crypto"
 	"github.com/hyperledger/burrow/keys"
@@ -17,34 +18,37 @@ import (
 	"google.golang.org/grpc"
 )
 
-func grpcKeysClient(output Output) pbkeys.KeysClient {
-	var opts []grpc.DialOption
-	opts = append(opts, grpc.WithInsecure())
-	conn, err := grpc.Dial(keys.KeyHost+":"+keys.KeyPort, opts...)
-	if err != nil {
-		output.Fatalf("Failed to connect to grpc server: %v", err)
-	}
-	return pbkeys.NewKeysClient(conn)
-}
-
 func Keys(output Output) func(cmd *cli.Cmd) {
 	return func(cmd *cli.Cmd) {
-		if keysHost := os.Getenv("MONAX_KEYS_HOST"); keysHost != "" {
-			keys.DefaultHost = keysHost
-		}
-		if keysPort := os.Getenv("MONAX_KEYS_PORT"); keysPort != "" {
-			keys.DefaultPort = keysPort
-		}
+		keysHost := cmd.String(cli.StringOpt{
+			Name:   "host",
+			Desc:   "set the host for talking to the key daemon",
+			Value:  keys.DefaultHost,
+			EnvVar: "MONAX_KEYS_HOST",
+		})
 
-		keys.KeyHost = *cmd.StringOpt("host", keys.DefaultHost, "set the host for talking to the key daemon")
+		keysPort := cmd.String(cli.StringOpt{
+			Name:   "host",
+			Desc:   "set the port for key daemon",
+			Value:  keys.DefaultPort,
+			EnvVar: "MONAX_KEYS_PORT",
+		})
 
-		keys.KeyPort = *cmd.StringOpt("port", keys.DefaultPort, "set the port for key daemon")
+		grpcKeysClient := func(output Output) pbkeys.KeysClient {
+			var opts []grpc.DialOption
+			opts = append(opts, grpc.WithInsecure())
+			conn, err := grpc.Dial(*keysHost+":"+*keysPort, opts...)
+			if err != nil {
+				output.Fatalf("Failed to connect to grpc server: %v", err)
+			}
+			return pbkeys.NewKeysClient(conn)
+		}
 
 		cmd.Command("server", "run keys server", func(cmd *cli.Cmd) {
-			keys.KeysDir = *cmd.StringOpt("dir", keys.DefaultDir, "specify the location of the directory containing key files")
+			keysDir := cmd.StringOpt("dir", keys.DefaultKeysDir, "specify the location of the directory containing key files")
 
 			cmd.Action = func() {
-				err := keys.StartStandAloneServer(keys.KeyHost, keys.KeyPort)
+				err := keys.StartStandAloneServer(*keysDir, *keysHost, *keysPort)
 				if err != nil {
 					output.Fatalf("Failed to start server: %v", err)
 				}
@@ -137,16 +141,24 @@ func Keys(output Output) func(cmd *cli.Cmd) {
 
 		cmd.Command("import", "import <priv key> | /path/to/keyfile | <key json>", func(cmd *cli.Cmd) {
 			curveType := cmd.StringOpt("t curvetype", "ed25519", "specify the curve type of key to create. Supports 'secp256k1' (ethereum),  'ed25519' (tendermint)")
+			noPassword := cmd.BoolOpt("n no-password", false, "don't use a password for this key")
 			key := cmd.StringArg("KEY", "", "private key, filename, or raw json")
 
 			cmd.Action = func() {
-				var privKeyBytes []byte
-				var err error
-				if _, err := os.Stat(*key); err == nil {
-					privKeyBytes, err = ioutil.ReadFile(*key)
+				var password string
+				if !*noPassword {
+					fmt.Printf("Enter Password:")
+					pwd, err := gopass.GetPasswdMasked()
 					if err != nil {
-						output.Fatalf("Failed to read file %s: %v", *key, err)
+						os.Exit(1)
 					}
+					password = string(pwd)
+				}
+
+				var privKeyBytes []byte
+				fileContents, err := ioutil.ReadFile(*key)
+				if err == nil {
+					*key = string(fileContents)
 				}
 
 				c := grpcKeysClient(output)
@@ -159,18 +171,18 @@ func Keys(output Output) func(cmd *cli.Cmd) {
 						output.Fatalf("failed to import json key: %v", err)
 					}
 
-					fmt.Printf("%X\n", resp.GetAddress())
+					fmt.Printf("%s\n", resp.GetAddress())
 				} else {
 					privKeyBytes, err = hex.DecodeString(*key)
 					if err != nil {
-						output.Fatalf("failed to hex decode key")
+						output.Fatalf("failed to hex decode key: %s", *key)
 					}
-					resp, err := c.Import(ctx, &pbkeys.ImportRequest{Keybytes: privKeyBytes, Curvetype: *curveType})
+					resp, err := c.Import(ctx, &pbkeys.ImportRequest{Passphrase: password, Keybytes: privKeyBytes, Curvetype: *curveType})
 					if err != nil {
 						output.Fatalf("failed to import json key: %v", err)
 					}
 
-					fmt.Printf("%X\n", resp.GetAddress())
+					fmt.Printf("%s\n", resp.GetAddress())
 
 				}
 			}
@@ -194,8 +206,9 @@ func Keys(output Output) func(cmd *cli.Cmd) {
 		})
 
 		cmd.Command("sign", "sign <some data>", func(cmd *cli.Cmd) {
+			name := cmd.StringOpt("name", "", "name of key to use")
 			addr := cmd.StringOpt("addr", "", "address of key to use")
-			msg := cmd.StringArg("HASH", "", "hash to sign")
+			msg := cmd.StringArg("MSG", "", "message to sign")
 			passphrase := cmd.StringOpt("passphrase", "", "passphrase for encrypted key")
 
 			cmd.Action = func() {
@@ -207,7 +220,7 @@ func Keys(output Output) func(cmd *cli.Cmd) {
 				c := grpcKeysClient(output)
 				ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
 				defer cancel()
-				resp, err := c.Sign(ctx, &pbkeys.SignRequest{Passphrase: *passphrase, Address: *addr, Hash: message})
+				resp, err := c.Sign(ctx, &pbkeys.SignRequest{Passphrase: *passphrase, Name: *name, Address: *addr, Message: message})
 				if err != nil {
 					output.Fatalf("failed to get public key: %v", err)
 				}
@@ -241,22 +254,23 @@ func Keys(output Output) func(cmd *cli.Cmd) {
 				c := grpcKeysClient(output)
 				ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
 				defer cancel()
-				_, err = c.Verify(ctx, &pbkeys.VerifyRequest{Curvetype: *curveType, Pub: publickey, Signature: signature, Hash: message})
+				_, err = c.Verify(ctx, &pbkeys.VerifyRequest{Curvetype: *curveType, Pub: publickey, Signature: signature, Message: message})
 				if err != nil {
 					output.Fatalf("failed to verify: %v", err)
 				}
+				output.Printf("true\n")
 			}
 		})
 
-		cmd.Command("add", "add key by name or addr", func(cmd *cli.Cmd) {
-			name := cmd.StringArg("name", "", "name of key to use")
-			addr := cmd.StringArg("addr", "", "address of key to use")
+		cmd.Command("name", "add key name to addr", func(cmd *cli.Cmd) {
+			keyname := cmd.StringArg("NAME", "", "name of key to use")
+			addr := cmd.StringArg("ADDR", "", "address of key to use")
 
 			cmd.Action = func() {
 				c := grpcKeysClient(output)
 				ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
 				defer cancel()
-				_, err := c.Add(ctx, &pbkeys.AddRequest{Keyname: *name, Address: *addr})
+				_, err := c.AddName(ctx, &pbkeys.AddNameRequest{Keyname: *keyname, Address: *addr})
 				if err != nil {
 					output.Fatalf("failed to add name to addr: %v", err)
 				}
@@ -274,20 +288,28 @@ func Keys(output Output) func(cmd *cli.Cmd) {
 				if err != nil {
 					output.Fatalf("failed to list key names: %v", err)
 				}
-				for _, k := range resp.Key {
-					fmt.Printf("key: %v\n", k)
+				if *name != "" {
+					for _, k := range resp.Key {
+						if k.Keyname == *name {
+							output.Printf("%s\n", k.Address)
+						}
+					}
+				} else {
+					for _, k := range resp.Key {
+						fmt.Printf("%v\n", k)
+					}
 				}
 			}
 		})
 
-		cmd.Command("rm", "rm key by name", func(cmd *cli.Cmd) {
+		cmd.Command("rm", "rm key name", func(cmd *cli.Cmd) {
 			name := cmd.StringArg("NAME", "", "key to remove")
 
 			cmd.Action = func() {
 				c := grpcKeysClient(output)
 				ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
 				defer cancel()
-				_, err := c.Remove(ctx, &pbkeys.Name{*name})
+				_, err := c.RemoveName(ctx, &pbkeys.Name{*name})
 				if err != nil {
 					output.Fatalf("failed to remove key: %v", err)
 				}
diff --git a/config/config.go b/config/config.go
index 5a812bce625ecac9bfd8c3e3ce17d5b481984ca7..24896f06d7fc50cefa1b6c228d6b87a9023c4a03 100644
--- a/config/config.go
+++ b/config/config.go
@@ -55,7 +55,18 @@ func (conf *BurrowConfig) Kernel(ctx context.Context) (*core.Kernel, error) {
 	if err != nil {
 		return nil, fmt.Errorf("could not generate logger from logging config: %v", err)
 	}
-	keyClient := keys.NewKeyClient(conf.Keys.URL, logger)
+	var keyClient keys.KeyClient
+	var keyStore *keys.KeyStore
+	if conf.Keys.RemoteAddress != "" {
+		keyClient, err = keys.NewRemoteKeyClient(conf.Keys.RemoteAddress, logger)
+		if err != nil {
+			return nil, err
+		}
+	} else {
+		*keyStore = keys.NewKeyStore(conf.Keys.KeysDirectory)
+		keyClient = keys.NewLocalKeyClient(*keyStore, logger)
+	}
+
 	val, err := keys.Addressable(keyClient, *conf.ValidatorAddress)
 	if err != nil {
 		return nil, fmt.Errorf("could not get validator addressable from keys client: %v", err)
@@ -71,7 +82,7 @@ func (conf *BurrowConfig) Kernel(ctx context.Context) (*core.Kernel, error) {
 	}
 
 	return core.NewKernel(ctx, keyClient, privValidator, conf.GenesisDoc, conf.Tendermint.TendermintConfig(), conf.RPC, conf.Keys,
-		exeOptions, logger)
+		keyStore, exeOptions, logger)
 }
 
 func (conf *BurrowConfig) JSONString() string {
diff --git a/core/integration/test_wrapper.go b/core/integration/test_wrapper.go
index 7c2ab3f6782269300d32d218b3b5c624bcc10b82..8a0e5a46d47526e632c5903518cab7349b1fc75f 100644
--- a/core/integration/test_wrapper.go
+++ b/core/integration/test_wrapper.go
@@ -82,7 +82,7 @@ func TestWrapper(privateAccounts []acm.PrivateAccount, genesisDoc *genesis.Genes
 	privValidator := validator.NewPrivValidatorMemory(validatorAccount, validatorAccount)
 	keyClient := mock.NewKeyClient(privateAccounts...)
 	kernel, err := core.NewKernel(context.Background(), keyClient, privValidator, genesisDoc, tmConf, rpc.DefaultRPCConfig(), keys.DefaultKeysConfig(),
-		nil, logger)
+		nil, nil, logger)
 	if err != nil {
 		panic(err)
 	}
diff --git a/core/kernel.go b/core/kernel.go
index 598505abe0df6df976884b1c3adeb00e6a554e05..437c43fcb9f24a07307ac7f186fa1271d6188912 100644
--- a/core/kernel.go
+++ b/core/kernel.go
@@ -34,6 +34,7 @@ import (
 	"github.com/hyperledger/burrow/execution"
 	"github.com/hyperledger/burrow/genesis"
 	"github.com/hyperledger/burrow/keys"
+	"github.com/hyperledger/burrow/keys/pbkeys"
 	"github.com/hyperledger/burrow/logging"
 	"github.com/hyperledger/burrow/logging/structure"
 	"github.com/hyperledger/burrow/process"
@@ -68,7 +69,7 @@ type Kernel struct {
 
 func NewKernel(ctx context.Context, keyClient keys.KeyClient, privValidator tm_types.PrivValidator,
 	genesisDoc *genesis.GenesisDoc, tmConf *tm_config.Config, rpcConfig *rpc.RPCConfig, keyConfig *keys.KeysConfig,
-	exeOptions []execution.ExecutionOption, logger *logging.Logger) (*Kernel, error) {
+	keyStore *keys.KeyStore, exeOptions []execution.ExecutionOption, logger *logging.Logger) (*Kernel, error) {
 
 	logger = logger.WithScope("NewKernel()").With(structure.TimeKey, kitlog.DefaultTimestampUTC)
 	tmLogger := logger.With(structure.CallerKey, kitlog.Caller(LoggingCallerDepth+1))
@@ -211,14 +212,25 @@ func NewKernel(ctx context.Context, keyClient keys.KeyClient, privValidator tm_t
 				}
 
 				grpcServer := grpc.NewServer()
-				err = keys.StartGRPCServer(grpcServer, keyConfig)
-				if err != nil {
-					return nil, err
+				var ks keys.KeyStore
+				if keyStore != nil {
+					ks = *keyStore
+				}
+
+				if keyConfig.GRPCServiceEnabled {
+					if keyStore == nil {
+						ks = keys.NewKeyStore(keyConfig.KeysDirectory)
+					}
+					pbkeys.RegisterKeysServer(grpcServer, &ks)
 				}
 
 				go grpcServer.Serve(listen)
 
-				return process.FromListeners(listen), nil
+				return process.ShutdownFunc(func(ctx context.Context) error {
+					grpcServer.Stop()
+					// listener is closed for us
+					return nil
+				}), nil
 			},
 		},
 	}
diff --git a/core/kernel_test.go b/core/kernel_test.go
index 480578bce3fd9b509357688395a5c3b1d743f100..e02ef7cd60463e64b0590a102be606cd7693c0e3 100644
--- a/core/kernel_test.go
+++ b/core/kernel_test.go
@@ -13,7 +13,6 @@ import (
 	"github.com/hyperledger/burrow/consensus/tendermint/validator"
 	"github.com/hyperledger/burrow/genesis"
 	"github.com/hyperledger/burrow/keys"
-	"github.com/hyperledger/burrow/keys/mock"
 	"github.com/hyperledger/burrow/logging"
 	"github.com/hyperledger/burrow/rpc"
 	"github.com/stretchr/testify/assert"
@@ -66,8 +65,10 @@ func bootWaitBlocksShutdown(privValidator tm_types.PrivValidator, genesisDoc *ge
 	tmConf *tm_config.Config, logger *logging.Logger,
 	blockChecker func(block *tm_types.EventDataNewBlock) (cont bool)) error {
 
-	kern, err := NewKernel(context.Background(), mock.NewKeyClient(), privValidator, genesisDoc, tmConf,
-		rpc.DefaultRPCConfig(), keys.DefaultKeysConfig(), nil, logger)
+	keyStore := keys.NewKeyStore(keys.DefaultKeysDir)
+	keyClient := keys.NewLocalKeyClient(keyStore, logging.NewNoopLogger())
+	kern, err := NewKernel(context.Background(), keyClient, privValidator, genesisDoc, tmConf,
+		rpc.DefaultRPCConfig(), keys.DefaultKeysConfig(), &keyStore, nil, logger)
 	if err != nil {
 		return err
 	}
diff --git a/crypto/crypto.go b/crypto/crypto.go
index b3ebf03e29606c8355917ef7bde020589cd3017b..400345fce3a4abae70942dd40a8cf76501ca3e19 100644
--- a/crypto/crypto.go
+++ b/crypto/crypto.go
@@ -4,16 +4,15 @@ import (
 	"bytes"
 	crand "crypto/rand"
 	"crypto/sha256"
-	"encoding/hex"
 	"encoding/json"
 	"fmt"
 	"io"
 
-	"golang.org/x/crypto/ripemd160"
-
 	"github.com/btcsuite/btcd/btcec"
 	tm_crypto "github.com/tendermint/go-crypto"
+	"github.com/tmthrgd/go-hex"
 	"golang.org/x/crypto/ed25519"
+	"golang.org/x/crypto/ripemd160"
 )
 
 type CurveType int8
@@ -46,6 +45,17 @@ func CurveTypeFromString(s string) (CurveType, error) {
 	}
 }
 
+func (p PublicKey) AddressHashType() string {
+	switch p.CurveType {
+	case CurveTypeEd25519:
+		return "go-crypto-0.5.0"
+	case CurveTypeSecp256k1:
+		return "btc"
+	default:
+		return ""
+	}
+}
+
 type ErrInvalidCurve string
 
 func (err ErrInvalidCurve) Error() string {
@@ -79,7 +89,7 @@ type PublicKeyJSON struct {
 func (p PublicKey) MarshalJSON() ([]byte, error) {
 	jStruct := PublicKeyJSON{
 		Type: p.CurveType.String(),
-		Data: fmt.Sprintf("%X", p.PublicKey),
+		Data: hex.EncodeUpperToString(p.PublicKey),
 	}
 	txt, err := json.Marshal(jStruct)
 	return txt, err
@@ -167,7 +177,7 @@ func (p PublicKey) RawBytes() []byte {
 }
 
 func (p PublicKey) String() string {
-	return fmt.Sprintf("%X", p.PublicKey[:])
+	return hex.EncodeUpperToString(p.PublicKey)
 }
 
 // Signable is an interface for all signable things.
diff --git a/deployment/config.go b/deployment/config.go
index 8f1047b638d8465ae527fc887368add3842e61bd..b5ead42643ef360ee97f81b0b55f3c7b7ec96756 100644
--- a/deployment/config.go
+++ b/deployment/config.go
@@ -8,13 +8,13 @@ import (
 	"text/template"
 
 	"github.com/hyperledger/burrow/config"
-	"github.com/hyperledger/burrow/keys/mock"
+	"github.com/hyperledger/burrow/keys"
 	"github.com/pkg/errors"
 	"github.com/tmthrgd/go-hex"
 )
 
 type Package struct {
-	Keys         []*mock.Key
+	Keys         []*keys.Key
 	BurrowConfig *config.BurrowConfig
 }
 
diff --git a/deployment/config_test.go b/deployment/config_test.go
deleted file mode 100644
index 0020ce7dddcde55fe90d56e6d732da16bb76043f..0000000000000000000000000000000000000000
--- a/deployment/config_test.go
+++ /dev/null
@@ -1,55 +0,0 @@
-package deployment
-
-import (
-	"encoding/json"
-	"fmt"
-	"testing"
-
-	"github.com/hyperledger/burrow/crypto"
-	"github.com/hyperledger/burrow/keys/mock"
-	"github.com/stretchr/testify/assert"
-	"github.com/stretchr/testify/require"
-)
-
-func TestMockKeyClient_DumpKeys(t *testing.T) {
-	keyClient := mock.NewKeyClient()
-	_, err := keyClient.Generate("foo", crypto.CurveTypeEd25519)
-	require.NoError(t, err)
-	_, err = keyClient.Generate("foobar", crypto.CurveTypeEd25519)
-	require.NoError(t, err)
-	pkg := Package{Keys: keyClient.Keys()}
-	dump, err := pkg.Dump(DefaultDumpKeysFormat)
-	require.NoError(t, err)
-
-	// Check JSON equal
-	var keys struct{ Keys []*mock.Key }
-	err = json.Unmarshal([]byte(dump), &keys)
-	require.NoError(t, err)
-	bs, err := json.MarshalIndent(keys, "", "  ")
-	require.NoError(t, err)
-	assert.Equal(t, string(bs), dump)
-}
-
-func TestMockKeyClient_DumpKeysKubernetes(t *testing.T) {
-	keyClient := mock.NewKeyClient()
-	_, err := keyClient.Generate("foo", crypto.CurveTypeEd25519)
-	require.NoError(t, err)
-	_, err = keyClient.Generate("foobar", crypto.CurveTypeEd25519)
-	require.NoError(t, err)
-	pkg := Package{Keys: keyClient.Keys()}
-	dump, err := pkg.Dump(KubernetesKeyDumpFormat)
-	require.NoError(t, err)
-	fmt.Println(dump)
-}
-
-func TestMockKeyClient_DumpKeysHelm(t *testing.T) {
-	keyClient := mock.NewKeyClient()
-	_, err := keyClient.Generate("foo", crypto.CurveTypeEd25519)
-	require.NoError(t, err)
-	_, err = keyClient.Generate("foobar", crypto.CurveTypeEd25519)
-	require.NoError(t, err)
-	pkg := Package{Keys: keyClient.Keys()}
-	dump, err := pkg.Dump(HelmDumpKeysFormat)
-	require.NoError(t, err)
-	fmt.Println(dump)
-}
diff --git a/keys/common/paths.go b/keys/common/paths.go
index 76d443a2fa9f12489bc1d5a50ed350a12950870b..075800636f3034306f135db7fff728811bace0c5 100644
--- a/keys/common/paths.go
+++ b/keys/common/paths.go
@@ -6,16 +6,6 @@ import (
 	"runtime"
 )
 
-var (
-	// Convenience directories.
-	MonaxRoot          = ResolveMonaxRoot()
-	MonaxContainerRoot = "/home/monax/.monax"
-
-	// Major directories.
-	KeysPath    = filepath.Join(MonaxRoot, "keys")
-	ScratchPath = filepath.Join(MonaxRoot, "scratch")
-)
-
 func HomeDir() string {
 	if runtime.GOOS == "windows" {
 		drive := os.Getenv("HOMEDRIVE")
diff --git a/keys/config.go b/keys/config.go
index 082911ec27de07b8ed13d433890ad5d0ac7a4efa..d50d61338f9934dbb9301c36ee6878142e1ac81c 100644
--- a/keys/config.go
+++ b/keys/config.go
@@ -1,14 +1,16 @@
 package keys
 
 type KeysConfig struct {
-	ServerEnabled bool
-	URL           string
+	GRPCServiceEnabled bool
+	RemoteAddress      string
+	KeysDirectory      string
 }
 
 func DefaultKeysConfig() *KeysConfig {
 	return &KeysConfig{
 		// Default Monax keys port
-		ServerEnabled: true,
-		URL:           "",
+		GRPCServiceEnabled: true,
+		RemoteAddress:      "",
+		KeysDirectory:      DefaultKeysDir,
 	}
 }
diff --git a/keys/core.go b/keys/core.go
index 8fb37c7ef7cbe69bfaec60a467de2b0aaa7a9d14..8642a820b331dc99c5ea8c43f30d99210886d433 100644
--- a/keys/core.go
+++ b/keys/core.go
@@ -1,7 +1,6 @@
 package keys
 
 import (
-	"encoding/hex"
 	"fmt"
 	"io/ioutil"
 	"os"
@@ -9,27 +8,16 @@ import (
 	"path/filepath"
 	"strings"
 
-	"github.com/hyperledger/burrow/keys/common"
-
 	tmint_crypto "github.com/hyperledger/burrow/crypto/helpers"
 	wire "github.com/tendermint/go-wire"
 )
 
-var (
-	DefaultKeyType  = "ed25519"
-	DefaultDir      = common.KeysPath
+const (
+	DefaultHost     = "localhost"
+	DefaultPort     = "10997"
 	DefaultHashType = "sha256"
-
-	DefaultHost = "localhost"
-	DefaultPort = "10997"
-	TestPort    = "7674"
-	TestAddr    = DefaultHost + ":" + TestPort
-
-	KeysDir string = ".monax-keys"
-	KeyHost string
-	KeyPort string
-
-	GlobalKeystore KeyStore
+	DefaultKeysDir  = ".keys"
+	TestPort        = "7674"
 )
 
 func returnDataDir(dir string) (string, error) {
@@ -52,12 +40,8 @@ func returnNamesDir(dir string) (string, error) {
 
 //-----
 
-func newKeyStore() (KeyStore, error) {
-	dir, err := returnDataDir(KeysDir)
-	if err != nil {
-		return nil, err
-	}
-	return NewKeyStoreFile(dir), nil
+func NewKeyStore(dir string) KeyStore {
+	return KeyStore{keysDirPath: dir}
 }
 
 //----------------------------------------------------------------
@@ -72,7 +56,7 @@ func writeKey(keyDir string, addr, keyJson []byte) ([]byte, error) {
 	return addr, nil
 }
 
-func coreExport(passphrase, addr string) ([]byte, error) {
+func coreExport(key *Key) ([]byte, error) {
 	type privValidator struct {
 		Address    []byte        `json:"address"`
 		PubKey     []interface{} `json:"pub_key"`
@@ -82,19 +66,8 @@ func coreExport(passphrase, addr string) ([]byte, error) {
 		LastStep   int           `json:"last_step"`
 	}
 
-	addrB, err := hex.DecodeString(addr)
-	if err != nil {
-		return nil, fmt.Errorf("addr is invalid hex: %s", err.Error())
-	}
-	key, err := GlobalKeystore.GetKey(passphrase, addrB)
-	if err != nil {
-		return nil, err
-	}
-
 	pub := key.Pubkey()
-	if err != nil {
-		return nil, err
-	}
+
 	var pubKeyWithType []interface{}
 	var pubKey tmint_crypto.PubKeyEd25519
 	copy(pubKey[:], pub)
@@ -108,7 +81,7 @@ func coreExport(passphrase, addr string) ([]byte, error) {
 	privKeyWithType = append(privKeyWithType, privKey)
 
 	privVal := &privValidator{
-		Address: addrB,
+		Address: key.Address[:],
 		PubKey:  pubKeyWithType,
 		PrivKey: privKeyWithType,
 	}
@@ -119,23 +92,23 @@ func coreExport(passphrase, addr string) ([]byte, error) {
 //----------------------------------------------------------------
 // manage names for keys
 
-func coreNameAdd(name, addr string) error {
-	namesDir, err := returnNamesDir(KeysDir)
+func coreNameAdd(keysDir, name, addr string) error {
+	namesDir, err := returnNamesDir(keysDir)
 	if err != nil {
 		return err
 	}
-	keysDir, err := returnDataDir(KeysDir)
+	dataDir, err := returnDataDir(keysDir)
 	if err != nil {
 		return err
 	}
-	if _, err := os.Stat(path.Join(keysDir, addr)); err != nil {
+	if _, err := os.Stat(path.Join(dataDir, addr+".json")); err != nil {
 		return fmt.Errorf("Unknown key %s", addr)
 	}
 	return ioutil.WriteFile(path.Join(namesDir, name), []byte(addr), 0600)
 }
 
-func coreNameList() (map[string]string, error) {
-	dir, err := returnNamesDir(KeysDir)
+func coreNameList(keysDir string) (map[string]string, error) {
+	dir, err := returnNamesDir(keysDir)
 	if err != nil {
 		return nil, err
 	}
@@ -154,8 +127,8 @@ func coreNameList() (map[string]string, error) {
 	return names, nil
 }
 
-func coreAddrList() (map[int]string, error) {
-	dir, err := returnDataDir(KeysDir)
+func coreAddrList(keysDir string) (map[int]string, error) {
+	dir, err := returnDataDir(keysDir)
 	if err != nil {
 		return nil, err
 	}
@@ -170,16 +143,16 @@ func coreAddrList() (map[int]string, error) {
 	return addrs, nil
 }
 
-func coreNameRm(name string) error {
-	dir, err := returnNamesDir(KeysDir)
+func coreNameRm(keysDir string, name string) error {
+	dir, err := returnNamesDir(keysDir)
 	if err != nil {
 		return err
 	}
 	return os.Remove(path.Join(dir, name))
 }
 
-func coreNameGet(name string) (string, error) {
-	dir, err := returnNamesDir(KeysDir)
+func coreNameGet(keysDir, name string) (string, error) {
+	dir, err := returnNamesDir(keysDir)
 	if err != nil {
 		return "", err
 	}
@@ -201,7 +174,7 @@ func checkMakeDataDir(dir string) error {
 }
 
 // return addr from name or addr
-func getNameAddr(name, addr string) (string, error) {
+func getNameAddr(keysDir, name, addr string) (string, error) {
 	if name == "" && addr == "" {
 		return "", fmt.Errorf("at least one of name or addr must be provided")
 	}
@@ -209,7 +182,7 @@ func getNameAddr(name, addr string) (string, error) {
 	// name takes precedent if both are given
 	var err error
 	if name != "" {
-		addr, err = coreNameGet(name)
+		addr, err = coreNameGet(keysDir, name)
 		if err != nil {
 			return "", err
 		}
diff --git a/keys/key_client.go b/keys/key_client.go
index 6e669ec2d56a269d6398861334941f47a0dd6552..49983e41c987427e403b747b41a96cbe5234cb11 100644
--- a/keys/key_client.go
+++ b/keys/key_client.go
@@ -27,8 +27,8 @@ import (
 )
 
 type KeyClient interface {
-	// Sign returns the signature bytes for given hash signed with the key associated with signAddress
-	Sign(signAddress crypto.Address, hash []byte) (signature crypto.Signature, err error)
+	// Sign returns the signature bytes for given message signed with the key associated with signAddress
+	Sign(signAddress crypto.Address, message []byte) (signature crypto.Signature, err error)
 
 	// PublicKey returns the public key associated with a given address
 	PublicKey(address crypto.Address) (publicKey crypto.PublicKey, err error)
@@ -44,6 +44,7 @@ var _ KeyClient = (*localKeyClient)(nil)
 var _ KeyClient = (*remoteKeyClient)(nil)
 
 type localKeyClient struct {
+	ks     KeyStore
 	logger *logging.Logger
 }
 
@@ -53,8 +54,8 @@ type remoteKeyClient struct {
 	logger     *logging.Logger
 }
 
-func (l localKeyClient) Sign(signAddress crypto.Address, hash []byte) (signature crypto.Signature, err error) {
-	resp, err := GlobalKeyServer.Sign(nil, &pbkeys.SignRequest{Address: signAddress.String(), Hash: hash})
+func (l localKeyClient) Sign(signAddress crypto.Address, message []byte) (signature crypto.Signature, err error) {
+	resp, err := l.ks.Sign(nil, &pbkeys.SignRequest{Address: signAddress.String(), Message: message})
 	if err != nil {
 		return crypto.Signature{}, err
 	}
@@ -66,7 +67,7 @@ func (l localKeyClient) Sign(signAddress crypto.Address, hash []byte) (signature
 }
 
 func (l localKeyClient) PublicKey(address crypto.Address) (publicKey crypto.PublicKey, err error) {
-	resp, err := GlobalKeyServer.PublicKey(nil, &pbkeys.PubRequest{Address: address.String()})
+	resp, err := l.ks.PublicKey(nil, &pbkeys.PubRequest{Address: address.String()})
 	if err != nil {
 		return crypto.PublicKey{}, err
 	}
@@ -79,7 +80,7 @@ func (l localKeyClient) PublicKey(address crypto.Address) (publicKey crypto.Publ
 
 // Generate requests that a key be generate within the keys instance and returns the address
 func (l localKeyClient) Generate(keyName string, curveType crypto.CurveType) (keyAddress crypto.Address, err error) {
-	resp, err := GlobalKeyServer.GenerateKey(nil, &pbkeys.GenRequest{Keyname: keyName, Curvetype: curveType.String()})
+	resp, err := l.ks.GenerateKey(nil, &pbkeys.GenRequest{Keyname: keyName, Curvetype: curveType.String()})
 	if err != nil {
 		return crypto.Address{}, err
 	}
@@ -94,7 +95,7 @@ func (l localKeyClient) HealthCheck() error {
 func (l remoteKeyClient) Sign(signAddress crypto.Address, message []byte) (signature crypto.Signature, err error) {
 	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
 	defer cancel()
-	req := pbkeys.SignRequest{Address: signAddress.String(), Hash: message}
+	req := pbkeys.SignRequest{Address: signAddress.String(), Message: message}
 	l.logger.TraceMsg("Sending Sign request to remote key server: ", fmt.Sprintf("%v", req))
 	resp, err := l.kc.Sign(ctx, &req)
 	if err != nil {
@@ -152,32 +153,22 @@ func (l remoteKeyClient) HealthCheck() error {
 
 // keyClient.New returns a new monax-keys client for provided rpc location
 // Monax-keys connects over http request-responses
-func NewKeyClient(rpcAddress string, logger *logging.Logger) KeyClient {
-	logger = logger.WithScope("NewKeyClient")
-	var client KeyClient
-	if rpcAddress != "" {
-		var opts []grpc.DialOption
-		opts = append(opts, grpc.WithInsecure())
-		conn, err := grpc.Dial(rpcAddress, opts...)
-		if err != nil {
-			// FIXME: we should return error, or handle this when the
-			// key client is used for the first time
-			panic("Failed to connect to grpc server")
-		}
-		kc := pbkeys.NewKeysClient(conn)
-
-		client = remoteKeyClient{kc: kc, rpcAddress: rpcAddress, logger: logger}
-	} else {
-		ks, err := newKeyStore()
-		if err != nil {
-			panic("Failed to start keys store")
-		}
-
-		GlobalKeystore = ks
-
-		client = localKeyClient{logger: logger}
+func NewRemoteKeyClient(rpcAddress string, logger *logging.Logger) (KeyClient, error) {
+	logger = logger.WithScope("RemoteKeyClient")
+	var opts []grpc.DialOption
+	opts = append(opts, grpc.WithInsecure())
+	conn, err := grpc.Dial(rpcAddress, opts...)
+	if err != nil {
+		return nil, err
 	}
-	return client
+	kc := pbkeys.NewKeysClient(conn)
+
+	return remoteKeyClient{kc: kc, rpcAddress: rpcAddress, logger: logger}, nil
+}
+
+func NewLocalKeyClient(ks KeyStore, logger *logging.Logger) KeyClient {
+	logger = logger.WithScope("LocalKeyClient")
+	return localKeyClient{ks: ks, logger: logger}
 }
 
 type signer struct {
diff --git a/keys/key_store.go b/keys/key_store.go
index 0dd857dae65628b3926ae0b0dff17d0b43d6d357..fe6c3d54ba306ea46a3dc17ebe1141216be17df3 100644
--- a/keys/key_store.go
+++ b/keys/key_store.go
@@ -59,14 +59,6 @@ func NewKeyFromPriv(curveType crypto.CurveType, PrivKeyBytes []byte) (*Key, erro
 	}, nil
 }
 
-type KeyStore interface {
-	GenerateKey(passphrase string, curveType crypto.CurveType) (*Key, error)
-	GetKey(passphrase string, addr []byte) (*Key, error)
-	GetAllAddresses() ([][]byte, error)
-	StoreKey(passphrase string, key *Key) error
-	DeleteKey(passphrase string, addr []byte) error
-}
-
 func (k *Key) Sign(hash []byte) ([]byte, error) {
 	signature, err := k.PrivateKey.Sign(hash)
 	if err != nil {
diff --git a/keys/key_store_file.go b/keys/key_store_file.go
index fc61ec69b6d27e36390dbd1846d7a371b827c72d..25c2f56728c7c436250bda1837c5b90c81874180 100644
--- a/keys/key_store_file.go
+++ b/keys/key_store_file.go
@@ -4,7 +4,6 @@ import (
 	"crypto/aes"
 	"crypto/cipher"
 	"crypto/rand"
-	"encoding/hex"
 	"encoding/json"
 	"fmt"
 	"io/ioutil"
@@ -14,15 +13,20 @@ import (
 	"sync"
 
 	"github.com/hyperledger/burrow/crypto"
+	"github.com/tmthrgd/go-hex"
 
 	"golang.org/x/crypto/scrypt"
 )
 
 const (
-	scryptN     = 1 << 18
-	scryptr     = 8
-	scryptp     = 1
-	scryptdkLen = 32
+	scryptN       = 1 << 18
+	scryptr       = 8
+	scryptp       = 1
+	scryptdkLen   = 32
+	CryptoNone    = "none"
+	CryptoAESGCM  = "scrypt-aes-gcm"
+	HashEd25519   = "go-crypto-0.5.0"
+	HashSecp256k1 = "btc"
 )
 
 //-----------------------------------------------------------------------------
@@ -48,11 +52,11 @@ type privateKeyJSON struct {
 
 func (k *Key) MarshalJSON() (j []byte, err error) {
 	jStruct := keyJSON{
-		k.CurveType.String(),
-		fmt.Sprintf("%X", k.Address),
-		k.Pubkey(),
-		"go-crypto-0.5.0",
-		privateKeyJSON{Crypto: "none", Plain: k.PrivateKey.RawBytes()},
+		CurveType:   k.CurveType.String(),
+		Address:     hex.EncodeToString(k.Address[:]),
+		PublicKey:   k.Pubkey(),
+		AddressHash: k.PublicKey.AddressHashType(),
+		PrivateKey:  privateKeyJSON{Crypto: CryptoNone, Plain: k.PrivateKey.RawBytes()},
 	}
 	j, err = json.Marshal(jStruct)
 	return j, err
@@ -64,7 +68,6 @@ func (k *Key) UnmarshalJSON(j []byte) (err error) {
 	if err != nil {
 		return err
 	}
-	// TODO: remove this
 	if len(keyJ.PrivateKey.Plain) == 0 {
 		return fmt.Errorf("no private key")
 	}
@@ -96,16 +99,12 @@ func IsValidKeyJson(j []byte) []byte {
 	return nil
 }
 
-type keyStoreFile struct {
+type KeyStore struct {
 	sync.Mutex
 	keysDirPath string
 }
 
-func NewKeyStoreFile(path string) KeyStore {
-	return &keyStoreFile{keysDirPath: path}
-}
-
-func (ks keyStoreFile) GenerateKey(passphrase string, curveType crypto.CurveType) (key *Key, err error) {
+func (ks KeyStore) Gen(passphrase string, curveType crypto.CurveType) (key *Key, err error) {
 	defer func() {
 		if r := recover(); r != nil {
 			err = fmt.Errorf("GenerateNewKey error: %v", r)
@@ -119,10 +118,14 @@ func (ks keyStoreFile) GenerateKey(passphrase string, curveType crypto.CurveType
 	return key, err
 }
 
-func (ks keyStoreFile) GetKey(passphrase string, keyAddr []byte) (*Key, error) {
+func (ks KeyStore) GetKey(passphrase string, keyAddr []byte) (*Key, error) {
 	ks.Lock()
 	defer ks.Unlock()
-	fileContent, err := GetKeyFile(ks.keysDirPath, keyAddr)
+	dataDirPath, err := returnDataDir(ks.keysDirPath)
+	if err != nil {
+		return nil, err
+	}
+	fileContent, err := GetKeyFile(dataDirPath, keyAddr)
 	if err != nil {
 		return nil, err
 	}
@@ -140,6 +143,30 @@ func (ks keyStoreFile) GetKey(passphrase string, keyAddr []byte) (*Key, error) {
 	}
 }
 
+func (ks KeyStore) AllKeys() ([]*Key, error) {
+
+	dataDirPath, err := returnDataDir(ks.keysDirPath)
+	if err != nil {
+		return nil, err
+	}
+	addrs, err := GetAllAddresses(dataDirPath)
+	if err != nil {
+		return nil, err
+	}
+
+	var list []*Key
+
+	for _, addr := range addrs {
+		k, err := ks.GetKey("", addr)
+		if err != nil {
+			return nil, err
+		}
+		list = append(list, k)
+	}
+
+	return list, nil
+}
+
 func DecryptKey(passphrase string, keyProtected *keyJSON) (*Key, error) {
 	salt := keyProtected.PrivateKey.Salt
 	nonce := keyProtected.PrivateKey.Nonce
@@ -181,13 +208,13 @@ func DecryptKey(passphrase string, keyProtected *keyJSON) (*Key, error) {
 	return k, nil
 }
 
-func (ks keyStoreFile) GetAllAddresses() (addresses [][]byte, err error) {
+func (ks KeyStore) GetAllAddresses() (addresses [][]byte, err error) {
 	ks.Lock()
 	defer ks.Unlock()
 	return GetAllAddresses(ks.keysDirPath)
 }
 
-func (ks keyStoreFile) StoreKey(passphrase string, key *Key) error {
+func (ks KeyStore) StoreKey(passphrase string, key *Key) error {
 	ks.Lock()
 	defer ks.Unlock()
 	if passphrase != "" {
@@ -197,16 +224,20 @@ func (ks keyStoreFile) StoreKey(passphrase string, key *Key) error {
 	}
 }
 
-func (ks keyStoreFile) StoreKeyPlain(key *Key) (err error) {
+func (ks KeyStore) StoreKeyPlain(key *Key) (err error) {
 	keyJSON, err := json.Marshal(key)
 	if err != nil {
 		return err
 	}
-	err = WriteKeyFile(key.Address[:], ks.keysDirPath, keyJSON)
+	dataDirPath, err := returnDataDir(ks.keysDirPath)
+	if err != nil {
+		return err
+	}
+	err = WriteKeyFile(key.Address[:], dataDirPath, keyJSON)
 	return err
 }
 
-func (ks keyStoreFile) StoreKeyEncrypted(passphrase string, key *Key) error {
+func (ks KeyStore) StoreKeyEncrypted(passphrase string, key *Key) error {
 	authArray := []byte(passphrase)
 	salt := make([]byte, 32)
 	_, err := rand.Read(salt)
@@ -242,53 +273,60 @@ func (ks keyStoreFile) StoreKeyEncrypted(passphrase string, key *Key) error {
 	cipherText := gcm.Seal(nil, nonce, toEncrypt, nil)
 
 	cipherStruct := privateKeyJSON{
-		Crypto: "scrypt-aes-gcm", Salt: salt, Nonce: nonce, CipherText: cipherText,
+		Crypto: CryptoAESGCM, Salt: salt, Nonce: nonce, CipherText: cipherText,
 	}
 	keyStruct := keyJSON{
-		key.CurveType.String(),
-		strings.ToUpper(hex.EncodeToString(key.Address[:])),
-		key.Pubkey(),
-		"go-crypto-0.5.0",
-		cipherStruct,
+		CurveType:   key.CurveType.String(),
+		Address:     strings.ToUpper(hex.EncodeToString(key.Address[:])),
+		PublicKey:   key.Pubkey(),
+		AddressHash: key.PublicKey.AddressHashType(),
+		PrivateKey:  cipherStruct,
 	}
 	keyJSON, err := json.Marshal(keyStruct)
 	if err != nil {
 		return err
 	}
+	dataDirPath, err := returnDataDir(ks.keysDirPath)
+	if err != nil {
+		return err
+	}
 
-	return WriteKeyFile(key.Address[:], ks.keysDirPath, keyJSON)
+	return WriteKeyFile(key.Address[:], dataDirPath, keyJSON)
 }
 
-func (ks keyStoreFile) DeleteKey(passphrase string, keyAddr []byte) (err error) {
-	keyDirPath := path.Join(ks.keysDirPath, strings.ToUpper(hex.EncodeToString(keyAddr)))
-	err = os.RemoveAll(keyDirPath)
-	return err
+func (ks KeyStore) DeleteKey(passphrase string, keyAddr []byte) (err error) {
+	dataDirPath, err := returnDataDir(ks.keysDirPath)
+	if err != nil {
+		return err
+	}
+	keyDirPath := path.Join(dataDirPath, strings.ToUpper(hex.EncodeToString(keyAddr))+".json")
+	return os.Remove(keyDirPath)
 }
 
-func GetKeyFile(keysDirPath string, keyAddr []byte) (fileContent []byte, err error) {
+func GetKeyFile(dataDirPath string, keyAddr []byte) (fileContent []byte, err error) {
 	fileName := strings.ToUpper(hex.EncodeToString(keyAddr))
-	return ioutil.ReadFile(path.Join(keysDirPath, fileName, fileName))
+	return ioutil.ReadFile(path.Join(dataDirPath, fileName+".json"))
 }
 
-func WriteKeyFile(addr []byte, keysDirPath string, content []byte) (err error) {
+func WriteKeyFile(addr []byte, dataDirPath string, content []byte) (err error) {
 	addrHex := strings.ToUpper(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
+	keyFilePath := path.Join(dataDirPath, addrHex+".json")
+	err = os.MkdirAll(dataDirPath, 0700) // read, write and dir search for user
 	if err != nil {
 		return err
 	}
 	return ioutil.WriteFile(keyFilePath, content, 0600) // read, write for user
 }
 
-func GetAllAddresses(keysDirPath string) (addresses [][]byte, err error) {
-	fileInfos, err := ioutil.ReadDir(keysDirPath)
+func GetAllAddresses(dataDirPath string) (addresses [][]byte, err error) {
+	fileInfos, err := ioutil.ReadDir(dataDirPath)
 	if err != nil {
 		return nil, err
 	}
 	addresses = make([][]byte, len(fileInfos))
 	for i, fileInfo := range fileInfos {
-		address, err := hex.DecodeString(fileInfo.Name())
+		addr := strings.TrimSuffix(fileInfo.Name(), "json")
+		address, err := hex.DecodeString(addr)
 		if err != nil {
 			continue
 		}
diff --git a/keys/pbkeys/keys.pb.go b/keys/pbkeys/keys.pb.go
index 4038f4fdfc5fa0600c5ec5956d62937d4530fb2d..a099818d370ebfe3db85f66d429ccafa7ed8a008 100644
--- a/keys/pbkeys/keys.pb.go
+++ b/keys/pbkeys/keys.pb.go
@@ -26,7 +26,7 @@ It has these top-level messages:
 	HashResponse
 	Key
 	ListResponse
-	AddRequest
+	AddNameRequest
 */
 package pbkeys
 
@@ -301,7 +301,8 @@ func (m *ExportResponse) GetExport() string {
 type SignRequest struct {
 	Passphrase string `protobuf:"bytes,1,opt,name=passphrase" json:"passphrase,omitempty"`
 	Address    string `protobuf:"bytes,2,opt,name=address" json:"address,omitempty"`
-	Hash       []byte `protobuf:"bytes,3,opt,name=hash,proto3" json:"hash,omitempty"`
+	Name       string `protobuf:"bytes,3,opt,name=name" json:"name,omitempty"`
+	Message    []byte `protobuf:"bytes,4,opt,name=message,proto3" json:"message,omitempty"`
 }
 
 func (m *SignRequest) Reset()                    { *m = SignRequest{} }
@@ -323,9 +324,16 @@ func (m *SignRequest) GetAddress() string {
 	return ""
 }
 
-func (m *SignRequest) GetHash() []byte {
+func (m *SignRequest) GetName() string {
 	if m != nil {
-		return m.Hash
+		return m.Name
+	}
+	return ""
+}
+
+func (m *SignRequest) GetMessage() []byte {
+	if m != nil {
+		return m.Message
 	}
 	return nil
 }
@@ -357,7 +365,7 @@ func (m *SignResponse) GetCurvetype() string {
 type VerifyRequest struct {
 	Curvetype string `protobuf:"bytes,1,opt,name=curvetype" json:"curvetype,omitempty"`
 	Pub       []byte `protobuf:"bytes,2,opt,name=pub,proto3" json:"pub,omitempty"`
-	Hash      []byte `protobuf:"bytes,3,opt,name=hash,proto3" json:"hash,omitempty"`
+	Message   []byte `protobuf:"bytes,3,opt,name=message,proto3" json:"message,omitempty"`
 	Signature []byte `protobuf:"bytes,4,opt,name=signature,proto3" json:"signature,omitempty"`
 }
 
@@ -380,9 +388,9 @@ func (m *VerifyRequest) GetPub() []byte {
 	return nil
 }
 
-func (m *VerifyRequest) GetHash() []byte {
+func (m *VerifyRequest) GetMessage() []byte {
 	if m != nil {
-		return m.Hash
+		return m.Message
 	}
 	return nil
 }
@@ -474,24 +482,24 @@ func (m *ListResponse) GetKey() []*Key {
 	return nil
 }
 
-type AddRequest struct {
+type AddNameRequest struct {
 	Keyname string `protobuf:"bytes,1,opt,name=keyname" json:"keyname,omitempty"`
 	Address string `protobuf:"bytes,2,opt,name=address" json:"address,omitempty"`
 }
 
-func (m *AddRequest) Reset()                    { *m = AddRequest{} }
-func (m *AddRequest) String() string            { return proto.CompactTextString(m) }
-func (*AddRequest) ProtoMessage()               {}
-func (*AddRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{18} }
+func (m *AddNameRequest) Reset()                    { *m = AddNameRequest{} }
+func (m *AddNameRequest) String() string            { return proto.CompactTextString(m) }
+func (*AddNameRequest) ProtoMessage()               {}
+func (*AddNameRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{18} }
 
-func (m *AddRequest) GetKeyname() string {
+func (m *AddNameRequest) GetKeyname() string {
 	if m != nil {
 		return m.Keyname
 	}
 	return ""
 }
 
-func (m *AddRequest) GetAddress() string {
+func (m *AddNameRequest) GetAddress() string {
 	if m != nil {
 		return m.Address
 	}
@@ -517,7 +525,7 @@ func init() {
 	proto.RegisterType((*HashResponse)(nil), "pbkeys.HashResponse")
 	proto.RegisterType((*Key)(nil), "pbkeys.Key")
 	proto.RegisterType((*ListResponse)(nil), "pbkeys.ListResponse")
-	proto.RegisterType((*AddRequest)(nil), "pbkeys.AddRequest")
+	proto.RegisterType((*AddNameRequest)(nil), "pbkeys.AddNameRequest")
 }
 
 // Reference imports to suppress errors if they are not otherwise used.
@@ -539,9 +547,9 @@ type KeysClient interface {
 	ImportJSON(ctx context.Context, in *ImportJSONRequest, opts ...grpc.CallOption) (*ImportResponse, error)
 	Export(ctx context.Context, in *ExportRequest, opts ...grpc.CallOption) (*ExportResponse, error)
 	Hash(ctx context.Context, in *HashRequest, opts ...grpc.CallOption) (*HashResponse, error)
-	Remove(ctx context.Context, in *Name, opts ...grpc.CallOption) (*Empty, error)
+	RemoveName(ctx context.Context, in *Name, opts ...grpc.CallOption) (*Empty, error)
 	List(ctx context.Context, in *Name, opts ...grpc.CallOption) (*ListResponse, error)
-	Add(ctx context.Context, in *AddRequest, opts ...grpc.CallOption) (*Empty, error)
+	AddName(ctx context.Context, in *AddNameRequest, opts ...grpc.CallOption) (*Empty, error)
 }
 
 type keysClient struct {
@@ -624,9 +632,9 @@ func (c *keysClient) Hash(ctx context.Context, in *HashRequest, opts ...grpc.Cal
 	return out, nil
 }
 
-func (c *keysClient) Remove(ctx context.Context, in *Name, opts ...grpc.CallOption) (*Empty, error) {
+func (c *keysClient) RemoveName(ctx context.Context, in *Name, opts ...grpc.CallOption) (*Empty, error) {
 	out := new(Empty)
-	err := grpc.Invoke(ctx, "/pbkeys.Keys/Remove", in, out, c.cc, opts...)
+	err := grpc.Invoke(ctx, "/pbkeys.Keys/RemoveName", in, out, c.cc, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -642,9 +650,9 @@ func (c *keysClient) List(ctx context.Context, in *Name, opts ...grpc.CallOption
 	return out, nil
 }
 
-func (c *keysClient) Add(ctx context.Context, in *AddRequest, opts ...grpc.CallOption) (*Empty, error) {
+func (c *keysClient) AddName(ctx context.Context, in *AddNameRequest, opts ...grpc.CallOption) (*Empty, error) {
 	out := new(Empty)
-	err := grpc.Invoke(ctx, "/pbkeys.Keys/Add", in, out, c.cc, opts...)
+	err := grpc.Invoke(ctx, "/pbkeys.Keys/AddName", in, out, c.cc, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -662,9 +670,9 @@ type KeysServer interface {
 	ImportJSON(context.Context, *ImportJSONRequest) (*ImportResponse, error)
 	Export(context.Context, *ExportRequest) (*ExportResponse, error)
 	Hash(context.Context, *HashRequest) (*HashResponse, error)
-	Remove(context.Context, *Name) (*Empty, error)
+	RemoveName(context.Context, *Name) (*Empty, error)
 	List(context.Context, *Name) (*ListResponse, error)
-	Add(context.Context, *AddRequest) (*Empty, error)
+	AddName(context.Context, *AddNameRequest) (*Empty, error)
 }
 
 func RegisterKeysServer(s *grpc.Server, srv KeysServer) {
@@ -815,20 +823,20 @@ func _Keys_Hash_Handler(srv interface{}, ctx context.Context, dec func(interface
 	return interceptor(ctx, in, info, handler)
 }
 
-func _Keys_Remove_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+func _Keys_RemoveName_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
 	in := new(Name)
 	if err := dec(in); err != nil {
 		return nil, err
 	}
 	if interceptor == nil {
-		return srv.(KeysServer).Remove(ctx, in)
+		return srv.(KeysServer).RemoveName(ctx, in)
 	}
 	info := &grpc.UnaryServerInfo{
 		Server:     srv,
-		FullMethod: "/pbkeys.Keys/Remove",
+		FullMethod: "/pbkeys.Keys/RemoveName",
 	}
 	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
-		return srv.(KeysServer).Remove(ctx, req.(*Name))
+		return srv.(KeysServer).RemoveName(ctx, req.(*Name))
 	}
 	return interceptor(ctx, in, info, handler)
 }
@@ -851,20 +859,20 @@ func _Keys_List_Handler(srv interface{}, ctx context.Context, dec func(interface
 	return interceptor(ctx, in, info, handler)
 }
 
-func _Keys_Add_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
-	in := new(AddRequest)
+func _Keys_AddName_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(AddNameRequest)
 	if err := dec(in); err != nil {
 		return nil, err
 	}
 	if interceptor == nil {
-		return srv.(KeysServer).Add(ctx, in)
+		return srv.(KeysServer).AddName(ctx, in)
 	}
 	info := &grpc.UnaryServerInfo{
 		Server:     srv,
-		FullMethod: "/pbkeys.Keys/Add",
+		FullMethod: "/pbkeys.Keys/AddName",
 	}
 	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
-		return srv.(KeysServer).Add(ctx, req.(*AddRequest))
+		return srv.(KeysServer).AddName(ctx, req.(*AddNameRequest))
 	}
 	return interceptor(ctx, in, info, handler)
 }
@@ -906,16 +914,16 @@ var _Keys_serviceDesc = grpc.ServiceDesc{
 			Handler:    _Keys_Hash_Handler,
 		},
 		{
-			MethodName: "Remove",
-			Handler:    _Keys_Remove_Handler,
+			MethodName: "RemoveName",
+			Handler:    _Keys_RemoveName_Handler,
 		},
 		{
 			MethodName: "List",
 			Handler:    _Keys_List_Handler,
 		},
 		{
-			MethodName: "Add",
-			Handler:    _Keys_Add_Handler,
+			MethodName: "AddName",
+			Handler:    _Keys_AddName_Handler,
 		},
 	},
 	Streams:  []grpc.StreamDesc{},
@@ -925,45 +933,45 @@ var _Keys_serviceDesc = grpc.ServiceDesc{
 func init() { proto.RegisterFile("keys.proto", fileDescriptor0) }
 
 var fileDescriptor0 = []byte{
-	// 636 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x55, 0xd1, 0x6b, 0x13, 0x4f,
-	0x10, 0x26, 0xb9, 0xfb, 0x5d, 0x9b, 0x2f, 0x49, 0xf9, 0xb9, 0x6a, 0x89, 0xa1, 0x4a, 0x59, 0x10,
-	0x43, 0xc1, 0x40, 0xab, 0x58, 0x14, 0x44, 0x8b, 0x94, 0x6a, 0x2b, 0xb5, 0xa4, 0xe0, 0x8b, 0xf8,
-	0x70, 0xe9, 0x8d, 0x4d, 0x88, 0x49, 0xae, 0xb7, 0x77, 0xc5, 0x7b, 0xf0, 0x1f, 0xf3, 0xaf, 0x93,
-	0xdd, 0xdb, 0xcd, 0xde, 0x9e, 0x4d, 0x0d, 0xf8, 0x76, 0x33, 0x3b, 0x33, 0xdf, 0xb7, 0xb3, 0xdf,
-	0xcc, 0x01, 0x13, 0xca, 0x45, 0x3f, 0x4e, 0xe6, 0xe9, 0x9c, 0x05, 0xf1, 0x50, 0x5a, 0x7c, 0x1b,
-	0xfe, 0x69, 0x38, 0x25, 0xd6, 0xc1, 0xda, 0x84, 0xf2, 0x59, 0x38, 0xa5, 0x4e, 0x6d, 0xbb, 0xd6,
-	0x6b, 0x0c, 0x8c, 0xc9, 0xd7, 0xf0, 0xdf, 0xe1, 0x34, 0x4e, 0x73, 0x1e, 0x01, 0x47, 0x34, 0x1b,
-	0xd0, 0x55, 0x46, 0x22, 0x65, 0x8f, 0x80, 0x38, 0x14, 0x22, 0x1e, 0x25, 0xa1, 0x30, 0x39, 0x25,
-	0x0f, 0xdb, 0x42, 0xe3, 0x22, 0x4b, 0xae, 0x29, 0xcd, 0x63, 0xea, 0xd4, 0xd5, 0xb1, 0x75, 0x94,
-	0xe1, 0x3c, 0x17, 0xee, 0x09, 0x9a, 0x0a, 0x45, 0xc4, 0xf3, 0x99, 0x50, 0x81, 0x61, 0x14, 0x25,
-	0x24, 0x84, 0xe1, 0xa5, 0x4d, 0xfe, 0x0a, 0x38, 0xcb, 0x86, 0x86, 0xce, 0xd2, 0x38, 0xc6, 0xe0,
-	0x2b, 0x9c, 0x82, 0x83, 0xfa, 0xe6, 0xaf, 0xd1, 0x54, 0xb9, 0x1a, 0xe4, 0x7f, 0x78, 0x71, 0x36,
-	0x54, 0x89, 0xad, 0x81, 0xfc, 0xbc, 0x9d, 0x3d, 0x3f, 0xc2, 0x9d, 0x0f, 0xd3, 0x78, 0x9e, 0xa4,
-	0xc7, 0xe7, 0x9f, 0x4e, 0x57, 0x6d, 0x08, 0x83, 0x2f, 0xc3, 0x0d, 0x0f, 0xf9, 0xcd, 0x77, 0xb0,
-	0x51, 0x14, 0x5a, 0xe1, 0xbe, 0x3f, 0xd1, 0x36, 0xb1, 0x2b, 0x03, 0x56, 0x2f, 0xee, 0xde, 0xcb,
-	0xab, 0xbe, 0x4a, 0x17, 0xeb, 0x13, 0xca, 0x87, 0x79, 0x4a, 0xa2, 0xe3, 0xab, 0x66, 0x2c, 0x6c,
-	0xfe, 0x15, 0xed, 0xc3, 0x1f, 0xff, 0x0a, 0x5f, 0xba, 0x9d, 0xe7, 0xde, 0xae, 0x87, 0x0d, 0x53,
-	0x5e, 0x77, 0x62, 0x13, 0x01, 0x29, 0x8f, 0xae, 0xad, 0x2d, 0xfe, 0x05, 0xcd, 0xf3, 0xf1, 0xe5,
-	0xca, 0x3a, 0x2c, 0x41, 0xd6, 0xff, 0x10, 0xc6, 0x28, 0x14, 0x23, 0xc5, 0xa4, 0x35, 0x50, 0xdf,
-	0xfc, 0x18, 0xad, 0xa2, 0xb8, 0x26, 0xb1, 0x85, 0x86, 0x18, 0x5f, 0xce, 0xc2, 0x34, 0x4b, 0x48,
-	0xeb, 0xc3, 0x3a, 0xfe, 0xa2, 0x92, 0x2b, 0xb4, 0x3f, 0x53, 0x32, 0xfe, 0x96, 0x1b, 0xaa, 0x4e,
-	0x78, 0xad, 0xda, 0x7c, 0x2d, 0xc2, 0xba, 0x15, 0xe1, 0x0d, 0x04, 0x5d, 0x42, 0x7e, 0x85, 0x10,
-	0x7f, 0x87, 0xe6, 0xfb, 0x50, 0x8c, 0x0c, 0x60, 0x17, 0xeb, 0x32, 0xa9, 0x84, 0xb7, 0xb0, 0x65,
-	0x5f, 0xa6, 0x24, 0x44, 0x78, 0x49, 0x1a, 0xd2, 0x98, 0x9c, 0xa3, 0x55, 0x14, 0xd1, 0x3d, 0x30,
-	0x34, 0x8a, 0x0a, 0x45, 0x9f, 0x5e, 0xc2, 0x3b, 0xa1, 0xfc, 0x96, 0xa9, 0x2b, 0x0d, 0x78, 0xdd,
-	0x1d, 0xf0, 0xa7, 0x68, 0x7d, 0x1c, 0x0b, 0xfb, 0xce, 0x0f, 0xe1, 0x4d, 0x28, 0xef, 0xd4, 0xb6,
-	0xbd, 0x5e, 0x73, 0xaf, 0xd9, 0x2f, 0xf6, 0x52, 0xff, 0x84, 0xf2, 0x81, 0xf4, 0xf3, 0xb7, 0xc0,
-	0x41, 0x14, 0x95, 0xc6, 0xfc, 0xe6, 0x35, 0xb5, 0xfc, 0x9d, 0xf7, 0x7e, 0xf9, 0xf0, 0x4f, 0x28,
-	0x17, 0xec, 0x85, 0x5a, 0x2d, 0x94, 0x84, 0x29, 0x49, 0xf2, 0xcc, 0x60, 0xd9, 0xad, 0xd6, 0xbd,
-	0xeb, 0xf8, 0x34, 0xc3, 0xe7, 0x68, 0x9c, 0x65, 0xc3, 0xef, 0xe3, 0x0b, 0x27, 0xcb, 0x2e, 0x1f,
-	0x9b, 0x55, 0x5e, 0x2a, 0xbb, 0xf0, 0xa5, 0x94, 0xd8, 0xe2, 0xb0, 0xa4, 0xda, 0xee, 0x3d, 0xd7,
-	0xa9, 0x53, 0xfa, 0x08, 0x0a, 0xc5, 0xb0, 0xfb, 0xe6, 0xdc, 0x51, 0x50, 0xb7, 0x6d, 0xdc, 0x6a,
-	0x23, 0xb3, 0x7d, 0x04, 0xc5, 0x4a, 0xb0, 0xf1, 0xce, 0x8a, 0xe8, 0x6e, 0x56, 0xdd, 0x1a, 0xe8,
-	0x0d, 0x60, 0x17, 0x18, 0x7b, 0xe0, 0x46, 0x95, 0x96, 0xda, 0xd2, 0x02, 0xfb, 0x08, 0x8a, 0x71,
-	0xb5, 0xc8, 0xce, 0x76, 0xb0, 0x89, 0x95, 0xa9, 0xde, 0x85, 0x2f, 0xc5, 0x65, 0xbb, 0x52, 0xd2,
-	0xab, 0xed, 0x8a, 0xa3, 0xbf, 0xc7, 0x08, 0x06, 0x34, 0x9d, 0x5f, 0x13, 0x6b, 0x99, 0x73, 0xf9,
-	0xcb, 0xaa, 0x36, 0x63, 0x07, 0xbe, 0xd4, 0x55, 0x25, 0x68, 0x51, 0xd2, 0xd1, 0x5c, 0x0f, 0xde,
-	0x41, 0x14, 0xd9, 0xb7, 0xb4, 0x0a, 0xab, 0x54, 0x1d, 0x06, 0xea, 0x77, 0xf9, 0xec, 0x77, 0x00,
-	0x00, 0x00, 0xff, 0xff, 0x93, 0xa5, 0xa8, 0x54, 0x3c, 0x07, 0x00, 0x00,
+	// 640 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x55, 0x51, 0x6f, 0xd3, 0x3c,
+	0x14, 0x55, 0x9b, 0x7c, 0xdd, 0x7a, 0xda, 0x4e, 0x1f, 0x06, 0xa6, 0x52, 0x0d, 0x34, 0xf9, 0x85,
+	0x31, 0x89, 0x8a, 0x0d, 0xc4, 0x04, 0x12, 0x42, 0x08, 0xa6, 0xc1, 0x86, 0xc6, 0xd4, 0x49, 0xbc,
+	0xf1, 0x90, 0xae, 0x97, 0xb5, 0x2a, 0x69, 0x43, 0x9c, 0x0c, 0xf2, 0xc0, 0xdf, 0xe3, 0x77, 0x21,
+	0x3b, 0x76, 0x6d, 0x47, 0xeb, 0xa8, 0xc4, 0x9b, 0xef, 0xcd, 0xbd, 0xf7, 0x1c, 0xdf, 0x9c, 0x9c,
+	0x00, 0x53, 0x2a, 0x44, 0x3f, 0x49, 0xe7, 0xd9, 0x9c, 0x35, 0x92, 0xa1, 0x8c, 0xf8, 0x36, 0xc2,
+	0xd3, 0x28, 0x26, 0xd6, 0xc5, 0xda, 0x94, 0x8a, 0x59, 0x14, 0x53, 0xb7, 0xb6, 0x5d, 0xdb, 0x69,
+	0x0e, 0x4c, 0xc8, 0xd7, 0xf0, 0xdf, 0x61, 0x9c, 0x64, 0x05, 0x1f, 0x01, 0x47, 0x34, 0x1b, 0xd0,
+	0xf7, 0x9c, 0x44, 0xc6, 0x1e, 0x00, 0x49, 0x24, 0x44, 0x32, 0x4e, 0x23, 0x61, 0x7a, 0x9c, 0x0c,
+	0xdb, 0x42, 0xf3, 0x22, 0x4f, 0xaf, 0x28, 0x2b, 0x12, 0xea, 0xd6, 0xd5, 0x63, 0x9b, 0x70, 0xe1,
+	0x02, 0x1f, 0xee, 0x21, 0x5a, 0x0a, 0x45, 0x24, 0xf3, 0x99, 0x50, 0x85, 0xd1, 0x68, 0x94, 0x92,
+	0x10, 0x86, 0x97, 0x0e, 0xf9, 0x4b, 0xe0, 0x2c, 0x1f, 0x1a, 0x3a, 0x4b, 0xeb, 0x18, 0x43, 0xa8,
+	0x70, 0x4a, 0x0e, 0xea, 0xcc, 0x5f, 0xa1, 0xa5, 0x7a, 0x35, 0xc8, 0xff, 0x08, 0x92, 0x7c, 0xa8,
+	0x1a, 0xdb, 0x03, 0x79, 0xbc, 0x99, 0x3d, 0x3f, 0xc2, 0xad, 0x0f, 0x71, 0x32, 0x4f, 0xb3, 0xe3,
+	0xf3, 0x4f, 0xa7, 0xab, 0x2e, 0x84, 0x21, 0x94, 0xe5, 0x86, 0x87, 0x3c, 0xf3, 0x5d, 0x6c, 0x94,
+	0x83, 0x56, 0xb8, 0xef, 0x2f, 0x74, 0x4c, 0xed, 0xca, 0x80, 0xd5, 0x8b, 0xfb, 0xf7, 0x0a, 0xaa,
+	0x6f, 0xa5, 0x87, 0xf5, 0x29, 0x15, 0xc3, 0x22, 0x23, 0xd1, 0x0d, 0xd5, 0x32, 0x16, 0x31, 0xff,
+	0x82, 0xce, 0xe1, 0xcf, 0x7f, 0x85, 0x77, 0x6e, 0x17, 0xf8, 0xb7, 0xdb, 0xc1, 0x86, 0x19, 0xaf,
+	0x37, 0xb1, 0x89, 0x06, 0xa9, 0x8c, 0x9e, 0xad, 0x23, 0x9e, 0xa3, 0x75, 0x3e, 0xb9, 0x5c, 0x59,
+	0x87, 0x0e, 0x64, 0xfd, 0x7a, 0x61, 0x04, 0x3e, 0xc1, 0x98, 0x84, 0x88, 0x2e, 0x49, 0x2f, 0xc0,
+	0x84, 0xfc, 0x18, 0xed, 0x12, 0x56, 0xd3, 0xdb, 0x42, 0x53, 0x4c, 0x2e, 0x67, 0x51, 0x96, 0xa7,
+	0xa4, 0x95, 0x63, 0x13, 0x7f, 0xd1, 0xcf, 0x0f, 0x74, 0x3e, 0x53, 0x3a, 0xf9, 0x5a, 0x98, 0x4b,
+	0x78, 0xe5, 0xb5, 0xea, 0x6b, 0xd1, 0xf2, 0xac, 0x5b, 0x79, 0x3a, 0x34, 0x03, 0x8f, 0xa6, 0x4f,
+	0x2b, 0xac, 0xd0, 0xe2, 0x6f, 0xd1, 0x7a, 0x1f, 0x89, 0xb1, 0x81, 0xed, 0x61, 0x7d, 0x1c, 0x89,
+	0xb1, 0x83, 0xba, 0x88, 0x5d, 0x88, 0xba, 0xbf, 0x09, 0x8e, 0x76, 0x39, 0x44, 0x6f, 0x82, 0x21,
+	0x94, 0x5d, 0x7a, 0x82, 0x3a, 0xf3, 0x17, 0x08, 0x4e, 0xa8, 0xb8, 0xe1, 0xab, 0x74, 0x0c, 0xa0,
+	0xee, 0x1b, 0xc0, 0x63, 0xb4, 0x3f, 0x4e, 0x84, 0xd5, 0xc1, 0x7d, 0x04, 0x53, 0x2a, 0xba, 0xb5,
+	0xed, 0x60, 0xa7, 0xb5, 0xdf, 0xea, 0x97, 0xbe, 0xd5, 0x3f, 0xa1, 0x62, 0x20, 0xf3, 0xfc, 0x1d,
+	0x36, 0xde, 0x8c, 0x46, 0xd2, 0xc3, 0x1c, 0x2b, 0xb8, 0xde, 0xca, 0x96, 0x6b, 0x61, 0xff, 0x77,
+	0x88, 0xf0, 0x84, 0x0a, 0xc1, 0x9e, 0x2b, 0xfb, 0xa1, 0x34, 0xca, 0x48, 0x5e, 0x80, 0x19, 0x3c,
+	0xeb, 0x7c, 0xbd, 0xdb, 0x5e, 0x4e, 0xb3, 0x7c, 0x86, 0xe6, 0x59, 0x3e, 0xfc, 0x36, 0xb9, 0xf0,
+	0xba, 0xac, 0x41, 0xd9, 0x2e, 0xd7, 0x78, 0xf6, 0x10, 0x4a, 0x51, 0xb1, 0xc5, 0x43, 0x47, 0xd9,
+	0xbd, 0x3b, 0x7e, 0x52, 0xb7, 0xf4, 0xd1, 0x28, 0xb5, 0xc3, 0xee, 0x9a, 0xe7, 0x9e, 0x96, 0x7a,
+	0x1d, 0x93, 0x56, 0xae, 0xcd, 0x0e, 0xd0, 0x28, 0x6d, 0xc3, 0xd6, 0x7b, 0x36, 0xd2, 0xdb, 0xac,
+	0xa6, 0x35, 0xd0, 0x6b, 0xc0, 0x9a, 0x1c, 0xbb, 0xe7, 0x57, 0x39, 0xc6, 0xb7, 0x74, 0xc0, 0x01,
+	0x1a, 0xe5, 0x27, 0x6d, 0x91, 0x3d, 0x07, 0xb1, 0x8d, 0x95, 0x2f, 0x7f, 0x0f, 0xa1, 0x14, 0x98,
+	0xdd, 0x8a, 0xa3, 0x59, 0xbb, 0x15, 0x4f, 0x83, 0x8f, 0x80, 0x01, 0xc5, 0xf3, 0x2b, 0x52, 0x3f,
+	0xb3, 0xb6, 0xa9, 0x91, 0x51, 0x75, 0x21, 0xbb, 0x08, 0xa5, 0xbe, 0x2a, 0x45, 0x8b, 0xb1, 0x9e,
+	0xf6, 0x9e, 0x60, 0x4d, 0x8b, 0x8b, 0x2d, 0xc8, 0xfa, 0x6a, 0xab, 0x4c, 0x1f, 0x36, 0xd4, 0xef,
+	0xf5, 0xe9, 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x3b, 0xed, 0x32, 0x21, 0x6c, 0x07, 0x00, 0x00,
 }
diff --git a/keys/pbkeys/keys.proto b/keys/pbkeys/keys.proto
index c5db218480544bccac3d12254d52c9a9fe19e1e1..06ef091eee5694daa1f546e04a85badf2acb9f9e 100644
--- a/keys/pbkeys/keys.proto
+++ b/keys/pbkeys/keys.proto
@@ -11,9 +11,9 @@ service Keys {
     rpc ImportJSON(ImportJSONRequest) returns (ImportResponse);
     rpc Export(ExportRequest) returns (ExportResponse);
     rpc Hash(HashRequest) returns (HashResponse);
-    rpc Remove(Name) returns (Empty);
+    rpc RemoveName(Name) returns (Empty);
     rpc List(Name) returns (ListResponse);
-    rpc Add(AddRequest) returns (Empty);
+    rpc AddName(AddNameRequest) returns (Empty);
 }
 
 message Name {
@@ -73,7 +73,8 @@ message ExportResponse {
 message SignRequest {
     string passphrase = 1;
     string address = 2;
-    bytes hash = 3;
+    string name = 3;
+    bytes message = 4;
 }
 
 message SignResponse {
@@ -84,7 +85,7 @@ message SignResponse {
 message VerifyRequest {
     string curvetype = 1;
     bytes pub = 2;
-    bytes hash = 3;
+    bytes message = 3;
     bytes signature = 4;
 }
 
@@ -106,7 +107,7 @@ message ListResponse {
     repeated Key key = 1;
 }
 
-message AddRequest {
+message AddNameRequest {
     string keyname = 1;
     string address = 2;
 }
diff --git a/keys/server.go b/keys/server.go
index 63232326a07bb630ff7e2630e9442af98f931b3c..3ffa0e4375084c987baf075fea31fdc00dc5e8f5 100644
--- a/keys/server.go
+++ b/keys/server.go
@@ -10,76 +10,45 @@ import (
 
 	"github.com/hyperledger/burrow/crypto"
 	"github.com/hyperledger/burrow/keys/pbkeys"
+	"github.com/tmthrgd/go-hex"
 	"golang.org/x/crypto/ripemd160"
 	"google.golang.org/grpc"
 )
 
 //------------------------------------------------------------------------
-// all cli commands pass through the http server
-// the server process also maintains the unlocked accounts
-
-type server struct{}
-
-var GlobalKeyServer server
-
-func startServer() error {
-	if GlobalKeystore == nil {
-		ks, err := newKeyStore()
-		if err != nil {
-			return err
-		}
-
-		GlobalKeystore = ks
-	}
-	GlobalKeyServer = server{}
-
-	return nil
-}
-
-func StartGRPCServer(grpcserver *grpc.Server, keyConfig *KeysConfig) error {
-	err := startServer()
-	if err != nil {
-		return err
-	}
-	if keyConfig.ServerEnabled {
-		pbkeys.RegisterKeysServer(grpcserver, &GlobalKeyServer)
-	}
-	return nil
-}
-
-func StartStandAloneServer(host, port string) error {
-	err := startServer()
-	if err != nil {
-		return err
-	}
+// all cli commands pass through the http KeyStore
+// the KeyStore process also maintains the unlocked accounts
 
+func StartStandAloneServer(keysDir, host, port string) error {
 	listen, err := net.Listen("tcp", host+":"+port)
 	if err != nil {
 		return err
 	}
 
+	ks := NewKeyStore(keysDir)
+
 	grpcServer := grpc.NewServer()
-	pbkeys.RegisterKeysServer(grpcServer, &server{})
+	pbkeys.RegisterKeysServer(grpcServer, &ks)
 	return grpcServer.Serve(listen)
 }
 
 //------------------------------------------------------------------------
 // handlers
 
-func (k *server) GenerateKey(ctx context.Context, in *pbkeys.GenRequest) (*pbkeys.GenResponse, error) {
+func (k *KeyStore) GenerateKey(ctx context.Context, in *pbkeys.GenRequest) (*pbkeys.GenResponse, error) {
 	curveT, err := crypto.CurveTypeFromString(in.Curvetype)
 	if err != nil {
 		return nil, err
 	}
 
-	key, err := GlobalKeystore.GenerateKey(in.Passphrase, curveT)
+	key, err := k.Gen(in.Passphrase, curveT)
 	if err != nil {
 		return nil, fmt.Errorf("error generating key %s %s", curveT, err)
 	}
 
 	addrH := key.Address.String()
 	if in.Keyname != "" {
-		err = coreNameAdd(in.Keyname, addrH)
+		err = coreNameAdd(k.keysDirPath, in.Keyname, addrH)
 		if err != nil {
 			return nil, err
 		}
@@ -88,14 +57,24 @@ func (k *server) GenerateKey(ctx context.Context, in *pbkeys.GenRequest) (*pbkey
 	return &pbkeys.GenResponse{Address: addrH}, nil
 }
 
-func (k *server) Export(ctx context.Context, in *pbkeys.ExportRequest) (*pbkeys.ExportResponse, error) {
-	addr, err := getNameAddr(in.GetName(), in.GetAddress())
+func (k *KeyStore) Export(ctx context.Context, in *pbkeys.ExportRequest) (*pbkeys.ExportResponse, error) {
+	addr, err := getNameAddr(k.keysDirPath, in.GetName(), in.GetAddress())
 
 	if err != nil {
 		return nil, err
 	}
 
-	resp, err := coreExport(in.GetPassphrase(), addr)
+	addrB, err := crypto.AddressFromHexString(addr)
+	if err != nil {
+		return nil, err
+	}
+
+	// No phrase needed for public key. I hope.
+	key, err := k.GetKey(in.GetPassphrase(), addrB.Bytes())
+	if err != nil {
+		return nil, err
+	}
+	resp, err := coreExport(key)
 	if err != nil {
 		return nil, err
 	}
@@ -103,8 +82,8 @@ func (k *server) Export(ctx context.Context, in *pbkeys.ExportRequest) (*pbkeys.
 	return &pbkeys.ExportResponse{Export: string(resp)}, nil
 }
 
-func (k *server) PublicKey(ctx context.Context, in *pbkeys.PubRequest) (*pbkeys.PubResponse, error) {
-	addr, err := getNameAddr(in.GetName(), in.GetAddress())
+func (k *KeyStore) PublicKey(ctx context.Context, in *pbkeys.PubRequest) (*pbkeys.PubResponse, error) {
+	addr, err := getNameAddr(k.keysDirPath, in.GetName(), in.GetAddress())
 	if err != nil {
 		return nil, err
 	}
@@ -115,7 +94,7 @@ func (k *server) PublicKey(ctx context.Context, in *pbkeys.PubRequest) (*pbkeys.
 	}
 
 	// No phrase needed for public key. I hope.
-	key, err := GlobalKeystore.GetKey("", addrB.Bytes())
+	key, err := k.GetKey("", addrB.Bytes())
 	if key == nil {
 		return nil, err
 	}
@@ -123,27 +102,32 @@ func (k *server) PublicKey(ctx context.Context, in *pbkeys.PubRequest) (*pbkeys.
 	return &pbkeys.PubResponse{Curvetype: key.CurveType.String(), Pub: key.Pubkey()}, nil
 }
 
-func (k *server) Sign(ctx context.Context, in *pbkeys.SignRequest) (*pbkeys.SignResponse, error) {
-	addr, err := crypto.AddressFromHexString(in.Address)
+func (k *KeyStore) Sign(ctx context.Context, in *pbkeys.SignRequest) (*pbkeys.SignResponse, error) {
+	addr, err := getNameAddr(k.keysDirPath, in.GetName(), in.GetAddress())
+	if err != nil {
+		return nil, err
+	}
+
+	addrB, err := crypto.AddressFromHexString(addr)
 	if err != nil {
 		return nil, err
 	}
 
-	key, err := GlobalKeystore.GetKey(in.GetPassphrase(), addr[:])
+	key, err := k.GetKey(in.GetPassphrase(), addrB[:])
 	if err != nil {
 		return nil, err
 	}
 
-	sig, err := key.Sign(in.GetHash())
+	sig, err := key.Sign(in.GetMessage())
 
 	return &pbkeys.SignResponse{Signature: sig}, nil
 }
 
-func (k *server) Verify(ctx context.Context, in *pbkeys.VerifyRequest) (*pbkeys.Empty, error) {
+func (k *KeyStore) Verify(ctx context.Context, in *pbkeys.VerifyRequest) (*pbkeys.Empty, error) {
 	if in.GetPub() == nil {
 		return nil, fmt.Errorf("must provide a pubkey")
 	}
-	if in.GetHash() == nil {
+	if in.GetMessage() == nil {
 		return nil, fmt.Errorf("must provide a message")
 	}
 	if in.GetSignature() == nil {
@@ -162,7 +146,7 @@ func (k *server) Verify(ctx context.Context, in *pbkeys.VerifyRequest) (*pbkeys.
 	if err != nil {
 		return nil, err
 	}
-	match := pubkey.Verify(in.GetHash(), sig)
+	match := pubkey.Verify(in.GetMessage(), sig)
 	if !match {
 		return nil, fmt.Errorf("Signature does not match")
 	}
@@ -170,7 +154,7 @@ func (k *server) Verify(ctx context.Context, in *pbkeys.VerifyRequest) (*pbkeys.
 	return &pbkeys.Empty{}, nil
 }
 
-func (k *server) Hash(ctx context.Context, in *pbkeys.HashRequest) (*pbkeys.HashResponse, error) {
+func (k *KeyStore) Hash(ctx context.Context, in *pbkeys.HashRequest) (*pbkeys.HashResponse, error) {
 	var hasher hash.Hash
 	switch in.GetHashtype() {
 	case "ripemd160":
@@ -184,25 +168,25 @@ func (k *server) Hash(ctx context.Context, in *pbkeys.HashRequest) (*pbkeys.Hash
 
 	hasher.Write(in.GetMessage())
 
-	return &pbkeys.HashResponse{Hash: fmt.Sprintf("%X", hasher.Sum(nil))}, nil
+	return &pbkeys.HashResponse{Hash: hex.EncodeUpperToString(hasher.Sum(nil))}, nil
 }
 
-func (k *server) ImportJSON(ctx context.Context, in *pbkeys.ImportJSONRequest) (*pbkeys.ImportResponse, error) {
+func (k *KeyStore) ImportJSON(ctx context.Context, in *pbkeys.ImportJSONRequest) (*pbkeys.ImportResponse, error) {
 	keyJSON := []byte(in.GetJSON())
 	var err error
 	addr := IsValidKeyJson(keyJSON)
 	if addr != nil {
-		_, err = writeKey(KeysDir, addr, keyJSON)
+		_, err = writeKey(k.keysDirPath, addr, keyJSON)
 	} else {
 		err = fmt.Errorf("invalid json key passed on command line")
 	}
 	if err != nil {
 		return nil, err
 	}
-	return &pbkeys.ImportResponse{Address: fmt.Sprintf("%X", addr)}, nil
+	return &pbkeys.ImportResponse{Address: hex.EncodeUpperToString(addr)}, nil
 }
 
-func (k *server) Import(ctx context.Context, in *pbkeys.ImportRequest) (*pbkeys.ImportResponse, error) {
+func (k *KeyStore) Import(ctx context.Context, in *pbkeys.ImportRequest) (*pbkeys.ImportResponse, error) {
 	curveT, err := crypto.CurveTypeFromString(in.GetCurvetype())
 	if err != nil {
 		return nil, err
@@ -213,20 +197,20 @@ func (k *server) Import(ctx context.Context, in *pbkeys.ImportRequest) (*pbkeys.
 	}
 
 	// store the new key
-	if err = GlobalKeystore.StoreKey(in.GetPassphrase(), key); err != nil {
+	if err = k.StoreKey(in.GetPassphrase(), key); err != nil {
 		return nil, err
 	}
 
 	if in.GetName() != "" {
-		if err := coreNameAdd(in.GetName(), key.Address.String()); err != nil {
+		if err := coreNameAdd(k.keysDirPath, in.GetName(), key.Address.String()); err != nil {
 			return nil, err
 		}
 	}
-	return &pbkeys.ImportResponse{Address: fmt.Sprintf("%X", key.Address)}, nil
+	return &pbkeys.ImportResponse{Address: hex.EncodeUpperToString(key.Address[:])}, nil
 }
 
-func (k *server) List(ctx context.Context, in *pbkeys.Name) (*pbkeys.ListResponse, error) {
-	names, err := coreNameList()
+func (k *KeyStore) List(ctx context.Context, in *pbkeys.Name) (*pbkeys.ListResponse, error) {
+	names, err := coreNameList(k.keysDirPath)
 	if err != nil {
 		return nil, err
 	}
@@ -240,15 +224,15 @@ func (k *server) List(ctx context.Context, in *pbkeys.Name) (*pbkeys.ListRespons
 	return &pbkeys.ListResponse{Key: list}, nil
 }
 
-func (k *server) Remove(ctx context.Context, in *pbkeys.Name) (*pbkeys.Empty, error) {
+func (k *KeyStore) RemoveName(ctx context.Context, in *pbkeys.Name) (*pbkeys.Empty, error) {
 	if in.GetKeyname() == "" {
 		return nil, fmt.Errorf("please specify a name")
 	}
 
-	return &pbkeys.Empty{}, coreNameRm(in.GetKeyname())
+	return &pbkeys.Empty{}, coreNameRm(k.keysDirPath, in.GetKeyname())
 }
 
-func (k *server) Add(ctx context.Context, in *pbkeys.AddRequest) (*pbkeys.Empty, error) {
+func (k *KeyStore) AddName(ctx context.Context, in *pbkeys.AddNameRequest) (*pbkeys.Empty, error) {
 	if in.GetKeyname() == "" {
 		return nil, fmt.Errorf("please specify a name")
 	}
@@ -257,5 +241,5 @@ func (k *server) Add(ctx context.Context, in *pbkeys.AddRequest) (*pbkeys.Empty,
 		return nil, fmt.Errorf("please specify an address")
 	}
 
-	return &pbkeys.Empty{}, coreNameAdd(in.GetKeyname(), strings.ToUpper(in.GetAddress()))
+	return &pbkeys.Empty{}, coreNameAdd(k.keysDirPath, in.GetKeyname(), strings.ToUpper(in.GetAddress()))
 }
diff --git a/keys/server_test.go b/keys/server_test.go
index c5266089ec79451b30181e216105cfc2dda1697e..614daaecb6f9eba0950acc29d9b1d43feef7f72a 100644
--- a/keys/server_test.go
+++ b/keys/server_test.go
@@ -37,7 +37,7 @@ var (
 func init() {
 	failedCh := make(chan error)
 	go func() {
-		err := StartStandAloneServer(DefaultHost, TestPort)
+		err := StartStandAloneServer(DefaultKeysDir, DefaultHost, TestPort)
 		failedCh <- err
 	}()
 	tick := time.NewTicker(time.Second)
@@ -126,12 +126,12 @@ func testServerSignAndVerify(t *testing.T, typ string) {
 	}
 	hash := sha3.Sha3([]byte("the hash of something!"))
 
-	sig, err := c.Sign(ctx, &pbkeys.SignRequest{Address: addr, Hash: hash})
+	sig, err := c.Sign(ctx, &pbkeys.SignRequest{Address: addr, Message: hash})
 	if err != nil {
 		t.Fatal(err)
 	}
 
-	_, err = c.Verify(ctx, &pbkeys.VerifyRequest{Signature: sig.GetSignature(), Pub: resp.GetPub(), Hash: hash, Curvetype: typ})
+	_, err = c.Verify(ctx, &pbkeys.VerifyRequest{Signature: sig.GetSignature(), Pub: resp.GetPub(), Message: hash, Curvetype: typ})
 	if err != nil {
 		t.Fatal(err)
 	}
diff --git a/keys/test.sh b/keys/test.sh
index d25704af191fe7434033cc9e69aa2d5d1abaaf1d..7bb16ed18f12b9ee425fdc03a178aaa4d91fb7cb 100755
--- a/keys/test.sh
+++ b/keys/test.sh
@@ -1,14 +1,17 @@
 #! /bin/bash
-set -e
 
 # tests
 # run the suite with and without the daemon
 
 # TODO: run the suite with/without encryption!
 
+
+burrow_bin=${burrow_bin:-burrow}
+
 echo "-----------------------------"
 echo "starting the server"
-monax-keys server &
+$burrow_bin keys server &
+keys_pid=$!
 sleep 1
 echo "-----------------------------"
 echo "testing the cli"
@@ -18,37 +21,40 @@ echo "testing the cli"
 
 echo "testing keys"
 
-KEYTYPES=("ed25519,ripemd160" "secp256k1,sha3" "secp256k1,ripemd160sha256")
-for KEYTYPE in ${KEYTYPES[*]}
+CURVETYPES=("ed25519" "secp256k1")
+for CURVETYPE in ${CURVETYPES[*]}
 do
 	# test key gen, sign verify:
 	# for each step, ensure it works using --addr or --name
-	echo "... $KEYTYPE"
+	echo "... $CURVETYPE"
 
-	HASH=`monax-keys hash --type sha256 ok`
+	HASH=`$burrow_bin keys hash --type sha256 ok`
 	#echo "HASH: $HASH"
 	NAME=testkey1
-	ADDR=`monax-keys gen --type $KEYTYPE --name $NAME --no-pass`
+	ADDR=`$burrow_bin keys gen --curvetype $CURVETYPE --name $NAME --no-password`
 	#echo "my addr: $ADDR"
-	PUB1=`monax-keys pub --name $NAME`
-	PUB2=`monax-keys pub --addr $ADDR`
+	PUB1=`$burrow_bin keys pub --name $NAME`
+	PUB2=`$burrow_bin keys pub --addr $ADDR`
 	if [ "$PUB1" != "$PUB2" ]; then
 		echo "FAILED pub: got $PUB2, expected $PUB1"
+		kill $keys_pid
 		exit 1
 	fi
 	echo "...... passed pub"
 
-	SIG1=`monax-keys sign --name $NAME $HASH`
-	VERIFY1=`monax-keys verify --type $KEYTYPE $HASH $SIG1 $PUB1`
+	SIG1=`$burrow_bin keys sign --name $NAME $HASH`
+	VERIFY1=`$burrow_bin keys verify --curvetype $CURVETYPE $HASH $SIG1 $PUB1`
 	if [ $VERIFY1 != "true" ]; then
 		echo "FAILED verify: got $VERIFY1 expected true"
+		kill $keys_pid
 		exit 1
 	fi
 
-	SIG2=`monax-keys sign --addr $ADDR $HASH`
-	VERIFY1=`monax-keys verify --type $KEYTYPE $HASH $SIG2 $PUB1`
+	SIG2=`$burrow_bin keys sign --addr $ADDR $HASH`
+	VERIFY1=`$burrow_bin keys verify --curvetype $CURVETYPE $HASH $SIG2 $PUB1`
 	if [ $VERIFY1 != "true" ]; then
 		echo "FAILED verify: got $VERIFY1 expected true"
+		kill $keys_pid
 		exit 1
 	fi
 
@@ -64,7 +70,7 @@ for HASHTYPE in ${HASHTYPES[*]}
 do
 	echo  "... $HASHTYPE"
 	HASH0=`echo -n $TOHASH | openssl dgst -$HASHTYPE | awk '{print toupper($2)}'`
-	HASH1=`monax-keys hash --type $HASHTYPE $TOHASH`
+	HASH1=`$burrow_bin keys hash --type $HASHTYPE $TOHASH`
 	if [ "$HASH0" != "$HASH1" ]; then
 		echo "FAILED hash $HASHTYPE: got $HASH1 expected $HASH0"
 	fi
@@ -77,39 +83,42 @@ echo "testing imports"
 # for each key type, import a priv key, ensure it returns
 # the right address. do again with both plain and encrypted jsons
 
-for KEYTYPE in ${KEYTYPES[*]}
+for CURVETYPE in ${CURVETYPES[*]}
 do
-	echo "... $KEYTYPE"
+	echo "... $CURVETYPE"
 	# create a key, get its address and priv, backup the json, delete the key
-	ADDR=`monax-keys gen --type $KEYTYPE --no-pass`
-	DIR=$HOME/.monax/keys/data/$ADDR
-	FILE=$DIR/$ADDR
-	PRIV=`cat $FILE |  jq -r .PrivateKey`
-	HEXPRIV=`echo -n "$PRIV" | base64 -d | hexdump -ve '1/1 "%.2X"'`
+	ADDR=`$burrow_bin keys gen --curvetype $CURVETYPE --no-password`
+	DIR=.keys/data
+	FILE=$DIR/$ADDR.json
+	PRIV=`cat $FILE |  jq -r .PrivateKey.Plain`
+	HEXPRIV=`echo -n "$PRIV" | base64 -d | xxd -p -u -c 256`
 	cp $FILE ~/$ADDR
 	rm -rf $DIR
 
 	# import the key via priv
-	ADDR2=`monax-keys import --no-pass --type $KEYTYPE $HEXPRIV`
+	ADDR2=`$burrow_bin keys import --no-password --curvetype $CURVETYPE $HEXPRIV`
 	if [ "$ADDR" != "$ADDR2" ]; then
-		echo "FAILED import $KEYTYPE: got $ADDR2 expected $ADDR"	
+		echo "FAILED import $CURVETYPE: got $ADDR2 expected $ADDR"
+		kill $keys_pid
 		exit
 	fi
 	rm -rf $DIR
 
 	# import the key via json
 	JSON=`cat ~/$ADDR`
-	ADDR2=`monax-keys import --no-pass --type $KEYTYPE $JSON`
+	ADDR2=`$burrow_bin keys import --no-password --curvetype $CURVETYPE $JSON`
 	if [ "$ADDR" != "$ADDR2" ]; then
-		echo "FAILED import (json) $KEYTYPE: got $ADDR2 expected $ADDR"	
+		echo "FAILED import (json) $CURVETYPE: got $ADDR2 expected $ADDR"
+		kill $keys_pid
 		exit
 	fi
 	rm -rf $DIR
 
 	# import the key via path
-	ADDR2=`monax-keys import --no-pass --type $KEYTYPE ~/$ADDR`
+	ADDR2=`$burrow_bin keys import --no-password --curvetype $CURVETYPE ~/$ADDR`
 	if [ "$ADDR" != "$ADDR2" ]; then
-		echo "FAILED import $KEYTYPE: got $ADDR2 expected $ADDR"	
+		echo "FAILED import $CURVETYPE: got $ADDR2 expected $ADDR"
+		kill $keys_pid
 		exit
 	fi
 	rm -rf $DIR
@@ -121,23 +130,26 @@ done
 echo "testing names"
 
 NAME=mykey
-ADDR=`monax-keys gen --name $NAME --no-pass`
-ADDR2=`monax-keys name $NAME`
+ADDR=`$burrow_bin keys gen --name $NAME --no-password`
+ADDR2=`$burrow_bin keys list --name $NAME`
 if [ "$ADDR" != "$ADDR2" ]; then
-	echo "FAILED name: got $ADDR2 expected $ADDR"	
+	echo "FAILED name: got $ADDR2 expected $ADDR"
+	kill $keys_pid
 	exit
 fi
 
 NAME2=mykey2
-monax-keys name $NAME2 $ADDR
-ADDR2=`monax-keys name $NAME2`
+$burrow_bin keys name $NAME2 $ADDR
+ADDR2=`$burrow_bin keys list --name $NAME2`
 if [ "$ADDR" != "$ADDR2" ]; then
-	echo "FAILED rename: got $ADDR2 expected $ADDR"	
+	echo "FAILED rename: got $ADDR2 expected $ADDR"
+	kill $keys_pid
 	exit
 fi
 
 echo "... passed"
 
+kill $keys_pid
 
 # TODO a little more on names...
 
diff --git a/keys/tests/build_tool.sh b/keys/tests/build_tool.sh
deleted file mode 100755
index 80b8f00016d28a3194199b0f48e154c8bafbb810..0000000000000000000000000000000000000000
--- a/keys/tests/build_tool.sh
+++ /dev/null
@@ -1,58 +0,0 @@
-#!/usr/bin/env bash
-# ----------------------------------------------------------
-# PURPOSE
-
-# This is the build script for the monax stack. It will
-# build the tool into docker containers in a reliable and
-# predicatable manner.
-
-# ----------------------------------------------------------
-# REQUIREMENTS
-
-# docker installed locally
-
-# ----------------------------------------------------------
-# USAGE
-
-# build_tool.sh
-
-# ----------------------------------------------------------
-
-TARGET=monax-keys
-IMAGE=quay.io/monax/keys
-
-set -e
-
-if [ "$JENKINS_URL" ] || [ "$CIRCLE_BRANCH" ]
-then
-  REPO=`pwd`
-  CI="true"
-else
-  REPO=$GOPATH/src/github.com/hyperledger/burrow/keys
-fi
-
-release_min=$(cat $REPO/version/version.go | tail -n 1 | cut -d \  -f 4 | tr -d '"')
-release_maj=$(echo $release_min | cut -d . -f 1-2)
-
-# Build
-docker build -t $IMAGE:build $REPO
-docker run --rm --entrypoint cat $IMAGE:build /usr/local/bin/$TARGET > $REPO/"$TARGET"_build_artifact
-
-#-----------------------------------------------------------------------------
-
-docker build -t $IMAGE:$release_min -f Dockerfile.deploy $REPO
-
-# Cleanup
-rm $REPO/"$TARGET"_build_artifact
-
-# Extra Tags
-if [[ "$branch" = "master" ]]
-then
-  docker tag -f $IMAGE:$release_min $IMAGE:$release_maj
-  docker tag -f $IMAGE:$release_min $IMAGE:latest
-fi
-
-if [ "$CIRCLE_BRANCH" ]
-then
-  docker tag -f $IMAGE:$release_min $IMAGE:latest
-fi
diff --git a/rpc/config.go b/rpc/config.go
index 9ece9ccc3aee5606e333e23ab180f0677003a12e..9449609d98ead8a4330fa4fac0f4d2a8930ff9bf 100644
--- a/rpc/config.go
+++ b/rpc/config.go
@@ -3,13 +3,13 @@ package rpc
 import "github.com/hyperledger/burrow/rpc/v0/server"
 
 type RPCConfig struct {
-	V0       *V0Config       `json:",omitempty" toml:",omitempty"`
-	TM       *TMConfig       `json:",omitempty" toml:",omitempty"`
-	Profiler *ProfilerConfig `json:",omitempty" toml:",omitempty"`
-	GRPC     *GRPCConfig     `json:",omitempty" toml:",omitempty"`
+	V0       *V0Config     `json:",omitempty" toml:",omitempty"`
+	TM       *ServerConfig `json:",omitempty" toml:",omitempty"`
+	Profiler *ServerConfig `json:",omitempty" toml:",omitempty"`
+	GRPC     *ServerConfig `json:",omitempty" toml:",omitempty"`
 }
 
-type TMConfig struct {
+type ServerConfig struct {
 	Enabled       bool
 	ListenAddress string
 }
@@ -45,22 +45,22 @@ func DefaultV0Config() *V0Config {
 	}
 }
 
-func DefaultTMConfig() *TMConfig {
-	return &TMConfig{
+func DefaultTMConfig() *ServerConfig {
+	return &ServerConfig{
 		Enabled:       true,
 		ListenAddress: "tcp://localhost:46657",
 	}
 }
 
-func DefaultGRPCConfig() *GRPCConfig {
-	return &GRPCConfig{
+func DefaultGRPCConfig() *ServerConfig {
+	return &ServerConfig{
 		Enabled:       true,
 		ListenAddress: "localhost:10997",
 	}
 }
 
-func DefaultProfilerConfig() *ProfilerConfig {
-	return &ProfilerConfig{
+func DefaultProfilerConfig() *ServerConfig {
+	return &ServerConfig{
 		Enabled:       false,
 		ListenAddress: "tcp://localhost:6060",
 	}