mirror of https://github.com/certusone/dc4bc.git
hash of the proposing DKG message, short description of operations
This commit is contained in:
parent
2e5ef31044
commit
5524de1b43
13
HowTo.md
13
HowTo.md
|
@ -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
|
||||
|
|
|
@ -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]",
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue