Merge branch 'master' into feat/remove-participant-address

This commit is contained in:
programmer10110 2020-09-21 11:53:35 +03:00
commit 63543446c0
7 changed files with 223 additions and 88 deletions

View File

@ -96,17 +96,27 @@ EcVs+nTi4iFERVeBHUPePDmvknBx95co7csKj0sZNuo=
sN7XbnvZCRtg650dVCCpPK/hQ/rMTSlxrdnvzJ75zV4W/Uzk9suvjNPtyRt7PDXLDTGNimn+4X/FcJj2K6vDdgqOrr9BHwMqJXnQykcv3IV0ggIUjpMMgdbQ+0iSseyq
```
Now you want to start the DKG procedure. This tells the node to send an InitDKG message that proposes to run DKG for 2 participants with `threshold=2`. You will be prompted to enter some required information about the suggested participants:
Now you want to start the DKG procedure. This tells the node to send an InitDKG message that proposes to run DKG with parameters which locate in a start_dkg_propose.json file.
```
$ ./dc4bc_cli start_dkg 2 2 --listen_addr localhost:8080
Enter a necessary data for participant 0:
Enter address: e0d8083f8a2d18f310bfbdc9649a83664470f46053ab53c105a054b08f9eff85
Enter pubkey (base64): 4NgIP4otGPMQv73JZJqDZkRw9GBTq1PBBaBUsI+e/4U=
Enter DKGPubKey (base64): sN7XbnvZCRtg650dVCCpPK/hQ/rMTSlxrdnvzJ75zV4W/Uzk9suvjNPtyRt7PDXLDTGNimn+4X/FcJj2K6vDdgqOrr9BHwMqJXnQykcv3IV0ggIUjpMMgdbQ+0iSseyq
Enter a necessary data for participant 1:
Enter address: 11c56cfa74e2e221444557811d43de3c39af927071f79728edcb0a8f4b1936ea
Enter pubkey (base64): EcVs+nTi4iFERVeBHUPePDmvknBx95co7csKj0sZNuo=
Enter DKGPubKey (base64): kJbOTZSwOKWYfg1KD/VxfRDEfk7kSgMzYiALJaLn2HJ08x5kIJWqkzFi/Z0B3ZEgBJROOybWPMVnQOpQ/DQwxYbxa6kgOPPBnY5WshX14vkgAtv+gE062rWLtFVBqZI+
$ ./dc4bc_cli start_dkg /path/to/start_dkg_propose.json --listen_addr localhost:8080
```
Example of start_dkg_propose.json file structure:
```
{
"SigningThreshold": 2,
"Participants": [
{
"Addr": "e0d8083f8a2d18f310bfbdc9649a83664470f46053ab53c105a054b08f9eff85",
"PubKey": "EcVs+nTi4iFERVeBHUPePDmvknBx95co7csKj0sZNuo=",
"DkgPubKey": "sN7XbnvZCRtg650dVCCpPK/hQ/rMTSlxrdnvzJ75zV4W/Uzk9suvjNPtyRt7PDXLDTGNimn+4X/FcJj2K6vDdgqOrr9BHwMqJXnQykcv3IV0ggIUjpMMgdbQ+0iSseyq"
},
{
"Addr": "addr2",
"PubKey": "cHVia2V5Mg==",
"DkgPubKey": "ZGtnX3B1YmtleV8y"
}
]
}
```
The message will be consumed by your node:
@ -121,11 +131,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

@ -1,21 +1,23 @@
package main
import (
"bufio"
"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"
"github.com/depools/dc4bc/fsm/state_machines/signing_proposal_fsm"
"github.com/depools/dc4bc/fsm/types/responses"
"io/ioutil"
"log"
"net/http"
"os"
"strconv"
"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"
@ -43,17 +45,13 @@ func main() {
proposeSignMessageCommand(),
getUsernameCommand(),
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 {
@ -89,12 +87,24 @@ 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))
}
if fsm.State(operation.Type) == signing_proposal_fsm.StateSigningAwaitConfirmations {
var payload responses.SigningProposalParticipantInvitationsResponse
if err := json.Unmarshal(operation.Payload, &payload); err != nil {
return fmt.Errorf("failed to unmarshal operation payload")
}
msgHash := md5.Sum(payload.SrcPayload)
fmt.Printf("Hash of the message to sign - %s\n", hex.EncodeToString(msgHash[:]))
}
fmt.Printf("Operation: %s\n", string(operationBz))
fmt.Println("-----------------------------------------------------")
}
return nil
@ -102,11 +112,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 {
@ -265,8 +270,8 @@ func readOperationFromCameraCommand() *cobra.Command {
func startDKGCommand() *cobra.Command {
return &cobra.Command{
Use: "start_dkg [participants count] [threshold]",
Args: cobra.ExactArgs(2),
Use: "start_dkg [proposing_file]",
Args: cobra.ExactArgs(1),
Short: "sends a propose message to start a DKG process",
RunE: func(cmd *cobra.Command, args []string) error {
listenAddr, err := cmd.Flags().GetString(flagListenAddr)
@ -274,61 +279,21 @@ func startDKGCommand() *cobra.Command {
return fmt.Errorf("failed to read configuration: %v", err)
}
participantsCount, err := strconv.Atoi(args[0])
dkgProposeFileData, err := ioutil.ReadFile(args[0])
if err != nil {
return fmt.Errorf("failed to get participants count: %w", err)
return fmt.Errorf("failed to read file: %w", err)
}
if participantsCount < 0 {
return fmt.Errorf("invalid number of participants: %d", participantsCount)
var req requests.SignatureProposalParticipantsListRequest
if err = json.Unmarshal(dkgProposeFileData, &req); err != nil {
return fmt.Errorf("failed to unmarshal dkg proposing file: %w", err)
}
threshold, err := strconv.Atoi(args[1])
if err != nil {
return fmt.Errorf("failed to get threshold: %w", err)
}
if participantsCount < 0 || threshold > participantsCount {
return fmt.Errorf("invalid threshold: %d", threshold)
if len(req.Participants) == 0 || req.SigningThreshold > len(req.Participants) {
return fmt.Errorf("invalid threshold: %d", req.SigningThreshold)
}
req.CreatedAt = time.Now()
reader := bufio.NewReader(os.Stdin)
var participants []*requests.SignatureProposalParticipantsEntry
for i := 0; i < participantsCount; i++ {
p := &requests.SignatureProposalParticipantsEntry{}
fmt.Printf("Enter a necessary data for participant %d:\n", i)
fmt.Printf("Enter address: ")
addr, _, err := reader.ReadLine()
if err != nil {
return fmt.Errorf("failed to read addr: %w", err)
}
p.Addr = string(addr)
fmt.Printf("Enter pubkey (base64): ")
pubKey, _, err := reader.ReadLine()
if err != nil {
return fmt.Errorf("failed to read pubKey: %w", err)
}
p.PubKey, err = base64.StdEncoding.DecodeString(string(pubKey))
if err != nil {
return fmt.Errorf("failed to decode pubKey: %w", err)
}
fmt.Printf("Enter DKGPubKey (base64): ")
DKGPubKey, _, err := reader.ReadLine()
if err != nil {
return fmt.Errorf("failed to read DKGPubKey: %w", err)
}
p.DkgPubKey, err = base64.StdEncoding.DecodeString(string(DKGPubKey))
if err != nil {
return fmt.Errorf("failed to decode DKGPubKey: %w", err)
}
participants = append(participants, p)
}
messageData := requests.SignatureProposalParticipantsListRequest{
Participants: participants,
SigningThreshold: threshold,
CreatedAt: time.Now(),
}
messageData := req
messageDataBz, err := json.Marshal(messageData)
if err != nil {
return fmt.Errorf("failed to marshal SignatureProposalParticipantsListRequest: %v\n", err)
@ -346,6 +311,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]",

View File

@ -0,0 +1,25 @@
{
"SigningThreshold": 3,
"Participants": [
{
"Addr": "addr1",
"PubKey": "cHVia2V5MQ==",
"DkgPubKey": "ZGtnX3B1YmtleV8x"
},
{
"Addr": "addr2",
"PubKey": "cHVia2V5Mg==",
"DkgPubKey": "ZGtnX3B1YmtleV8y"
},
{
"Addr": "addr3",
"PubKey": "cHVia2V5Mw==",
"DkgPubKey": "ZGtnX3B1YmtleV8z"
},
{
"Addr": "addr4",
"PubKey": "cHVia2V5NA==",
"DkgPubKey": "ZGtnX3B1YmtleV80"
}
]
}

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

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

View File

@ -12,6 +12,7 @@ type SignatureProposalParticipantInvitationEntry struct {
Addr string
Threshold int
DkgPubKey []byte
PubKey []byte
}
// Public lists for proposal confirmation process

View File

@ -61,10 +61,7 @@ func (p *CameraProcessor) ReadQR() ([]byte, error) {
}
data, err := ReadDataFromQR(imgObject)
if err != nil {
if _, ok := err.(gozxing.NotFoundException); ok {
continue
}
return nil, err
continue
}
return data, nil
}
@ -88,9 +85,6 @@ func ReadDataFromQR(img image.Image) ([]byte, error) {
qrReader := qrcode.NewQRCodeReader()
result, err := qrReader.Decode(bmp, nil)
if err != nil {
if _, ok := err.(gozxing.NotFoundException); ok {
return nil, err
}
return nil, fmt.Errorf("failed to decode the QR-code contents: %w", err)
}
return []byte(result.String()), nil