Skip to content

Commit

Permalink
Merge pull request #26 from mit-pdos/optiks
Browse files Browse the repository at this point in the history
move from coniks to optiks
  • Loading branch information
sanjit-bhat authored Oct 8, 2024
2 parents 4be4d51 + 7f809d1 commit 408220a
Show file tree
Hide file tree
Showing 54 changed files with 3,393 additions and 1,889 deletions.
4 changes: 3 additions & 1 deletion .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@ updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
interval: "monthly"
time: "04:00"
timezone: "US/Eastern"
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
go:
strategy:
matrix:
go: ["1.22"]
go: ["1.23"]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand All @@ -37,7 +37,7 @@ jobs:
- name: Lint
uses: dominikh/staticcheck-action@v1
with:
version: "v0.4.7"
version: "v0.5.1"
min-go-version: ${{ matrix.go }}
install-go: false
cache-key: ${{ matrix.go }}
Expand Down Expand Up @@ -68,7 +68,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: "1.22"
go-version: "1.23"

- name: Run extra CI checks
run: python etc/ci-check.py
Expand Down
92 changes: 92 additions & 0 deletions advrpc/advrpc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package advrpc

// advrpc provides a basic RPC lib on top of an adversarial network.
// for testing, it returns the right bytes from the right rpc id.
// however, its formal model says that rpc calls return arbitrary bytes.

import (
"github.com/mit-pdos/pav/marshalutil"
"github.com/mit-pdos/pav/netffi"
"github.com/tchajed/marshal"
)

// # Server

type Server struct {
handlers map[uint64]func([]byte, *[]byte)
}

func (s *Server) handle(conn *netffi.Conn, rpcId uint64, data []byte) {
f, ok0 := s.handlers[rpcId]
if !ok0 {
// adv gave bad rpcId.
return
}
resp := new([]byte)
f(data, resp)
// ignore errors. if err, client will timeout, then retry.
conn.Send(*resp)
}

func (s *Server) read(conn *netffi.Conn) {
for {
req, err0 := conn.Receive()
if err0 {
// connection done. quit thread.
break
}
rpcId, data, err1 := marshalutil.ReadInt(req)
if err1 {
// adv didn't even give rpcId.
continue
}
go func() {
s.handle(conn, rpcId, data)
}()
}
}

func (s *Server) Serve(addr uint64) {
l := netffi.Listen(addr)
go func() {
for {
conn := l.Accept()
go func() {
s.read(conn)
}()
}
}()
}

func NewServer(handlers map[uint64]func([]byte, *[]byte)) *Server {
return &Server{handlers: handlers}
}

// # Client

// Client is meant for exclusive use.
type Client struct {
conn *netffi.Conn
}

func Dial(addr uint64) *Client {
c := netffi.Dial(addr)
return &Client{conn: c}
}

// Call does an rpc, and returns error on fail.
func (c *Client) Call(rpcId uint64, args []byte, reply *[]byte) bool {
req0 := make([]byte, 0, 8+len(args))
req1 := marshal.WriteInt(req0, rpcId)
req2 := marshal.WriteBytes(req1, args)
if c.conn.Send(req2) {
return true
}

resp, err0 := c.conn.Receive()
if err0 {
return true
}
*reply = resp
return false
}
91 changes: 91 additions & 0 deletions advrpc/advrpc_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package advrpc

import (
"github.com/mit-pdos/pav/marshalutil"
"github.com/tchajed/marshal"
"math/rand/v2"
"testing"
)

type Args struct {
A, B uint64
}

func Multiply(args *Args) uint64 {
return args.A * args.B
}

func encArgs(args *Args) []byte {
var b0 []byte
b1 := marshal.WriteInt(b0, args.A)
b2 := marshal.WriteInt(b1, args.B)
return b2
}

func decArgs(args []byte) (*Args, bool) {
a, args0, err0 := marshalutil.ReadInt(args)
if err0 {
return nil, true
}
b, args1, err1 := marshalutil.ReadInt(args0)
if err1 || len(args1) != 0 {
return nil, true
}
return &Args{A: a, B: b}, false
}

func encReply(reply uint64) []byte {
var b0 []byte
return marshal.WriteInt(b0, reply)
}

func decReply(reply *[]byte) (uint64, bool) {
if reply == nil {
return 0, true
}
out, reply0, err0 := marshalutil.ReadInt(*reply)
if err0 || len(reply0) != 0 {
return 0, true
}
return out, false
}

func servStub(args []byte, reply *[]byte) {
args0, err0 := decArgs(args)
if err0 {
*reply = nil
}
*reply = encReply(Multiply(args0))
}

func TestRPC(t *testing.T) {
h := map[uint64]func([]byte, *[]byte){
2: servStub,
}
s := NewServer(h)
addr := makeUniqueAddr()
s.Serve(addr)

c := Dial(addr)
args0 := &Args{A: 7, B: 8}
args1 := encArgs(args0)
reply0 := new([]byte)
err1 := c.Call(2, args1, reply0)
if err1 {
t.Fatal()
}

reply1, err2 := decReply(reply0)
if err2 {
t.Fatal()
}
if reply1 != 7*8 {
t.Fatal()
}
}

func makeUniqueAddr() uint64 {
port := uint64(rand.IntN(4000)) + 6000
// left shift to make IP 0.0.0.0.
return port << 32
}
62 changes: 56 additions & 6 deletions cryptoffi/cryptoffi.go
Original file line number Diff line number Diff line change
@@ -1,26 +1,28 @@
package cryptoffi

import (
"bytes"
"crypto/ed25519"
"crypto/rand"
"crypto/sha512"
"github.com/google/keytransparency/core/crypto/vrf"
"github.com/google/keytransparency/core/crypto/vrf/p256"
"log"
)

type Sig = []byte

const (
HashLen uint64 = 32
SigLen uint64 = 64
)

// Hashing.
// # Hash

func Hash(data []byte) []byte {
h := sha512.Sum512_256(data)
return h[:]
}

// Signatures.
// # Signature

type PrivateKey ed25519.PrivateKey

Expand All @@ -34,10 +36,58 @@ func GenerateKey() (PublicKey, PrivateKey) {
return PublicKey(pub), PrivateKey(priv)
}

func (priv PrivateKey) Sign(message []byte) Sig {
func (priv PrivateKey) Sign(message []byte) []byte {
return ed25519.Sign(ed25519.PrivateKey(priv), message)
}

func (pub PublicKey) Verify(message []byte, sig Sig) bool {
// Verify rets okay if proof verifies.
func (pub PublicKey) Verify(message []byte, sig []byte) bool {
return ed25519.Verify(ed25519.PublicKey(pub), message, sig)
}

// # VRF

type VrfPrivateKey struct {
sk vrf.PrivateKey
}

type VrfPublicKey struct {
pk vrf.PublicKey
}

func VrfGenerateKey() (*VrfPublicKey, *VrfPrivateKey) {
sk, pk := p256.GenerateKey()
return &VrfPublicKey{pk: pk}, &VrfPrivateKey{sk: sk}
}

// TODO: check that Google CT's VRF satisfies all the properties we need.
// maybe re-write to use sha256 and the more robust [internal ed25519].
// [internal ed25519]: https://pkg.go.dev/filippo.io/edwards25519
func (priv VrfPrivateKey) Hash(data []byte) ([]byte, []byte) {
h, proof := priv.sk.Evaluate(data)
// TODO: check that proof doesn't have h inside it.
// that'd be a waste of space.
return h[:], proof
}

// Verify rets okay if proof verifies.
func (pub VrfPublicKey) Verify(data, hash, proof []byte) bool {
h, err := pub.pk.ProofToHash(data, proof)
if err != nil {
return false
}
return bytes.Equal(hash, h[:])
}

// # Random

// RandBytes returns [n] random bytes.
func RandBytes(n uint64) []byte {
b := make([]byte, n)
_, err := rand.Read(b)
// don't care about recovering from crypto/rand failures.
if err != nil {
panic("crypto/rand call failed")
}
return b
}
41 changes: 41 additions & 0 deletions cryptoffi/cryptoffi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,44 @@ func TestVerifyFalse(t *testing.T) {
t.Fatal()
}
}

func TestVRF(t *testing.T) {
pk0, sk0 := VrfGenerateKey()

// check same hashes for same input.
d0 := []byte("d0")
h0, p0 := sk0.Hash(d0)
if !pk0.Verify(d0, h0, p0) {
t.Fatal()
}
h1, p1 := sk0.Hash(d0)
if !pk0.Verify(d0, h1, p1) {
t.Fatal()
}
if !bytes.Equal(h0, h1) {
t.Fatal()
}

// check diff hashes for diff inputs.
d1 := []byte("d1")
h2, p2 := sk0.Hash(d1)
if !pk0.Verify(d1, h2, p2) {
t.Fatal()
}
if bytes.Equal(h0, h2) {
t.Fatal()
}

// check verify false if use bad pk.
pk1, _ := VrfGenerateKey()
if pk1.Verify(d1, h2, p2) {
t.Fatal()
}

// check verify false on bad proof.
p3 := bytes.Clone(p2)
p3[0] = ^p3[0]
if pk0.Verify(d1, h2, p3) {
t.Fatal()
}
}
4 changes: 2 additions & 2 deletions etc/ci-check.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@


class Tests(unittest.TestCase):
def test_kt_rpc_compiled(self):
cmd = "go run ./rpc --in kt/rpc.go && git diff --exit-code kt/rpc.out.go"
def test_kt_serde_compiled(self):
cmd = "go run ./serde --in kt/serde.go && git diff --exit-code kt/serde.out.go"
res = subprocess.run(
cmd, cwd=proj_root, shell=True, capture_output=True, text=True
)
Expand Down
17 changes: 11 additions & 6 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
module github.com/mit-pdos/pav

go 1.22
go 1.23

require (
github.com/goose-lang/goose v0.9.0
github.com/google/keytransparency v0.3.0
github.com/goose-lang/primitive v0.1.0
github.com/goose-lang/std v0.5.0
github.com/mit-pdos/gokv v0.1.1
github.com/tchajed/marshal v0.6.2
golang.org/x/tools v0.24.0
golang.org/x/tools v0.26.0
)

require (
github.com/goose-lang/primitive v0.1.0 // indirect
golang.org/x/mod v0.20.0 // indirect
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b // indirect
github.com/golang/protobuf v1.4.2 // indirect
github.com/google/trillian v1.3.10 // indirect
golang.org/x/crypto v0.0.0-20200311171314-f7b00557c8c4 // indirect
golang.org/x/mod v0.21.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/text v0.16.0 // indirect
google.golang.org/protobuf v1.25.0 // indirect
)
Loading

0 comments on commit 408220a

Please sign in to comment.