mirror of https://github.com/certusone/dc4bc.git
WIP: tests
This commit is contained in:
parent
381075f652
commit
f84d664f32
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
|
@ -22,6 +22,7 @@ type Operation struct {
|
|||
CreatedAt time.Time
|
||||
DKGIdentifier string
|
||||
To string
|
||||
Event fsm.Event
|
||||
}
|
||||
|
||||
func (o *Operation) Check(o2 *Operation) error {
|
||||
|
|
Loading…
Reference in New Issue