SPORTS

Change-Id: Ic272cba9811948aac3ac2b4713ed61ebf73955d4
diff --git a/runtime/internal/flow/conn/grpc/conn.go b/runtime/internal/flow/conn/grpc/conn.go
new file mode 100644
index 0000000..5ce7b6a
--- /dev/null
+++ b/runtime/internal/flow/conn/grpc/conn.go
@@ -0,0 +1,88 @@
+// Copyright 2016 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package grpc
+
+import (
+	"bytes"
+	"encoding/binary"
+	"errors"
+	"fmt"
+	"io"
+	"net"
+	"time"
+
+	"golang.org/x/crypto/nacl/box"
+)
+
+// Implements net.Conn. Encrypts messages using keys negotioated via NaCl.
+// TODO: blessings
+// TODO: discharges and caveats
+// TODO: ensuer that all 5 of these are set. Constructor?
+// TODO: do I need to check the message size as in box_coipher.Seal?
+// TODO: make all these keys not pointers?
+type conn struct {
+	rawConn   net.Conn
+	publicKey *[32]byte
+	secretKey *[32]byte
+	sharedKey *[32]byte
+	binding   []byte
+	nonce     [24]byte
+	counter   uint64 // Why is this so weirdly handled in advanceNonce?
+}
+
+func (c *conn) Read(b []byte) (n int, err error) {
+	return 0, nil
+}
+
+// TODO: all this casting is gross
+func (c *conn) Write(b []byte) (n int, err error) {
+	tmp := make([]byte, len(b)+box.Overhead) // TODO: is this enough? Also, why do we need both of tmp and out?
+	out := box.SealAfterPrecomputation(tmp, b, c.currentNonce(), c.sharedKey)
+	c.advanceNonce()
+	bytesCopied, err := io.Copy(c.rawConn, bytes.NewReader(out))
+	if err != nil {
+		return int(bytesCopied), err
+	}
+	if bytesCopied != int64(len(out)) {
+		errMsg := fmt.Sprintf("Did not write entire message. Expected to write %d bytes but wrote %d.", len(out), bytesCopied)
+		return -1, errors.New(errMsg)
+	}
+	return int(bytesCopied), nil
+}
+
+// TODO: cover these up with an interface?
+func (c *conn) Close() error {
+	return c.rawConn.Close()
+}
+
+func (c *conn) LocalAddr() net.Addr {
+	return c.rawConn.LocalAddr()
+}
+
+func (c *conn) RemoteAddr() net.Addr {
+	return c.rawConn.RemoteAddr()
+}
+
+func (c *conn) SetDeadline(t time.Time) error {
+	return c.rawConn.SetDeadline(t)
+}
+
+func (c *conn) SetReadDeadline(t time.Time) error {
+	return c.rawConn.SetReadDeadline(t)
+}
+
+func (c *conn) SetWriteDeadline(t time.Time) error {
+	return c.rawConn.SetWriteDeadline(t)
+}
+
+// TODO: should I just collapse current and advance?
+func (c *conn) currentNonce() *[24]byte {
+	return &c.nonce
+}
+
+func (c *conn) advanceNonce() {
+	c.counter++
+	binary.LittleEndian.PutUint64(c.nonce[:], c.counter)
+}