Skip to content

Commit

Permalink
Merge pull request #18 from mit-pdos/evid-modular
Browse files Browse the repository at this point in the history
split evid into signedLink and signedPut. more modular
  • Loading branch information
sanjit-bhat authored Aug 9, 2024
2 parents 039ba55 + e6f109f commit 9453df4
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 52 deletions.
99 changes: 52 additions & 47 deletions ktmerkle/evidence.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,87 +6,92 @@ import (
"github.com/mit-pdos/pav/merkle"
)

type signedLink struct {
epoch epochTy
prevLink linkTy
dig merkle.Digest
sig cryptoffi.Sig
}

func (o *signedLink) check(pk cryptoffi.PublicKey) (linkTy, errorTy) {
preLink := (&chainSepSome{epoch: o.epoch, prevLink: o.prevLink, data: o.dig}).encode()
link := cryptoffi.Hash(preLink)
sepLink := (&servSepLink{link: link}).encode()
ok := pk.Verify(sepLink, o.sig)
return link, !ok
}

type signedPut struct {
epoch epochTy
id merkle.Id
val merkle.Val
sig cryptoffi.Sig
}

func (o *signedPut) check(pk cryptoffi.PublicKey) errorTy {
sepPut := (&servSepPut{epoch: o.epoch, id: o.id, val: o.val}).encode()
okPut := pk.Verify(sepPut, o.sig)
return !okPut
}

// evidServLink is evidence that the server signed two conflicting links,
// either zero or one epochs away.
type evidServLink struct {
epoch0 epochTy
prevLink0 linkTy
dig0 merkle.Digest
sig0 cryptoffi.Sig

epoch1 epochTy
prevLink1 linkTy
dig1 merkle.Digest
sig1 cryptoffi.Sig
sln0 *signedLink
sln1 *signedLink
}

// check returns an error if the evidence does not check out.
// otherwise, it proves that the server was dishonest.
func (e *evidServLink) check(servPk cryptoffi.PublicKey) errorTy {
linkSep0 := (&chainSepSome{epoch: e.epoch0, prevLink: e.prevLink0, data: e.dig0}).encode()
link0 := cryptoffi.Hash(linkSep0)
enc0 := (&servSepLink{link: link0}).encode()
ok0 := servPk.Verify(enc0, e.sig0)
if !ok0 {
link0, err0 := e.sln0.check(servPk)
if err0 {
return errSome
}

linkSep1 := (&chainSepSome{epoch: e.epoch1, prevLink: e.prevLink1, data: e.dig1}).encode()
link1 := cryptoffi.Hash(linkSep1)
enc1 := (&servSepLink{link: link1}).encode()
ok1 := servPk.Verify(enc1, e.sig1)
if !ok1 {
link1, err1 := e.sln1.check(servPk)
if err1 {
return errSome
}

if e.epoch0 == e.epoch1 {
if e.sln0.epoch == e.sln1.epoch {
return std.BytesEqual(link0, link1)
}
if e.epoch0 == e.epoch1-1 {
return std.BytesEqual(link0, e.prevLink1)
if e.sln0.epoch == e.sln1.epoch-1 {
return std.BytesEqual(link0, e.sln1.prevLink)
}
return errSome
}

// evidServPut is evidence when a server promises to put a value at a certain
// epoch but actually there's a different value (as evidenced by a merkle proof).
type evidServPut struct {
epoch epochTy
// For signed link.
prevLink linkTy
dig merkle.Digest
linkSig cryptoffi.Sig
// For signed put.
id merkle.Id
val0 merkle.Val
putSig cryptoffi.Sig
// For merkle inclusion.
val1 merkle.Val
sln *signedLink
sp *signedPut
// merkle inclusion.
val merkle.Val
proof merkle.Proof
}

func (e *evidServPut) check(servPk cryptoffi.PublicKey) errorTy {
// Proof of signing the link.
preLink := (&chainSepSome{epoch: e.epoch, prevLink: e.prevLink, data: e.dig}).encode()
link := cryptoffi.Hash(preLink)
preLinkSig := (&servSepLink{link: link}).encode()
linkOk := servPk.Verify(preLinkSig, e.linkSig)
if !linkOk {
_, err0 := e.sln.check(servPk)
if err0 {
return errSome
}

// Proof of signing the put promise.
prePut := (&servSepPut{epoch: e.epoch, id: e.id, val: e.val0}).encode()
putOk := servPk.Verify(prePut, e.putSig)
if !putOk {
err1 := e.sp.check(servPk)
if err1 {
return errSome
}

// Proof of merkle inclusion of the other val.
err0 := merkle.CheckProof(merkle.MembProofTy, e.proof, e.id, e.val1, e.dig)
if err0 {
// merkle inclusion of the other val.
err2 := merkle.CheckProof(merkle.MembProofTy, e.proof, e.sp.id, e.val, e.sln.dig)
if err2 {
return errSome
}

return std.BytesEqual(e.val0, e.val1)
if e.sln.epoch != e.sp.epoch {
return errSome
}
return std.BytesEqual(e.sp.val, e.val)
}
20 changes: 15 additions & 5 deletions ktmerkle/ktmerkle.go
Original file line number Diff line number Diff line change
Expand Up @@ -264,25 +264,29 @@ func (c *client) addLink(epoch epochTy, prevLink linkTy, dig merkle.Digest, sig
if !ok0 {
return nil, errSome
}
newSigLn := &signedLink{epoch: epoch, prevLink: prevLink, dig: dig, sig: sig}

// Check if epoch already exists.
cachedLink, ok1 := c.links[epoch]
if ok1 && !std.BytesEqual(cachedLink.link, link) {
evid := &evidServLink{epoch0: epoch, prevLink0: cachedLink.prevLink, dig0: cachedLink.dig, sig0: cachedLink.sig, epoch1: epoch, prevLink1: prevLink, dig1: dig, sig1: sig}
cachedSigLn := &signedLink{epoch: epoch, prevLink: cachedLink.prevLink, dig: cachedLink.dig, sig: cachedLink.sig}
evid := &evidServLink{sln0: newSigLn, sln1: cachedSigLn}
return evid, errSome
}

// Check if epoch-1 already exists.
cachedPrevLink, ok2 := c.links[epoch-1]
if epoch > 0 && ok2 && !std.BytesEqual(cachedPrevLink.link, prevLink) {
evid := &evidServLink{epoch0: epoch - 1, prevLink0: cachedPrevLink.prevLink, dig0: cachedPrevLink.dig, sig0: cachedPrevLink.sig, epoch1: epoch, prevLink1: prevLink, dig1: dig, sig1: sig}
cachedSigLn := &signedLink{epoch: epoch - 1, prevLink: cachedLink.prevLink, dig: cachedLink.dig, sig: cachedLink.sig}
evid := &evidServLink{sln0: cachedSigLn, sln1: newSigLn}
return evid, errSome
}

// Check if epoch+1 already exists.
cachedNextLink, ok3 := c.links[epoch+1]
if epoch < maxUint64 && ok3 && !std.BytesEqual(link, cachedNextLink.prevLink) {
evid := &evidServLink{epoch0: epoch, prevLink0: link, dig0: dig, sig0: sig, epoch1: epoch + 1, prevLink1: cachedNextLink.prevLink, dig1: cachedNextLink.dig, sig1: cachedNextLink.sig}
cachedSigLn := &signedLink{epoch: epoch + 1, prevLink: cachedLink.prevLink, dig: cachedLink.dig, sig: cachedLink.sig}
evid := &evidServLink{sln0: newSigLn, sln1: cachedSigLn}
return evid, errSome
}

Expand Down Expand Up @@ -372,6 +376,8 @@ func (c *client) fetchLink(epoch epochTy) (*evidServLink, errorTy) {
// there could be lots of errors, but currently, we mainly
// return an error if there's evidence.
// TODO: maybe change err handling, in selfCheck as well.
// TODO: maybe split cross-epoch consistency check into sep routine.
// it seems nice to have (but not necessary) for both audit and selfCheck.
func (c *client) audit(adtrAddr grove_ffi.Address, adtrPk cryptoffi.PublicKey) (epochTy, *evidServLink, errorTy) {
// Note: potential attack.
// Key serv refuses to fill in a hole, even though we have bigger digests.
Expand Down Expand Up @@ -417,7 +423,9 @@ func (c *client) audit(adtrAddr grove_ffi.Address, adtrPk cryptoffi.PublicKey) (

// Check if our chain diverges from adtr.
if !std.BytesEqual(lastLink.link, adtrLink) {
evid := &evidServLink{epoch0: lastEpoch, prevLink0: lastLink.prevLink, dig0: lastLink.dig, sig0: lastLink.sig, epoch1: lastEpoch, prevLink1: reply.prevLink, dig1: reply.dig, sig1: reply.servSig}
adtrSigLn := &signedLink{epoch: lastEpoch, prevLink: reply.prevLink, dig: reply.dig, sig: reply.servSig}
mySigLn := &signedLink{epoch: lastEpoch, prevLink: lastLink.prevLink, dig: lastLink.dig, sig: lastLink.sig}
evid := &evidServLink{sln0: adtrSigLn, sln1: mySigLn}
return 0, evid, errSome
}
return epoch, nil, errNone
Expand Down Expand Up @@ -449,7 +457,9 @@ func (c *client) selfCheckAt(epoch epochTy) (*evidServLink, *evidServPut, errorT
if !std.BytesEqual(expVal, reply.val) {
// The put promise is only valid on a boundary epoch.
if isBoundary {
ev := &evidServPut{epoch: epoch, prevLink: reply.prevLink, dig: reply.dig, linkSig: reply.sig, id: c.id, val0: expVal, putSig: putSig, val1: reply.val, proof: reply.proof}
sigLn := &signedLink{epoch: epoch, prevLink: reply.prevLink, dig: reply.dig, sig: reply.sig}
sigPut := &signedPut{epoch: epoch, id: c.id, val: expVal, sig: putSig}
ev := &evidServPut{sln: sigLn, sp: sigPut, val: reply.val, proof: reply.proof}
return nil, ev, errSome
} else {
return nil, nil, errSome
Expand Down

0 comments on commit 9453df4

Please sign in to comment.