WIP: tests

This commit is contained in:
programmer10110 2020-08-14 13:55:01 +03:00
parent 381075f652
commit f84d664f32
3 changed files with 279 additions and 20 deletions

View File

@ -13,9 +13,9 @@ import (
"github.com/depools/dc4bc/qr"
"go.dedis.ch/kyber/v3"
"go.dedis.ch/kyber/v3/encrypt/ecies"
"go.dedis.ch/kyber/v3/group/edwards25519"
"go.dedis.ch/kyber/v3/pairing/bn256"
dkgPedersen "go.dedis.ch/kyber/v3/share/dkg/pedersen"
"log"
"sync"
)
@ -57,7 +57,6 @@ func (am *AirgappedMachine) getParticipantID(dkgIdentifier string) (int, error)
}
func (am *AirgappedMachine) encryptData(dkgIdentifier, to string, data []byte) ([]byte, error) {
suite := edwards25519.NewBlakeSHA256Ed25519()
dkgInstance, ok := am.dkgInstances[dkgIdentifier]
if !ok {
return nil, fmt.Errorf("invalid dkg identifier: %s", dkgIdentifier)
@ -68,7 +67,7 @@ func (am *AirgappedMachine) encryptData(dkgIdentifier, to string, data []byte) (
return nil, fmt.Errorf("failed to get pk for participant %s: %w", to, err)
}
encryptedData, err := ecies.Encrypt(suite, pk, data, suite.Hash)
encryptedData, err := ecies.Encrypt(am.suite, pk, data, am.suite.Hash)
if err != nil {
return nil, fmt.Errorf("failed to encrypt data: %w", err)
}
@ -76,9 +75,7 @@ func (am *AirgappedMachine) encryptData(dkgIdentifier, to string, data []byte) (
}
func (am *AirgappedMachine) decryptData(data []byte) ([]byte, error) {
suite := edwards25519.NewBlakeSHA256Ed25519()
decryptedData, err := ecies.Decrypt(suite, am.secKey, data, suite.Hash)
decryptedData, err := ecies.Decrypt(am.suite, am.secKey, data, am.suite.Hash)
if err != nil {
return nil, fmt.Errorf("failed to decrypt data: %w", err)
}
@ -115,6 +112,10 @@ func (am *AirgappedMachine) GetPubKey() kyber.Point {
return am.pubKey
}
type Commits struct {
MarshaledCommit []byte
}
func (am *AirgappedMachine) handleStateDkgCommitsAwaitConfirmations(o *client.Operation) error {
var (
payload responses.SignatureProposalParticipantStatusResponse
@ -142,28 +143,36 @@ func (am *AirgappedMachine) handleStateDkgCommitsAwaitConfirmations(o *client.Op
return fmt.Errorf("failed to init dkg instance: %w", err)
}
commits, err := json.Marshal(dkgInstance.GetCommits())
if err != nil {
return fmt.Errorf("failed to marshal commits: %w", err)
// TODO: come up with something better
var commits []Commits
dkgCommits := dkgInstance.GetCommits()
for _, commit := range dkgCommits {
commitBz, err := commit.MarshalBinary()
if err != nil {
return fmt.Errorf("failed to marshal commits: %w", err)
}
commits = append(commits, Commits{MarshaledCommit: commitBz})
}
commitsBz, err := json.Marshal(commits)
am.dkgInstances[o.DKGIdentifier] = dkgInstance
req := requests.DKGProposalCommitConfirmationRequest{
ParticipantId: dkgInstance.ParticipantID,
Commit: commits,
Commit: commitsBz,
CreatedAt: o.CreatedAt,
}
reqBz, err := client.FSMRequestToBytes(dkg_proposal_fsm.EventDKGCommitConfirmationReceived, req)
reqBz, err := json.Marshal(req)
if err != nil {
return fmt.Errorf("failed to generate fsm request: %w", err)
}
o.Result = reqBz
o.Event = dkg_proposal_fsm.EventDKGCommitConfirmationReceived
return nil
}
// We have many deals which should be sent privately to a required participant, so func returns a slice of operations
func (am *AirgappedMachine) handleStateDkgDealsAwaitConfirmations(o *client.Operation) ([]client.Operation, error) {
func (am *AirgappedMachine) handleStateDkgDealsAwaitConfirmations(o client.Operation) ([]client.Operation, error) {
var (
payload responses.DKGProposalCommitParticipantResponse
err error
@ -179,11 +188,19 @@ func (am *AirgappedMachine) handleStateDkgDealsAwaitConfirmations(o *client.Oper
}
for _, entry := range payload {
var commits []kyber.Point
var commits []Commits
if err = json.Unmarshal(entry.Commit, &commits); err != nil {
return nil, fmt.Errorf("failed to unmarshal commits: %w", err)
}
dkgInstance.StoreCommits(entry.Title, commits)
dkgCommits := make([]kyber.Point, 0, len(commits))
for _, c := range commits {
commit := am.suite.Point()
if err = commit.UnmarshalBinary(c.MarshaledCommit); err != nil {
return nil, fmt.Errorf("failed to unmarshal commit: %w", err)
}
dkgCommits = append(dkgCommits, commit)
}
dkgInstance.StoreCommits(entry.Title, dkgCommits)
}
deals, err := dkgInstance.GetDeals()
@ -212,12 +229,13 @@ func (am *AirgappedMachine) handleStateDkgDealsAwaitConfirmations(o *client.Oper
CreatedAt: o.CreatedAt,
}
o.To = toParticipant
reqBz, err := client.FSMRequestToBytes(dkg_proposal_fsm.EventDKGDealConfirmationReceived, req)
reqBz, err := json.Marshal(req)
if err != nil {
return nil, fmt.Errorf("failed to generate fsm request: %w", err)
}
o.Result = reqBz
operations = append(operations, *o)
o.Event = dkg_proposal_fsm.EventDKGDealConfirmationReceived
operations = append(operations, o)
}
return operations, nil
}
@ -267,12 +285,13 @@ func (am *AirgappedMachine) handleStateDkgResponsesAwaitConfirmations(o *client.
CreatedAt: o.CreatedAt,
}
reqBz, err := client.FSMRequestToBytes(dkg_proposal_fsm.EventDKGResponseConfirmationReceived, req)
reqBz, err := json.Marshal(req)
if err != nil {
return fmt.Errorf("failed to generate fsm request: %w", err)
}
o.Result = reqBz
o.Event = dkg_proposal_fsm.EventDKGResponseConfirmationReceived
return nil
}
@ -320,11 +339,12 @@ func (am *AirgappedMachine) handleStateDkgMasterKeyAwaitConfirmations(o *client.
MasterKey: masterPubKeyBz,
CreatedAt: o.CreatedAt,
}
reqBz, err := client.FSMRequestToBytes(dkg_proposal_fsm.EventDKGMasterKeyConfirmationReceived, req)
reqBz, err := json.Marshal(req)
if err != nil {
return fmt.Errorf("failed to generate fsm request: %w", err)
}
o.Result = reqBz
o.Event = dkg_proposal_fsm.EventDKGMasterKeyConfirmationReceived
return nil
}
@ -348,7 +368,7 @@ func (am *AirgappedMachine) HandleOperation(operation client.Operation) ([]clien
case dkg_proposal_fsm.StateDkgCommitsAwaitConfirmations:
err = am.handleStateDkgCommitsAwaitConfirmations(&operation)
case dkg_proposal_fsm.StateDkgDealsAwaitConfirmations:
operations, err = am.handleStateDkgDealsAwaitConfirmations(&operation)
operations, err = am.handleStateDkgDealsAwaitConfirmations(operation)
case dkg_proposal_fsm.StateDkgResponsesAwaitConfirmations:
err = am.handleStateDkgResponsesAwaitConfirmations(&operation)
case dkg_proposal_fsm.StateDkgMasterKeyAwaitConfirmations:
@ -359,6 +379,8 @@ func (am *AirgappedMachine) HandleOperation(operation client.Operation) ([]clien
// if we have error after handling the operation, we write the error to the operation, so we can feed it to a FSM
if err != nil {
log.Println(fmt.Sprintf("failed to handle operation %s, returning response with errot to client: %v",
operation.Type, err))
if e := am.writeErrorRequestToOperation(&operation, err); e != nil {
return nil, fmt.Errorf("failed to write error request to an operation: %w", e)
}
@ -431,10 +453,11 @@ func (am *AirgappedMachine) writeErrorRequestToOperation(o *client.Operation, ha
CreatedAt: o.CreatedAt,
}
errorEvent := eventToErrorMap[fsm.State(o.Type)]
reqBz, err := client.FSMRequestToBytes(errorEvent, req)
reqBz, err := json.Marshal(req)
if err != nil {
return fmt.Errorf("failed to generate fsm request: %w", err)
}
o.Result = reqBz
o.Event = errorEvent
return nil
}

235
airgapped/airgapped_test.go Normal file
View File

@ -0,0 +1,235 @@
package airgapped
import (
"encoding/json"
"fmt"
"github.com/depools/dc4bc/client"
"github.com/depools/dc4bc/fsm/state_machines/dkg_proposal_fsm"
"github.com/depools/dc4bc/fsm/state_machines/signature_proposal_fsm"
"github.com/depools/dc4bc/fsm/types/requests"
"github.com/depools/dc4bc/fsm/types/responses"
"github.com/google/uuid"
"sync"
"testing"
"time"
)
type Node struct {
ParticipantID int
Participant string
Machine *AirgappedMachine
commits []requests.DKGProposalCommitConfirmationRequest
deals []requests.DKGProposalDealConfirmationRequest
responses []requests.DKGProposalResponseConfirmationRequest
masterKey []requests.DKGProposalMasterKeyConfirmationRequest
}
func (n *Node) storeOperation(t *testing.T, o client.Operation) {
switch o.Event {
case dkg_proposal_fsm.EventDKGCommitConfirmationReceived:
var req requests.DKGProposalCommitConfirmationRequest
if err := json.Unmarshal(o.Result, &req); err != nil {
t.Errorf("failed to unmarshal fsm req: %v", err)
}
n.commits = append(n.commits, req)
case dkg_proposal_fsm.EventDKGDealConfirmationReceived:
var req requests.DKGProposalDealConfirmationRequest
if err := json.Unmarshal(o.Result, &req); err != nil {
t.Errorf("failed to unmarshal fsm req: %v", err)
}
n.deals = append(n.deals, req)
case dkg_proposal_fsm.EventDKGResponseConfirmationReceived:
var req requests.DKGProposalResponseConfirmationRequest
if err := json.Unmarshal(o.Result, &req); err != nil {
t.Errorf("failed to unmarshal fsm req: %v", err)
}
n.responses = append(n.responses, req)
case dkg_proposal_fsm.EventDKGMasterKeyConfirmationReceived:
var req requests.DKGProposalMasterKeyConfirmationRequest
if err := json.Unmarshal(o.Result, &req); err != nil {
t.Errorf("failed to unmarshal fsm req: %v", err)
}
n.masterKey = append(n.masterKey, req)
default:
t.Errorf("invalid event: %s", o.Event)
}
}
type Transport struct {
nodes []*Node
}
func (tr *Transport) BroadcastOperation(t *testing.T, operation client.Operation) {
for _, node := range tr.nodes {
if operation.To == "" || operation.To == node.Participant {
node.storeOperation(t, operation)
}
}
}
func createOperation(t *testing.T, opType string, to string, req interface{}) client.Operation {
reqBz, err := json.Marshal(req)
if err != nil {
t.Errorf("failed to marshal request: %v", err)
}
op := client.Operation{
ID: uuid.New().String(),
Type: client.OperationType(opType),
Payload: reqBz,
Result: nil,
CreatedAt: time.Now(),
DKGIdentifier: "dkg_identifier",
To: to,
}
return op
}
func TestAirgappedFullDKG(t *testing.T) {
nodesCount := 4
participants := make([]string, nodesCount)
for i := 0; i < nodesCount; i++ {
participants[i] = fmt.Sprintf("Participant#%d", i)
}
tr := &Transport{}
for i := 0; i < nodesCount; i++ {
am := NewAirgappedMachine()
node := Node{
ParticipantID: i,
Participant: participants[i],
Machine: am,
}
tr.nodes = append(tr.nodes, &node)
}
var initReq responses.SignatureProposalParticipantInvitationsResponse
for _, n := range tr.nodes {
entry := &responses.SignatureProposalParticipantInvitationEntry{
ParticipantId: n.ParticipantID,
Title: n.Participant,
}
initReq = append(initReq, entry)
}
op := createOperation(t, string(signature_proposal_fsm.StateAwaitParticipantsConfirmations), "", initReq)
runStep(tr, func(n *Node, wg *sync.WaitGroup) {
defer wg.Done()
_, err := n.Machine.HandleOperation(op)
if err != nil {
t.Errorf("%s: failed to handle operation %s: %v", n.Participant, op.Type, err)
}
})
// get commits
var getCommitsRequest responses.SignatureProposalParticipantStatusResponse
for _, n := range tr.nodes {
pubKey, err := n.Machine.pubKey.MarshalBinary()
if err != nil {
t.Errorf("%s: failed to marshal pubkey: %v", n.Participant, err)
}
entry := &responses.SignatureProposalParticipantStatusEntry{
ParticipantId: n.ParticipantID,
Title: n.Participant,
DkgPubKey: pubKey,
}
getCommitsRequest = append(getCommitsRequest, entry)
}
op = createOperation(t, string(dkg_proposal_fsm.StateDkgCommitsAwaitConfirmations), "", getCommitsRequest)
runStep(tr, func(n *Node, wg *sync.WaitGroup) {
defer wg.Done()
operations, err := n.Machine.HandleOperation(op)
if err != nil {
t.Errorf("%s: failed to handle operation %s: %v", n.Participant, op.Type, err)
}
for _, op := range operations {
tr.BroadcastOperation(t, op)
}
})
//deals
runStep(tr, func(n *Node, wg *sync.WaitGroup) {
defer wg.Done()
var payload responses.DKGProposalCommitParticipantResponse
for _, req := range n.commits {
p := responses.DKGProposalCommitParticipantEntry{
ParticipantId: req.ParticipantId,
Title: fmt.Sprintf("Participant#%d", req.ParticipantId),
Commit: req.Commit,
}
payload = append(payload, &p)
}
op := createOperation(t, string(dkg_proposal_fsm.StateDkgDealsAwaitConfirmations), "", payload)
operations, err := n.Machine.HandleOperation(op)
if err != nil {
t.Errorf("%s: failed to handle operation %s: %v", n.Participant, op.Type, err)
}
for _, op := range operations {
tr.BroadcastOperation(t, op)
}
})
//responses
runStep(tr, func(n *Node, wg *sync.WaitGroup) {
defer wg.Done()
var payload responses.DKGProposalDealParticipantResponse
for _, req := range n.deals {
p := responses.DKGProposalDealParticipantEntry{
ParticipantId: req.ParticipantId,
Title: fmt.Sprintf("Participant#%d", req.ParticipantId),
Deal: req.Deal,
}
payload = append(payload, &p)
}
op := createOperation(t, string(dkg_proposal_fsm.StateDkgResponsesAwaitConfirmations), "", payload)
operations, err := n.Machine.HandleOperation(op)
if err != nil {
t.Errorf("%s: failed to handle operation %s: %v", n.Participant, op.Type, err)
}
for _, op := range operations {
tr.BroadcastOperation(t, op)
}
})
//master key
runStep(tr, func(n *Node, wg *sync.WaitGroup) {
defer wg.Done()
var payload responses.DKGProposalResponsesParticipantResponse
for _, req := range n.responses {
p := responses.DKGProposalResponsesParticipantEntry{
ParticipantId: req.ParticipantId,
Title: fmt.Sprintf("Participant#%d", req.ParticipantId),
Responses: req.Response,
}
payload = append(payload, &p)
}
op := createOperation(t, string(dkg_proposal_fsm.StateDkgMasterKeyAwaitConfirmations), "", payload)
operations, err := n.Machine.HandleOperation(op)
if err != nil {
t.Errorf("%s: failed to handle operation %s: %v", n.Participant, op.Type, err)
}
for _, op := range operations {
tr.BroadcastOperation(t, op)
}
})
for _, n := range tr.nodes {
fmt.Println(n.masterKey)
}
}
func runStep(transport *Transport, cb func(n *Node, wg *sync.WaitGroup)) {
var wg = &sync.WaitGroup{}
for _, node := range transport.nodes {
wg.Add(1)
n := node
go cb(n, wg)
}
wg.Wait()
}

View File

@ -22,6 +22,7 @@ type Operation struct {
CreatedAt time.Time
DKGIdentifier string
To string
Event fsm.Event
}
func (o *Operation) Check(o2 *Operation) error {