Skip to content

Commit

Permalink
Merge pull request #25 from dedis/proof_12
Browse files Browse the repository at this point in the history
Adding a proof
  • Loading branch information
kc1212 committed Apr 20, 2018
2 parents a07ac1d + b52269a commit 70e68b4
Show file tree
Hide file tree
Showing 11 changed files with 425 additions and 80 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.tags
8 changes: 6 additions & 2 deletions omniledger/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,11 +126,15 @@ func get(c *cli.Context) error {
return err
}
key := c.Args().Get(2)
resp, err := service.NewClient().GetValue(group.Roster, scid, []byte(key))
resp, err := service.NewClient().GetProof(group.Roster, scid, []byte(key))
if err != nil {
return errors.New("couldn't get value: " + err.Error())
}
log.Infof("Read value: %x = %x", key, *resp.Value)
_, vs, err := resp.Proof.KeyValue()
if err != nil {
return err
}
log.Infof("Read value: %x = %x", key, vs[0])
return nil
}

Expand Down
16 changes: 9 additions & 7 deletions omniledger/service/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,15 @@ func (c *Client) SetKeyValue(r *onet.Roster, id skipchain.SkipBlockID,
return reply, nil
}

// GetValue returns the value of a key or nil if it doesn't exist.
func (c *Client) GetValue(r *onet.Roster, id skipchain.SkipBlockID, key []byte) (*GetValueResponse, error) {
reply := &GetValueResponse{}
err := c.SendProtobuf(r.List[0], &GetValue{
Version: CurrentVersion,
SkipchainID: id,
Key: key,
// GetProof returns a proof for the key stored in the skipchain.
// The proof can be verified with the genesis skipblock and
// can proof the existence or the absence of the key.
func (c *Client) GetProof(r *onet.Roster, id skipchain.SkipBlockID, key []byte) (*GetProofResponse, error) {
reply := &GetProofResponse{}
err := c.SendProtobuf(r.List[0], &GetProof{
Version: CurrentVersion,
ID: id,
Key: key,
}, reply)
if err != nil {
return nil, err
Expand Down
34 changes: 33 additions & 1 deletion omniledger/service/api_test.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,41 @@
package service_test

import (
"testing"

// We need to include the service so it is started.
"gopkg.in/dedis/kyber.v2/suites"

// We need to include the service so it is started.
"github.com/dedis/student_18_omniledger/omniledger/service"
"github.com/stretchr/testify/require"
"gopkg.in/dedis/cothority.v2"
"gopkg.in/dedis/onet.v2"
)

var tSuite = suites.MustFind("Ed25519")

func TestClient_GetProof(t *testing.T) {
l := onet.NewTCPTest(cothority.Suite)
_, roster, _ := l.GenTree(3, true)
defer l.CloseAll()
c := service.NewClient()
csr, err := c.CreateSkipchain(roster, service.Transaction{Key: []byte{1}})
require.Nil(t, err)

key := []byte{1, 2, 3, 4}
value := []byte{5, 6, 7, 8}
_, err = c.SetKeyValue(roster, csr.Skipblock.SkipChainID(),
service.Transaction{
Key: key,
Value: value,
})
require.Nil(t, err)

p, err := c.GetProof(roster, csr.Skipblock.SkipChainID(), key)
require.Nil(t, err)
require.Nil(t, p.Proof.Verify(csr.Skipblock))
k, vs, err := p.Proof.KeyValue()
require.Nil(t, err)
require.Equal(t, k, key)
require.Equal(t, value, vs[0])
}
32 changes: 14 additions & 18 deletions omniledger/service/messages.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ func init() {
network.RegisterMessages(
&CreateSkipchain{}, &CreateSkipchainResponse{},
&SetKeyValue{}, &SetKeyValueResponse{},
&GetValue{}, &GetValueResponse{},
)
}

Expand Down Expand Up @@ -83,26 +82,23 @@ type SetKeyValueResponse struct {
SkipblockID *skipchain.SkipBlockID
}

// GetValue looks up the value in the given skipchain and returns the
// stored value, or an error if either the skipchain or the key doesn't exist.
type GetValue struct {
// GetProof returns the proof that the given key is in the collection.
type GetProof struct {
// Version of the protocol
Version Version
// SkipchainID represents the skipchain where the value is stored
SkipchainID skipchain.SkipBlockID
// Key to retrieve
Key []byte
Kind []byte
// Key is the key we want to look up
Key []byte
// ID is any block that is know to us in the skipchain, can be the genesis
// block or any later block. The proof returned will be starting at this block.
ID skipchain.SkipBlockID
}

// GetValueResponse returns the value or an error if the key hasn't been found.
type GetValueResponse struct {
//Version of the protocol
// GetProofResponse can be used together with the Genesis block to proof that
// the returned key/value pair is in the collection.
type GetProofResponse struct {
// Version of the protocol
Version Version
// Value of the key
Value *[]byte
// Signature as sent when the value was stored
Signature *[]byte
// Proof the value is correct
Proof *[]byte
// Proof contains everything necessary to prove the inclusion
// of the included key/value pair given a genesis skipblock.
Proof Proof
}
107 changes: 107 additions & 0 deletions omniledger/service/proof.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package service

import (
"bytes"
"errors"

"github.com/dedis/student_18_omniledger/omniledger/collection"
"gopkg.in/dedis/cothority.v2"
"gopkg.in/dedis/cothority.v2/skipchain"
"gopkg.in/dedis/onet.v2/network"
)

// Proof represents everything necessary to verify a given
// key/value pair is stored in a skipchain. The proof is in three parts:
// 1. Collection proofs the presence or absence of the key. In case of
// the key being present, the value is included in the proof
// 2. Latest is used to verify the merkle tree root used in the collection-proof
// is stored in the latest skipblock
// 3. Links proves that the latest skipblock is part of the skipchain
//
// This Structure could later be moved to cothority/skipchain.
type Proof struct {
// InclusionProof is the deserialized InclusionProof
InclusionProof collection.Proof
// Providing the latest skipblock to retrieve the Merkle tree root.
Latest skipchain.SkipBlock
// Proving the path to the latest skipblock.
Links []skipchain.ForwardLink
}

// NewProof creates a proof for key in the skipchain with the given id. It uses
// the collectionDB to look up the key and the skipblockdb to create the correct
// proof for the forward links.
func NewProof(c *collectionDB, s *skipchain.SkipBlockDB, id skipchain.SkipBlockID,
key []byte) (p *Proof, err error) {
p = &Proof{}
p.InclusionProof, err = c.coll.Get(key).Proof()
if err != nil {
return
}
sb := s.GetByID(id)
if sb == nil {
return nil, errors.New("didn't find skipchain")
}
for len(sb.ForwardLink) > 0 {
link := sb.ForwardLink[len(sb.ForwardLink)-1]
p.Links = append(p.Links, *link)
sb = s.GetByID(link.To)
if sb == nil {
return nil, errors.New("missing block in chain")
}
}
p.Latest = *sb
// p.ProofBytes = p.proof.Consistent()
return
}

// ErrorVerifyCollection is returned if the collection-proof itself
// is not properly set up.
var ErrorVerifyCollection = errors.New("collection inclusion proof is wrong")

// ErrorVerifyMerkleRoot is returned if the root of the collection
// is different than the stored value in the skipblock.
var ErrorVerifyMerkleRoot = errors.New("root of collection is not in skipblock")

// ErrorVerifySkipchain is returned if the stored skipblock doesn't
// have a proper proof that it comes from the genesis block.
var ErrorVerifySkipchain = errors.New("stored skipblock is not properly evolved from genesis block")

// Verify takes a skipchain id and verifies that the proof is valid for this skipchain.
// It verifies the collection-proof, that the merkle-root is stored in the skipblock
// of the proof and the fact that the skipblock is indeed part of the skipchain.
// If all verifications are correct, the error will be nil.
func (p Proof) Verify(genesis *skipchain.SkipBlock) error {
if !p.InclusionProof.Consistent() {
return ErrorVerifyCollection
}
_, d, err := network.Unmarshal(p.Latest.Data, cothority.Suite)
if err != nil {
return err
}
if !bytes.Equal(p.InclusionProof.TreeRootHash(), d.(*Data).MerkleRoot) {
return ErrorVerifyMerkleRoot
}
sbid := genesis.SkipChainID()
publics := genesis.Roster.Publics()
for _, l := range p.Links {
if err = l.Verify(cothority.Suite, publics); err != nil {
return ErrorVerifySkipchain
}
if !l.From.Equal(sbid) {
return ErrorVerifySkipchain
}
sbid = l.To
if l.NewRoster != nil {
publics = l.NewRoster.Publics()
}
}
return nil
}

// KeyValue returns the key and the values stored in the proof.
func (p Proof) KeyValue() (key []byte, values [][]byte, err error) {
key = p.InclusionProof.Key
values, err = p.InclusionProof.RawValues()
return
}
Loading

0 comments on commit 70e68b4

Please sign in to comment.