Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
330 changes: 103 additions & 227 deletions calypso/api.go
Original file line number Diff line number Diff line change
@@ -1,261 +1,137 @@
package calypso

import (
"time"

"go.dedis.ch/cothority/v3"
"go.dedis.ch/cothority/v3/byzcoin"
"go.dedis.ch/cothority/v3/darc"
"go.dedis.ch/cothority/v3/skipchain"
"go.dedis.ch/kyber/v3"
"go.dedis.ch/onet/v3"
"go.dedis.ch/onet/v3/network"
"go.dedis.ch/protobuf"
"time"
)

// TODO: add LTSID of type kyber.Point
// TODO: think about authentication
// TODO: add CreateAndAuthorise
// TODO: add REST interface

// Client is a class to communicate to the calypso service.
type Client struct {
bcClient *byzcoin.Client
c *onet.Client
ltsReply *CreateLTSReply
*onet.Client
}

// WriteReply is returned upon successfully spawning a Write instance.
type WriteReply struct {
*byzcoin.AddTxResponse
byzcoin.InstanceID
// NewClient creates a new client to interact with the Calypso Service.
func NewClient() *Client {
return &Client{Client: onet.NewClient(cothority.Suite, ServiceName)}
}

// ReadReply is is returned upon successfully spawning a Read instance.
type ReadReply struct {
*byzcoin.AddTxResponse
byzcoin.InstanceID
// CreateLTS starts a new Distributed Key Generation with the nodes in the roster and
// return the collective public key X. This X is also used later to identify the
// LTS instance, as there can be more than one LTS group on a node.
//
// This can only be called from localhost, except if the environment variable
// COTHORITY_ALLOW_INSECURE_ADMIN is set to 'true'.
//
// In case of error, X is nil, and the error indicates what is wrong.
//
// TODO: return the DKG proof instead of the aggregate public key
func (c *Client) CreateLTS(ltsRoster *onet.Roster) (X kyber.Point, err error) {
return
}

// NewClient instantiates a new Client.
// It takes as input an "initialized" byzcoin client
// with an already created ledger
func NewClient(byzcoin *byzcoin.Client) *Client {
return &Client{bcClient: byzcoin, c: onet.NewClient(
cothority.Suite, ServiceName)}
// Authorise sets up an authorisation option for this node. All the nodes that
// are part of the LTS need to be set up with the same authorisation option.
//
// As with CreateLTS, this API can only be called from localhost, except if
// the environment variable COTHORITY_ALLOW_INSECURE_ADMIN is set to 'true'.
//
// If the authorisation is stored successfully, nil is returned.
func (c *Client) Authorise(X kyber.Point, auth Auth) (err error) {
return
}

// CreateLTS creates a random LTSID that can be used to reference the LTS group
// created. It first sends a transaction to ByzCoin to spawn a LTS instance,
// then it asks the Calypso cothority to start the DKG.
func (c *Client) CreateLTS(ltsRoster *onet.Roster, darcID darc.ID, signers []darc.Signer, counters []uint64) (reply *CreateLTSReply, err error) {
// Make the transaction and get its proof
buf, err := protobuf.Encode(&LtsInstanceInfo{*ltsRoster})
if err != nil {
return nil, err
}
inst := byzcoin.Instruction{
InstanceID: byzcoin.NewInstanceID(darcID),
Spawn: &byzcoin.Spawn{
ContractID: ContractLongTermSecretID,
Args: []byzcoin.Argument{
{
Name: "lts_instance_info",
Value: buf,
},
},
},
SignerCounter: counters,
}
tx := byzcoin.ClientTransaction{
Instructions: []byzcoin.Instruction{inst},
}
if err := tx.FillSignersAndSignWith(signers...); err != nil {
return nil, err
}
if _, err := c.bcClient.AddTransactionAndWait(tx, 4); err != nil {
return nil, err
}
resp, err := c.bcClient.GetProof(tx.Instructions[0].DeriveID("").Slice())
if err != nil {
return nil, err
}

// Start the DKG
reply = &CreateLTSReply{}
err = c.c.SendProtobuf(c.bcClient.Roster.List[0], &CreateLTS{
Proof: resp.Proof,
}, reply)
if err != nil {
return nil, err
}
return reply, nil
// Reencrypt requests the re-encryption of the secret stored in the grant.
// The grant must also contain the ephemeral key to which the secret will be
// reencrypted to.
// Finally the grant must contain information about how to verify that the
// reencryption request is valid.
//
// This can be called from anywhere.
//
// If the grant is valid, the reencrypted XHat is returned and err is nil. In case
// of error, XHat is nil, and the error will be returned.
func (c *Client) Reencrypt(X kyber.Point, grant Grant) (XHat kyber.Point, err error) {
return
}

// Authorise adds a ByzCoinID to the list of authorized IDs for each
// server in the roster. The AuthoriseByzcoinID service refuses requests
// that do not come from localhost.
//
// It should be called by the administrator at the beginning, before any other
// API calls are made. A ByzCoinID that is not authorised will not be allowed to
// call the other APIs.
func (c *Client) Authorise(who *network.ServerIdentity, what skipchain.SkipBlockID) error {
reply := &AuthoriseReply{}
err := c.c.SendProtobuf(who, &Authorise{ByzCoinID: what}, reply)
if err != nil {
return err
}
return nil
// Auth holds all possible authentication structures. When using it to call
// Authorise, only one of the fields must be non-nil.
type Auth struct {
ByzCoin *AuthByzCoin
// TODO: rename to X509Cert
HyperLedgerFabric *AuthX509Cert
Ethereum *AuthEthereum
}

// DecryptKey takes as input Read- and Write- Proofs. It verifies that
// the read/write requests match and then re-encrypts the secret
// given the public key information of the reader.
func (c *Client) DecryptKey(dkr *DecryptKey) (reply *DecryptKeyReply, err error) {
reply = &DecryptKeyReply{}
err = c.c.SendProtobuf(c.bcClient.Roster.List[0], dkr, reply)
if err != nil {
return nil, err
}
return reply, nil
// AuthByzCoin holds the information necessary to authenticate a byzcoin request.
// In the ByzCoin model, all requests are valid as long as they are stored in the
// blockchain with the given ID.
// The TTL is to avoid that too old requests are re-used. If it is 0, it is disabled.
type AuthByzCoin struct {
ByzCoinID skipchain.SkipBlockID
TTL time.Time
}

// WaitProof calls the byzcoin client's wait proof
func (c *Client) WaitProof(id byzcoin.InstanceID, interval time.Duration,
value []byte) (*byzcoin.Proof, error) {
return c.bcClient.WaitProof(id, interval, value)
// AuthX509Cert holds the information necessary to authenticate a HyperLedger/Fabric
// request. In its simplest form, it is simply the CA that will have to sign the
// certificates of the requesters.
// The Threshold indicates how many clients must have signed the request before it
// is accepted.
type AuthX509Cert struct {
// Slice of ASN.1 encoded X509 certificates.
CA [][]byte
Threshold int
}

// AddWrite creates a Write Instance by adding a transaction on the byzcoin client.
// Input:
// - write - A Write structure
// - signer - The data owner who will sign the transaction
// - signerCtr - A monotonically increaing counter for every signer
// - darc - The darc governing this instance
// - wait - The number of blocks to wait -- 0 means no wait
//
// Output:
// - reply - WriteReply containing the transaction response and instance id
// - err - Error if any, nil otherwise.
func (c *Client) AddWrite(write *Write, signer darc.Signer, signerCtr uint64,
darc darc.Darc, wait int) (
reply *WriteReply, err error) {
reply = &WriteReply{}
if err != nil {
return nil, err
}
writeBuf, err := protobuf.Encode(write)
if err != nil {
return nil, err
}
ctx := byzcoin.ClientTransaction{
Instructions: byzcoin.Instructions{{
InstanceID: byzcoin.NewInstanceID(darc.GetBaseID()),
Spawn: &byzcoin.Spawn{
ContractID: ContractWriteID,
Args: byzcoin.Arguments{{
Name: "write", Value: writeBuf}},
},
SignerCounter: []uint64{signerCtr},
}},
}
//Sign the transaction
err = ctx.FillSignersAndSignWith(signer)
if err != nil {
return nil, err
}
reply.InstanceID = ctx.Instructions[0].DeriveID("")
//Delegate the work to the byzcoin client
reply.AddTxResponse, err = c.bcClient.AddTransactionAndWait(ctx, wait)
if err != nil {
return nil, err
}
return reply, err
// AuthEthereum holds the information necessary to authenticate an Ethereum
// request. It holds the ContractAddress that serves as the basis to generate
// new requests.
type AuthEthereum struct {
ContractAddress []byte
}

// AddRead creates a Read Instance by adding a transaction on the byzcoin client.
// Input:
// - proof - A ByzCoin proof of the Write Operation.
// - signer - The data owner who will sign the transaction
// - signerCtr - A monotonically increaing counter for every signer
// - darc - The darc governing this instance
// - wait - The number of blocks to wait -- 0 means no wait
//
// Output:
// - reply - ReadReply containing the transaction response and instance id
// - err - Error if any, nil otherwise.
func (c *Client) AddRead(proof *byzcoin.Proof, signer darc.Signer, signerCtr uint64,
darc darc.Darc, wait int) (
reply *ReadReply, err error) {
var readBuf []byte
read := &Read{
Write: byzcoin.NewInstanceID(proof.InclusionProof.Key()),
Xc: signer.Ed25519.Point,
}
reply = &ReadReply{}
readBuf, err = protobuf.Encode(read)
if err != nil {
return nil, err
}
// Grant holds one of the possible grant proofs for a reencryption request. Each
// grant proof must hold the secret to be reencrypted, the ephemeral key, as well
// as the proof itself that the request is valid. For each of the authentication
// schemes, this proof will be different.
type Grant struct {
ByzCoin *GrantByzCoin
X509Cert *GrantX509Cert
Ethereum *GrantEthereum
}

if err != nil {
return nil, err
}
ctx := byzcoin.ClientTransaction{
Instructions: byzcoin.Instructions{{
InstanceID: byzcoin.NewInstanceID(proof.InclusionProof.Key()),
Spawn: &byzcoin.Spawn{
ContractID: ContractReadID,
Args: byzcoin.Arguments{{Name: "read", Value: readBuf}},
},
SignerCounter: []uint64{signerCtr},
}},
}
err = ctx.FillSignersAndSignWith(signer)
reply.InstanceID = ctx.Instructions[0].DeriveID("")
if err != nil {
return nil, err
}
reply.AddTxResponse, err = c.bcClient.AddTransactionAndWait(ctx, wait)
if err != nil {
return nil, err
}
return reply, nil
// GrantByzCoin holds the proof of the write instance, holding the secret itself.
// The proof of the read instance holds the ephemeral key. Both proofs can be
// verified using one of the stored ByzCoinIDs.
type GrantByzCoin struct {
// Write is the proof containing the write request.
Write byzcoin.Proof
// Read is the proof that he has been accepted to read the secret.
Read byzcoin.Proof
}

// SpawnDarc spawns a Darc Instance by adding a transaction on the byzcoin client.
// Input:
// - signer - The signer authorizing the spawn of this darc (calypso "admin")
// - signerCtr - A monotonically increaing counter for every signer
// - controlDarc - The darc governing this spawning
// - spawnDarc - The darc to be spawned
// - wait - The number of blocks to wait -- 0 means no wait
//
// Output:
// - reply - AddTxResponse containing the transaction response
// - err - Error if any, nil otherwise.
func (c *Client) SpawnDarc(signer darc.Signer, signerCtr uint64,
controlDarc darc.Darc, spawnDarc darc.Darc, wait int) (
reply *byzcoin.AddTxResponse, err error) {
reply = &byzcoin.AddTxResponse{}
if err != nil {
return nil, err
}
darcBuf, err := spawnDarc.ToProto()
if err != nil {
return nil, err
}
// GrantX509Cert holds the proof that at least a threshold number of clients
// accepted the reencryption.
// For each client, there must exist a certificate that can be verified by the
// CA certificate from AuthX509Cert. Additionally, each client must sign the
// following message:
// sha256( Secret | Ephemeral | Time )
type GrantX509Cert struct {
Secret kyber.Point
Certificates [][]byte
}

ctx := byzcoin.ClientTransaction{
Instructions: []byzcoin.Instruction{{
InstanceID: byzcoin.NewInstanceID(controlDarc.GetBaseID()),
Spawn: &byzcoin.Spawn{
ContractID: byzcoin.ContractDarcID,
Args: []byzcoin.Argument{{
Name: "darc",
Value: darcBuf,
}},
},
SignerCounter: []uint64{signerCtr},
}},
}
err = ctx.FillSignersAndSignWith(signer)
if err != nil {
return nil, err
}
return c.bcClient.AddTransactionAndWait(ctx, wait)
// GrantEthereum holds the proof that the read request has been successfully stored
// in Ethereum.
type GrantEthereum struct {
Contract []byte
}
Loading