From 20ac1d8bee1507763e95cdec95533de87e6cfdd5 Mon Sep 17 00:00:00 2001 From: Vasiliy Shapovalov Date: Sat, 5 Dec 2020 12:20:06 +0300 Subject: [PATCH 1/8] Print mnemonic on init --- airgapped/storage.go | 17 ++++++++++++++--- go.mod | 3 ++- go.sum | 6 ++++++ 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/airgapped/storage.go b/airgapped/storage.go index d11f24f4..9f398453 100644 --- a/airgapped/storage.go +++ b/airgapped/storage.go @@ -2,6 +2,7 @@ package airgapped import ( "crypto/rand" + "crypto/sha512" "encoding/json" "errors" "fmt" @@ -11,6 +12,8 @@ import ( client "github.com/lidofinance/dc4bc/client/types" "github.com/syndtr/goleveldb/leveldb" + "github.com/tyler-smith/go-bip39" + "golang.org/x/crypto/pbkdf2" ) const ( @@ -26,18 +29,26 @@ type RoundOperationLog map[string][]client.Operation func (am *Machine) loadBaseSeed() error { seed, err := am.getBaseSeed() if errors.Is(err, leveldb.ErrNotFound) { - log.Println("Base seed not initialized, generating a new one...") + log.Println("Base seed not initialized, making a new one...") + entropy, err := bip39.NewEntropy(256) //maximum + if err != nil { + return fmt.Errorf("failed to generate bip39 entropy: %w", err) + } seed = make([]byte, seedSize) - _, err = rand.Read(seed) + + mnemonic, err := bip39.NewMnemonic(entropy) if err != nil { - return fmt.Errorf("failed to rand.Read: %w", err) + return fmt.Errorf("failed to generate new mnemonic form entropy: %w", err) } + seed = pbkdf2.Key([]byte(mnemonic), []byte("mnemonic"), 2048, seedSize, sha512.New) + if err := am.storeBaseSeed(seed); err != nil { return fmt.Errorf("failed to storeBaseSeed: %w", err) } log.Println("Successfully generated a new seed") + log.Println("Write down your mnemonic: ", mnemonic) } else if err != nil { return fmt.Errorf("failed to getBaseSeed: %w", err) } diff --git a/go.mod b/go.mod index 35d8cee7..5325f8bc 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,8 @@ require ( github.com/spf13/viper v1.7.1 github.com/stretchr/testify v1.6.1 github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca - golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de + github.com/tyler-smith/go-bip39 v1.1.0 + golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c gopkg.in/matryer/try.v1 v1.0.0-20150601225556-312d2599e12e lukechampine.com/frand v1.3.0 ) diff --git a/go.sum b/go.sum index a344f6ce..b0a027fe 100644 --- a/go.sum +++ b/go.sum @@ -969,6 +969,8 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1 github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= github.com/tyler-smith/go-bip39 v1.0.2 h1:+t3w+KwLXO6154GNJY+qUtIxLTmFjfUmpguQT1OlOT8= github.com/tyler-smith/go-bip39 v1.0.2/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= +github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= +github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= github.com/uber/jaeger-client-go v2.15.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= @@ -1073,6 +1075,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de h1:ikNHVSjEfnvz6sxdSPCaPt572qowuyMDMJLLm3Db3ig= golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c h1:9HhBz5L/UjnK9XLtiZhYAdue5BVKep3PMmS2LuPDt8k= +golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1208,6 +1212,8 @@ golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200824131525-c12d262b63d8 h1:AvbQYmiaaaza3cW3QXRyPo5kYgpFIzOAfeAAN7m3qQ4= golang.org/x/sys v0.0.0-20200824131525-c12d262b63d8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221 h1:/ZHdbVpdR/jk3g30/d4yUL0JU9kksj8+F/bnQUVLGDM= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= From 62832824ea10260be4af5b2b9a7e8f9cb4b0aa89 Mon Sep 17 00:00:00 2001 From: Vasiliy Shapovalov Date: Sat, 5 Dec 2020 12:26:11 +0300 Subject: [PATCH 2/8] Add set base seed function --- airgapped/storage.go | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/airgapped/storage.go b/airgapped/storage.go index 9f398453..f46651f4 100644 --- a/airgapped/storage.go +++ b/airgapped/storage.go @@ -59,6 +59,26 @@ func (am *Machine) loadBaseSeed() error { return nil } +func (am *Machine) setBaseSeed(mnemonic string) error { + entropy, err :=bip39.EntropyFromMnemonic(mnemonic) + if err != nil { + return fmt.Errorf("failed to validate mnemonic: %w", err) + } + seed = pbkdf2.Key([]byte(mnemonic), []byte("mnemonic"), 2048, seedSize, sha512.New) + + if err := am.storeBaseSeed(seed); err != nil { + return fmt.Errorf("failed to storeBaseSeed: %w", err) + } + + log.Println("Successfully set a base seed") + + am.baseSeed = seed + am.baseSuite = bls12381.NewBLS12381Suite(am.baseSeed) + + return nil +} + + func (am *Machine) storeBaseSeed(seed []byte) error { if err := am.db.Put([]byte(baseSeedKey), seed, nil); err != nil { return fmt.Errorf("failed to put baseSeed: %w", err) From d54815d428c7e5857b32e948360ca58d791c8a06 Mon Sep 17 00:00:00 2001 From: Vasiliy Shapovalov Date: Sat, 5 Dec 2020 12:53:53 +0300 Subject: [PATCH 3/8] add set_seed command --- airgapped/storage.go | 8 ++++---- cmd/airgapped/main.go | 27 +++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/airgapped/storage.go b/airgapped/storage.go index f46651f4..902f6cf9 100644 --- a/airgapped/storage.go +++ b/airgapped/storage.go @@ -34,7 +34,7 @@ func (am *Machine) loadBaseSeed() error { if err != nil { return fmt.Errorf("failed to generate bip39 entropy: %w", err) } - seed = make([]byte, seedSize) + mnemonic, err := bip39.NewMnemonic(entropy) if err != nil { @@ -59,12 +59,12 @@ func (am *Machine) loadBaseSeed() error { return nil } -func (am *Machine) setBaseSeed(mnemonic string) error { - entropy, err :=bip39.EntropyFromMnemonic(mnemonic) +func (am *Machine) SetBaseSeed(mnemonic string) error { + _, err :=bip39.EntropyFromMnemonic(mnemonic) if err != nil { return fmt.Errorf("failed to validate mnemonic: %w", err) } - seed = pbkdf2.Key([]byte(mnemonic), []byte("mnemonic"), 2048, seedSize, sha512.New) + seed := pbkdf2.Key([]byte(mnemonic), []byte("mnemonic"), 2048, seedSize, sha512.New) if err := am.storeBaseSeed(seed); err != nil { return fmt.Errorf("failed to storeBaseSeed: %w", err) diff --git a/cmd/airgapped/main.go b/cmd/airgapped/main.go index 0a18a660..fb8fe0d4 100644 --- a/cmd/airgapped/main.go +++ b/cmd/airgapped/main.go @@ -100,6 +100,10 @@ func NewPrompt(machine *airgapped.Machine) (*prompt, error) { commandHandler: p.changeConfigurationCommand, description: "changes a configuration variables (frames delay, chunk size, etc...)", }) + p.addCommand("set_seed", &promptCommand{ + commandHandler: p.setSeedCommand, + description: "resets a global random seed using BIP39 word list. WARNING! Only do that on a fresh database with no operation carried out.", + }) return &p, nil } @@ -288,6 +292,29 @@ func (p *prompt) dropOperationLogCommand() error { return nil } +func (p *prompt) setSeedCommand() error { + p.print("> WARNING! this will overwrite your old seed, which might make DKGs you've done with it unusable.") + p.print("> Only do this on a fresh db_path. Type 'ok' to continue: ") + ok, err := p.reader.ReadString('\n') + if err != nil { + return fmt.Errorf("failed to read confirmation: %w", err) + } + if strings.Trim(ok, " \n") != "ok" { + return nil + } + + p.print("> Enter the BIP39 mnemonic for a random seed: ") + mnemonic, err := p.reader.ReadString('\n') + if err != nil { + return fmt.Errorf("failed to read BIP39 mnemonic: %w", err) + } + + if err := p.airgapped.SetBaseSeed(strings.Trim(mnemonic, " \n")); err != nil { + return fmt.Errorf("failed to set base seed: %w", err) + } + return nil +} + func (p *prompt) verifySignCommand() error { p.print("> Enter the DKGRoundIdentifier: ") dkgRoundIdentifier, err := p.reader.ReadString('\n') From 914e85fc62672754197245eb2bc8e0132f478cc1 Mon Sep 17 00:00:00 2001 From: Vasiliy Shapovalov Date: Sat, 5 Dec 2020 12:57:20 +0300 Subject: [PATCH 4/8] Add newline to prompt, shuffle logs around --- airgapped/storage.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/airgapped/storage.go b/airgapped/storage.go index 902f6cf9..a21bd5e9 100644 --- a/airgapped/storage.go +++ b/airgapped/storage.go @@ -70,11 +70,12 @@ func (am *Machine) SetBaseSeed(mnemonic string) error { return fmt.Errorf("failed to storeBaseSeed: %w", err) } - log.Println("Successfully set a base seed") am.baseSeed = seed am.baseSuite = bls12381.NewBLS12381Suite(am.baseSeed) + log.Println("Successfully set a base seed") + return nil } From 02754627e1bf5406475b87fdc951b5a2d2275090 Mon Sep 17 00:00:00 2001 From: Andrej Zavgorodnij Date: Sat, 5 Dec 2020 17:44:26 +0300 Subject: [PATCH 5/8] added keys generation --- Makefile | 2 - airgapped/airgapped.go | 22 ++++++--- airgapped/storage.go | 10 ++--- cmd/airgapped/main.go | 17 +++++-- cmd/airgapped_state_cleaner/main.go | 69 ----------------------------- cmd/dc4bc_cli/main.go | 5 ++- 6 files changed, 36 insertions(+), 89 deletions(-) delete mode 100644 cmd/airgapped_state_cleaner/main.go diff --git a/Makefile b/Makefile index 9d694687..75717993 100755 --- a/Makefile +++ b/Makefile @@ -45,7 +45,5 @@ build: CGO_ENABLED=0 go build -o dc4bc_airgapped ./cmd/airgapped/ @echo "Building dc4bc_prysm_compatibility_checker..." go build -o dc4bc_prysm_compatibility_checker_linux ./cmd/prysm_compatibility_checker/ - @echo "Building Airgapped state cleaner..." - go build -o airgapped_state_cleaner ./cmd/airgapped_state_cleaner/ .PHONY: mocks diff --git a/airgapped/airgapped.go b/airgapped/airgapped.go index 28fc8aeb..53a8f70a 100644 --- a/airgapped/airgapped.go +++ b/airgapped/airgapped.go @@ -32,6 +32,7 @@ type Machine struct { dkgInstances map[string]*dkg.DKG qrProcessor qr.Processor + // Used to encrypt local sensitive data, e.g. BLS keyrings. encryptionKey []byte pubKey kyber.Point secKey kyber.Scalar @@ -86,23 +87,32 @@ func (am *Machine) SetResultQRFolder(resultQRFolder string) { am.resultQRFolder = resultQRFolder } -// InitKeys load keys public and private keys for DKG from LevelDB. If keys does not exist, creates them. +// InitKeys load keys public and private keys for DKG from LevelDB. If keys do not exist, it creates them. func (am *Machine) InitKeys() error { err := am.LoadKeysFromDB() if err != nil && err != leveldb.ErrNotFound { return fmt.Errorf("failed to load keys from db: %w", err) } - // if keys were not generated yet + + // If keys were not generated yet. if err == leveldb.ErrNotFound { - am.secKey = am.baseSuite.Scalar().Pick(am.baseSuite.RandomStream()) - am.pubKey = am.baseSuite.Point().Mul(am.secKey, nil) - return am.SaveKeysToDB() + return am.GenerateKeys() + } + + return nil +} + +func (am *Machine) GenerateKeys() error { + am.secKey = am.baseSuite.Scalar().Pick(am.baseSuite.RandomStream()) + am.pubKey = am.baseSuite.Point().Mul(am.secKey, nil) + if err := am.SaveKeysToDB(); err != nil { + return fmt.Errorf("failed to SaveKeysToDB: %w", err) } return nil } -// SetEncryptionKey set a key to encrypt and decrypt a sensitive data +// SetEncryptionKey set a key to encrypt and decrypt sensitive data. func (am *Machine) SetEncryptionKey(key []byte) { am.encryptionKey = key } diff --git a/airgapped/storage.go b/airgapped/storage.go index a21bd5e9..acad527b 100644 --- a/airgapped/storage.go +++ b/airgapped/storage.go @@ -22,6 +22,7 @@ const ( saltDBKey = "salt_key" baseSeedKey = "base_seed_key" operationsLogDBKey = "operations_log" + mnemonicSalt = "mnemonic" ) type RoundOperationLog map[string][]client.Operation @@ -34,14 +35,13 @@ func (am *Machine) loadBaseSeed() error { if err != nil { return fmt.Errorf("failed to generate bip39 entropy: %w", err) } - mnemonic, err := bip39.NewMnemonic(entropy) if err != nil { return fmt.Errorf("failed to generate new mnemonic form entropy: %w", err) } - seed = pbkdf2.Key([]byte(mnemonic), []byte("mnemonic"), 2048, seedSize, sha512.New) + seed = pbkdf2.Key([]byte(mnemonic), []byte(mnemonicSalt), 2048, seedSize, sha512.New) if err := am.storeBaseSeed(seed); err != nil { return fmt.Errorf("failed to storeBaseSeed: %w", err) @@ -60,17 +60,16 @@ func (am *Machine) loadBaseSeed() error { } func (am *Machine) SetBaseSeed(mnemonic string) error { - _, err :=bip39.EntropyFromMnemonic(mnemonic) + _, err := bip39.EntropyFromMnemonic(mnemonic) if err != nil { return fmt.Errorf("failed to validate mnemonic: %w", err) } - seed := pbkdf2.Key([]byte(mnemonic), []byte("mnemonic"), 2048, seedSize, sha512.New) + seed := pbkdf2.Key([]byte(mnemonic), []byte(mnemonicSalt), 2048, seedSize, sha512.New) if err := am.storeBaseSeed(seed); err != nil { return fmt.Errorf("failed to storeBaseSeed: %w", err) } - am.baseSeed = seed am.baseSuite = bls12381.NewBLS12381Suite(am.baseSeed) @@ -79,7 +78,6 @@ func (am *Machine) SetBaseSeed(mnemonic string) error { return nil } - func (am *Machine) storeBaseSeed(seed []byte) error { if err := am.db.Put([]byte(baseSeedKey), seed, nil); err != nil { return fmt.Errorf("failed to put baseSeed: %w", err) diff --git a/cmd/airgapped/main.go b/cmd/airgapped/main.go index fb8fe0d4..638cfe55 100644 --- a/cmd/airgapped/main.go +++ b/cmd/airgapped/main.go @@ -7,8 +7,6 @@ import ( "encoding/json" "flag" "fmt" - client "github.com/lidofinance/dc4bc/client/types" - "github.com/syndtr/goleveldb/leveldb" "io" "io/ioutil" "log" @@ -20,6 +18,9 @@ import ( "syscall" "time" + client "github.com/lidofinance/dc4bc/client/types" + "github.com/syndtr/goleveldb/leveldb" + "golang.org/x/crypto/ssh/terminal" "github.com/lidofinance/dc4bc/airgapped" @@ -51,7 +52,7 @@ type prompt struct { func NewPrompt(machine *airgapped.Machine) (*prompt, error) { p := prompt{ - reader: bufio.NewReaderSize(os.Stdin, 1 << 22), + reader: bufio.NewReaderSize(os.Stdin, 1<<22), airgapped: machine, commands: make(map[string]*promptCommand), currentCommand: "", @@ -104,6 +105,7 @@ func NewPrompt(machine *airgapped.Machine) (*prompt, error) { commandHandler: p.setSeedCommand, description: "resets a global random seed using BIP39 word list. WARNING! Only do that on a fresh database with no operation carried out.", }) + return &p, nil } @@ -293,8 +295,9 @@ func (p *prompt) dropOperationLogCommand() error { } func (p *prompt) setSeedCommand() error { - p.print("> WARNING! this will overwrite your old seed, which might make DKGs you've done with it unusable.") + p.print("> WARNING! this will overwrite your old seed, which might make DKGs you've done with it unusable.\n") p.print("> Only do this on a fresh db_path. Type 'ok' to continue: ") + ok, err := p.reader.ReadString('\n') if err != nil { return fmt.Errorf("failed to read confirmation: %w", err) @@ -312,6 +315,11 @@ func (p *prompt) setSeedCommand() error { if err := p.airgapped.SetBaseSeed(strings.Trim(mnemonic, " \n")); err != nil { return fmt.Errorf("failed to set base seed: %w", err) } + + if err := p.airgapped.GenerateKeys(); err != nil { + return fmt.Errorf("failed to GenerateKeys: %w", err) + } + return nil } @@ -537,6 +545,7 @@ func main() { } }() go p.dropSensitiveDataByTicker(passwordLifeDuration) + if err = p.run(); err != nil { p.printf("Error occurred: %v", err) } diff --git a/cmd/airgapped_state_cleaner/main.go b/cmd/airgapped_state_cleaner/main.go deleted file mode 100644 index 066ac2e1..00000000 --- a/cmd/airgapped_state_cleaner/main.go +++ /dev/null @@ -1,69 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - "github.com/lidofinance/dc4bc/airgapped" - client "github.com/lidofinance/dc4bc/client/types" - "github.com/syndtr/goleveldb/leveldb" - "os" -) - -const operationsLogDBKey = "operations_log" - -func main() { - stateDir := os.Args[1] - dkgRoundID := os.Args[2] - - db, err := leveldb.OpenFile(stateDir, nil) - if err != nil { - fmt.Printf("failed to open db file %s for keys: %v\n", stateDir, err) - return - } - defer db.Close() - - roundOperationsLog, err := getRoundOperationLog(db) - if err != nil { - fmt.Printf("failed to getRoundOperationLog: %v\n", err) - return - } - - roundOperations := roundOperationsLog[dkgRoundID] - var cleanRoundOperations []client.Operation - - knownOperations := map[string]bool{} - for _, operation := range roundOperations { - if knownOperations[operation.ID] { - fmt.Println("Found a duplicate operation with ID:", operation.ID) - continue - } - - cleanRoundOperations = append(cleanRoundOperations, operation) - knownOperations[operation.ID] = true - } - - roundOperationsLog[dkgRoundID] = cleanRoundOperations - roundOperationsLogBz, err := json.Marshal(roundOperationsLog) - if err != nil { - fmt.Printf("failed to marshal operationsLog: %v\n", err) - return - } - - if err := db.Put([]byte(operationsLogDBKey), roundOperationsLogBz, nil); err != nil { - fmt.Printf("failed to put updated operationsLog: %v\n", err) - } -} - -func getRoundOperationLog(db *leveldb.DB) (airgapped.RoundOperationLog, error) { - operationsLogBz, err := db.Get([]byte(operationsLogDBKey), nil) - if err != nil { - return nil, err - } - - var roundOperationsLog airgapped.RoundOperationLog - if err := json.Unmarshal(operationsLogBz, &roundOperationsLog); err != nil { - return nil, fmt.Errorf("failed to unmarshal stored operationsLog: %w", err) - } - - return roundOperationsLog, nil -} \ No newline at end of file diff --git a/cmd/dc4bc_cli/main.go b/cmd/dc4bc_cli/main.go index 947818cd..8df943cb 100644 --- a/cmd/dc4bc_cli/main.go +++ b/cmd/dc4bc_cli/main.go @@ -7,7 +7,6 @@ import ( "encoding/hex" "encoding/json" "fmt" - "github.com/lidofinance/dc4bc/fsm/state_machines" "io/ioutil" "log" "net/http" @@ -17,6 +16,8 @@ import ( "strings" "time" + "github.com/lidofinance/dc4bc/fsm/state_machines" + "github.com/lidofinance/dc4bc/fsm/fsm" "github.com/lidofinance/dc4bc/fsm/state_machines/signature_proposal_fsm" "github.com/lidofinance/dc4bc/fsm/state_machines/signing_proposal_fsm" @@ -686,7 +687,7 @@ func getFSMStatusCommand() *cobra.Command { } if len(waiting) > 0 { - fmt.Printf("Waiting for a data from: %s\n", strings.Join(waiting, ", ")) + fmt.Printf("Waiting for data from: %s\n", strings.Join(waiting, ", ")) } if len(confirmed) > 0 { fmt.Printf("Received a data from: %s\n", strings.Join(confirmed, ", ")) From 9734c48a087a1d42f3f9f88cea8ae1e1ed18d447 Mon Sep 17 00:00:00 2001 From: Andrej Zavgorodnij Date: Sat, 5 Dec 2020 18:33:48 +0300 Subject: [PATCH 6/8] removed airgapped_state_cleaner from targets --- Makefile | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Makefile b/Makefile index 75717993..8a38cf95 100755 --- a/Makefile +++ b/Makefile @@ -21,8 +21,6 @@ build-darwin: CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -o dc4bc_airgapped_darwin ./cmd/airgapped/ @echo "Building dc4bc_prysm_compatibility_checker..." GOOS=darwin GOARCH=amd64 go build -o dc4bc_prysm_compatibility_checker_darwin ./cmd/prysm_compatibility_checker/ - @echo "Building Airgapped state cleaner..." - GOOS=darwin GOARCH=amd64 go build -o airgapped_state_cleaner_darwin ./cmd/airgapped_state_cleaner/ build-linux: @echo "Building dc4bc_d..." @@ -33,8 +31,6 @@ build-linux: CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o dc4bc_airgapped_linux ./cmd/airgapped/ @echo "Building dc4bc_prysm_compatibility_checker..." GOOS=linux GOARCH=amd64 go build -o dc4bc_prysm_compatibility_checker_linux ./cmd/prysm_compatibility_checker/ - @echo "Building Airgapped state cleaner..." - GOOS=linux GOARCH=amd64 go build -o airgapped_state_cleaner_linux ./cmd/airgapped_state_cleaner/ build: @echo "Building dc4bc_d..." From df34327d2cfc61fa53c5748388b26fb3f60832fa Mon Sep 17 00:00:00 2001 From: Andrej Zavgorodnij Date: Mon, 7 Dec 2020 12:45:38 +0300 Subject: [PATCH 7/8] Merged master --- cmd/airgapped/main.go | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/cmd/airgapped/main.go b/cmd/airgapped/main.go index 35a3fe60..01889d8c 100644 --- a/cmd/airgapped/main.go +++ b/cmd/airgapped/main.go @@ -20,15 +20,11 @@ import ( "syscall" "time" + "github.com/lidofinance/dc4bc/airgapped" + client "github.com/lidofinance/dc4bc/client/types" "github.com/lidofinance/dc4bc/qr" - "github.com/syndtr/goleveldb/leveldb" - - client "github.com/lidofinance/dc4bc/client/types" - "golang.org/x/crypto/ssh/terminal" - - "github.com/lidofinance/dc4bc/airgapped" ) func init() { From d9dd09af87e638c04ce6e9b6d7ed1ea5d744499d Mon Sep 17 00:00:00 2001 From: vshvsh Date: Mon, 7 Dec 2020 12:50:25 +0300 Subject: [PATCH 8/8] Add seed backup, air gapped dkg key QR code guides --- HowTo.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/HowTo.md b/HowTo.md index 17b419e2..d5d953e6 100644 --- a/HowTo.md +++ b/HowTo.md @@ -78,14 +78,14 @@ A laptop that can run Tails (linux distribution) and has a webcam. Preferably it NB: If you know what you're doing set up an airgapped machine yourself or use one you already have. Tails live dvd/usb is not the best possible setup - it's just good enough in our opinion. -Backup media: Three usb drives at least 1gb in capacity. Preferably from different vendors so that they wouldn't fail all at the same time. These drives will store the secrets that are used in threshold signing ceremonies. You will keep these backup drives until withdrawals are enabled in eth2. +Backup media: paper wallet or another media you will use to backup bip39 word-based seed. You will keep this backup until withdrawals are enabled in eth2. -Plaintext media: 1+ gb usb drive or cd/dvd for non-secrets (executables and the like). If you choose USB drive, you'll be disposing of that particular drive (not backup ones!) by the end of a ceremony. +Plaintext media: 1+ gb usb drive or cd/dvd for non-secrets (executables and the like). If you choose USB drive, you'll be disposing of that particular drive by the end of a ceremony. 1. Make a bootable media for tails using https://tails.boum.org/install/index.en.html instructions. Live dvd is preferabe to a usb stick but usb stick is a valid option. Verification of an image signature per instructions on Tail's site is strongly recommended. 2. Prepare a plaintext media: run a script `sh airapped_folder/setup.sh` to set up a folder with one on your hot node, then copy/burn that folder on the plaintext media. It contains airapped node binary, firefox distribution, qr code reader html file and deploy script to easily copy all that to tails distribution. -2. If your airgapped laptop allows it, switch the wireless hardware off. Boot into Tails, selecting "no network connection" as an additional option on starting (always select this option on an airgapped machine). From this point on to the end of ceremony the machine shouldn't ever connect to the network; if you can afford having it permanently airgapped forever - can by useful in crypto - do it. -3. Use this instruction to make https://tails.boum.org/doc/encryption_and_privacy/encrypted_volumes/index.en.html encrypted volumes on all three backup media, all with strong password. You can use the same password. Make volumes small (<500mb): we don't need a lot of space for data and larger encrypted volumes are slower. +3. If your airgapped laptop allows it, switch the wireless hardware off. Boot into Tails, selecting "no network connection" as an additional option on starting (always select this option on an airgapped machine). From this point on to the end of ceremony the machine shouldn't ever connect to the network; if you can afford having it permanently airgapped forever - can by useful in crypto - do it. +4. Insert a plaintext media and run `sh ./deploy.sh` from there to copy all the needed files to your ephemeral home dir on tails. Now you've got all paraphernalia set up and can proceed with the guide further. @@ -109,7 +109,7 @@ $ ./dc4bc_airgapped --db_path ./stores/dc4bc_john_doe_airgapped_state --password ``` * `--db_path` Specifies the directory in which the Aigapped machibne state will be stored. If the directory that you specified does not exist, the Airgapped machine will generate new keys for you on startup. *N.B.: It is very important not to put your Airgapped machine state to `/tmp` or to occasionally lose it. Please make sure that you keep your Airgapped machine state in a safe place and make a backup.* -Backup it to the encrypted media immediately: if these keys are lost durin the ceremony, the dkg ceremony is. toast; if they are lost after, you won't be able to participate in the signing. +Backup the generated bip39 seed on a paper wallet; if you need to restore it, use the `set_seed` command in the airgapped executable's console. * `--password_expiration` Specifies the time in which you'll be able to use the Airgapped machine without re-entering your password. The Airgapped machine will ask you to create a new password during the first run. Make sure that the password is not lost. @@ -131,8 +131,11 @@ EcVs+nTi4iFERVeBHUPePDmvknBx95co7csKj0sZNuo= # Inside the airgapped shell: >>> show_dkg_pubkey sN7XbnvZCRtg650dVCCpPK/hQ/rMTSlxrdnvzJ75zV4W/Uzk9suvjNPtyRt7PDXLDTGNimn+4X/FcJj2K6vDdgqOrr9BHwMqJXnQykcv3IV0ggIUjpMMgdbQ+0iSseyq +>>> generate_dkg_pubkey_qr +A QR code with DKG public key was saved to: /tmp/dc4bc_qr_dkg_pub_key.gif ``` + **N.B.: You can start and stop both the Client node and the Airgapped machine any time you want given that the states are stored safely on your computer. When you restart the Airgapped machine, make sure that you run the `replay_operations_log` command exactly once before performing any actions — that will make the Airgapped machine replay the state and be ready for new actions. Please do not replay the log more than once during one Airgapped session, this might lead to undefined state.** Now you want to start the DKG procedure. *This action must be done exactly once by only one of the participants. The participants must decide who will send the initial message collectively.*