diff --git a/airgapped/airgapped.go b/airgapped/airgapped.go index ad8aec5..b2a6345 100644 --- a/airgapped/airgapped.go +++ b/airgapped/airgapped.go @@ -3,6 +3,7 @@ package airgapped import ( "encoding/json" "fmt" + "github.com/depools/dc4bc/fsm/state_machines/signing_proposal_fsm" "log" "sync" @@ -190,6 +191,10 @@ func (am *AirgappedMachine) HandleOperation(operation client.Operation) (client. err = am.handleStateDkgResponsesAwaitConfirmations(&operation) case dkg_proposal_fsm.StateDkgMasterKeyAwaitConfirmations: err = am.handleStateDkgMasterKeyAwaitConfirmations(&operation) + case signing_proposal_fsm.StateSigningAwaitPartialKeys: + err = am.handleStateSigningAwaitPartialSigns(&operation) + case signing_proposal_fsm.StateSigningPartialKeysCollected: + err = am.reconstructThresholdSignature(&operation) default: err = fmt.Errorf("invalid operation type: %s", operation.Type) } diff --git a/airgapped/airgapped_test.go b/airgapped/airgapped_test.go index bd937a0..74a8c44 100644 --- a/airgapped/airgapped_test.go +++ b/airgapped/airgapped_test.go @@ -7,6 +7,7 @@ import ( client "github.com/depools/dc4bc/client/types" "github.com/depools/dc4bc/fsm/fsm" "github.com/depools/dc4bc/fsm/state_machines/dkg_proposal_fsm" + "github.com/depools/dc4bc/fsm/state_machines/signing_proposal_fsm" "github.com/depools/dc4bc/fsm/types/requests" "github.com/depools/dc4bc/fsm/types/responses" "github.com/depools/dc4bc/storage" @@ -29,6 +30,7 @@ type Node struct { deals []requests.DKGProposalDealConfirmationRequest responses []requests.DKGProposalResponseConfirmationRequest masterKeys []requests.DKGProposalMasterKeyConfirmationRequest + partialSigns []requests.SigningProposalPartialKeyRequest } func (n *Node) storeOperation(t *testing.T, msg storage.Message) { @@ -57,6 +59,12 @@ func (n *Node) storeOperation(t *testing.T, msg storage.Message) { t.Fatalf("failed to unmarshal fsm req: %v", err) } n.masterKeys = append(n.masterKeys, req) + case signing_proposal_fsm.EventSigningPartialKeyReceived: + var req requests.SigningProposalPartialKeyRequest + if err := json.Unmarshal(msg.Data, &req); err != nil { + t.Fatalf("failed to unmarshal fsm req: %v", err) + } + n.partialSigns = append(n.partialSigns, req) default: t.Fatalf("invalid event: %s", msg.Event) } @@ -91,7 +99,7 @@ func createOperation(t *testing.T, opType string, to string, req interface{}) cl } func TestAirgappedAllSteps(t *testing.T) { - nodesCount := 25 + nodesCount := 10 participants := make([]string, nodesCount) for i := 0; i < nodesCount; i++ { participants[i] = fmt.Sprintf("Participant#%d", i) @@ -220,27 +228,52 @@ func TestAirgappedAllSteps(t *testing.T) { } msgToSign := []byte("i am a message") - sigShares := make([][]byte, 0) - for _, n := range tr.nodes { - sigShare, err := n.Machine.createPartialSign(msgToSign, DKGIdentifier) + + //partialSigns + runStep(tr, func(n *Node, wg *sync.WaitGroup) { + defer wg.Done() + + payload := responses.SigningProposalParticipantInvitationsResponse{ + SrcPayload: msgToSign, + } + + op := createOperation(t, string(signing_proposal_fsm.StateSigningAwaitPartialKeys), "", payload) + + operation, err := n.Machine.HandleOperation(op) if err != nil { - t.Fatalf("failed to create sig share: %v", err.Error()) + t.Fatalf("%s: failed to handle operation %s: %v", n.Participant, op.Type, err) } - sigShares = append(sigShares, sigShare) - } - - fullSign, err := tr.nodes[0].Machine.recoverFullSign(msgToSign, sigShares, DKGIdentifier) - if err != nil { - t.Fatalf("failed to recover full sign: %v", err.Error()) - } - - for _, n := range tr.nodes { - if err = n.Machine.verifySign(msgToSign, fullSign, DKGIdentifier); err != nil { - t.Fatalf("failed to verify signature: %v", err) + for _, msg := range operation.ResultMsgs { + tr.BroadcastMessage(t, msg) } - } + }) - fmt.Println("DKG succeeded, signature recovered and verified") + //recover full signature + runStep(tr, func(n *Node, wg *sync.WaitGroup) { + defer wg.Done() + + var payload responses.SigningProcessParticipantResponse + for _, req := range n.partialSigns { + p := responses.SigningProcessParticipantEntry{ + ParticipantId: req.ParticipantId, + Addr: fmt.Sprintf("Participant#%d", req.ParticipantId), + PartialSign: req.PartialSign, + } + payload.Participants = append(payload.Participants, &p) + } + payload.SrcPayload = msgToSign + op := createOperation(t, string(signing_proposal_fsm.StateSigningPartialKeysCollected), "", payload) + + operation, err := n.Machine.HandleOperation(op) + if err != nil { + t.Fatalf("%s: failed to handle operation %s: %v", n.Participant, op.Type, err) + } + for _, msg := range operation.ResultMsgs { + tr.BroadcastMessage(t, msg) + } + }) + + fmt.Println("DKG succeeded, signature recovered") } func runStep(transport *Transport, cb func(n *Node, wg *sync.WaitGroup)) { diff --git a/airgapped/bls.go b/airgapped/bls.go index c833081..6484024 100644 --- a/airgapped/bls.go +++ b/airgapped/bls.go @@ -1,41 +1,73 @@ package airgapped import ( + "encoding/json" "fmt" + client "github.com/depools/dc4bc/client/types" + "github.com/depools/dc4bc/fsm/state_machines/signing_proposal_fsm" + "github.com/depools/dc4bc/fsm/types/requests" + "github.com/depools/dc4bc/fsm/types/responses" "go.dedis.ch/kyber/v3/sign/bls" "go.dedis.ch/kyber/v3/sign/tbls" ) // commented because fsm is not ready -//func (am *AirgappedMachine) handleStateSigningAwaitPartialKeys(o *client.Operation) error { -// var ( -// payload responses.DKGProposalResponsesParticipantResponse -// err error -// ) -// -// if err = json.Unmarshal(o.Payload, &payload); err != nil { -// return fmt.Errorf("failed to unmarshal payload: %w", err) -// } -// -// partialSign, err := am.createPartialSign(nil, o.DKGIdentifier) -// if err != nil { -// return fmt.Errorf("failed to create partialSign for msg: %w", err) -// } -// -// req := requests.SigningProposalPartialKeyRequest{ -// ParticipantId: 0, // TODO: from where? -// PartialSign: partialSign, -// CreatedAt: o.CreatedAt, -// } -// reqBz, err := json.Marshal(req) -// if err != nil { -// return fmt.Errorf("failed to generate fsm request: %w", err) -// } -// -// o.Result = reqBz -// o.Event = signing_proposal_fsm.EventSigningPartialKeyReceived -// return nil -//} +func (am *AirgappedMachine) handleStateSigningAwaitPartialSigns(o *client.Operation) error { + var ( + payload responses.SigningProposalParticipantInvitationsResponse + err error + ) + + if err = json.Unmarshal(o.Payload, &payload); err != nil { + return fmt.Errorf("failed to unmarshal payload: %w", err) + } + + partialSign, err := am.createPartialSign(payload.SrcPayload, o.DKGIdentifier) + if err != nil { + return fmt.Errorf("failed to create partialSign for msg: %w", err) + } + + participantID, err := am.getParticipantID(o.DKGIdentifier) + if err != nil { + return fmt.Errorf("failed to get paricipant id: %w", err) + } + req := requests.SigningProposalPartialKeyRequest{ + ParticipantId: participantID, + PartialSign: partialSign, + CreatedAt: o.CreatedAt, + } + reqBz, err := json.Marshal(req) + if err != nil { + return fmt.Errorf("failed to generate fsm request: %w", err) + } + + o.Event = signing_proposal_fsm.EventSigningPartialKeyReceived + o.ResultMsgs = append(o.ResultMsgs, createMessage(*o, reqBz)) + return nil +} + +func (am *AirgappedMachine) reconstructThresholdSignature(o *client.Operation) error { + var ( + payload responses.SigningProcessParticipantResponse + err error + ) + + if err = json.Unmarshal(o.Payload, &payload); err != nil { + return fmt.Errorf("failed to unmarshal payload: %w", err) + } + + partialSignatures := make([][]byte, 0, len(payload.Participants)) + for _, participant := range payload.Participants { + partialSignatures = append(partialSignatures, participant.PartialSign) + } + + reconstructedSignature, err := am.recoverFullSign(payload.SrcPayload, partialSignatures, o.DKGIdentifier) + if err != nil { + return fmt.Errorf("failed to reconsruct full signature for msg: %w", err) + } + fmt.Println(reconstructedSignature) + return nil +} func (am *AirgappedMachine) createPartialSign(msg []byte, dkgIdentifier string) ([]byte, error) { blsKeyring, err := am.loadBLSKeyring(dkgIdentifier) diff --git a/airgapped/dkg.go b/airgapped/dkg.go index c178225..a64347e 100644 --- a/airgapped/dkg.go +++ b/airgapped/dkg.go @@ -313,7 +313,7 @@ func (am *AirgappedMachine) handleStateDkgMasterKeyAwaitConfirmations(o *client. o.Event = dkg_proposal_fsm.EventDKGMasterKeyConfirmationReceived o.ResultMsgs = append(o.ResultMsgs, createMessage(*o, reqBz)) - fmt.Println(dkgInstance.ParticipantID, pubKey.String()) + //fmt.Println(dkgInstance.ParticipantID, pubKey.String()) return nil }