Merge branch 'master' into fix/airgapped-camera-lock

This commit is contained in:
programmer10110 2020-11-03 18:41:45 +03:00
commit b3cec9b3be
24 changed files with 311 additions and 140 deletions

View File

@ -92,7 +92,7 @@ Print your communication public key and encryption public key and save it somewh
$ ./dc4bc_cli get_pubkey --listen_addr localhost:8080
EcVs+nTi4iFERVeBHUPePDmvknBx95co7csKj0sZNuo=
# Inside the airgapped shell:
>>> show_dkg_pub_key
>>> show_dkg_pubkey
sN7XbnvZCRtg650dVCCpPK/hQ/rMTSlxrdnvzJ75zV4W/Uzk9suvjNPtyRt7PDXLDTGNimn+4X/FcJj2K6vDdgqOrr9BHwMqJXnQykcv3IV0ggIUjpMMgdbQ+0iSseyq
```
@ -106,12 +106,12 @@ Example of start_dkg_propose.json file structure:
"SigningThreshold": 2,
"Participants": [
{
"Addr": "e0d8083f8a2d18f310bfbdc9649a83664470f46053ab53c105a054b08f9eff85",
"Username": "john_doe",
"PubKey": "EcVs+nTi4iFERVeBHUPePDmvknBx95co7csKj0sZNuo=",
"DkgPubKey": "sN7XbnvZCRtg650dVCCpPK/hQ/rMTSlxrdnvzJ75zV4W/Uzk9suvjNPtyRt7PDXLDTGNimn+4X/FcJj2K6vDdgqOrr9BHwMqJXnQykcv3IV0ggIUjpMMgdbQ+0iSseyq"
},
{
"Addr": "addr2",
"Username": "jane_doe",
"PubKey": "cHVia2V5Mg==",
"DkgPubKey": "ZGtnX3B1YmtleV8y"
}
@ -124,7 +124,7 @@ The message will be consumed by your node:
[john_doe] starting to poll messages from append-only log...
[john_doe] Starting HTTP server on address: localhost:8080
[john_doe] Handling message with offset 0, type event_sig_proposal_init
[john_doe] message event_sig_proposal_init done successfully from e0d8083f8a2d18f310bfbdc9649a83664470f46053ab53c105a054b08f9eff85
[john_doe] message event_sig_proposal_init done successfully from john_doe
[john_doe] Successfully processed message with offset 0, type event_sig_proposal_init
```
@ -181,7 +181,7 @@ Operation successfully scanned
After scanning the response, a message is send to the message board. When all participants perform the necessary operations, the node will proceed to the next step:
```
[john_doe] message event_sig_proposal_confirm_by_participant done successfully from b8c083cd717b9958e141be5956bab1e463a7a0d85e4fe8924833601d43d671c4
[john_doe] message event_sig_proposal_confirm_by_participant done successfully from john_doe
```
Further actions are repetitive. Check for new pending operations:
```
@ -202,9 +202,8 @@ Now we have to collectively sign a message. Some participant will run the comman
# Inside dc4bc_airgapped prompt:
$ >>> show_finished_dkg
AABB10CABB10
$ echo "the message to sign" | base64
dGhlIG1lc3NhZ2UgdG8gc2lnbgo=
$ ./dc4bc_cli sign_data AABB10CABB10 dGhlIG1lc3NhZ2UgdG8gc2lnbgo= --listen_addr localhost:8080
$ echo "the message to sign" > data.txt
$ ./dc4bc_cli sign_data AABB10CABB10 data.txt --listen_addr localhost:8080
```
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:
```

View File

@ -264,8 +264,7 @@ func (am *Machine) HandleQR() (string, error) {
return "", fmt.Errorf("failed to marshal operation: %w", err)
}
qrPath := filepath.Join(am.resultQRFolder, fmt.Sprintf("%s_%s_%s.gif", resultOperation.Type, resultOperation.ID,
resultOperation.To))
qrPath := filepath.Join(am.resultQRFolder, fmt.Sprintf("dc4bc_qr_%s-response.gif", resultOperation.ID))
if err = am.qrProcessor.WriteQR(qrPath, operationBz); err != nil {
return "", fmt.Errorf("failed to write QR: %w", err)
}

View File

@ -147,7 +147,7 @@ func TestAirgappedAllSteps(t *testing.T) {
}
entry := &responses.SignatureProposalParticipantInvitationEntry{
ParticipantId: n.ParticipantID,
Addr: n.Participant,
Username: n.Participant,
Threshold: threshold,
DkgPubKey: pubKey,
}
@ -172,7 +172,7 @@ func TestAirgappedAllSteps(t *testing.T) {
}
entry := &responses.DKGProposalPubKeysParticipantEntry{
ParticipantId: n.ParticipantID,
Addr: n.Participant,
Username: n.Participant,
DkgPubKey: pubKey,
}
getCommitsRequest = append(getCommitsRequest, entry)
@ -198,7 +198,7 @@ func TestAirgappedAllSteps(t *testing.T) {
for _, req := range n.commits {
p := responses.DKGProposalCommitParticipantEntry{
ParticipantId: req.ParticipantId,
Addr: fmt.Sprintf("Participant#%d", req.ParticipantId),
Username: fmt.Sprintf("Participant#%d", req.ParticipantId),
DkgCommit: req.Commit,
}
payload = append(payload, &p)
@ -222,7 +222,7 @@ func TestAirgappedAllSteps(t *testing.T) {
for _, req := range n.deals {
p := responses.DKGProposalDealParticipantEntry{
ParticipantId: req.ParticipantId,
Addr: fmt.Sprintf("Participant#%d", req.ParticipantId),
Username: fmt.Sprintf("Participant#%d", req.ParticipantId),
DkgDeal: req.Deal,
}
payload = append(payload, &p)
@ -246,7 +246,7 @@ func TestAirgappedAllSteps(t *testing.T) {
for _, req := range n.responses {
p := responses.DKGProposalResponseParticipantEntry{
ParticipantId: req.ParticipantId,
Addr: fmt.Sprintf("Participant#%d", req.ParticipantId),
Username: fmt.Sprintf("Participant#%d", req.ParticipantId),
DkgResponse: req.Response,
}
payload = append(payload, &p)
@ -300,7 +300,7 @@ func TestAirgappedAllSteps(t *testing.T) {
for _, req := range n.partialSigns {
p := responses.SigningProcessParticipantEntry{
ParticipantId: req.ParticipantId,
Addr: fmt.Sprintf("Participant#%d", req.ParticipantId),
Username: fmt.Sprintf("Participant#%d", req.ParticipantId),
PartialSign: req.PartialSign,
}
payload.Participants = append(payload.Participants, &p)
@ -371,7 +371,7 @@ func TestAirgappedMachine_Replay(t *testing.T) {
}
entry := &responses.SignatureProposalParticipantInvitationEntry{
ParticipantId: n.ParticipantID,
Addr: n.Participant,
Username: n.Participant,
Threshold: threshold,
DkgPubKey: pubKey,
}
@ -396,7 +396,7 @@ func TestAirgappedMachine_Replay(t *testing.T) {
}
entry := &responses.DKGProposalPubKeysParticipantEntry{
ParticipantId: n.ParticipantID,
Addr: n.Participant,
Username: n.Participant,
DkgPubKey: pubKey,
}
getCommitsRequest = append(getCommitsRequest, entry)
@ -422,7 +422,7 @@ func TestAirgappedMachine_Replay(t *testing.T) {
for _, req := range n.commits {
p := responses.DKGProposalCommitParticipantEntry{
ParticipantId: req.ParticipantId,
Addr: fmt.Sprintf("Participant#%d", req.ParticipantId),
Username: fmt.Sprintf("Participant#%d", req.ParticipantId),
DkgCommit: req.Commit,
}
payload = append(payload, &p)
@ -484,7 +484,7 @@ func TestAirgappedMachine_Replay(t *testing.T) {
for _, req := range n.deals {
p := responses.DKGProposalDealParticipantEntry{
ParticipantId: req.ParticipantId,
Addr: fmt.Sprintf("Participant#%d", req.ParticipantId),
Username: fmt.Sprintf("Participant#%d", req.ParticipantId),
DkgDeal: req.Deal,
}
payload = append(payload, &p)
@ -508,7 +508,7 @@ func TestAirgappedMachine_Replay(t *testing.T) {
for _, req := range n.responses {
p := responses.DKGProposalResponseParticipantEntry{
ParticipantId: req.ParticipantId,
Addr: fmt.Sprintf("Participant#%d", req.ParticipantId),
Username: fmt.Sprintf("Participant#%d", req.ParticipantId),
DkgResponse: req.Response,
}
payload = append(payload, &p)
@ -562,7 +562,7 @@ func TestAirgappedMachine_Replay(t *testing.T) {
for _, req := range n.partialSigns {
p := responses.SigningProcessParticipantEntry{
ParticipantId: req.ParticipantId,
Addr: fmt.Sprintf("Participant#%d", req.ParticipantId),
Username: fmt.Sprintf("Participant#%d", req.ParticipantId),
PartialSign: req.PartialSign,
}
payload.Participants = append(payload.Participants, &p)

View File

@ -113,7 +113,7 @@ func (am *Machine) handleStateDkgCommitsAwaitConfirmations(o *client.Operation)
if err = pubKey.UnmarshalBinary(entry.DkgPubKey); err != nil {
return fmt.Errorf("failed to unmarshal pubkey: %w", err)
}
dkgInstance.StorePubKey(entry.Addr, entry.ParticipantId, pubKey)
dkgInstance.StorePubKey(entry.Username, entry.ParticipantId, pubKey)
}
if err = dkgInstance.InitDKGInstance(am.baseSeed); err != nil {
@ -182,7 +182,7 @@ func (am *Machine) handleStateDkgDealsAwaitConfirmations(o *client.Operation) er
}
dkgCommits = append(dkgCommits, commit)
}
dkgInstance.StoreCommits(entry.Addr, dkgCommits)
dkgInstance.StoreCommits(entry.Username, dkgCommits)
}
deals, err := dkgInstance.GetDeals()
@ -245,7 +245,7 @@ func (am *Machine) handleStateDkgResponsesAwaitConfirmations(o *client.Operation
if err = json.Unmarshal(decryptedDealBz, &deal); err != nil {
return fmt.Errorf("failed to unmarshal deal")
}
dkgInstance.StoreDeal(entry.Addr, &deal)
dkgInstance.StoreDeal(entry.Username, &deal)
}
processedResponses, err := dkgInstance.ProcessDeals()
@ -298,7 +298,7 @@ func (am *Machine) handleStateDkgMasterKeyAwaitConfirmations(o *client.Operation
if err = json.Unmarshal(entry.DkgResponse, &entryResponses); err != nil {
return fmt.Errorf("failed to unmarshal responses: %w", err)
}
dkgInstance.StoreResponses(entry.Addr, entryResponses)
dkgInstance.StoreResponses(entry.Username, entryResponses)
}
if err = dkgInstance.ProcessResponses(); err != nil {

View File

@ -230,7 +230,7 @@ func (c *BaseClient) ProcessMessage(message storage.Message) error {
if err != nil {
return fmt.Errorf("failed to get SigningQuorumParticipant: %w", err)
}
if initiator.Addr == c.GetUsername() {
if initiator.Username == c.GetUsername() {
break
}
}
@ -400,9 +400,9 @@ func (c *BaseClient) signMessage(message []byte) ([]byte, error) {
}
func (c *BaseClient) verifyMessage(fsmInstance *state_machines.FSMInstance, message storage.Message) error {
senderPubKey, err := fsmInstance.GetPubKeyByAddr(message.SenderAddr)
senderPubKey, err := fsmInstance.GetPubKeyByUsername(message.SenderAddr)
if err != nil {
return fmt.Errorf("failed to GetPubKeyByAddr: %w", err)
return fmt.Errorf("failed to GetPubKeyByUsername: %w", err)
}
if !ed25519.Verify(senderPubKey, message.Bytes(), message.Signature) {

View File

@ -63,22 +63,22 @@ func TestClient_ProcessMessage(t *testing.T) {
messageData := requests.SignatureProposalParticipantsListRequest{
Participants: []*requests.SignatureProposalParticipantsEntry{
{
Addr: senderAddr,
Username: senderAddr,
PubKey: senderKeyPair.Pub,
DkgPubKey: make([]byte, 128),
},
{
Addr: "111",
Username: "111",
PubKey: client.NewKeyPair().Pub,
DkgPubKey: make([]byte, 128),
},
{
Addr: "222",
Username: "222",
PubKey: client.NewKeyPair().Pub,
DkgPubKey: make([]byte, 128),
},
{
Addr: "333",
Username: "333",
PubKey: client.NewKeyPair().Pub,
DkgPubKey: make([]byte, 128),
},

View File

@ -230,7 +230,7 @@ func TestFullFlow(t *testing.T) {
log.Fatalln("failed to get DKG pubKey:", err.Error())
}
participants = append(participants, &requests.SignatureProposalParticipantsEntry{
Addr: node.client.GetUsername(),
Username: node.client.GetUsername(),
PubKey: node.client.GetPubKey(),
DkgPubKey: dkgPubKey,
})

View File

@ -8,7 +8,6 @@ import (
"io/ioutil"
"log"
"net/http"
"time"
"github.com/depools/dc4bc/client/types"
@ -80,6 +79,9 @@ func (c *BaseClient) StartHTTPServer(listenAddr string) error {
mux.HandleFunc("/startDKG", c.startDKGHandler)
mux.HandleFunc("/proposeSignMessage", c.proposeSignDataHandler)
mux.HandleFunc("/saveOffset", c.saveOffsetHandler)
mux.HandleFunc("/getOffset", c.getOffsetHandler)
mux.HandleFunc("/getFSMDump", c.getFSMDumpHandler)
mux.HandleFunc("/getFSMList", c.getFSMList)
@ -138,6 +140,47 @@ func (c *BaseClient) getPubkeyHandler(w http.ResponseWriter, r *http.Request) {
successResponse(w, c.GetPubKey())
}
func (c *BaseClient) getOffsetHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
errorResponse(w, http.StatusBadRequest, "Wrong HTTP method")
return
}
offset, err := c.state.LoadOffset()
if err != nil {
errorResponse(w, http.StatusInternalServerError, fmt.Sprintf("failed to load offset: %v", err))
return
}
successResponse(w, offset)
}
func (c *BaseClient) saveOffsetHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
errorResponse(w, http.StatusBadRequest, "Wrong HTTP method")
return
}
reqBytes, err := ioutil.ReadAll(r.Body)
if err != nil {
errorResponse(w, http.StatusBadRequest, fmt.Sprintf("failed to read request body: %v", err))
return
}
defer r.Body.Close()
var req map[string]uint64
if err = json.Unmarshal(reqBytes, &req); err != nil {
errorResponse(w, http.StatusInternalServerError, fmt.Sprintf("failed to unmarshal request: %v", err))
return
}
if _, ok := req["offset"]; !ok {
errorResponse(w, http.StatusInternalServerError, fmt.Sprintf("offset cannot be null: %v", err))
return
}
if err = c.state.SaveOffset(req["offset"]); err != nil {
errorResponse(w, http.StatusInternalServerError, fmt.Sprintf("failed to save offset: %v", err))
return
}
successResponse(w, "ok")
}
func (c *BaseClient) sendMessageHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
errorResponse(w, http.StatusBadRequest, "Wrong HTTP method")
@ -313,7 +356,7 @@ func (c *BaseClient) proposeSignDataHandler(w http.ResponseWriter, r *http.Reque
errorResponse(w, http.StatusInternalServerError, fmt.Sprintf("failed to get FSM instance: %v", err))
return
}
participantID, err := fsmInstance.GetIDByAddr(c.GetUsername())
participantID, err := fsmInstance.GetIDByUsername(c.GetUsername())
if err != nil {
errorResponse(w, http.StatusInternalServerError, fmt.Sprintf("failed to get participantID: %v", err))
return

View File

@ -9,6 +9,7 @@ import (
"os"
"os/signal"
"runtime"
"strconv"
"strings"
"syscall"
"time"
@ -35,10 +36,17 @@ type terminal struct {
commands map[string]*terminalCommand
currentCommand string
stopDroppingSensitiveData chan bool
}
func NewTerminal(machine *airgapped.Machine) *terminal {
t := terminal{bufio.NewReader(os.Stdin), machine, make(map[string]*terminalCommand), ""}
t := terminal{
bufio.NewReader(os.Stdin),
machine,
make(map[string]*terminalCommand),
"",
make(chan bool),
}
t.addCommand("read_qr", &terminalCommand{
commandHandler: t.readQRCommand,
description: "Reads QR chunks from camera, handle a decoded operation and returns paths to qr chunks of operation's result",
@ -47,7 +55,7 @@ func NewTerminal(machine *airgapped.Machine) *terminal {
commandHandler: t.helpCommand,
description: "shows available commands",
})
t.addCommand("show_dkg_pub_key", &terminalCommand{
t.addCommand("show_dkg_pubkey", &terminalCommand{
commandHandler: t.showDKGPubKeyCommand,
description: "shows a dkg pub key",
})
@ -74,6 +82,10 @@ func NewTerminal(machine *airgapped.Machine) *terminal {
commandHandler: t.verifySignCommand,
description: "verifies a BLS signature of a message",
})
t.addCommand("change_configuration", &terminalCommand{
commandHandler: t.changeConfigurationCommand,
description: "changes a configuration variables (frames delay, chunk size, etc...)",
})
return &t
}
@ -142,6 +154,62 @@ func (t *terminal) replayOperationLogCommand() error {
return nil
}
func (t *terminal) changeConfigurationCommand() error {
fmt.Print("> Enter a new path to save QR codes (leave empty to avoid changes): ")
newQRCodesfolder, _, err := t.reader.ReadLine()
if err != nil {
return fmt.Errorf("failed to read input: %w", err)
}
if len(newQRCodesfolder) > 0 {
t.airgapped.SetResultQRFolder(string(newQRCodesfolder))
fmt.Printf("Folder to save QR codes was changed to: %s\n", string(newQRCodesfolder))
}
fmt.Print("> Enter a new frames delay in 100ths of second (leave empty to avoid changes): ")
framesDelayInput, _, err := t.reader.ReadLine()
if err != nil {
return fmt.Errorf("failed to read input: %w", err)
}
if len(framesDelayInput) > 0 {
framesDelay, err := strconv.Atoi(string(framesDelayInput))
if err != nil {
return fmt.Errorf("failed to parse new frames delay: %w", err)
}
t.airgapped.SetQRProcessorFramesDelay(framesDelay)
fmt.Printf("Frames delay was changed to: %d\n", framesDelay)
}
fmt.Print("> Enter a new QR chunk size (leave empty to avoid changes): ")
chunkSizeInput, _, err := t.reader.ReadLine()
if err != nil {
return fmt.Errorf("failed to read input: %w", err)
}
if len(chunkSizeInput) > 0 {
chunkSize, err := strconv.Atoi(string(chunkSizeInput))
if err != nil {
return fmt.Errorf("failed to parse new chunk size: %w", err)
}
t.airgapped.SetQRProcessorChunkSize(chunkSize)
fmt.Printf("Chunk size was changed to: %d\n", chunkSize)
}
fmt.Print("> Enter a password expiration duration (leave empty to avoid changes): ")
durationInput, _, err := t.reader.ReadLine()
if err != nil {
return fmt.Errorf("failed to read input: %w", err)
}
if len(durationInput) > 0 {
duration, err := time.ParseDuration(string(durationInput))
if err != nil {
return fmt.Errorf("failed to parse new duration: %w", err)
}
t.stopDroppingSensitiveData <- true
go t.dropSensitiveDataByTicker(duration)
fmt.Printf("Password expiration was changed to: %s\n", duration.String())
}
return nil
}
func (t *terminal) dropOperationLogCommand() error {
fmt.Print("> Enter the DKGRoundIdentifier: ")
dkgRoundIdentifier, err := t.reader.ReadString('\n')
@ -252,10 +320,16 @@ func (t *terminal) run() error {
}
}
func (t *terminal) dropSensitiveData(passExpiration time.Duration) {
func (t *terminal) dropSensitiveDataByTicker(passExpiration time.Duration) {
ticker := time.NewTicker(passExpiration)
for range ticker.C {
t.airgapped.DropSensitiveData()
defer ticker.Stop()
for {
select {
case <-ticker.C:
t.airgapped.DropSensitiveData()
case <-t.stopDroppingSensitiveData:
return
}
}
}
@ -295,7 +369,6 @@ func main() {
signal.Notify(c, os.Interrupt)
t := NewTerminal(air)
go t.dropSensitiveData(passwordLifeDuration)
go func() {
for range c {
if t.currentCommand == "read_qr" {
@ -305,7 +378,7 @@ func main() {
fmt.Printf("Intercepting SIGINT, please type `exit` to stop the machine\n>>> ")
}
}()
go t.dropSensitiveDataByTicker(passwordLifeDuration)
if err = t.run(); err != nil {
log.Fatalf(err.Error())
}

View File

@ -13,6 +13,7 @@ import (
"net/http"
"path/filepath"
"sort"
"strconv"
"strings"
"time"
@ -58,6 +59,8 @@ func main() {
getHashOfStartDKGCommand(),
getSignaturesCommand(),
getSignatureCommand(),
saveOffsetCommand(),
getOffsetCommand(),
getFSMStatusCommand(),
getFSMListCommand(),
)
@ -270,7 +273,7 @@ func getOperationQRPathCommand() *cobra.Command {
return fmt.Errorf("failed to get operations: %s", operation.ErrorMessage)
}
operationQRPath := filepath.Join(qrCodeFolder, fmt.Sprintf("dc4bc_qr_%s", operationID))
operationQRPath := filepath.Join(qrCodeFolder, fmt.Sprintf("dc4bc_qr_%s-request", operationID))
qrPath := fmt.Sprintf("%s.gif", operationQRPath)
@ -329,6 +332,62 @@ func getPubKeyCommand() *cobra.Command {
}
}
func saveOffsetCommand() *cobra.Command {
return &cobra.Command{
Use: "save_offset [offset]",
Short: "saves a new offset for a storage",
Args: cobra.ExactArgs(1),
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)
}
offset, err := strconv.ParseUint(args[0], 10, 64)
if err != nil {
return fmt.Errorf("failed to parse uint: %w", err)
}
req := map[string]uint64{"offset": offset}
data, err := json.Marshal(req)
if err != nil {
return fmt.Errorf("failed to create request: %w", err)
}
resp, err := rawPostRequest(fmt.Sprintf("http://%s/saveOffset", listenAddr), "application/json", data)
if err != nil {
return fmt.Errorf("failed to save offset: %w", err)
}
if resp.ErrorMessage != "" {
return fmt.Errorf("failed to save offset: %v", resp.ErrorMessage)
}
fmt.Println(resp.Result.(string))
return nil
},
}
}
func getOffsetCommand() *cobra.Command {
return &cobra.Command{
Use: "get_offset",
Short: "returns a current offset for the storage",
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)
}
resp, err := rawGetRequest(fmt.Sprintf("http://%s//getOffset", listenAddr))
if err != nil {
return fmt.Errorf("failed to get offset: %w", err)
}
if resp.ErrorMessage != "" {
return fmt.Errorf("failed to get offset: %v", resp.ErrorMessage)
}
fmt.Println(uint64(resp.Result.(float64)))
return nil
},
}
}
func getUsernameCommand() *cobra.Command {
return &cobra.Command{
Use: "get_username",
@ -373,7 +432,7 @@ func rawPostRequest(url string, contentType string, data []byte) (*client.Respon
func readOperationFromCameraCommand() *cobra.Command {
return &cobra.Command{
Use: "read_from_camera",
Use: "read_qr",
Short: "opens the camera and reads QR codes which should contain a processed operation",
RunE: func(cmd *cobra.Command, args []string) error {
listenAddr, err := cmd.Flags().GetString(flagListenAddr)
@ -472,7 +531,7 @@ func getHashOfStartDKGCommand() *cobra.Command {
if _, err := hashPayload.Write(p.DkgPubKey); err != nil {
return err
}
if _, err := hashPayload.Write([]byte(p.Addr)); err != nil {
if _, err := hashPayload.Write([]byte(p.Username)); err != nil {
return err
}
}
@ -574,7 +633,7 @@ func getFSMStatusCommand() *cobra.Command {
quorum[k] = v
}
}
if strings.HasPrefix(string(dump.State), "state_sig") {
if strings.HasPrefix(string(dump.State), "state_sig_") {
for k, v := range dump.Payload.SignatureProposalPayload.Quorum {
quorum[k] = v
}
@ -586,13 +645,13 @@ func getFSMStatusCommand() *cobra.Command {
for _, p := range quorum {
if strings.Contains(p.GetStatus().String(), "Await") {
waiting = append(waiting, p.GetAddr())
waiting = append(waiting, p.GetUsername())
}
if strings.Contains(p.GetStatus().String(), "Error") {
failed = append(failed, p.GetAddr())
failed = append(failed, p.GetUsername())
}
if strings.Contains(p.GetStatus().String(), "Confirmed") {
confirmed = append(confirmed, p.GetAddr())
confirmed = append(confirmed, p.GetUsername())
}
}

View File

@ -2,22 +2,22 @@
"SigningThreshold": 3,
"Participants": [
{
"Addr": "addr1",
"Username": "addr1",
"PubKey": "Otwt+xeI7Po3aNIcLWugnMIHxWcoTPnI3kylUkIFq80=",
"DkgPubKey": "icmEgjz+F/W6qC347pIvu317GOZA7vj4cthe/+6+GtTvh4hng0C6yx40f7RTKcNuCe+xUATI2dNEciyx7ntUaAzBOuuzRuYmOIYjBTFmt8Zms/9K1EVMhXm0zGFb5rfP"
},
{
"Addr": "addr2",
"Username": "addr2",
"PubKey": "PTX6ck8mBg+n8fRJC2MdTJGq7i9PrvfxWALgZ/B7YJo=",
"DkgPubKey": "r7GSpa+roaukv8B+ulGWKNNjquY/B5rLPvyrjD5u36nrT69p8yQtSHHM7yp59gDuA8CIrb1ph0JsaTXYCsyjVuSzChCJVMxTNPqr/vB911DTkhkO1M2HcKYkyj2fzHHL"
},
{
"Addr": "addr3",
"Username": "addr3",
"PubKey": "PTX6ck8mBg+n8fRJC2MdTJGq7i9PrvfxWALgZ/B7YJo=",
"DkgPubKey": "r7GSpa+roaukv8B+ulGWKNNjquY/B5rLPvyrjD5u36nrT69p8yQtSHHM7yp59gDuA8CIrb1ph0JsaTXYCsyjVuSzChCJVMxTNPqr/vB911DTkhkO1M2HcKYkyj2fzHHL"
},
{
"Addr": "addr4",
"Username": "addr4",
"PubKey": "PTX6ck8mBg+n8fRJC2MdTJGq7i9PrvfxWALgZ/B7YJo=",
"DkgPubKey": "r7GSpa+roaukv8B+ulGWKNNjquY/B5rLPvyrjD5u36nrT69p8yQtSHHM7yp59gDuA8CIrb1ph0JsaTXYCsyjVuSzChCJVMxTNPqr/vB911DTkhkO1M2HcKYkyj2fzHHL"
}

View File

@ -20,13 +20,13 @@ type DKGInvitationResponse responses.SignatureProposalParticipantInvitationsResp
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 }
func (d DKGInvitationResponse) Less(i, j int) bool { return d[i].Username < d[j].Username }
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 }
func (d DKGParticipants) Less(i, j int) bool { return d[i].Username < d[j].Username }
type OperationsResponse struct {
ErrorMessage string `json:"error_message,omitempty"`
@ -74,7 +74,7 @@ func calcStartDKGMessageHash(payload []byte) ([]byte, error) {
if _, err := hashPayload.Write(p.DkgPubKey); err != nil {
return nil, err
}
if _, err := hashPayload.Write([]byte(p.Addr)); err != nil {
if _, err := hashPayload.Write([]byte(p.Username)); err != nil {
return nil, err
}
}

View File

@ -42,7 +42,7 @@ func (m *DKGProposalFSM) actionInitDKGProposal(inEvent fsm.Event, args ...interf
for participantId, participant := range m.payload.SignatureProposalPayload.Quorum {
m.payload.DKGProposalPayload.Quorum[participantId] = &internal.DKGProposalParticipant{
Addr: participant.Addr,
Username: participant.Username,
DkgPubKey: make([]byte, len(participant.DkgPubKey)),
Status: internal.CommitAwaitConfirmation,
UpdatedAt: participant.UpdatedAt,
@ -59,7 +59,7 @@ func (m *DKGProposalFSM) actionInitDKGProposal(inEvent fsm.Event, args ...interf
for participantId, participant := range m.payload.DKGProposalPayload.Quorum {
responseEntry := &responses.DKGProposalPubKeysParticipantEntry{
ParticipantId: participantId,
Addr: participant.Addr,
Username: participant.Username,
DkgPubKey: participant.DkgPubKey,
}
responseData = append(responseData, responseEntry)
@ -158,7 +158,7 @@ func (m *DKGProposalFSM) actionValidateDkgProposalAwaitCommits(inEvent fsm.Event
for participantId, participant := range m.payload.DKGProposalPayload.Quorum {
responseEntry := &responses.DKGProposalCommitParticipantEntry{
ParticipantId: participantId,
Addr: participant.Addr,
Username: participant.Username,
DkgCommit: participant.DkgCommit,
}
responseData = append(responseData, responseEntry)
@ -263,7 +263,7 @@ func (m *DKGProposalFSM) actionValidateDkgProposalAwaitDeals(inEvent fsm.Event,
}
responseEntry := &responses.DKGProposalDealParticipantEntry{
ParticipantId: participantId,
Addr: participant.Addr,
Username: participant.Username,
DkgDeal: participant.DkgDeal,
}
responseData = append(responseData, responseEntry)
@ -365,7 +365,7 @@ func (m *DKGProposalFSM) actionValidateDkgProposalAwaitResponses(inEvent fsm.Eve
for participantId, participant := range m.payload.DKGProposalPayload.Quorum {
responseEntry := &responses.DKGProposalResponseParticipantEntry{
ParticipantId: participantId,
Addr: participant.Addr,
Username: participant.Username,
DkgResponse: participant.DkgResponse,
}
responseData = append(responseData, responseEntry)

View File

@ -117,45 +117,45 @@ func (p *DumpedMachineStatePayload) SigningQuorumUpdate(id int, participant *Sig
}
}
func (p *DumpedMachineStatePayload) SetPubKeyAddr(addr string, pubKey ed25519.PublicKey) {
func (p *DumpedMachineStatePayload) SetPubKeyUsername(username string, pubKey ed25519.PublicKey) {
if p.PubKeys == nil {
p.PubKeys = make(map[string]ed25519.PublicKey)
}
p.PubKeys[addr] = pubKey
p.PubKeys[username] = pubKey
}
func (p *DumpedMachineStatePayload) SetIDAddr(addr string, id int) {
func (p *DumpedMachineStatePayload) SetIDUsername(username string, id int) {
if p.IDs == nil {
p.IDs = make(map[string]int)
}
p.IDs[addr] = id
p.IDs[username] = id
}
func (p *DumpedMachineStatePayload) GetPubKeyByAddr(addr string) (ed25519.PublicKey, error) {
func (p *DumpedMachineStatePayload) GetPubKeyByUsername(username string) (ed25519.PublicKey, error) {
if p.PubKeys == nil {
return nil, errors.New("{PubKeys} not initialized")
}
if addr == "" {
return nil, errors.New("{addr} cannot be empty")
if username == "" {
return nil, errors.New("{username} cannot be empty")
}
pubKey, ok := p.PubKeys[addr]
pubKey, ok := p.PubKeys[username]
if !ok {
return nil, errors.New("cannot find public key by {addr}")
return nil, errors.New("cannot find public key by {username}")
}
return pubKey, nil
}
func (p *DumpedMachineStatePayload) GetIDByAddr(addr string) (int, error) {
func (p *DumpedMachineStatePayload) GetIDByUsername(username string) (int, error) {
if p.IDs == nil {
return -1, errors.New("{IDs} not initialized")
}
if addr == "" {
return -1, errors.New("{addr} cannot be empty")
if username == "" {
return -1, errors.New("{username} cannot be empty")
}
id, ok := p.IDs[addr]
id, ok := p.IDs[username]
if !ok {
return -1, errors.New("cannot find id by {addr}")
return -1, errors.New("cannot find id by {username}")
}
return id, nil
}

View File

@ -41,7 +41,7 @@ type SignatureConfirmation struct {
}
type SignatureProposalParticipant struct {
Addr string
Username string
PubKey ed25519.PublicKey
DkgPubKey []byte
// For validation user confirmation: sign(InvitationSecret, PubKey) => user
@ -55,8 +55,8 @@ func (sigP SignatureProposalParticipant) GetStatus() ParticipantStatus {
return sigP.Status
}
func (sigP SignatureProposalParticipant) GetAddr() string {
return sigP.Addr
func (sigP SignatureProposalParticipant) GetUsername() string {
return sigP.Username
}
func (c *SignatureConfirmation) IsExpired() bool {
@ -87,7 +87,7 @@ const (
)
type DKGProposalParticipant struct {
Addr string
Username string
DkgPubKey []byte
DkgCommit []byte
DkgDeal []byte
@ -102,8 +102,8 @@ func (dkgP DKGProposalParticipant) GetStatus() ParticipantStatus {
return dkgP.Status
}
func (dkgP DKGProposalParticipant) GetAddr() string {
return dkgP.Addr
func (dkgP DKGProposalParticipant) GetUsername() string {
return dkgP.Username
}
type DKGProposalQuorum map[int]*DKGProposalParticipant
@ -204,7 +204,7 @@ func (s SigningParticipantStatus) String() string {
}
type SigningProposalParticipant struct {
Addr string
Username string
Status SigningParticipantStatus
PartialSign []byte
Error error
@ -215,6 +215,6 @@ func (signingP SigningProposalParticipant) GetStatus() ParticipantStatus {
return signingP.Status
}
func (signingP SigningProposalParticipant) GetAddr() string {
return signingP.Addr
func (signingP SigningProposalParticipant) GetUsername() string {
return signingP.Username
}

View File

@ -29,7 +29,7 @@ type FSMInstance struct {
type Participant interface {
GetStatus() internal.ParticipantStatus
GetAddr() string
GetUsername() string
}
// Create new fsm with unique id
@ -91,12 +91,12 @@ func FromDump(data []byte) (*FSMInstance, error) {
return i, err
}
func (i *FSMInstance) GetPubKeyByAddr(addr string) (ed25519.PublicKey, error) {
func (i *FSMInstance) GetPubKeyByUsername(username string) (ed25519.PublicKey, error) {
if i.dump == nil {
return nil, errors.New("dump not initialized")
}
return i.dump.Payload.GetPubKeyByAddr(addr)
return i.dump.Payload.GetPubKeyByUsername(username)
}
func (i *FSMInstance) SigningQuorumGetParticipant(id int) (*internal.SigningProposalParticipant, error) {
@ -107,12 +107,12 @@ func (i *FSMInstance) SigningQuorumGetParticipant(id int) (*internal.SigningProp
return i.dump.Payload.SigningQuorumGet(id), nil
}
func (i *FSMInstance) GetIDByAddr(addr string) (int, error) {
func (i *FSMInstance) GetIDByUsername(username string) (int, error) {
if i.dump == nil {
return -1, errors.New("dump not initialized")
}
return i.dump.Payload.GetIDByAddr(addr)
return i.dump.Payload.GetIDByUsername(username)
}
func (i *FSMInstance) Do(event fsm.Event, args ...interface{}) (result *fsm.Response, dump []byte, err error) {

View File

@ -21,12 +21,12 @@ import (
)
const (
addrMockLen = 32
keysMockLen = 128
usernameMockLen = 32
keysMockLen = 128
)
type testParticipantsPayload struct {
Addr string
Username string
HotPrivKey ed25519.PrivateKey
HotPubKey ed25519.PublicKey
DkgPubKey []byte
@ -41,8 +41,8 @@ var (
dkgId = "1b7a6382afe0fbe2ff127a5779f5e9b042e685cabefeadcf4ef27c6089a56bfb"
// map {addr} -> {participant}
testAddrMapParticipants = map[string]*testParticipantsPayload{}
// map {username} -> {participant}
testUsernameMapParticipants = map[string]*testParticipantsPayload{}
// map {dkg_queue_id} -> {participant}
testIdMapParticipants = map[int]*testParticipantsPayload{}
@ -62,7 +62,7 @@ func init() {
for i := 0; i < 3; i++ {
participant := &testParticipantsPayload{
Addr: base64.StdEncoding.EncodeToString(genDataMock(addrMockLen)),
Username: base64.StdEncoding.EncodeToString(genDataMock(usernameMockLen)),
HotPrivKey: genDataMock(keysMockLen),
HotPubKey: genDataMock(keysMockLen),
DkgPubKey: genDataMock(keysMockLen),
@ -71,7 +71,7 @@ func init() {
DkgResponse: genDataMock(keysMockLen),
DkgPartialKey: genDataMock(keysMockLen),
}
testAddrMapParticipants[participant.Addr] = participant
testUsernameMapParticipants[participant.Username] = participant
}
}
@ -162,10 +162,10 @@ func Test_SignatureProposal_EventInitProposal_Positive(t *testing.T) {
// Make request
request := make([]*requests.SignatureProposalParticipantsEntry, 0)
for _, participant := range testAddrMapParticipants {
for _, participant := range testUsernameMapParticipants {
request = append(request, &requests.SignatureProposalParticipantsEntry{
Addr: participant.Addr,
Username: participant.Username,
PubKey: participant.HotPubKey,
DkgPubKey: participant.DkgPubKey,
})
@ -196,14 +196,14 @@ func Test_SignatureProposal_EventInitProposal_Positive(t *testing.T) {
t.Fatalf("expected unique {ParticipantId}")
}
if participant.Addr == "" {
t.Fatalf("expected not empty {Addr}")
if participant.Username == "" {
t.Fatalf("expected not empty {Username}")
}
participantEntry, ok := testAddrMapParticipants[participant.Addr]
participantEntry, ok := testUsernameMapParticipants[participant.Username]
if !ok {
t.Fatalf("expected exist {Addr}")
t.Fatalf("expected exist {Username}")
}
testIdMapParticipants[participant.ParticipantId] = participantEntry
@ -409,8 +409,8 @@ func Test_DkgProposal_EventDKGCommitConfirmationReceived(t *testing.T) {
t.Fatalf("expected exist {ParticipantId}")
}
if responseEntry.Addr == "" {
t.Fatalf("expected {Addr} non zero length")
if responseEntry.Username == "" {
t.Fatalf("expected {Username} non zero length")
}
if len(responseEntry.DkgCommit) == 0 {
@ -534,8 +534,8 @@ func Test_DkgProposal_EventDKGDealConfirmationReceived(t *testing.T) {
t.Fatalf("expected exist {ParticipantId}")
}
if responseEntry.Addr == "" {
t.Fatalf("expected {Addr} non zero length")
if responseEntry.Username == "" {
t.Fatalf("expected {Username} non zero length")
}
if len(responseEntry.DkgDeal) == 0 {
@ -653,8 +653,8 @@ func Test_DkgProposal_EventDKGResponseConfirmationReceived_Positive(t *testing.T
t.Fatalf("expected exist {ParticipantId}")
}
if responseEntry.Addr == "" {
t.Fatalf("expected {Addr} non zero length")
if responseEntry.Username == "" {
t.Fatalf("expected {Username} non zero length")
}
if len(responseEntry.DkgResponse) == 0 {

View File

@ -40,9 +40,8 @@ func (m *SignatureProposalFSM) actionInitSignatureProposal(inEvent fsm.Event, ar
}
for index, participant := range request.Participants {
//participantId := createFingerprint(&participant.DkgPubKey)
m.payload.SignatureProposalPayload.Quorum[index] = &internal.SignatureProposalParticipant{
Addr: participant.Addr,
Username: participant.Username,
PubKey: participant.PubKey,
DkgPubKey: participant.DkgPubKey,
Status: internal.SigConfirmationAwaitConfirmation,
@ -50,8 +49,8 @@ func (m *SignatureProposalFSM) actionInitSignatureProposal(inEvent fsm.Event, ar
UpdatedAt: request.CreatedAt,
}
m.payload.SetPubKeyAddr(participant.Addr, participant.PubKey)
m.payload.SetIDAddr(participant.Addr, index)
m.payload.SetPubKeyUsername(participant.Username, participant.PubKey)
m.payload.SetIDUsername(participant.Username, index)
}
// Checking fo quorum length
@ -67,7 +66,7 @@ func (m *SignatureProposalFSM) actionInitSignatureProposal(inEvent fsm.Event, ar
for participantId, participant := range m.payload.SignatureProposalPayload.Quorum {
responseEntry := &responses.SignatureProposalParticipantInvitationEntry{
ParticipantId: participantId,
Addr: participant.Addr,
Username: participant.Username,
Threshold: participant.Threshold,
DkgPubKey: participant.DkgPubKey,
PubKey: participant.PubKey,
@ -171,7 +170,7 @@ func (m *SignatureProposalFSM) actionValidateSignatureProposal(fsm.Event, ...int
for participantId, participant := range m.payload.SignatureProposalPayload.Quorum {
responseEntry := &responses.SignatureProposalParticipantStatusEntry{
ParticipantId: participantId,
Addr: participant.Addr,
Username: participant.Username,
Status: uint8(participant.Status),
}
responseData = append(responseData, responseEntry)

View File

@ -75,7 +75,7 @@ func (m *SigningProposalFSM) actionStartSigningProposal(inEvent fsm.Event, args
// Initialize new quorum
for id, dkgEntry := range m.payload.DKGProposalPayload.Quorum {
m.payload.SigningProposalPayload.Quorum[id] = &internal.SigningProposalParticipant{
Addr: dkgEntry.Addr,
Username: dkgEntry.Username,
Status: internal.SigningAwaitConfirmation,
UpdatedAt: request.CreatedAt,
}
@ -95,7 +95,7 @@ func (m *SigningProposalFSM) actionStartSigningProposal(inEvent fsm.Event, args
for participantId, participant := range m.payload.SigningProposalPayload.Quorum {
responseEntry := &responses.SigningProposalParticipantInvitationEntry{
ParticipantId: participantId,
Addr: participant.Addr,
Username: participant.Username,
Status: uint8(participant.Status),
}
responseData.Participants = append(responseData.Participants, responseEntry)
@ -296,7 +296,7 @@ func (m *SigningProposalFSM) actionValidateSigningPartialSignsAwaitConfirmations
for participantId, participant := range m.payload.SigningProposalPayload.Quorum {
responseEntry := &responses.SigningProcessParticipantEntry{
ParticipantId: participantId,
Addr: participant.Addr,
Username: participant.Username,
PartialSign: participant.PartialSign,
}
responseData.Participants = append(responseData.Participants, responseEntry)

View File

@ -13,7 +13,7 @@ type SignatureProposalParticipantsListRequest struct {
}
type SignatureProposalParticipantsEntry struct {
Addr string
Username string
PubKey []byte
DkgPubKey []byte
}

View File

@ -20,21 +20,21 @@ func (r *SignatureProposalParticipantsListRequest) Validate() error {
return errors.New("{SigningThreshold} cannot be higher than {ParticipantsCount}")
}
uniqueAddresses := make(map[string]bool)
uniqueUsernames := make(map[string]bool)
for _, participant := range r.Participants {
if _, ok := uniqueAddresses[participant.Addr]; ok {
return errors.New("{Addr} must be unique")
if _, ok := uniqueUsernames[participant.Username]; ok {
return errors.New("{Username} must be unique")
}
uniqueAddresses[participant.Addr] = true
uniqueUsernames[participant.Username] = true
}
for _, participant := range r.Participants {
if len(participant.Addr) < 3 {
return errors.New("{Addr} minimum length is {3}")
if len(participant.Username) < 3 {
return errors.New("{Username} minimum length is {3}")
}
if len(participant.Addr) > 150 {
return errors.New("{Addr} maximum length is {150}")
if len(participant.Username) > 150 {
return errors.New("{Username} maximum length is {150}")
}
if len(participant.PubKey) < 10 {

View File

@ -4,7 +4,7 @@ type DKGProposalPubKeysParticipantResponse []*DKGProposalPubKeysParticipantEntry
type DKGProposalPubKeysParticipantEntry struct {
ParticipantId int
Addr string
Username string
DkgPubKey []byte
}
@ -12,7 +12,7 @@ type DKGProposalCommitParticipantResponse []*DKGProposalCommitParticipantEntry
type DKGProposalCommitParticipantEntry struct {
ParticipantId int
Addr string
Username string
DkgCommit []byte
}
@ -20,7 +20,7 @@ type DKGProposalDealParticipantResponse []*DKGProposalDealParticipantEntry
type DKGProposalDealParticipantEntry struct {
ParticipantId int
Addr string
Username string
DkgDeal []byte
}
@ -28,6 +28,6 @@ type DKGProposalResponseParticipantResponse []*DKGProposalResponseParticipantEnt
type DKGProposalResponseParticipantEntry struct {
ParticipantId int
Addr string
Username string
DkgResponse []byte
}

View File

@ -8,11 +8,10 @@ type SignatureProposalParticipantInvitationsResponse []*SignatureProposalPartici
type SignatureProposalParticipantInvitationEntry struct {
ParticipantId int
// Public title for address, such as name, nickname, organization
Addr string
Threshold int
DkgPubKey []byte
PubKey []byte
Username string
Threshold int
DkgPubKey []byte
PubKey []byte
}
// Public lists for proposal confirmation process
@ -21,7 +20,7 @@ type SignatureProposalParticipantStatusResponse []*SignatureProposalParticipantS
type SignatureProposalParticipantStatusEntry struct {
ParticipantId int
Addr string
Username string
Status uint8
DkgPubKey []byte
}

View File

@ -12,7 +12,7 @@ type SigningProposalParticipantInvitationsResponse struct {
type SigningProposalParticipantInvitationEntry struct {
ParticipantId int
Addr string
Username string
Status uint8
}
@ -33,7 +33,7 @@ type SigningProposalParticipantStatusResponse struct {
type SigningProposalParticipantStatusEntry struct {
ParticipantId int
Addr string
Username string
Status uint8
}
@ -47,6 +47,6 @@ type SigningProcessParticipantResponse struct {
type SigningProcessParticipantEntry struct {
ParticipantId int
Addr string
Username string
PartialSign []byte
}