Merge "android: Save go panics to file and then send to logcat on load"
diff --git a/examples/bank/bank/main.go b/examples/bank/bank/main.go
index 92228f6..1145486 100644
--- a/examples/bank/bank/main.go
+++ b/examples/bank/bank/main.go
@@ -95,7 +95,7 @@
 		}
 
 		// Make a NewClient and update the other one. Do not close the old client; we need its connection to the Mount Table.
-		client, err = runtime.NewClient(veyron2.LocalID(derivedIdentity))
+		client, err = runtime.NewClient(veyron2.LocalID(newPublicID))
 		if err != nil {
 			log.Fatalf("failed to create new client: %s\n", err)
 		}
diff --git a/examples/boxes/android/src/boxesp2p/main.go b/examples/boxes/android/src/boxesp2p/main.go
index 8b0b724..a4748e3 100644
--- a/examples/boxes/android/src/boxesp2p/main.go
+++ b/examples/boxes/android/src/boxesp2p/main.go
@@ -398,7 +398,7 @@
 
 	// Initialize veyron runtime and bind to the signalling server used to rendezvous with
 	// another peer device. TODO(gauthamt): Switch to using the nameserver for signalling.
-	gs.runtime = rt.Init(veyron2.LocalID(privateID))
+	gs.runtime = rt.Init(veyron2.RuntimeID(privateID))
 	if gs.signalling, err = boxes.BindBoxSignalling(naming.JoinAddressName("@2@tcp@162.222.181.93:8509@08a93d90836cd94d4dc1acbe40b9048d@1@1@@", "signalling")); err != nil {
 		panic(fmt.Errorf("failed to bind to signalling server:%v\n", err))
 	}
diff --git a/examples/todos/test/util.go b/examples/todos/test/util.go
index e3555c9..9f10a45 100644
--- a/examples/todos/test/util.go
+++ b/examples/todos/test/util.go
@@ -21,7 +21,7 @@
 // getRuntime initializes the veyron2.Runtime if needed, then returns it.
 func getRuntime() veyron2.Runtime {
 	// returns Runtime if already initialized
-	return rt.Init(veyron2.LocalID(security.FakePrivateID("todos")))
+	return rt.Init(veyron2.RuntimeID(security.FakePrivateID("todos")))
 }
 
 // startServer starts a store server and returns the server name as well as a
diff --git a/examples/todos/todos_init/main.go b/examples/todos/todos_init/main.go
index 6121a38..44db7c2 100644
--- a/examples/todos/todos_init/main.go
+++ b/examples/todos/todos_init/main.go
@@ -166,7 +166,7 @@
 	// (since only the admin can put data). The identity here matches with that
 	// used for server.ServerConfig.Admin in todos_stored/main.go. An alternative
 	// would be to relax the ACLs on the store.
-	rt.Init(veyron2.LocalID(security.FakePrivateID("anonymous")))
+	rt.Init(veyron2.RuntimeID(security.FakePrivateID("anonymous")))
 
 	vlog.Infof("Binding to store on %s", storeName)
 	st, err := vstore.New(storeName)
diff --git a/runtimes/google/ipc/flow_test.go b/runtimes/google/ipc/flow_test.go
index 8850b21..47dfb93 100644
--- a/runtimes/google/ipc/flow_test.go
+++ b/runtimes/google/ipc/flow_test.go
@@ -9,12 +9,16 @@
 	"time"
 
 	_ "veyron/lib/testutil"
+	isecurity "veyron/runtimes/google/security"
+
 	"veyron2/ipc"
 	"veyron2/naming"
 	"veyron2/security"
 	"veyron2/verror"
 )
 
+var testID = newID("test")
+
 // newTestFlows returns the two ends of a bidirectional flow.  Each end has its
 // own bookkeeping, to allow testing of method calls.
 func newTestFlows() (*testFlow, *testFlow) {
@@ -34,8 +38,8 @@
 func (f *testFlow) RemoteAddr() net.Addr               { return nil }
 func (f *testFlow) LocalEndpoint() naming.Endpoint     { return nil }
 func (f *testFlow) RemoteEndpoint() naming.Endpoint    { return nil }
-func (f *testFlow) LocalID() security.PublicID         { return security.FakePublicID("test") }
-func (f *testFlow) RemoteID() security.PublicID        { return security.FakePublicID("test") }
+func (f *testFlow) LocalID() security.PublicID         { return testID.PublicID() }
+func (f *testFlow) RemoteID() security.PublicID        { return testID.PublicID() }
 func (f *testFlow) SetReadDeadline(t time.Time) error  { return nil }
 func (f *testFlow) SetWriteDeadline(t time.Time) error { return nil }
 func (f *testFlow) SetDeadline(t time.Time) error      { return nil }
@@ -139,3 +143,7 @@
 		}
 	}
 }
+
+func init() {
+	isecurity.TrustIdentityProviders(testID)
+}
diff --git a/runtimes/google/ipc/full_test.go b/runtimes/google/ipc/full_test.go
index 9b24996..03a3d5a 100644
--- a/runtimes/google/ipc/full_test.go
+++ b/runtimes/google/ipc/full_test.go
@@ -39,8 +39,8 @@
 var (
 	errAuthorizer = errors.New("ipc: application Authorizer denied access")
 	errMethod     = verror.Abortedf("server returned an error")
-	clientID      security.PrivateID
-	serverID      security.PrivateID
+	clientID      = newID("client")
+	serverID      = newID("server")
 	clock         = new(fakeClock)
 )
 
@@ -259,7 +259,7 @@
 
 func startServer(t *testing.T, serverID security.PrivateID, sm stream.Manager, ns naming.Namespace, ts interface{}) (naming.Endpoint, ipc.Server) {
 	vlog.VI(1).Info("InternalNewServer")
-	server, err := InternalNewServer(InternalNewContext(), sm, ns, listenerID(serverID))
+	server, err := InternalNewServer(InternalNewContext(), sm, ns, vc.FixedLocalID(serverID))
 	if err != nil {
 		t.Errorf("InternalNewServer failed: %v", err)
 	}
@@ -327,18 +327,25 @@
 }
 
 func (b bundle) cleanup(t *testing.T) {
-	stopServer(t, b.server, b.ns)
-	b.client.Close()
+	if b.server != nil {
+		stopServer(t, b.server, b.ns)
+	}
+	if b.client != nil {
+		b.client.Close()
+	}
 }
 
 func createBundle(t *testing.T, clientID, serverID security.PrivateID, ts interface{}) (b bundle) {
 	b.sm = imanager.InternalNew(naming.FixedRoutingID(0x555555555))
 	b.ns = newNamespace()
-	b.ep, b.server = startServer(t, serverID, b.sm, b.ns, ts)
-	var err error
-	b.client, err = InternalNewClient(b.sm, b.ns, veyron2.LocalID(clientID))
-	if err != nil {
-		t.Fatalf("InternalNewClient failed: %v", err)
+	if serverID != nil {
+		b.ep, b.server = startServer(t, serverID, b.sm, b.ns, ts)
+	}
+	if clientID != nil {
+		var err error
+		if b.client, err = InternalNewClient(b.sm, b.ns, vc.FixedLocalID(clientID)); err != nil {
+			t.Fatalf("InternalNewClient failed: %v", err)
+		}
 	}
 	return
 }
@@ -352,10 +359,7 @@
 }
 
 func derive(blessor security.PrivateID, name string, caveats ...security.ServiceCaveat) security.PrivateID {
-	id, err := isecurity.NewPrivateID("irrelevant")
-	if err != nil {
-		panic(err)
-	}
+	id := newID("irrelevant")
 	derivedID, err := id.Derive(bless(blessor, id.PublicID(), name, caveats...))
 	if err != nil {
 		panic(err)
@@ -394,7 +398,7 @@
 func TestMultipleCallsToServe(t *testing.T) {
 	sm := imanager.InternalNew(naming.FixedRoutingID(0x555555555))
 	ns := newNamespace()
-	server, err := InternalNewServer(InternalNewContext(), sm, ns, listenerID(serverID))
+	server, err := InternalNewServer(InternalNewContext(), sm, ns, vc.FixedLocalID(serverID))
 	if err != nil {
 		t.Errorf("InternalNewServer failed: %v", err)
 	}
@@ -484,7 +488,7 @@
 	for _, test := range tests {
 		name := fmt.Sprintf("(clientID:%q serverID:%q)", test.clientID, test.serverID)
 		_, server := startServer(t, test.serverID, mgr, ns, &testServer{})
-		client, err := InternalNewClient(mgr, ns, veyron2.LocalID(test.clientID))
+		client, err := InternalNewClient(mgr, ns, vc.FixedLocalID(test.clientID))
 		if err != nil {
 			t.Errorf("%s: Client creation failed: %v", name, err)
 			stopServer(t, server, ns)
@@ -715,10 +719,10 @@
 		return fmt.Sprintf("%q RPCing %s.%s(%v)", t.clientID.PublicID(), t.name, t.method, t.args)
 	}
 
-	b := createBundle(t, nil, serverID, &testServer{})
+	b := createBundle(t, nil, serverID, &testServer{}) // we only create the server, a separate client will be created for each test.
 	defer b.cleanup(t)
 	for _, test := range tests {
-		client, err := InternalNewClient(b.sm, b.ns, veyron2.LocalID(test.clientID))
+		client, err := InternalNewClient(b.sm, b.ns, vc.FixedLocalID(test.clientID))
 		if err != nil {
 			t.Fatalf("InternalNewClient failed: %v", err)
 		}
@@ -969,7 +973,7 @@
 		{[]ipc.ServerOpt{veyron2.PublishFirst, veyron2.EndpointRewriteOpt("example.com")}, []string{"example.com"}},
 	}
 	for i, c := range cases {
-		server, err := InternalNewServer(InternalNewContext(), sm, ns, append([]ipc.ServerOpt{listenerID(serverID)}, c.opts...)...)
+		server, err := InternalNewServer(InternalNewContext(), sm, ns, append(c.opts, vc.FixedLocalID(serverID))...)
 		if err != nil {
 			t.Errorf("InternalNewServer failed: %v", err)
 			continue
@@ -1102,12 +1106,12 @@
 func TestProxy(t *testing.T) {
 	sm := imanager.InternalNew(naming.FixedRoutingID(0x555555555))
 	ns := newNamespace()
-	client, err := InternalNewClient(sm, ns, veyron2.LocalID(clientID))
+	client, err := InternalNewClient(sm, ns, vc.FixedLocalID(clientID))
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer client.Close()
-	server, err := InternalNewServer(InternalNewContext(), sm, ns, listenerID(serverID))
+	server, err := InternalNewServer(InternalNewContext(), sm, ns, vc.FixedLocalID(serverID))
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1189,7 +1193,7 @@
 	ns := newNamespace()
 	id := loadIdentityFromFile(argv[1])
 	isecurity.TrustIdentityProviders(id)
-	server, err := InternalNewServer(InternalNewContext(), mgr, ns, listenerID(id))
+	server, err := InternalNewServer(InternalNewContext(), mgr, ns, vc.FixedLocalID(id))
 	if err != nil {
 		vlog.Fatalf("InternalNewServer failed: %v", err)
 	}
@@ -1225,13 +1229,6 @@
 }
 
 func init() {
-	var err error
-	if clientID, err = isecurity.NewPrivateID("client"); err != nil {
-		vlog.Fatalf("failed isecurity.NewPrivateID: %s", err)
-	}
-	if serverID, err = isecurity.NewPrivateID("server"); err != nil {
-		vlog.Fatalf("failed isecurity.NewPrivateID: %s", err)
-	}
 	isecurity.TrustIdentityProviders(clientID)
 	isecurity.TrustIdentityProviders(serverID)
 
diff --git a/runtimes/google/ipc/stream/crypto/crypto_test.go b/runtimes/google/ipc/stream/crypto/crypto_test.go
index 8720ccc..84b0d76 100644
--- a/runtimes/google/ipc/stream/crypto/crypto_test.go
+++ b/runtimes/google/ipc/stream/crypto/crypto_test.go
@@ -37,8 +37,7 @@
 	crypter.String() // Only to test that String does not crash.
 }
 
-func testSimple(t *testing.T, crypters func(testing.TB) (Crypter, Crypter)) {
-	c1, c2 := crypters(t)
+func testSimple(t *testing.T, c1, c2 Crypter) {
 	// Execute String just to check that it does not crash.
 	c1.String()
 	c2.String()
@@ -63,11 +62,21 @@
 	t.Logf("Byte overhead of encryption: %v", overhead)
 }
 
-func TestTLS(t *testing.T) { testSimple(t, tlsCrypters) }
-func TestBox(t *testing.T) { testSimple(t, boxCrypters) }
+func TestTLS(t *testing.T) {
+	server, client := net.Pipe()
+	c1, c2 := tlsCrypters(t, server, client)
+	testSimple(t, c1, c2)
+}
+
+func TestBox(t *testing.T) {
+	server, client := net.Pipe()
+	c1, c2 := boxCrypters(t, server, client)
+	testSimple(t, c1, c2)
+}
 
 func TestTLSNil(t *testing.T) {
-	c1, c2 := tlsCrypters(t)
+	conn1, conn2 := net.Pipe()
+	c1, c2 := tlsCrypters(t, conn1, conn2)
 	if t.Failed() {
 		return
 	}
@@ -89,7 +98,8 @@
 	// 16K (it is represented by a uint16).
 	// http://tools.ietf.org/html/rfc5246#section-6.2.1
 	const dataLen = 16384 + 1
-	enc, dec := tlsCrypters(t)
+	conn1, conn2 := net.Pipe()
+	enc, dec := tlsCrypters(t, conn1, conn2)
 	cipher, err := enc.Encrypt(iobuf.NewSlice(make([]byte, dataLen)))
 	if err != nil {
 		t.Fatal(err)
@@ -103,8 +113,9 @@
 	}
 }
 
-func tlsCrypters(t testing.TB) (Crypter, Crypter) {
-	serverConn, clientConn := net.Pipe()
+type factory func(t testing.TB, server, client net.Conn) (Crypter, Crypter)
+
+func tlsCrypters(t testing.TB, serverConn, clientConn net.Conn) (Crypter, Crypter) {
 	crypters := make(chan Crypter)
 	go func() {
 		server, err := NewTLSServer(serverConn, iobuf.NewPool(0))
@@ -126,8 +137,7 @@
 	return c1, c2
 }
 
-func boxCrypters(t testing.TB) (Crypter, Crypter) {
-	serverConn, clientConn := net.Pipe()
+func boxCrypters(t testing.TB, serverConn, clientConn net.Conn) (Crypter, Crypter) {
 	crypters := make(chan Crypter)
 	for _, conn := range []net.Conn{serverConn, clientConn} {
 		go func(conn net.Conn) {
@@ -141,12 +151,15 @@
 	return <-crypters, <-crypters
 }
 
-func benchmarkEncrypt(b *testing.B, crypters func(testing.TB) (Crypter, Crypter), size int) {
+func benchmarkEncrypt(b *testing.B, crypters factory, size int) {
 	plaintext := make([]byte, size)
 	if _, err := rand.Read(plaintext); err != nil {
 		b.Fatal(err)
 	}
-	e, _ := crypters(b)
+	conn1, conn2 := net.Pipe()
+	defer conn1.Close()
+	defer conn2.Close()
+	e, _ := crypters(b, conn1, conn2)
 	b.SetBytes(int64(size))
 	b.ResetTimer()
 	for i := 0; i < b.N; i++ {
@@ -170,12 +183,15 @@
 func BenchmarkBoxEncrypt_1M(b *testing.B)  { benchmarkEncrypt(b, boxCrypters, 1<<20) }
 func BenchmarkBoxEncrypt_5M(b *testing.B)  { benchmarkEncrypt(b, boxCrypters, 5<<20) }
 
-func benchmarkRoundTrip(b *testing.B, crypters func(testing.TB) (Crypter, Crypter), size int) {
+func benchmarkRoundTrip(b *testing.B, crypters factory, size int) {
 	plaintext := make([]byte, size)
 	if _, err := rand.Read(plaintext); err != nil {
 		b.Fatal(err)
 	}
-	e, d := crypters(b)
+	conn1, conn2 := net.Pipe()
+	defer conn1.Close()
+	defer conn2.Close()
+	e, d := crypters(b, conn1, conn2)
 	b.SetBytes(int64(size))
 	b.ResetTimer()
 	for i := 0; i < b.N; i++ {
@@ -201,3 +217,15 @@
 func BenchmarkBoxRoundTrip_10K(b *testing.B) { benchmarkRoundTrip(b, boxCrypters, 10<<10) }
 func BenchmarkBoxRoundTrip_1M(b *testing.B)  { benchmarkRoundTrip(b, boxCrypters, 1<<20) }
 func BenchmarkBoxRoundTrip_5M(b *testing.B)  { benchmarkRoundTrip(b, boxCrypters, 5<<20) }
+
+func benchmarkSetup(b *testing.B, crypters factory) {
+	for i := 0; i < b.N; i++ {
+		conn1, conn2 := net.Pipe()
+		crypters(b, conn1, conn2)
+		conn1.Close()
+		conn2.Close()
+	}
+}
+
+func BenchmarkTLSSetup(b *testing.B) { benchmarkSetup(b, tlsCrypters) }
+func BenchmarkBoxSetup(b *testing.B) { benchmarkSetup(b, boxCrypters) }
diff --git a/runtimes/google/ipc/stream/manager/manager_test.go b/runtimes/google/ipc/stream/manager/manager_test.go
index 943a667..2e02ffb 100644
--- a/runtimes/google/ipc/stream/manager/manager_test.go
+++ b/runtimes/google/ipc/stream/manager/manager_test.go
@@ -15,14 +15,22 @@
 	"veyron/runtimes/google/ipc/stream/vc"
 	"veyron/runtimes/google/ipc/version"
 	inaming "veyron/runtimes/google/naming"
+	isecurity "veyron/runtimes/google/security"
 
-	"veyron2"
 	"veyron2/ipc/stream"
 	"veyron2/naming"
 	"veyron2/security"
 	"veyron2/vlog"
 )
 
+func newID(name string) security.PrivateID {
+	id, err := isecurity.NewPrivateID(name)
+	if err != nil {
+		panic(err)
+	}
+	return id
+}
+
 func init() {
 	// The testutil package's init sets GOMAXPROCS to NumCPU.  We want to
 	// force GOMAXPROCS to remain at 1, in order to trigger a particular
@@ -121,12 +129,11 @@
 	server := InternalNew(naming.FixedRoutingID(0x55555555))
 	client := InternalNew(naming.FixedRoutingID(0xcccccccc))
 
-	serverID := security.FakePrivateID("server")
-	clientID := security.FakePrivateID("client")
-
+	clientID := newID("client")
+	serverID := newID("server")
 	// VCSecurityLevel is intentionally not provided to Listen - to test
 	// default behavior.
-	ln, ep, err := server.Listen("tcp", "localhost:0", vc.ListenerID(serverID))
+	ln, ep, err := server.Listen("tcp", "localhost:0", vc.FixedLocalID(serverID))
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -156,7 +163,7 @@
 	go func() {
 		// VCSecurityLevel is intentionally not provided to Dial - to
 		// test default behavior.
-		vc, err := client.Dial(ep, veyron2.LocalID(clientID))
+		vc, err := client.Dial(ep, vc.FixedLocalID(clientID))
 		if err != nil {
 			errs <- err
 			return
@@ -287,16 +294,14 @@
 }
 
 func TestSessionTicketCache(t *testing.T) {
-	serverID := vc.ListenerID(security.FakePrivateID("TestSessionTicketCacheServer"))
 	server := InternalNew(naming.FixedRoutingID(0x55555555))
-	_, ep, err := server.Listen("tcp", "localhost:0", serverID)
+	_, ep, err := server.Listen("tcp", "localhost:0", vc.FixedLocalID(newID("server")))
 	if err != nil {
 		t.Fatal(err)
 	}
 
-	clientID := veyron2.LocalID(security.FakePrivateID("TestSessionTicketCacheClient"))
 	client := InternalNew(naming.FixedRoutingID(0xcccccccc))
-	if _, err = client.Dial(ep, clientID); err != nil {
+	if _, err = client.Dial(ep, vc.FixedLocalID(newID("TestSessionTicketCacheClient"))); err != nil {
 		t.Fatalf("Dial(%q) failed: %v", ep, err)
 	}
 
@@ -314,7 +319,7 @@
 
 	// Have the server read from each flow and write to rchan.
 	rchan := make(chan string)
-	ln, ep, err := server.Listen("tcp", "localhost:0", vc.ListenerID(security.FakePrivateID("server")))
+	ln, ep, err := server.Listen("tcp", "localhost:0", vc.FixedLocalID(newID("server")))
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -350,7 +355,7 @@
 	var vcs [nVCs]stream.VC
 	for i := 0; i < nVCs; i++ {
 		var err error
-		vcs[i], err = client.Dial(ep, veyron2.LocalID(security.FakePrivateID("client")))
+		vcs[i], err = client.Dial(ep, vc.FixedLocalID(newID("client")))
 		if err != nil {
 			t.Fatal(err)
 		}
@@ -399,7 +404,7 @@
 	}
 	go acceptLoop(ln)
 
-	// We'd like an enpoint that contains an address that's different
+	// We'd like an endpoint that contains an address that's different
 	// to the one used for the connection. In practice this is awkward
 	// to achieve since we don't want to listen on ":0" since that will
 	// annoy firewalls. Instead we listen on 127.0.0.1 and we fabricate an
@@ -465,7 +470,7 @@
 
 func runServer(argv []string) {
 	server := InternalNew(naming.FixedRoutingID(0x55555555))
-	_, ep, err := server.Listen("tcp", argv[0], vc.ListenerID(security.FakePrivateID("server")))
+	_, ep, err := server.Listen("tcp", argv[0], vc.FixedLocalID(newID("server")))
 	if err != nil {
 		fmt.Println(err)
 		return
diff --git a/runtimes/google/ipc/stream/proxy/proxy.go b/runtimes/google/ipc/stream/proxy/proxy.go
index e0022d5..433ad73 100644
--- a/runtimes/google/ipc/stream/proxy/proxy.go
+++ b/runtimes/google/ipc/stream/proxy/proxy.go
@@ -31,7 +31,7 @@
 type Proxy struct {
 	ln         net.Listener
 	rid        naming.RoutingID
-	id         security.PrivateID
+	id         vc.LocalID
 	mu         sync.RWMutex
 	servers    *servermap
 	processes  map[*process]struct{}
@@ -135,14 +135,17 @@
 	proxy := &Proxy{
 		ln:         ln,
 		rid:        rid,
-		id:         identity,
 		servers:    &servermap{m: make(map[naming.RoutingID]*server)},
 		processes:  make(map[*process]struct{}),
 		pubAddress: pubAddress,
 	}
+	if identity != nil {
+		proxy.id = vc.FixedLocalID(identity)
+	}
 	go proxy.listenLoop()
 	return proxy, nil
 }
+
 func (p *Proxy) listenLoop() {
 	proxyLog().Infof("Proxy listening on (%q, %q): %v", p.ln.Addr().Network(), p.ln.Addr(), p.Endpoint())
 	for {
@@ -313,7 +316,7 @@
 				p.routeCounters(process, m.Counters)
 				if vcObj != nil {
 					server := &server{Process: process, VC: vcObj}
-					go p.runServer(server, vcObj.HandshakeAcceptedVC(vc.ListenerID(p.id)))
+					go p.runServer(server, vcObj.HandshakeAcceptedVC(p.id))
 				}
 				break
 			}
diff --git a/runtimes/google/ipc/stream/proxy/proxy_test.go b/runtimes/google/ipc/stream/proxy/proxy_test.go
index c28e618..7b3e1dd 100644
--- a/runtimes/google/ipc/stream/proxy/proxy_test.go
+++ b/runtimes/google/ipc/stream/proxy/proxy_test.go
@@ -4,6 +4,7 @@
 	"bytes"
 	"fmt"
 	"io"
+	"reflect"
 	"strings"
 	"testing"
 
@@ -11,12 +12,21 @@
 	"veyron/runtimes/google/ipc/stream/manager"
 	"veyron/runtimes/google/ipc/stream/proxy"
 	"veyron/runtimes/google/ipc/stream/vc"
+	isecurity "veyron/runtimes/google/security"
 
 	"veyron2/ipc/stream"
 	"veyron2/naming"
 	"veyron2/security"
 )
 
+func newID(name string) security.PrivateID {
+	id, err := isecurity.NewPrivateID(name)
+	if err != nil {
+		panic(err)
+	}
+	return id
+}
+
 func TestProxy(t *testing.T) {
 	// Using "tcp4" instead of "tcp" because the latter can end up with
 	// IPv6 addresses and our Google Compute Engine integration test
@@ -110,7 +120,8 @@
 }
 
 func TestProxyIdentity(t *testing.T) {
-	proxy, err := proxy.New(naming.FixedRoutingID(0xbbbbbbbbbbbbbbbb), security.FakePrivateID("proxy"), "tcp4", "127.0.0.1:0", "")
+	proxyID := newID("proxy")
+	proxy, err := proxy.New(naming.FixedRoutingID(0xbbbbbbbbbbbbbbbb), proxyID, "tcp4", "127.0.0.1:0", "")
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -128,7 +139,7 @@
 	if err != nil {
 		t.Fatal(err)
 	}
-	if got, want := fmt.Sprintf("%v", flow.RemoteID()), "fake/proxy"; got != want {
+	if got, want := fmt.Sprintf("%v", flow.RemoteID()), fmt.Sprintf("%v", proxyID.PublicID()); got != want {
 		t.Errorf("Proxy has identity %q want %q", flow.RemoteID(), want)
 	}
 }
@@ -141,8 +152,11 @@
 
 	server := manager.InternalNew(naming.FixedRoutingID(0x5555555555555555))
 	defer server.Shutdown()
-	serverID := security.FakePrivateID("server")
-	ln, ep, err := server.Listen(proxy.Endpoint().Network(), proxy.Endpoint().String(), vc.ListenerID(serverID))
+	serverID := newID("server")
+	if err != nil {
+		t.Fatal(err)
+	}
+	ln, ep, err := server.Listen(proxy.Endpoint().Network(), proxy.Endpoint().String(), vc.FixedLocalID(serverID))
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -165,7 +179,7 @@
 	if err != nil {
 		t.Fatal(err)
 	}
-	if got, want := fmt.Sprintf("%v", flow.RemoteID()), "fake/server"; got != want {
+	if got, want := flow.RemoteID(), serverID.PublicID(); !reflect.DeepEqual(got, want) {
 		t.Errorf("Got %q want %q", got, want)
 	}
 }
diff --git a/runtimes/google/ipc/stream/vc/auth.go b/runtimes/google/ipc/stream/vc/auth.go
index 0378b31..0d4b094 100644
--- a/runtimes/google/ipc/stream/vc/auth.go
+++ b/runtimes/google/ipc/stream/vc/auth.go
@@ -21,15 +21,19 @@
 )
 
 // authenticateAsServer executes the authentication protocol at the server and
-// returns the identity of the client.
-func authenticateAsServer(conn io.ReadWriteCloser, serverID security.PrivateID, crypter crypto.Crypter) (clientID security.PublicID, err error) {
+// returns the identity of the client and server.
+func authenticateAsServer(conn io.ReadWriteCloser, localID LocalID, crypter crypto.Crypter) (clientID, serverID security.PublicID, err error) {
 	// The authentication protocol has the server doing the final read, so
 	// it is the one that closes the connection.
 	defer conn.Close()
-	if err = writeIdentity(conn, serverChannelEnd, crypter, serverID); err != nil {
+	if serverID, err = localID.AsServer(); err != nil {
 		return
 	}
-	return readIdentity(conn, clientChannelEnd, crypter)
+	if err = writeIdentity(conn, serverChannelEnd, crypter, localID, serverID); err != nil {
+		return
+	}
+	clientID, err = readIdentity(conn, clientChannelEnd, crypter)
+	return
 }
 
 // authenticateAsClient executes the authentication protocol at the client and
@@ -37,12 +41,17 @@
 //
 // If serverName is non-nil, the authentication protocol will be considered
 // successfull iff the server identity matches the provided regular expression.
-func authenticateAsClient(conn io.ReadWriteCloser, clientID security.PrivateID, crypter crypto.Crypter) (serverID security.PublicID, err error) {
+func authenticateAsClient(conn io.ReadWriteCloser, localID LocalID, crypter crypto.Crypter) (serverID, clientID security.PublicID, err error) {
 	defer conn.Close()
 	if serverID, err = readIdentity(conn, serverChannelEnd, crypter); err != nil {
 		return
 	}
-	err = writeIdentity(conn, clientChannelEnd, crypter, clientID)
+	// TODO(ashankar,ataly): Have the ability to avoid talking to a server we do not want to.
+	// Will require calling Authorize on the server id?
+	if clientID, err = localID.AsClient(serverID); err != nil {
+		return
+	}
+	err = writeIdentity(conn, clientChannelEnd, crypter, localID, clientID)
 	return
 }
 
@@ -64,7 +73,7 @@
 	errSingleCertificateRequired = errors.New("exactly one X.509 certificate chain with exactly one certificate is required")
 )
 
-func writeIdentity(w io.Writer, chEnd string, enc crypto.Encrypter, id security.PrivateID) error {
+func writeIdentity(w io.Writer, chEnd string, enc crypto.Encrypter, id LocalID, pub security.PublicID) error {
 	// Compute channel id - encrypted chEnd string
 	chid, err := enc.Encrypt(iobuf.NewSlice([]byte(chEnd)))
 	if err != nil {
@@ -74,7 +83,7 @@
 
 	// VOM-encode and encrypt the (public) identity.
 	var buf bytes.Buffer
-	if err := vom.NewEncoder(&buf).Encode(id.PublicID()); err != nil {
+	if err := vom.NewEncoder(&buf).Encode(pub); err != nil {
 		return err
 	}
 	eid, err := enc.Encrypt(iobuf.NewSlice(buf.Bytes()))
diff --git a/runtimes/google/ipc/stream/vc/init.go b/runtimes/google/ipc/stream/vc/init.go
new file mode 100644
index 0000000..a801353
--- /dev/null
+++ b/runtimes/google/ipc/stream/vc/init.go
@@ -0,0 +1,17 @@
+package vc
+
+import (
+	isecurity "veyron/runtimes/google/security"
+
+	"veyron2/security"
+	"veyron2/vlog"
+)
+
+var anonymousID security.PrivateID
+
+func init() {
+	var err error
+	if anonymousID, err = isecurity.NewPrivateID("anonymous"); err != nil {
+		vlog.Fatalf("could create anonymousID for IPCs: %s", err)
+	}
+}
diff --git a/runtimes/google/ipc/stream/vc/listener_test.go b/runtimes/google/ipc/stream/vc/listener_test.go
index a449242..a621b97 100644
--- a/runtimes/google/ipc/stream/vc/listener_test.go
+++ b/runtimes/google/ipc/stream/vc/listener_test.go
@@ -5,12 +5,24 @@
 	"testing"
 	"time"
 
+	isecurity "veyron/runtimes/google/security"
+
 	"veyron2/naming"
 	"veyron2/security"
 )
 
+var testID = newID("test")
+
 type noopFlow struct{}
 
+func newID(name string) security.PrivateID {
+	id, err := isecurity.NewPrivateID(name)
+	if err != nil {
+		panic(err)
+	}
+	return id
+}
+
 // net.Conn methods
 func (*noopFlow) Read([]byte) (int, error)           { return 0, nil }
 func (*noopFlow) Write([]byte) (int, error)          { return 0, nil }
@@ -27,8 +39,8 @@
 func (*noopFlow) SetWriteDeadline(t time.Time) error { return nil }
 
 // Other stream.Flow methods
-func (*noopFlow) LocalID() security.PublicID  { return security.FakePublicID("test") }
-func (*noopFlow) RemoteID() security.PublicID { return security.FakePublicID("test") }
+func (*noopFlow) LocalID() security.PublicID  { return testID.PublicID() }
+func (*noopFlow) RemoteID() security.PublicID { return testID.PublicID() }
 
 func TestListener(t *testing.T) {
 	ln := newListener()
diff --git a/runtimes/google/ipc/stream/vc/vc.go b/runtimes/google/ipc/stream/vc/vc.go
index 09d719d..7f70721 100644
--- a/runtimes/google/ipc/stream/vc/vc.go
+++ b/runtimes/google/ipc/stream/vc/vc.go
@@ -90,27 +90,48 @@
 	Helper       Helper
 }
 
-// ListenerIDOpt is the interface for providing an identity to an ipc.StreamListener.
-type ListenerIDOpt interface {
+// LocalID is the interface for providing a PrivateID and a PublicIDStore to
+// be used at the local end of VCs.
+type LocalID interface {
 	stream.ListenerOpt
-	// Identity returns the identity to be used by the ipc.StreamListener.
-	Identity() security.PrivateID
+	stream.VCOpt
+	// Sign signs an arbitrary length message (often the hash of a larger message)
+	// using a private key.
+	Sign(message []byte) (security.Signature, error)
+
+	// AsClient returns a PublicID to be used while authenticating as a client to the
+	// provided server as a client. An error is returned if no such PublicID can be returned.
+	AsClient(server security.PublicID) (security.PublicID, error)
+
+	// AsServer returns a PublicID to be used while authenticating as a server to other
+	// clients. An error is returned if no such PublicID can be returned.
+	AsServer() (security.PublicID, error)
+	IPCClientOpt()
+	IPCServerOpt()
 }
 
-// listenerIDOpt implements ListenerIDOpt.
-type listenerIDOpt struct {
-	id security.PrivateID
+// fixedLocalID implements vc.LocalID.
+type fixedLocalID struct {
+	security.PrivateID
 }
 
-func (opt *listenerIDOpt) Identity() security.PrivateID {
-	return opt.id
+func (f fixedLocalID) AsClient(security.PublicID) (security.PublicID, error) {
+	return f.PrivateID.PublicID(), nil
 }
 
-func (*listenerIDOpt) IPCStreamListenerOpt() {}
+func (f fixedLocalID) AsServer() (security.PublicID, error) {
+	return f.PrivateID.PublicID(), nil
+}
 
-// ListenerID provides an implementation of ListenerIDOpt with a fixed identity.
-func ListenerID(id security.PrivateID) ListenerIDOpt {
-	return &listenerIDOpt{id}
+func (fixedLocalID) IPCStreamListenerOpt() {}
+func (fixedLocalID) IPCStreamVCOpt()       {}
+func (fixedLocalID) IPCClientOpt()         {}
+func (fixedLocalID) IPCServerOpt()         {}
+
+// FixedLocalID creates a LocalID using the provided PrivateID. The
+// provided PrivateID must always be non-nil.
+func FixedLocalID(id security.PrivateID) LocalID {
+	return fixedLocalID{id}
 }
 
 // InternalNew creates a new VC, which implements the stream.VC interface.
@@ -347,13 +368,13 @@
 // authentication etc.) under the assumption that the VC was initiated by the
 // local process (i.e., the local process "Dial"ed to create the VC).
 func (vc *VC) HandshakeDialedVC(opts ...stream.VCOpt) error {
-	var localID security.PrivateID
+	var localID LocalID
 	var tlsSessionCache tls.ClientSessionCache
 	var securityLevel veyron2.VCSecurityLevel
 	for _, o := range opts {
 		switch v := o.(type) {
-		case veyron2.LocalIDOpt:
-			localID = v.PrivateID
+		case LocalID:
+			localID = v
 		case veyron2.VCSecurityLevel:
 			securityLevel = v
 		case crypto.TLSClientSessionCache:
@@ -362,7 +383,9 @@
 	}
 	switch securityLevel {
 	case veyron2.VCSecurityConfidential:
-		localID = anonymousIfNilPrivateID(localID)
+		if localID == nil {
+			localID = FixedLocalID(anonymousID)
+		}
 	case veyron2.VCSecurityNone:
 		return nil
 	default:
@@ -394,7 +417,7 @@
 	if err != nil {
 		return vc.err(fmt.Errorf("failed to create a Flow for authentication: %v", err))
 	}
-	remoteID, err := authenticateAsClient(authConn, localID, crypter)
+	rID, lID, err := authenticateAsClient(authConn, localID, crypter)
 	if err != nil {
 		return vc.err(fmt.Errorf("authentication failed: %v", err))
 	}
@@ -403,11 +426,11 @@
 	vc.handshakeFID = handshakeFID
 	vc.authFID = authFID
 	vc.crypter = crypter
-	vc.localID = localID.PublicID()
-	vc.remoteID = remoteID
+	vc.localID = lID
+	vc.remoteID = rID
 	vc.mu.Unlock()
 
-	vlog.VI(1).Infof("Client VC %v authenticated. RemoteID:%v LocalID:%v", vc, remoteID, localID)
+	vlog.VI(1).Infof("Client VC %v authenticated. RemoteID:%v LocalID:%v", vc, rID, lID)
 	return nil
 }
 
@@ -430,12 +453,12 @@
 		result <- HandshakeResult{ln, err}
 		return result
 	}
-	var localID security.PrivateID
+	var localID LocalID
 	var securityLevel veyron2.VCSecurityLevel
 	for _, o := range opts {
 		switch v := o.(type) {
-		case ListenerIDOpt:
-			localID = v.Identity()
+		case LocalID:
+			localID = v
 		case veyron2.VCSecurityLevel:
 			securityLevel = v
 		}
@@ -450,7 +473,9 @@
 	vc.helper.AddReceiveBuffers(vc.VCI(), SharedFlowID, DefaultBytesBufferedPerFlow)
 	switch securityLevel {
 	case veyron2.VCSecurityConfidential:
-		localID = anonymousIfNilPrivateID(localID)
+		if localID == nil {
+			localID = FixedLocalID(anonymousID)
+		}
 	case veyron2.VCSecurityNone:
 		return finish(ln, nil)
 	default:
@@ -493,7 +518,7 @@
 		vc.mu.Lock()
 		vc.authFID = vc.findFlowLocked(authConn)
 		vc.mu.Unlock()
-		remoteID, err := authenticateAsServer(authConn, localID, crypter)
+		rID, lID, err := authenticateAsServer(authConn, localID, crypter)
 		if err != nil {
 			sendErr(fmt.Errorf("Authentication failed: %v", err))
 			return
@@ -501,12 +526,12 @@
 
 		vc.mu.Lock()
 		vc.crypter = crypter
-		vc.localID = localID.PublicID()
-		vc.remoteID = remoteID
+		vc.localID = lID
+		vc.remoteID = rID
 		close(vc.acceptHandshakeDone)
 		vc.acceptHandshakeDone = nil
 		vc.mu.Unlock()
-		vlog.VI(1).Infof("Server VC %v authenticated. RemoteID:%v LocalID:%v", vc, remoteID, localID)
+		vlog.VI(1).Infof("Server VC %v authenticated. RemoteID:%v LocalID:%v", vc, rID, lID)
 		result <- HandshakeResult{ln, nil}
 	}()
 	return result
@@ -641,15 +666,5 @@
 	if id != nil {
 		return id
 	}
-	// TODO(ashankar): Have an Anonymous identity that also encodes the
-	// public key so that changing the keys in code doesn't prevent new
-	// binaries from talking to old ones.
-	return security.FakePublicID("anonymous")
-}
-
-func anonymousIfNilPrivateID(id security.PrivateID) security.PrivateID {
-	if id != nil {
-		return id
-	}
-	return security.FakePrivateID("anonymous")
+	return anonymousID.PublicID()
 }
diff --git a/runtimes/google/ipc/stream/vc/vc_test.go b/runtimes/google/ipc/stream/vc/vc_test.go
index ae93fd8..f1b1e2e 100644
--- a/runtimes/google/ipc/stream/vc/vc_test.go
+++ b/runtimes/google/ipc/stream/vc/vc_test.go
@@ -4,6 +4,7 @@
 
 import (
 	"bytes"
+	"fmt"
 	"io"
 	"net"
 	"reflect"
@@ -18,6 +19,7 @@
 	"veyron/runtimes/google/lib/bqueue"
 	"veyron/runtimes/google/lib/bqueue/drrqueue"
 	"veyron/runtimes/google/lib/iobuf"
+	isecurity "veyron/runtimes/google/security"
 
 	"veyron2"
 	"veyron2/ipc/stream"
@@ -35,10 +37,18 @@
 )
 
 var (
-	clientID = security.FakePrivateID("client")
-	serverID = security.FakePrivateID("server")
+	clientID = newID("client")
+	serverID = newID("server")
 )
 
+func newID(name string) security.PrivateID {
+	id, err := isecurity.NewPrivateID(name)
+	if err != nil {
+		panic(err)
+	}
+	return id
+}
+
 // testFlowEcho writes a random string of 'size' bytes on the flow and then
 // ensures that the same string is read back.
 func testFlowEcho(t *testing.T, flow stream.Flow, size int) {
@@ -73,30 +83,43 @@
 	}
 }
 
+func matchID(got, want security.PublicID) error {
+	if want == nil {
+		if got.Names() != nil {
+			return fmt.Errorf("got identity with names: %v, want one with names: nil", got.Names())
+		}
+		return nil
+	}
+	if g, w := got.Names(), want.Names(); !reflect.DeepEqual(got.Names(), want.Names()) {
+		return fmt.Errorf("got identity with names: %v, want one with names: %v", g, w)
+	}
+	if g, w := got.PublicKey(), want.PublicKey(); !reflect.DeepEqual(got.PublicKey(), want.PublicKey()) {
+		return fmt.Errorf("got identity with public key: %v, want one with public key: %v", g, w)
+	}
+	return nil
+}
+
 func testHandshake(t *testing.T, security veyron2.VCSecurityLevel, localID, remoteID security.PublicID) {
 	h, vc := New(security)
 	flow, err := vc.Connect()
 	if err != nil {
 		t.Fatal(err)
 	}
-	lID := flow.LocalID()
-	if !reflect.DeepEqual(lID.Names(), localID.Names()) {
-		t.Errorf("Client says LocalID is %q want %q", lID, localID)
+	lID, rID := flow.LocalID(), flow.RemoteID()
+	if (lID == nil) || (rID == nil) {
+		t.Error("Either the LocalID or the RemoteID of the flow is nil")
 	}
-	rID := flow.RemoteID()
-	if !reflect.DeepEqual(rID.Names(), remoteID.Names()) {
-		t.Errorf("Client says RemoteID is %q want %q", rID, remoteID)
+	if err := matchID(lID, localID); err != nil {
+		t.Errorf("Client identity mismatch: %s", err)
 	}
-	if g, w := lID.PublicKey(), localID.PublicKey(); !reflect.DeepEqual(g, w) {
-		t.Errorf("Client identity public key mismatch. Got %v want %v", g, w)
-	}
-	if g, w := rID.PublicKey(), remoteID.PublicKey(); !reflect.DeepEqual(g, w) {
-		t.Errorf("Server identity public key mismatch. Got %v want %v", g, w)
+	if err := matchID(rID, remoteID); err != nil {
+		t.Errorf("Server identity mismatch: %s", err)
 	}
 	h.Close()
 }
+
 func TestHandshake(t *testing.T) {
-	testHandshake(t, SecurityNone, security.FakePublicID("anonymous"), security.FakePublicID("anonymous"))
+	testHandshake(t, SecurityNone, nil, nil)
 }
 func TestHandshakeTLS(t *testing.T) {
 	testHandshake(t, SecurityTLS, clientID.PublicID(), serverID.PublicID())
@@ -273,8 +296,8 @@
 	go clientH.pipeLoop(serverH.VC)
 	go serverH.pipeLoop(clientH.VC)
 
-	c := serverH.VC.HandshakeAcceptedVC(security, vc.ListenerID(serverID))
-	if err := clientH.VC.HandshakeDialedVC(security, veyron2.LocalID(clientID)); err != nil {
+	c := serverH.VC.HandshakeAcceptedVC(security, vc.FixedLocalID(serverID))
+	if err := clientH.VC.HandshakeDialedVC(security, vc.FixedLocalID(clientID)); err != nil {
 		panic(err)
 	}
 	hr := <-c
diff --git a/runtimes/google/ipc/stream/vif/vif_test.go b/runtimes/google/ipc/stream/vif/vif_test.go
index ab377f4..a743542 100644
--- a/runtimes/google/ipc/stream/vif/vif_test.go
+++ b/runtimes/google/ipc/stream/vif/vif_test.go
@@ -18,14 +18,21 @@
 	"veyron/runtimes/google/ipc/stream/vc"
 	"veyron/runtimes/google/ipc/stream/vif"
 	iversion "veyron/runtimes/google/ipc/version"
+	isecurity "veyron/runtimes/google/security"
 
-	"veyron2"
 	"veyron2/ipc/stream"
 	"veyron2/ipc/version"
 	"veyron2/naming"
-	"veyron2/security"
 )
 
+func newLocalID(name string) vc.LocalID {
+	id, err := isecurity.NewPrivateID(name)
+	if err != nil {
+		panic(err)
+	}
+	return vc.FixedLocalID(id)
+}
+
 func TestSingleFlowCreatedAtClient(t *testing.T) {
 	client, server := NewClientServer()
 	defer client.Close()
@@ -415,8 +422,7 @@
 	if client, err = vif.InternalNewDialedVIF(c1, naming.FixedRoutingID(0xc), clientVersions); err != nil {
 		panic(err)
 	}
-	serverID := vc.ListenerID(security.FakePrivateID("server"))
-	if server, err = vif.InternalNewAcceptedVIF(c2, naming.FixedRoutingID(0x5), serverVersions, serverID); err != nil {
+	if server, err = vif.InternalNewAcceptedVIF(c2, naming.FixedRoutingID(0x5), serverVersions, newLocalID("server")); err != nil {
 		panic(err)
 	}
 	return
@@ -456,8 +462,7 @@
 	scChan := make(chan stream.Connector)
 	errChan := make(chan error)
 	go func() {
-		clientID := veyron2.LocalID(security.FakePrivateID("client"))
-		vc, err := client.Dial(ep, clientID)
+		vc, err := client.Dial(ep, newLocalID("client"))
 		errChan <- err
 		vcChan <- vc
 	}()
diff --git a/runtimes/google/ipc/testutil_test.go b/runtimes/google/ipc/testutil_test.go
index e726013..f990ca7 100644
--- a/runtimes/google/ipc/testutil_test.go
+++ b/runtimes/google/ipc/testutil_test.go
@@ -5,7 +5,10 @@
 	"testing"
 
 	_ "veyron/lib/testutil"
+	"veyron/runtimes/google/ipc/stream/vc"
+	isecurity "veyron/runtimes/google/security"
 
+	"veyron2/ipc"
 	"veyron2/security"
 	"veyron2/verror"
 )
@@ -38,19 +41,13 @@
 	}
 }
 
-// listenerIDOpt implements vc.ListenerIDOpt and veyron2/ipc.ServerOpt.
-type listenerIDOpt struct {
-	id security.PrivateID
+func newID(name string) security.PrivateID {
+	id, err := isecurity.NewPrivateID(name)
+	if err != nil {
+		panic(err)
+	}
+	return id
 }
 
-func (opt *listenerIDOpt) Identity() security.PrivateID {
-	return opt.id
-}
-
-func (*listenerIDOpt) IPCStreamListenerOpt() {}
-
-func (*listenerIDOpt) IPCServerOpt() {}
-
-func listenerID(id security.PrivateID) *listenerIDOpt {
-	return &listenerIDOpt{id}
-}
+var _ ipc.ClientOpt = vc.FixedLocalID(newID("irrelevant"))
+var _ ipc.ServerOpt = vc.FixedLocalID(newID("irrelevant"))
diff --git a/runtimes/google/rt/ipc.go b/runtimes/google/rt/ipc.go
index 2b54fad..150bfdf 100644
--- a/runtimes/google/rt/ipc.go
+++ b/runtimes/google/rt/ipc.go
@@ -1,22 +1,81 @@
 package rt
 
 import (
+	"errors"
 	"fmt"
 
 	iipc "veyron/runtimes/google/ipc"
 	imanager "veyron/runtimes/google/ipc/stream/manager"
+	"veyron/runtimes/google/ipc/stream/vc"
 
 	"veyron2"
 	"veyron2/context"
 	"veyron2/ipc"
 	"veyron2/ipc/stream"
 	"veyron2/naming"
+	"veyron2/security"
 )
 
+// fixedPublicIDStore implements security.PublicIDStore. It embeds a (fixed) PublicID that
+// is both the default and the PublicID to be used for any peer. Adding a new PublicID
+// to the store is disallowed, and setting the default principal-pattern is a no-op.
+type fixedPublicIDStore struct {
+	id security.PublicID
+}
+
+func (fixedPublicIDStore) Add(id security.PublicID, peerPattern security.PrincipalPattern) error {
+	return errors.New("adding new PublicIDs is disallowed for this PublicIDStore")
+}
+
+func (s fixedPublicIDStore) ForPeer(peer security.PublicID) (security.PublicID, error) {
+	return s.id, nil
+}
+
+func (s fixedPublicIDStore) DefaultPublicID() (security.PublicID, error) {
+	return s.id, nil
+}
+
+func (fixedPublicIDStore) SetDefaultPrincipalPattern(pattern security.PrincipalPattern) {}
+
+// localID is an option for passing a PrivateID and PublicIDStore
+// to a server or client.
+type localID struct {
+	id    security.PrivateID
+	store security.PublicIDStore
+}
+
+func (lID *localID) Sign(message []byte) (security.Signature, error) {
+	return lID.id.Sign(message)
+}
+
+func (lID *localID) AsClient(server security.PublicID) (security.PublicID, error) {
+	return lID.store.ForPeer(server)
+}
+
+func (lID *localID) AsServer() (security.PublicID, error) {
+	return lID.store.DefaultPublicID()
+}
+
+func (*localID) IPCClientOpt()         {}
+func (*localID) IPCStreamVCOpt()       {}
+func (*localID) IPCServerOpt()         {}
+func (*localID) IPCStreamListenerOpt() {}
+
+// newLocalID returns a localID embedding the runtime's PrivateID and a fixed
+// PublicIDStore constructed from the provided PublicID or the runtiume's PublicIDStore
+// if the provided PublicID is nil.
+func (rt *vrt) newLocalID(id security.PublicID) vc.LocalID {
+	lID := &localID{id: rt.id, store: rt.store}
+	if id != nil {
+		lID.store = fixedPublicIDStore{id}
+	}
+	return lID
+}
+
 func (rt *vrt) NewClient(opts ...ipc.ClientOpt) (ipc.Client, error) {
 	sm := rt.sm
 	ns := rt.ns
-	cIDOpt := veyron2.LocalID(rt.id.Identity())
+	var id security.PublicID
 	var otherOpts []ipc.ClientOpt
 	for _, opt := range opts {
 		switch topt := opt.(type) {
@@ -25,14 +84,14 @@
 		case veyron2.NamespaceOpt:
 			ns = topt.Namespace
 		case veyron2.LocalIDOpt:
-			cIDOpt = topt
+			id = topt.PublicID
 		default:
 			otherOpts = append(otherOpts, opt)
 		}
 	}
-	if cIDOpt.PrivateID != nil {
-		otherOpts = append(otherOpts, cIDOpt)
-	}
+	// Add the option that provides the local identity to the client.
+	otherOpts = append(otherOpts, rt.newLocalID(id))
+
 	return iipc.InternalNewClient(sm, ns, otherOpts...)
 }
 
@@ -68,17 +127,20 @@
 	// Start the http debug server exactly once for this runtime.
 	rt.startHTTPDebugServerOnce()
 	ns := rt.ns
+	var id security.PublicID
 	var otherOpts []ipc.ServerOpt
 	for _, opt := range opts {
 		switch topt := opt.(type) {
 		case veyron2.NamespaceOpt:
 			ns = topt
+		case veyron2.LocalIDOpt:
+			id = topt.PublicID
 		default:
 			otherOpts = append(otherOpts, opt)
 		}
 	}
-	// Add the option that provides the identity currently used by the runtime.
-	otherOpts = append(otherOpts, rt.id)
+	// Add the option that provides the local identity to the server.
+	otherOpts = append(otherOpts, rt.newLocalID(id))
 
 	ctx := rt.NewContext()
 	return iipc.InternalNewServer(ctx, sm, ns, otherOpts...)
diff --git a/runtimes/google/rt/ipc_test.go b/runtimes/google/rt/ipc_test.go
new file mode 100644
index 0000000..1822541
--- /dev/null
+++ b/runtimes/google/rt/ipc_test.go
@@ -0,0 +1,188 @@
+package rt_test
+
+import (
+	"fmt"
+	"reflect"
+	"sort"
+	"testing"
+	"time"
+
+	_ "veyron/lib/testutil"
+	isecurity "veyron/runtimes/google/security"
+
+	"veyron2"
+	"veyron2/ipc"
+	"veyron2/naming"
+	"veyron2/rt"
+	"veyron2/security"
+)
+
+type testService struct{}
+
+func (*testService) EchoIDs(call ipc.ServerCall) (server, client []string) {
+	return call.LocalID().Names(), call.RemoteID().Names()
+}
+
+type S []string
+
+func newID(name string) security.PrivateID {
+	id, err := isecurity.NewPrivateID(name)
+	if err != nil {
+		panic(err)
+	}
+	return id
+}
+
+func bless(blessor security.PrivateID, blessee security.PublicID, name string) security.PublicID {
+	blessedID, err := blessor.Bless(blessee, name, 5*time.Minute, nil)
+	if err != nil {
+		panic(err)
+	}
+	return blessedID
+}
+
+func add(store security.PublicIDStore, id security.PublicID, pattern security.PrincipalPattern) {
+	if err := store.Add(id, pattern); err != nil {
+		panic(err)
+	}
+}
+
+func call(r veyron2.Runtime, client ipc.Client, name string) (clientNames, serverNames []string, err error) {
+	c, err := client.StartCall(r.NewContext(), name, "EchoIDs", nil)
+	if err != nil {
+		return nil, nil, err
+	}
+	if err := c.Finish(&serverNames, &clientNames); err != nil {
+		return nil, nil, err
+	}
+	sort.Strings(clientNames)
+	sort.Strings(serverNames)
+	return
+}
+
+func TestClientServerIDs(t *testing.T) {
+	stopServer := func(server ipc.Server) {
+		if err := server.Stop(); err != nil {
+			t.Fatalf("server.Stop failed: %s", err)
+		}
+	}
+	var (
+		self   = newID("self")
+		google = newID("google")
+		veyron = newID("veyron")
+
+		googleGmailService   = bless(google, self.PublicID(), "gmail")
+		googleYoutubeService = bless(google, self.PublicID(), "youtube")
+		veyronService        = bless(veyron, self.PublicID(), "service")
+		googleGmailClient    = bless(google, self.PublicID(), "gmailClient")
+		googleYoutubeClient  = bless(google, self.PublicID(), "youtubeClient")
+		veyronClient         = bless(veyron, self.PublicID(), "client")
+	)
+	isecurity.TrustIdentityProviders(google)
+	isecurity.TrustIdentityProviders(veyron)
+
+	serverR, err := rt.New(veyron2.RuntimeID(self))
+	if err != nil {
+		t.Fatalf("rt.New() failed: %s", err)
+	}
+	clientR, err := rt.New(veyron2.RuntimeID(self))
+	if err != nil {
+		t.Fatalf("rt.New() failed: %s", err)
+	}
+
+	// Add PublicIDs for running "google/gmail" and "google/youtube" services to
+	// serverR's PublicIDStore. Since these PublicIDs are meant to be by
+	// servers only they are tagged with "".
+	add(serverR.PublicIDStore(), googleGmailService, "")
+	add(serverR.PublicIDStore(), googleYoutubeService, "")
+	// Add PublicIDs for communicating the "google/gmail" and "google/youtube" services
+	// to the clientR's PublicIDStore.
+	add(clientR.PublicIDStore(), googleGmailClient, "google/*")
+	add(clientR.PublicIDStore(), googleYoutubeClient, "google/youtube")
+
+	type testcase struct {
+		server, client                   security.PublicID
+		defaultPattern                   security.PrincipalPattern
+		wantServerNames, wantClientNames []string
+	}
+	tests := []testcase{
+		{
+			defaultPattern:  security.AllPrincipals,
+			wantServerNames: S{"self", "google/gmail", "google/youtube"},
+			wantClientNames: S{"self", "google/gmailClient", "google/youtubeClient"},
+		},
+		{
+			defaultPattern:  "google/gmail",
+			wantServerNames: S{"google/gmail"},
+			wantClientNames: S{"self", "google/gmailClient"},
+		},
+		{
+			defaultPattern:  "google/youtube",
+			wantServerNames: S{"google/youtube"},
+			wantClientNames: S{"self", "google/gmailClient", "google/youtubeClient"},
+		},
+		{
+			server:          veyronService,
+			defaultPattern:  security.AllPrincipals,
+			wantServerNames: S{"veyron/service"},
+			wantClientNames: S{"self"},
+		},
+		{
+			client:          veyronClient,
+			defaultPattern:  security.AllPrincipals,
+			wantServerNames: S{"self", "google/gmail", "google/youtube"},
+			wantClientNames: S{"veyron/client"},
+		},
+		{
+			server:          veyronService,
+			client:          veyronClient,
+			defaultPattern:  security.AllPrincipals,
+			wantServerNames: S{"veyron/service"},
+			wantClientNames: S{"veyron/client"},
+		},
+	}
+	name := func(t testcase) string {
+		return fmt.Sprintf("TestCase{clientPublicIDStore: %v, serverPublicIDStore: %v, client option: %v, server option: %v}", clientR.PublicIDStore(), serverR.PublicIDStore(), t.client, t.server)
+	}
+	for _, test := range tests {
+		serverR.PublicIDStore().SetDefaultPrincipalPattern(test.defaultPattern)
+		server, err := serverR.NewServer(veyron2.LocalID(test.server))
+		if err != nil {
+			t.Errorf("serverR.NewServer(...) failed: %s", err)
+			continue
+		}
+		endpoint, err := server.Listen("tcp", "127.0.0.1:0")
+		if err != nil {
+			t.Errorf("error listening to service: ", err)
+			continue
+		}
+		defer stopServer(server)
+		if err := server.Serve("", ipc.SoloDispatcher(&testService{}, security.NewACLAuthorizer(security.ACL{security.AllPrincipals: security.AllLabels}))); err != nil {
+			t.Errorf("error serving service: ", err)
+			continue
+		}
+
+		client, err := clientR.NewClient(veyron2.LocalID(test.client))
+		if err != nil {
+			t.Errorf("clientR.NewClient(...) failed: %s", err)
+			continue
+		}
+		defer client.Close()
+
+		clientNames, serverNames, err := call(clientR, client, naming.JoinAddressName(fmt.Sprintf("%v", endpoint), ""))
+		if err != nil {
+			t.Errorf("IPC failed: %s", err)
+			continue
+		}
+		sort.Strings(test.wantClientNames)
+		sort.Strings(test.wantServerNames)
+		if !reflect.DeepEqual(clientNames, test.wantClientNames) {
+			t.Errorf("TestCase: %s, Got clientNames: %v, want: %v", name(test), clientNames, test.wantClientNames)
+			continue
+		}
+		if !reflect.DeepEqual(serverNames, test.wantServerNames) {
+			t.Errorf("TestCase: %s, Got serverNames: %v, want: %v", name(test), serverNames, test.wantServerNames)
+			continue
+		}
+	}
+}
diff --git a/runtimes/google/rt/rt.go b/runtimes/google/rt/rt.go
index 805adf4..3f4f429 100644
--- a/runtimes/google/rt/rt.go
+++ b/runtimes/google/rt/rt.go
@@ -15,6 +15,7 @@
 	"veyron2/ipc/stream"
 	"veyron2/naming"
 	"veyron2/product"
+	"veyron2/security"
 	"veyron2/vlog"
 )
 
@@ -23,7 +24,8 @@
 	sm      stream.Manager
 	ns      naming.Namespace
 	signals chan os.Signal
-	id      *currentIDOpt
+	id      security.PrivateID
+	store   security.PublicIDStore
 	client  ipc.Client
 	mgmt    *mgmtImpl
 	debug   debugServer
@@ -61,13 +63,13 @@
 func (rt *vrt) init(opts ...veyron2.ROpt) error {
 	flag.Parse()
 	rt.initHTTPDebugServer()
-	rt.id = &currentIDOpt{}
 	nsRoots := []string{}
-
 	for _, o := range opts {
 		switch v := o.(type) {
-		case veyron2.LocalIDOpt:
-			rt.id.setIdentity(v.PrivateID)
+		case veyron2.RuntimeIDOpt:
+			rt.id = v.PrivateID
+		case veyron2.RuntimePublicIDStoreOpt:
+			rt.store = v
 		case veyron2.ProductOpt:
 			rt.product = v.T
 		case veyron2.NamespaceRoots:
@@ -123,11 +125,11 @@
 		return err
 	}
 
-	if err = rt.initIdentity(); err != nil {
+	if err = rt.initSecurity(); err != nil {
 		return err
 	}
 
-	if rt.client, err = rt.NewClient(veyron2.LocalID(rt.id.Identity())); err != nil {
+	if rt.client, err = rt.NewClient(); err != nil {
 		return err
 	}
 
diff --git a/runtimes/google/rt/security.go b/runtimes/google/rt/security.go
index b25b95d..b14babf 100644
--- a/runtimes/google/rt/security.go
+++ b/runtimes/google/rt/security.go
@@ -4,7 +4,6 @@
 	"fmt"
 	"os"
 	"os/user"
-	"sync"
 
 	isecurity "veyron/runtimes/google/security"
 
@@ -12,61 +11,53 @@
 	"veyron2/vlog"
 )
 
-// currentIDOpt is an option that can be used to pass the identity currently used
-// by the runtime to an ipc.Server or ipc.StreamListener.
-type currentIDOpt struct {
-	id security.PrivateID
-	mu sync.RWMutex
-}
-
-func (id *currentIDOpt) Identity() security.PrivateID {
-	id.mu.RLock()
-	defer id.mu.RUnlock()
-	return id.id
-}
-
-func (id *currentIDOpt) setIdentity(newID security.PrivateID) {
-	// TODO(ataly): Whenever setIdentity is invoked on the identity currently used by
-	// the runtime, the following changes must also be performed:
-	// * the identity provider of the new identity must be tursted.
-	// * the default client used by the runtime must also be replaced with
-	//   a client using the new identity.
-	id.mu.Lock()
-	defer id.mu.Unlock()
-	id.id = newID
-}
-
-func (*currentIDOpt) IPCServerOpt() {}
-
-func (*currentIDOpt) IPCStreamListenerOpt() {}
-
 func (rt *vrt) NewIdentity(name string) (security.PrivateID, error) {
 	return isecurity.NewPrivateID(name)
 }
 
 func (rt *vrt) Identity() security.PrivateID {
-	return rt.id.Identity()
+	return rt.id
+}
+
+func (rt *vrt) PublicIDStore() security.PublicIDStore {
+	return rt.store
+}
+
+func (rt *vrt) initSecurity() error {
+	if err := rt.initIdentity(); err != nil {
+		return err
+	}
+	if rt.store == nil {
+		rt.store = isecurity.NewPublicIDStore()
+		// TODO(ashankar,ataly): What should the tag for the runtime's PublicID in the
+		// runtime's store be? Below we use security.AllPrincipals but this means that
+		// the PublicID *always* gets used for any peer. This may not be desirable.
+		if err := rt.store.Add(rt.id.PublicID(), security.AllPrincipals); err != nil {
+			return fmt.Errorf("could not initialize a PublicIDStore for the runtime: %s", err)
+		}
+	}
+	// Always trust our own identity providers.
+	// TODO(ataly, ashankar): We should trust the identity providers of all PublicIDs in the store.
+	trustIdentityProviders(rt.id)
+	return nil
 }
 
 func (rt *vrt) initIdentity() error {
-	if rt.id.Identity() == nil {
-		var id security.PrivateID
-		var err error
-		if file := os.Getenv("VEYRON_IDENTITY"); len(file) > 0 {
-			if id, err = loadIdentityFromFile(file); err != nil {
-				return fmt.Errorf("Could not load identity from %q: %v", file, err)
-			}
-		} else {
-			name := defaultIdentityName()
-			vlog.VI(2).Infof("No identity provided to the runtime, minting one for %q", name)
-			if id, err = rt.NewIdentity(name); err != nil {
-				return fmt.Errorf("Could not create new identity: %v", err)
-			}
-		}
-		rt.id.setIdentity(id)
+	if rt.id != nil {
+		return nil
 	}
-	// Always trust our own identity providers.
-	trustIdentityProviders(rt.id.Identity())
+	var err error
+	if file := os.Getenv("VEYRON_IDENTITY"); len(file) > 0 {
+		if rt.id, err = loadIdentityFromFile(file); err != nil || rt.id == nil {
+			return fmt.Errorf("Could not load identity from %q: %v", file, err)
+		}
+	} else {
+		name := defaultIdentityName()
+		vlog.VI(2).Infof("No identity provided to the runtime, minting one for %q", name)
+		if rt.id, err = rt.NewIdentity(name); err != nil || rt.id == nil {
+			return fmt.Errorf("Could not create new identity: %v", err)
+		}
+	}
 	return nil
 }
 
diff --git a/services/mounttable/lib/mounttable_test.go b/services/mounttable/lib/mounttable_test.go
index e961bc5..cfea7f8 100644
--- a/services/mounttable/lib/mounttable_test.go
+++ b/services/mounttable/lib/mounttable_test.go
@@ -29,9 +29,9 @@
 }
 
 var (
-	rootID  = veyron2.LocalID(security.FakePrivateID("root"))
-	bobID   = veyron2.LocalID(security.FakePrivateID("bob"))
-	aliceID = veyron2.LocalID(security.FakePrivateID("alice"))
+	rootID  = veyron2.LocalID(security.FakePublicID("root"))
+	bobID   = veyron2.LocalID(security.FakePublicID("bob"))
+	aliceID = veyron2.LocalID(security.FakePublicID("alice"))
 )
 
 const ttlSecs = 60 * 60
@@ -169,7 +169,12 @@
 }
 
 func newMT(t *testing.T, acl string) (ipc.Server, string) {
-	r := rt.Init()
+	// It is necessary for the private key of runtime's identity and
+	// the public key of the LocalIDOpts passed to clients to correspond.
+	// Since the LocalIDOpts are FakePublicIDs, we initialize the runtime
+	// below with a FakePrivateID. (Note all FakePublicIDs and FakePrivateIDs
+	// always have corresponding public and private keys respectively.)
+	r := rt.Init(veyron2.RuntimeID(security.FakePrivateID("irrelevant")))
 	server, err := r.NewServer(veyron2.ServesMountTableOpt(true))
 	if err != nil {
 		boom(t, "r.NewServer: %s", err)
diff --git a/services/mounttable/lib/neighborhood_test.go b/services/mounttable/lib/neighborhood_test.go
index 471edba..4c5bbb3 100644
--- a/services/mounttable/lib/neighborhood_test.go
+++ b/services/mounttable/lib/neighborhood_test.go
@@ -25,7 +25,7 @@
 
 func TestNeighborhood(t *testing.T) {
 	r := rt.Init()
-	id := veyron2.LocalID(rt.R().Identity())
+	id := veyron2.LocalID(rt.R().Identity().PublicID())
 	vlog.Infof("TestNeighborhood")
 	server, err := r.NewServer()
 	if err != nil {
diff --git a/services/wsprd/wspr/wspr_test.go b/services/wsprd/wspr/wspr_test.go
index d03d7fa..fd697ee 100644
--- a/services/wsprd/wspr/wspr_test.go
+++ b/services/wsprd/wspr/wspr_test.go
@@ -410,9 +410,8 @@
 	defer rt.mounttableServer.Stop()
 	defer rt.proxyServer.Shutdown()
 	defer rt.wsp.cleanup()
-
 	if err != nil {
-		t.Errorf("could not serve server %v", err)
+		t.Fatalf("could not serve server %v", err)
 	}
 
 	if len(rt.writer.stream) != 1 {