veyron/runtimes/google/ipc/stream/crypto: Add benchmarks for connection
setup.

This commit only adds the benchmarks and make a strong case for using nacl/box
as the encryption layer since by avoiding unnecessary certification
verification, the handshake time improves by 140x on my desktop and 10x on the
raspberry pi.

The benchmarks demonstrate (and mimic real-world usage) that connection setup
to a Pi takes 3 seconds with the current code and can be improved to 200ms
using the box crypter.

I also tried the TLS benchmarks using an ECDSA certificate and the
ECDHE_ECDSA_WITH_RC4_128_SHA cipher suite instead of an RSA certificate
with TLS_ECDHE_RSA_WITH_RC4_128_SHA. Switching to ECDSA certificates
also improves time considerably, but really we need to figure out
a way to avoid certificate verification (especially since we do not
place any faith in these certificates). Either by switching to box
or by using TLS_DH_anon_* or some family of cipher suites in TLS.

Benchmark summary:
Desktop (Intel Xeon 3.2Ghz)
                     us-per-handshake  speedup
TLS with RSA keys     32938             1x (baseline)
TLS with ECDSA keys    8143             4x
Box                     223             147x

Raspberri Pi          ms-per-handshake  speedup
TLS with RSA keys     2856              1x (baseline)
TLS with ECDSA keys    739              3x
Box                    290              10x

Change-Id: Icb60a3cc1be33ff63c3b2a0562fbf18feff38753
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) }