hash of the proposing DKG message, short description of operations

This commit is contained in:
programmer10110 2020-09-16 16:27:47 +03:00
parent 2e5ef31044
commit 5524de1b43
5 changed files with 158 additions and 17 deletions

View File

@ -136,11 +136,20 @@ The message will be consumed by your node:
Now you have a pending operation in your operation pool. Get the list of pending operations:
```
$ ./dc4bc_cli get_operations --listen_addr localhost:8080
Operation ID: 6d98f39d-1b24-49ce-8473-4f5d934ab2dc
Operation: {"ID":"6d98f39d-1b24-49ce-8473-4f5d934ab2dc","Type":"state_sig_proposal_await_participants_confirmations","Payload":"W3siUGFydGljaXBhbnRJZCI6MCwiQWRkciI6ImUwZDgwODNmOGEyZDE4ZjMxMGJmYmRjOTY0OWE4MzY2NDQ3MGY0NjA1M2FiNTNjMTA1YTA1NGIwOGY5ZWZmODVcbiIsIlRocmVzaG9sZCI6Mn0seyJQYXJ0aWNpcGFudElkIjoxLCJBZGRyIjoiMTFjNTZjZmE3NGUyZTIyMTQ0NDU1NzgxMWQ0M2RlM2MzOWFmOTI3MDcxZjc5NzI4ZWRjYjBhOGY0YjE5MzZlYVxuIiwiVGhyZXNob2xkIjoyfV0=","ResultMsgs":null,"CreatedAt":"2020-09-11T14:28:54.343122+03:00","DKGIdentifier":"191fb020fd30edd891b066f72e5a5e3a","To":"","Event":""}
DKG round ID: 3086f09822d7ba4bfb9af14c12d2c8ef
Operation ID: 30fa9c21-b79f-4a53-a84b-e7ad574c1a51
Description: confirm participation in the new DKG round
Hash of the proposing DKG message - a60bd47a831cd58a96bdd4381ee15afc
-----------------------------------------------------
```
You can check the hash of the proposing DKG message:
```
./dc4bc_cli get_start_dkg_file_hash start_dkg_propose.json
a60bd47a831cd58a96bdd4381ee15afc
```
The command returns a hash of the proposing message. If it is not equal to the hash from the list of pending operations, that means the person who proposed to start the DKG round changed the parameters that you agreed on the Conferce Call.
Copy the Operation ID and make the node produce a QR-code for it:
```
$ ./dc4bc_cli get_operation_qr 6d98f39d-1b24-49ce-8473-4f5d934ab2dc --listen_addr localhost:8080

View File

@ -2,17 +2,20 @@ package main
import (
"bytes"
"crypto/md5"
"encoding/base64"
"encoding/hex"
"encoding/json"
"fmt"
"github.com/depools/dc4bc/fsm/fsm"
"github.com/depools/dc4bc/fsm/state_machines/signature_proposal_fsm"
"io/ioutil"
"log"
"net/http"
"sort"
"time"
"github.com/depools/dc4bc/client"
"github.com/depools/dc4bc/client/types"
"github.com/depools/dc4bc/fsm/types/requests"
"github.com/depools/dc4bc/qr"
"github.com/spf13/cobra"
@ -40,17 +43,13 @@ func main() {
proposeSignMessageCommand(),
getAddressCommand(),
getPubKeyCommand(),
getHashOfStartDKGCommand(),
)
if err := rootCmd.Execute(); err != nil {
log.Fatalf("Failed to execute root command: %v", err)
}
}
type OperationsResponse struct {
ErrorMessage string `json:"error_message,omitempty"`
Result map[string]*types.Operation `json:"result"`
}
func getOperationsRequest(host string) (*OperationsResponse, error) {
resp, err := http.Get(fmt.Sprintf("http://%s/getOperations", host))
if err != nil {
@ -86,12 +85,16 @@ func getOperationsCommand() *cobra.Command {
return fmt.Errorf("failed to get operations: %s", operations.ErrorMessage)
}
for _, operation := range operations.Result {
fmt.Printf("DKG round ID: %s\n", operation.DKGIdentifier)
fmt.Printf("Operation ID: %s\n", operation.ID)
operationBz, err := json.Marshal(operation)
if err != nil {
return fmt.Errorf("failed to marshal operation: %w", err)
fmt.Printf("Description: %s\n", getShortOperationDescription(operation.Type))
if fsm.State(operation.Type) == signature_proposal_fsm.StateAwaitParticipantsConfirmations {
payloadHash, err := calcStartDKGMessageHash(operation.Payload)
if err != nil {
return fmt.Errorf("failed to get hash of start DKG message: %w", err)
}
fmt.Printf("Hash of the proposing DKG message - %s\n", hex.EncodeToString(payloadHash))
}
fmt.Printf("Operation: %s\n", string(operationBz))
fmt.Println("-----------------------------------------------------")
}
return nil
@ -99,11 +102,6 @@ func getOperationsCommand() *cobra.Command {
}
}
type OperationQRPathsResponse struct {
ErrorMessage string `json:"error_message,omitempty"`
Result []string `json:"result"`
}
func getOperationsQRPathsRequest(host string, operationID string) (*OperationQRPathsResponse, error) {
resp, err := http.Get(fmt.Sprintf("http://%s/getOperationQRPath?operationID=%s", host, operationID))
if err != nil {
@ -303,6 +301,47 @@ func startDKGCommand() *cobra.Command {
}
}
func getHashOfStartDKGCommand() *cobra.Command {
return &cobra.Command{
Use: "get_start_dkg_file_hash [proposing_file]",
Args: cobra.ExactArgs(1),
Short: "returns hash of proposing message for DKG start to verify correctness",
RunE: func(cmd *cobra.Command, args []string) error {
dkgProposeFileData, err := ioutil.ReadFile(args[0])
if err != nil {
return fmt.Errorf("failed to read file: %w", err)
}
var req requests.SignatureProposalParticipantsListRequest
if err = json.Unmarshal(dkgProposeFileData, &req); err != nil {
return fmt.Errorf("failed to unmarshal dkg proposing file: %w", err)
}
participants := DKGParticipants(req.Participants)
sort.Sort(participants)
hashPayload := bytes.NewBuffer(nil)
if _, err := hashPayload.Write([]byte(fmt.Sprintf("%d", req.SigningThreshold))); err != nil {
return err
}
for _, p := range participants {
if _, err := hashPayload.Write(p.PubKey); err != nil {
return err
}
if _, err := hashPayload.Write(p.DkgPubKey); err != nil {
return err
}
if _, err := hashPayload.Write([]byte(p.Addr)); err != nil {
return err
}
}
hash := md5.Sum(hashPayload.Bytes())
fmt.Println(hex.EncodeToString(hash[:]))
return nil
},
}
}
func proposeSignMessageCommand() *cobra.Command {
return &cobra.Command{
Use: "sign_data [dkg_id] [data]",

89
cmd/dc4bc_cli/types.go Normal file
View File

@ -0,0 +1,89 @@
package main
import (
"bytes"
"crypto/md5"
"encoding/json"
"fmt"
"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/signature_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"
"sort"
)
type DKGInvitationResponse responses.SignatureProposalParticipantInvitationsResponse
func (d DKGInvitationResponse) Len() int { return len(d) }
func (d DKGInvitationResponse) Swap(i, j int) { d[i], d[j] = d[j], d[i] }
func (d DKGInvitationResponse) Less(i, j int) bool { return d[i].Addr < d[j].Addr }
type DKGParticipants []*requests.SignatureProposalParticipantsEntry
func (d DKGParticipants) Len() int { return len(d) }
func (d DKGParticipants) Swap(i, j int) { d[i], d[j] = d[j], d[i] }
func (d DKGParticipants) Less(i, j int) bool { return d[i].Addr < d[j].Addr }
type OperationsResponse struct {
ErrorMessage string `json:"error_message,omitempty"`
Result map[string]*types.Operation `json:"result"`
}
type OperationQRPathsResponse struct {
ErrorMessage string `json:"error_message,omitempty"`
Result []string `json:"result"`
}
func calcStartDKGMessageHash(payload []byte) ([]byte, error) {
var msg DKGInvitationResponse
if err := json.Unmarshal(payload, &msg); err != nil {
return nil, fmt.Errorf("failed to unmarshal payload: %w", err)
}
sort.Sort(msg)
hashPayload := bytes.NewBuffer(nil)
// threshold is the same for everyone
if _, err := hashPayload.Write([]byte(fmt.Sprintf("%d", msg[0].Threshold))); err != nil {
return nil, err
}
for _, p := range msg {
if _, err := hashPayload.Write(p.PubKey); err != nil {
return nil, err
}
if _, err := hashPayload.Write(p.DkgPubKey); err != nil {
return nil, err
}
if _, err := hashPayload.Write([]byte(p.Addr)); err != nil {
return nil, err
}
}
hash := md5.Sum(hashPayload.Bytes())
return hash[:], nil
}
func getShortOperationDescription(operationType types.OperationType) string {
switch fsm.State(operationType) {
case signature_proposal_fsm.StateAwaitParticipantsConfirmations:
return "confirm participation in the new DKG round"
case dkg_proposal_fsm.StateDkgCommitsAwaitConfirmations:
return "send commits for the DKG round"
case dkg_proposal_fsm.StateDkgDealsAwaitConfirmations:
return "send deals for the DKG round"
case dkg_proposal_fsm.StateDkgResponsesAwaitConfirmations:
return "send responses for the DKG round"
case dkg_proposal_fsm.StateDkgMasterKeyAwaitConfirmations:
return "reconstruct the public key and broadcast it"
case signing_proposal_fsm.StateSigningAwaitConfirmations:
return "confirm participation in a new message signing"
case signing_proposal_fsm.StateSigningAwaitPartialSigns:
return "send your partial sign for the message"
case signing_proposal_fsm.StateSigningPartialSignsCollected:
return "recover full signature for the message"
default:
return "unknown operation"
}
}

View File

@ -68,6 +68,8 @@ func (m *SignatureProposalFSM) actionInitSignatureProposal(inEvent fsm.Event, ar
ParticipantId: participantId,
Addr: participant.Addr,
Threshold: participant.Threshold,
DkgPubKey: participant.DkgPubKey,
PubKey: participant.PubKey,
}
responseData = append(responseData, responseEntry)
}

View File

@ -11,6 +11,8 @@ type SignatureProposalParticipantInvitationEntry struct {
// Public title for address, such as name, nickname, organization
Addr string
Threshold int
DkgPubKey []byte
PubKey []byte
}
// Public lists for proposal confirmation process