Merge branch 'master' into feat/follow-ups

# Conflicts:
#	client/client.go
#	client/http_server.go
#	client/types/types.go
This commit is contained in:
Andrej Zavgorodnij 2020-10-05 18:02:10 +03:00
commit 32fde1b880
15 changed files with 480 additions and 60 deletions

View File

@ -148,14 +148,12 @@ The command returns a hash of the proposing message. If it is not equal to the h
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
List of paths to QR codes for operation 6d98f39d-1b24-49ce-8473-4f5d934ab2dc:
0) QR code: /tmp/dc4bc_qr_6d98f39d-1b24-49ce-8473-4f5d934ab2dc-0
1) QR code: /tmp/dc4bc_qr_6d98f39d-1b24-49ce-8473-4f5d934ab2dc-1
QR code was saved to: /tmp/dc4bc_qr_6d98f39d-1b24-49ce-8473-4f5d934ab2dc-0.gif
```
A single operation might be split into several QR-codes. Open the first QR code in your default image viewer and take a photo of it:
A single operation might be split into several QR-codes, which will be located in a single GIF file. Open the GIF-animation in any gif viewer and take a video of it:
```
open /tmp/dc4bc_qr_6d98f39d-1b24-49ce-8473-4f5d934ab2dc-0
open /tmp/dc4bc_qr_6d98f39d-1b24-49ce-8473-4f5d934ab2dc-0.gif
```
Now go to `dc4bc_airgapped` prompt and enter:
@ -164,25 +162,19 @@ Now go to `dc4bc_airgapped` prompt and enter:
>>> read_qr
```
A new window will be opened showing what your laptop's camera sees. Place the photo of the QR from the previous step in front of the camera and wait for the airgapped machine to scan it. You will have to scan all operation QR codes that were produced by the node.
A new window will be opened showing what your laptop's camera sees. Place the animation of the QR-gif from the previous step in front of the camera and wait for the airgapped machine to scan it (progress can be seen in window's title).
After you've scanned all QR codes, you will be shown the path to the QR code that contains the response of `dc4bc_airgapped`. Note that it may be split into several chunks:
After you've scanned all QR codes, you will be shown the path to the QR code that contains the response of `dc4bc_airgapped`. Note that it may be split into several chunks like on the client:
```
An operation in the readed QR code handled successfully, a result operation saved by chunks in following qr codes:
Operation's chunk #0: result_qr_codes/state_sig_proposal_await_participants_confirmations_de09e754-3bc8-4e67-9651-dcdba3316dba_-0.png
Operation's chunk #1: result_qr_codes/state_sig_proposal_await_participants_confirmations_de09e754-3bc8-4e67-9651-dcdba3316dba_-1.png
Operation's chunk #2: result_qr_codes/state_sig_proposal_await_participants_confirmations_de09e754-3bc8-4e67-9651-dcdba3316dba_-2.png
Operation's chunk #3: result_qr_codes/state_sig_proposal_await_participants_confirmations_de09e754-3bc8-4e67-9651-dcdba3316dba_-3.png
Operation's chunk #4: result_qr_codes/state_sig_proposal_await_participants_confirmations_de09e754-3bc8-4e67-9651-dcdba3316dba_-4.png
Operation's chunk #5: result_qr_codes/state_sig_proposal_await_participants_confirmations_de09e754-3bc8-4e67-9651-dcdba3316dba_-5.png
Operation's chunk #6: result_qr_codes/state_sig_proposal_await_participants_confirmations_de09e754-3bc8-4e67-9651-dcdba3316dba_-6.png
Operation's chunk: result_qr_codes/state_sig_proposal_await_participants_confirmations_de09e754-3bc8-4e67-9651-dcdba3316dba_-0.gif
```
Open the first response QR code in your default image viewer and take a photo of it. Then go to the node and run:
Open the response QR-gif in any gif viewer and take a video of it. Then go to the node and run:
```
$ ./dc4bc_cli read_from_camera --listen_addr localhost:8080
```
The procedure is the same as with `dc4bc_airgapped`: scan all QR codes until you see a success message:
The procedure is the same as with `dc4bc_airgapped`: scan QR-gif until you see a success message:
```
Operation successfully scanned
```
@ -216,8 +208,25 @@ $ ./dc4bc_cli sign_data AABB10CABB10 dGhlIG1lc3NhZ2UgdG8gc2lnbgo= --listen_addr
```
Further actions are repetitive and are similar to the DKG procedure. Check for new pending operations, feed them to `dc4bc_airgapped`, pass the responses to the client, then wait for new operations, etc. After some back and forth you'll see the node tell you that the signature is ready:
```
[john_doe] Handling operation state_signing_partial_signs_collected in airgapped
[176 141 250 6 188 93 29 163 218 11 179 113 24 74 95 62 89 163 219 249 135 53 26 212 55 134 143 107 117 216 112 85 163 6 117 153 161 171 235 145 198 253 60 53 22 3 36 84]
[john_doe] Handling message with offset 40, type signature_reconstructed
Successfully processed message with offset 40, type signature_reconstructed
```
Now you have the full reconstructed signature.
Now you have the full reconstructed signature.
```
./dc4bc_cli get_signatures AABB10CABB10
Hash of the signing data: b8fbfd0b1ed86412dd15637967788909
DKG round ID: AABB10CABB10
Participant: john_doe
Reconstructed signature for the data: tK+3CV2CI0flgwWLuhrZA5eaFfuJIvpLAc6CbAy5XBuRpzuCkjOZLCU6z1SvlwQIBJp5dAVa2rtbSy1jl98YtidujVWeUDNUz+kRl2C1C1BeLG5JvzQxhgr2dDxq0thu
```
It'll show you a list of broadcasted reconstructed signatures for a given DKG round.
You can verify any signature by executing `verify_signature` command inside the airgapped prompt:
```
>>> verify_signature
> Enter the DKGRoundIdentifier: AABB10CABB10
> Enter the BLS signature: tK+3CV2CI0flgwWLuhrZA5eaFfuJIvpLAc6CbAy5XBuRpzuCkjOZLCU6z1SvlwQIBJp5dAVa2rtbSy1jl98YtidujVWeUDNUz+kRl2C1C1BeLG5JvzQxhgr2dDxq0thu
> Enter the message which was signed (base64): dGhlIG1lc3NhZ2UgdG8gc2lnbgo=
Signature is correct!
```

View File

@ -70,6 +70,8 @@ func (n *Node) storeOperation(t *testing.T, msg storage.Message) {
t.Fatalf("failed to unmarshal fsm req: %v", err)
}
n.partialSigns = append(n.partialSigns, req)
case client.SignatureReconstructed:
return
default:
t.Fatalf("invalid event: %s", msg.Event)
}

View File

@ -1,7 +1,6 @@
package airgapped
import (
"encoding/base64"
"encoding/json"
"fmt"
@ -107,7 +106,18 @@ func (am *Machine) reconstructThresholdSignature(o *client.Operation) error {
if err != nil {
return fmt.Errorf("failed to reconsruct full signature for msg: %w", err)
}
fmt.Println(base64.StdEncoding.EncodeToString(reconstructedSignature))
response := client.ReconstructedSignature{
Data: payload.SrcPayload,
Signature: reconstructedSignature,
DKGRoundID: o.DKGIdentifier,
}
respBz, err := json.Marshal(response)
if err != nil {
return fmt.Errorf("failed to generate reconstructed signature response: %w", err)
}
o.Event = client.SignatureReconstructed
o.ResultMsgs = append(o.ResultMsgs, createMessage(*o, respBz))
return nil
}

View File

@ -6,6 +6,7 @@ import (
"encoding/json"
"errors"
"fmt"
"github.com/depools/dc4bc/fsm/types/responses"
"log"
"path/filepath"
"sync"
@ -135,7 +136,29 @@ func (c *BaseClient) SendMessage(message storage.Message) error {
return nil
}
// processSignature saves a broadcasted reconstructed signature to a LevelDB
func (c *Client) processSignature(message storage.Message) error {
var (
signature types.ReconstructedSignature
err error
)
if err = json.Unmarshal(message.Data, &signature); err != nil {
return fmt.Errorf("failed to unmarshal reconstructed signature: %w", err)
}
signature.Participant = message.SenderAddr
return c.state.SaveSignature(signature)
}
func (c *BaseClient) ProcessMessage(message storage.Message) error {
if fsm.Event(message.Event) == types.SignatureReconstructed {
if err := c.processSignature(message); err != nil {
return fmt.Errorf("failed to process signature: %w", err)
}
if err := c.state.SaveOffset(message.Offset + 1); err != nil {
return fmt.Errorf("failed to SaveOffset: %w", err)
}
return nil
}
fsmInstance, err := c.getFSMInstance(message.DkgRoundID)
if err != nil {
return fmt.Errorf("failed to getFSMInstance: %w", err)
@ -199,6 +222,18 @@ func (c *BaseClient) ProcessMessage(message storage.Message) error {
sipf.StateSigningPartialSignsCollected,
sipf.StateSigningAwaitConfirmations:
if resp.Data != nil {
// if we are initiator of signing, then we don't need to confirm our participation
if data, ok := resp.Data.(responses.SigningProposalParticipantInvitationsResponse); ok {
initiator, err := fsmInstance.SigningQuorumGetParticipant(data.InitiatorId)
if err != nil {
return fmt.Errorf("failed to get SigningQuorumParticipant: %w", err)
}
if initiator.Addr == c.GetUsername() {
break
}
}
bz, err := json.Marshal(resp.Data)
if err != nil {
return fmt.Errorf("failed to marshal FSM response: %w", err)
@ -216,6 +251,20 @@ func (c *BaseClient) ProcessMessage(message storage.Message) error {
c.Logger.Log("State %s does not require an operation", resp.State)
}
// switch FSM state by hand due to implementation specifics
if resp.State == sipf.StateSigningPartialSignsCollected {
fsmInstance, err = state_machines.FromDump(fsmDump)
if err != nil {
return fmt.Errorf("failed get state_machines from dump: %w", err)
}
resp, fsmDump, err = fsmInstance.Do(sipf.EventSigningRestart, requests.DefaultRequest{
CreatedAt: time.Now(),
})
if err != nil {
return fmt.Errorf("failed to Do operation in FSM: %w", err)
}
}
if operation != nil {
if err := c.state.PutOperation(operation); err != nil {
return fmt.Errorf("failed to PutOperation: %w", err)
@ -237,6 +286,17 @@ func (c *BaseClient) GetOperations() (map[string]*types.Operation, error) {
return c.state.GetOperations()
}
//GetSignatures returns all signatures for the given DKG round that were reconstructed on the airgapped machine and
// broadcasted by users
func (c *Client) GetSignatures(dkgID string) (map[string][]types.ReconstructedSignature, error) {
return c.state.GetSignatures(dkgID)
}
//GetSignatureByDataHash returns a list of reconstructed signatures of the signed data broadcasted by users
func (c *Client) GetSignatureByDataHash(dkgID, sigID string) ([]types.ReconstructedSignature, error) {
return c.state.GetSignatureByDataHash(dkgID, sigID)
}
// getOperationJSON returns a specific JSON-encoded operation
func (c *BaseClient) getOperationJSON(operationID string) ([]byte, error) {
operation, err := c.state.GetOperationByID(operationID)

View File

@ -117,7 +117,7 @@ func (n *node) run(t *testing.T) {
if err = pubKey.UnmarshalBinary(pubKeyReq.MasterKey); err != nil {
t.Fatalf("failed to unmarshal pubkey: %v", err)
}
if err = ioutil.WriteFile(fmt.Sprintf("/tmp/dc4bc_participant_%d.pubkey",
if err = ioutil.WriteFile(fmt.Sprintf("/tmp/participant_%d.pubkey",
pubKeyReq.ParticipantId), []byte(pubKey.String()), 0666); err != nil {
t.Fatalf("failed to write pubkey to temp file: %v", err)
}
@ -196,7 +196,7 @@ func TestFullFlow(t *testing.T) {
if err != nil {
t.Fatalf("node %d failed to init client: %v\n", nodeID, err)
}
airgappedMachine.SetEncryptionKey(clt.GetPubKey()) //just for testing
airgappedMachine.SetEncryptionKey([]byte("very_strong_password")) //just for testing
if err = airgappedMachine.InitKeys(); err != nil {
t.Errorf(err.Error())
}
@ -261,17 +261,7 @@ func TestFullFlow(t *testing.T) {
log.Println("Propose message to sign")
dkgRoundID := md5.Sum(messageDataBz)
messageDataSign := requests.SigningProposalStartRequest{
ParticipantId: len(nodes) - 1,
SrcPayload: []byte("message to sign"),
CreatedAt: time.Now(),
}
messageDataSignBz, err := json.Marshal(messageDataSign)
if err != nil {
t.Fatalf("failed to marshal SigningProposalStartRequest: %v\n", err)
}
messageDataBz, err = json.Marshal(map[string][]byte{"data": messageDataSignBz,
messageDataBz, err = json.Marshal(map[string][]byte{"data": []byte("message to sign"),
"dkgID": dkgRoundID[:]})
if err != nil {
t.Fatalf("failed to marshal SignatureProposalParticipantsListRequest: %v\n", err)

View File

@ -13,7 +13,12 @@ import (
"github.com/depools/dc4bc/fsm/fsm"
spf "github.com/depools/dc4bc/fsm/state_machines/signature_proposal_fsm"
sif "github.com/depools/dc4bc/fsm/state_machines/signing_proposal_fsm"
"github.com/depools/dc4bc/fsm/types/requests"
"github.com/google/uuid"
"io/ioutil"
"log"
"net/http"
"time"
"github.com/depools/dc4bc/qr"
"github.com/depools/dc4bc/storage"
@ -67,6 +72,9 @@ func (c *BaseClient) StartHTTPServer(listenAddr string) error {
mux.HandleFunc("/getOperations", c.getOperationsHandler)
mux.HandleFunc("/getOperationQRPath", c.getOperationQRPathHandler)
mux.HandleFunc("/getSignatures", c.getSignaturesHandler)
mux.HandleFunc("/getSignatureByDataHash", c.getSignatureByDataHashHandler)
mux.HandleFunc("/getOperationQR", c.getOperationQRToBodyHandler)
mux.HandleFunc("/handleProcessedOperationJSON", c.handleJSONOperationHandler)
mux.HandleFunc("/getOperation", c.getOperationHandler)
@ -135,6 +143,36 @@ func (c *BaseClient) getOperationsHandler(w http.ResponseWriter, r *http.Request
successResponse(w, operations)
}
func (c *Client) getSignaturesHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
errorResponse(w, http.StatusBadRequest, "Wrong HTTP method")
return
}
signatures, err := c.GetSignatures(r.URL.Query().Get("dkgID"))
if err != nil {
errorResponse(w, http.StatusInternalServerError, fmt.Sprintf("failed to get signatures: %v", err))
return
}
successResponse(w, signatures)
}
func (c *Client) getSignatureByDataHashHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
errorResponse(w, http.StatusBadRequest, "Wrong HTTP method")
return
}
signature, err := c.GetSignatureByDataHash(r.URL.Query().Get("dkgID"), r.URL.Query().Get("hash"))
if err != nil {
errorResponse(w, http.StatusInternalServerError, fmt.Sprintf("failed to get signature: %v", err))
return
}
successResponse(w, signature)
}
func (c *BaseClient) getOperationQRPathHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
errorResponse(w, http.StatusBadRequest, "Wrong HTTP method")
@ -234,9 +272,32 @@ func (c *BaseClient) proposeSignDataHandler(w http.ResponseWriter, r *http.Reque
return
}
message, err := c.buildMessage(hex.EncodeToString(req["dkgID"]), sif.EventSigningStart, req["data"])
fsmInstance, err := c.getFSMInstance(hex.EncodeToString(req["dkgID"]))
if err != nil {
errorResponse(w, http.StatusInternalServerError, fmt.Sprintf("failed to get FSM instance: %v", err))
return
}
participantID, err := fsmInstance.GetIDByAddr(c.GetUsername())
if err != nil {
errorResponse(w, http.StatusInternalServerError, fmt.Sprintf("failed to get participantID: %v", err))
return
}
messageDataSign := requests.SigningProposalStartRequest{
ParticipantId: participantID,
SrcPayload: req["data"],
CreatedAt: time.Now(),
}
messageDataSignBz, err := json.Marshal(messageDataSign)
if err != nil {
errorResponse(w, http.StatusInternalServerError, fmt.Sprintf("failed to marshal SigningProposalStartRequest: %v", err))
return
}
message, err := c.buildMessage(hex.EncodeToString(req["dkgID"]), sif.EventSigningStart, messageDataSignBz)
if err != nil {
errorResponse(w, http.StatusInternalServerError, fmt.Sprintf("failed to build message: %v", err))
return
}
if err = c.SendMessage(*message); err != nil {
errorResponse(w, http.StatusInternalServerError, fmt.Sprintf("failed to send message: %v", err))

View File

@ -1,7 +1,9 @@
package client
import (
"crypto/md5"
"encoding/binary"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
@ -15,9 +17,10 @@ import (
)
const (
offsetKey = "offset"
operationsKey = "operations"
fsmStateKey = "fsm_state"
offsetKey = "offset"
operationsKey = "operations"
fsmStateKey = "fsm_state"
signaturesKeyPrefix = "signatures"
)
// State is the client's state (it keeps the offset, the FSM state and
@ -33,6 +36,10 @@ type State interface {
DeleteOperation(operationID string) error
GetOperations() (map[string]*types.Operation, error)
GetOperationByID(operationID string) (*types.Operation, error)
SaveSignature(signature types.ReconstructedSignature) error
GetSignatureByDataHash(dkgID, signatureID string) ([]types.ReconstructedSignature, error)
GetSignatures(dkgID string) (map[string][]types.ReconstructedSignature, error)
}
type LevelDBState struct {
@ -253,3 +260,79 @@ func (s *LevelDBState) getOperations() (map[string]*types.Operation, error) {
return operations, nil
}
func makeSignatureKey(dkgID string) []byte {
return []byte(fmt.Sprintf("%s_%s", signaturesKeyPrefix, dkgID))
}
func (s *LevelDBState) getSignatures(dkgID string) (map[string][]types.ReconstructedSignature, error) {
bz, err := s.stateDb.Get(makeSignatureKey(dkgID), nil)
if err != nil {
if err == leveldb.ErrNotFound {
return nil, nil
}
return nil, fmt.Errorf("failed to get signatures for dkgID %s: %w", dkgID, err)
}
var signatures map[string][]types.ReconstructedSignature
if err := json.Unmarshal(bz, &signatures); err != nil {
return nil, fmt.Errorf("failed to unmarshal Operations: %w", err)
}
return signatures, nil
}
func (s *LevelDBState) GetSignatures(dkgID string) (map[string][]types.ReconstructedSignature, error) {
s.Lock()
defer s.Unlock()
return s.getSignatures(dkgID)
}
func (s *LevelDBState) GetSignatureByDataHash(dkgID, signatureID string) ([]types.ReconstructedSignature, error) {
s.Lock()
defer s.Unlock()
signatures, err := s.getSignatures(dkgID)
if err != nil {
return nil, fmt.Errorf("failed to getSignatures: %w", err)
}
signature, ok := signatures[signatureID]
if !ok {
return nil, errors.New("signature not found")
}
return signature, nil
}
func (s *LevelDBState) SaveSignature(signature types.ReconstructedSignature) error {
s.Lock()
defer s.Unlock()
signatures, err := s.getSignatures(signature.DKGRoundID)
if err != nil {
return fmt.Errorf("failed to getSignatures: %w", err)
}
if signatures == nil {
signatures = make(map[string][]types.ReconstructedSignature)
}
dataHash := md5.Sum(signature.Data)
dataHashString := hex.EncodeToString(dataHash[:])
sig := signatures[dataHashString]
sig = append(sig, signature)
signatures[dataHashString] = sig
signaturesJSON, err := json.Marshal(signatures)
if err != nil {
return fmt.Errorf("failed to marshal signatures: %w", err)
}
if err := s.stateDb.Put(makeSignatureKey(signature.DKGRoundID), signaturesJSON, nil); err != nil {
return fmt.Errorf("failed to save signatures: %w", err)
}
return nil
}

View File

@ -18,9 +18,17 @@ import (
type OperationType string
const (
DKGCommits OperationType = "dkg_commits"
DKGCommits OperationType = "dkg_commits"
SignatureReconstructed fsm.Event = "signature_reconstructed"
)
type ReconstructedSignature struct {
Data []byte
Signature []byte
Participant string
DKGRoundID string
}
// Operation is the type for any Operation that might be required for
// both DKG and signing process (e.g.,
type Operation struct {

View File

@ -54,6 +54,8 @@ func main() {
getUsernameCommand(),
getPubKeyCommand(),
getHashOfStartDKGCommand(),
getSignaturesCommand(),
getSignatureCommand(),
)
if err := rootCmd.Execute(); err != nil {
log.Fatalf("Failed to execute root command: %v", err)
@ -120,6 +122,100 @@ func getOperationsCommand() *cobra.Command {
}
}
func getSignaturesRequest(host string, dkgID string) (*SignaturesResponse, error) {
resp, err := http.Get(fmt.Sprintf("http://%s/getSignatures?dkgID=%s", host, dkgID))
if err != nil {
return nil, fmt.Errorf("failed to get signatures: %w", err)
}
defer resp.Body.Close()
responseBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read body: %w", err)
}
var response SignaturesResponse
if err = json.Unmarshal(responseBody, &response); err != nil {
return nil, fmt.Errorf("failed to unmarshal response: %v", err)
}
return &response, nil
}
func getSignaturesCommand() *cobra.Command {
return &cobra.Command{
Use: "get_signatures [dkgID]",
Args: cobra.ExactArgs(1),
Short: "returns all signatures for the given DKG round that were reconstructed on the airgapped machine",
RunE: func(cmd *cobra.Command, args []string) error {
listenAddr, err := cmd.Flags().GetString(flagListenAddr)
if err != nil {
return fmt.Errorf("failed to read configuration: %v", err)
}
signatures, err := getSignaturesRequest(listenAddr, args[0])
if err != nil {
return fmt.Errorf("failed to get signatures: %w", err)
}
if signatures.ErrorMessage != "" {
return fmt.Errorf("failed to get signatures: %s", signatures.ErrorMessage)
}
for dataHash, signature := range signatures.Result {
fmt.Printf("Hash of the signing data: %s\n", dataHash)
for _, participantSig := range signature {
fmt.Printf("\tDKG round ID: %s\n", participantSig.DKGRoundID)
fmt.Printf("\tParticipant: %s\n", participantSig.Participant)
fmt.Printf("\tReconstructed signature for the data: %s\n", base64.StdEncoding.EncodeToString(participantSig.Signature))
fmt.Println()
}
}
return nil
},
}
}
func getSignatureRequest(host string, dkgID, dataHash string) (*SignatureResponse, error) {
resp, err := http.Get(fmt.Sprintf("http://%s/getSignatureByDataHash?dkgID=%s&hash=%s", host, dkgID, dataHash))
if err != nil {
return nil, fmt.Errorf("failed to get signatures: %w", err)
}
defer resp.Body.Close()
responseBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read body: %w", err)
}
var response SignatureResponse
if err = json.Unmarshal(responseBody, &response); err != nil {
return nil, fmt.Errorf("failed to unmarshal response: %v", err)
}
return &response, nil
}
func getSignatureCommand() *cobra.Command {
return &cobra.Command{
Use: "get_signature [dkgID] [hash_of_the_signed_data]",
Args: cobra.ExactArgs(2),
Short: "returns a list of reconstructed signatures of the signed data broadcasted by users",
RunE: func(cmd *cobra.Command, args []string) error {
listenAddr, err := cmd.Flags().GetString(flagListenAddr)
if err != nil {
return fmt.Errorf("failed to read configuration: %v", err)
}
signatures, err := getSignatureRequest(listenAddr, args[0], args[1])
if err != nil {
return fmt.Errorf("failed to get signatures: %w", err)
}
if signatures.ErrorMessage != "" {
return fmt.Errorf("failed to get signatures: %s", signatures.ErrorMessage)
}
for _, participantSig := range signatures.Result {
fmt.Printf("\tParticipant: %s\n", participantSig.Participant)
fmt.Printf("\tReconstructed signature for the data: %s\n", base64.StdEncoding.EncodeToString(participantSig.Signature))
fmt.Println()
}
return nil
},
}
}
func getOperationRequest(host string, operationID string) (*OperationResponse, error) {
resp, err := http.Get(fmt.Sprintf("http://%s/getOperation?operationID=%s", host, operationID))
if err != nil {
@ -385,9 +481,9 @@ func getHashOfStartDKGCommand() *cobra.Command {
func proposeSignMessageCommand() *cobra.Command {
return &cobra.Command{
Use: "sign_data [dkg_id] [data]",
Use: "sign_data [dkg_id] [file_path]",
Args: cobra.ExactArgs(2),
Short: "sends a propose message to sign the data",
Short: "sends a propose message to sign the data in the file",
RunE: func(cmd *cobra.Command, args []string) error {
listenAddr, err := cmd.Flags().GetString(flagListenAddr)
if err != nil {
@ -399,22 +495,12 @@ func proposeSignMessageCommand() *cobra.Command {
return fmt.Errorf("failed to decode dkgID: %w", err)
}
data, err := base64.StdEncoding.DecodeString(args[1])
data, err := ioutil.ReadFile(args[1])
if err != nil {
return fmt.Errorf("failed to decode data")
return fmt.Errorf("failed to read the file")
}
messageDataSign := requests.SigningProposalStartRequest{
ParticipantId: 0, //TODO: determine participantID
SrcPayload: data,
CreatedAt: time.Now(),
}
messageDataSignBz, err := json.Marshal(messageDataSign)
if err != nil {
return fmt.Errorf("failed to marshal SigningProposalStartRequest: %v", err)
}
messageDataBz, err := json.Marshal(map[string][]byte{"data": messageDataSignBz,
messageDataBz, err := json.Marshal(map[string][]byte{"data": data,
"dkgID": dkgID})
if err != nil {
return fmt.Errorf("failed to marshal SigningProposalStartRequest: %v", err)

View File

@ -32,6 +32,16 @@ type OperationsResponse struct {
Result map[string]*types.Operation `json:"result"`
}
type SignaturesResponse struct {
ErrorMessage string `json:"error_message,omitempty"`
Result map[string][]types.ReconstructedSignature `json:"result"`
}
type SignatureResponse struct {
ErrorMessage string `json:"error_message,omitempty"`
Result []types.ReconstructedSignature `json:"result"`
}
type OperationResponse struct {
ErrorMessage string `json:"error_message,omitempty"`
Result []byte `json:"result"`

View File

@ -21,6 +21,7 @@ type DumpedMachineStatePayload struct {
DKGProposalPayload *DKGConfirmation
SigningProposalPayload *SigningConfirmation
PubKeys map[string]ed25519.PublicKey
IDs map[string]int
}
// Signature quorum
@ -123,6 +124,13 @@ func (p *DumpedMachineStatePayload) SetPubKeyAddr(addr string, pubKey ed25519.Pu
p.PubKeys[addr] = pubKey
}
func (p *DumpedMachineStatePayload) SetIDAddr(addr string, id int) {
if p.IDs == nil {
p.IDs = make(map[string]int)
}
p.IDs[addr] = id
}
func (p *DumpedMachineStatePayload) GetPubKeyByAddr(addr string) (ed25519.PublicKey, error) {
if p.PubKeys == nil {
return nil, errors.New("{PubKeys} not initialized")
@ -137,3 +145,17 @@ func (p *DumpedMachineStatePayload) GetPubKeyByAddr(addr string) (ed25519.Public
return pubKey, nil
}
func (p *DumpedMachineStatePayload) GetIDByAddr(addr string) (int, error) {
if p.IDs == nil {
return -1, errors.New("{IDs} not initialized")
}
if addr == "" {
return -1, errors.New("{addr} cannot be empty")
}
id, ok := p.IDs[addr]
if !ok {
return -1, errors.New("cannot find id by {addr}")
}
return id, nil
}

View File

@ -94,6 +94,22 @@ func (i *FSMInstance) GetPubKeyByAddr(addr string) (ed25519.PublicKey, error) {
return i.dump.Payload.GetPubKeyByAddr(addr)
}
func (i *FSMInstance) SigningQuorumGetParticipant(id int) (*internal.SigningProposalParticipant, error) {
if i.dump == nil {
return nil, errors.New("dump not initialized")
}
return i.dump.Payload.SigningQuorumGet(id), nil
}
func (i *FSMInstance) GetIDByAddr(addr string) (int, error) {
if i.dump == nil {
return -1, errors.New("dump not initialized")
}
return i.dump.Payload.GetIDByAddr(addr)
}
func (i *FSMInstance) Do(event fsm.Event, args ...interface{}) (result *fsm.Response, dump []byte, err error) {
var dumpErr error

View File

@ -51,6 +51,7 @@ func (m *SignatureProposalFSM) actionInitSignatureProposal(inEvent fsm.Event, ar
}
m.payload.SetPubKeyAddr(participant.Addr, participant.PubKey)
m.payload.SetIDAddr(participant.Addr, index)
}
// Checking fo quorum length

View File

@ -150,3 +150,47 @@ func (mr *MockStateMockRecorder) GetOperationByID(operationID interface{}) *gomo
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetOperationByID", reflect.TypeOf((*MockState)(nil).GetOperationByID), operationID)
}
// SaveSignature mocks base method
func (m *MockState) SaveSignature(signature types.ReconstructedSignature) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "SaveSignature", signature)
ret0, _ := ret[0].(error)
return ret0
}
// SaveSignature indicates an expected call of SaveSignature
func (mr *MockStateMockRecorder) SaveSignature(signature interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SaveSignature", reflect.TypeOf((*MockState)(nil).SaveSignature), signature)
}
// GetSignatureByDataHash mocks base method
func (m *MockState) GetSignatureByDataHash(dkgID, signatureID string) ([]types.ReconstructedSignature, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetSignatureByDataHash", dkgID, signatureID)
ret0, _ := ret[0].([]types.ReconstructedSignature)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetSignatureByDataHash indicates an expected call of GetSignatureByDataHash
func (mr *MockStateMockRecorder) GetSignatureByDataHash(dkgID, signatureID interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSignatureByDataHash", reflect.TypeOf((*MockState)(nil).GetSignatureByDataHash), dkgID, signatureID)
}
// GetSignatures mocks base method
func (m *MockState) GetSignatures(dkgID string) (map[string][]types.ReconstructedSignature, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetSignatures", dkgID)
ret0, _ := ret[0].(map[string][]types.ReconstructedSignature)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetSignatures indicates an expected call of GetSignatures
func (mr *MockStateMockRecorder) GetSignatures(dkgID interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSignatures", reflect.TypeOf((*MockState)(nil).GetSignatures), dkgID)
}

View File

@ -32,12 +32,6 @@ func (m *MockProcessor) EXPECT() *MockProcessorMockRecorder {
return m.recorder
}
func (m *MockProcessor) SetDelay(int) {
}
func (m *MockProcessor) SetChunkSize(int) {
}
// ReadQR mocks base method
func (m *MockProcessor) ReadQR() ([]byte, error) {
m.ctrl.T.Helper()
@ -66,3 +60,27 @@ func (mr *MockProcessorMockRecorder) WriteQR(path, data interface{}) *gomock.Cal
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WriteQR", reflect.TypeOf((*MockProcessor)(nil).WriteQR), path, data)
}
// SetDelay mocks base method
func (m *MockProcessor) SetDelay(delay int) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "SetDelay", delay)
}
// SetDelay indicates an expected call of SetDelay
func (mr *MockProcessorMockRecorder) SetDelay(delay interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetDelay", reflect.TypeOf((*MockProcessor)(nil).SetDelay), delay)
}
// SetChunkSize mocks base method
func (m *MockProcessor) SetChunkSize(chunkSize int) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "SetChunkSize", chunkSize)
}
// SetChunkSize indicates an expected call of SetChunkSize
func (mr *MockProcessorMockRecorder) SetChunkSize(chunkSize interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetChunkSize", reflect.TypeOf((*MockProcessor)(nil).SetChunkSize), chunkSize)
}