diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 79c86c52a..c2b92be46 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -157,6 +157,10 @@ var ( Name: "fast", Usage: "Enables fast syncing through state downloads", } + LightKDFFlag = cli.BoolFlag{ + Name: "lightkdf", + Usage: "Reduce KDF memory & CPU usage at some expense of KDF strength", + } // miner settings // TODO: refactor CPU vs GPU mining flags @@ -579,7 +583,13 @@ func MakeAccountManager(ctx *cli.Context) *accounts.Manager { if ctx.GlobalBool(TestNetFlag.Name) { dataDir += "/testnet" } - ks := crypto.NewKeyStorePassphrase(filepath.Join(dataDir, "keystore")) + scryptN := crypto.StandardScryptN + scryptP := crypto.StandardScryptP + if ctx.GlobalBool(LightKDFFlag.Name) { + scryptN = crypto.LightScryptN + scryptP = crypto.LightScryptP + } + ks := crypto.NewKeyStorePassphrase(filepath.Join(dataDir, "keystore"), scryptN, scryptP) return accounts.NewManager(ks) } diff --git a/common/natspec/natspec_e2e_test.go b/common/natspec/natspec_e2e_test.go index 706a294ec..5c0d43091 100644 --- a/common/natspec/natspec_e2e_test.go +++ b/common/natspec/natspec_e2e_test.go @@ -128,7 +128,7 @@ func testEth(t *testing.T) (ethereum *eth.Ethereum, err error) { db, _ := ethdb.NewMemDatabase() addr := common.HexToAddress(testAddress) core.WriteGenesisBlockForTesting(db, core.GenesisAccount{addr, common.String2Big(testBalance)}) - ks := crypto.NewKeyStorePassphrase(filepath.Join(tmp, "keystore")) + ks := crypto.NewKeyStorePassphrase(filepath.Join(tmp, "keystore"), crypto.LightScryptN, crypto.LightScryptP) am := accounts.NewManager(ks) keyb, err := crypto.HexToECDSA(testKey) if err != nil { diff --git a/common/natspec/natspec_e2e_test.go.orig b/common/natspec/natspec_e2e_test.go.orig index ae8e17ad9..601a9edbd 100644 --- a/common/natspec/natspec_e2e_test.go.orig +++ b/common/natspec/natspec_e2e_test.go.orig @@ -106,7 +106,7 @@ func testEth(t *testing.T) (ethereum *eth.Ethereum, err error) { } // create a testAddress - ks := crypto.NewKeyStorePassphrase("/tmp/eth-natspec/keystore") + ks := crypto.NewKeyStorePassphrase("/tmp/eth-natspec/keystore", crypto.LightScryptN, crypto.LightScryptP) am := accounts.NewManager(ks) testAccount, err := am.NewAccount("password") if err != nil { diff --git a/crypto/crypto.go b/crypto/crypto.go index 035d2ab80..8685d62d3 100644 --- a/crypto/crypto.go +++ b/crypto/crypto.go @@ -215,7 +215,7 @@ func Decrypt(prv *ecdsa.PrivateKey, ct []byte) ([]byte, error) { // Used only by block tests. func ImportBlockTestKey(privKeyBytes []byte) error { - ks := NewKeyStorePassphrase(common.DefaultDataDir() + "/keystore") + ks := NewKeyStorePassphrase(common.DefaultDataDir()+"/keystore", LightScryptN, LightScryptP) ecKey := ToECDSA(privKeyBytes) key := &Key{ Id: uuid.NewRandom(), diff --git a/crypto/key_store_passphrase.go b/crypto/key_store_passphrase.go index c7ee00987..94411d2f9 100644 --- a/crypto/key_store_passphrase.go +++ b/crypto/key_store_passphrase.go @@ -45,19 +45,29 @@ import ( const ( keyHeaderKDF = "scrypt" - // 2^18 / 8 / 1 uses 256MB memory and approx 1s CPU time on a modern CPU. - scryptN = 1 << 18 - scryptr = 8 - scryptp = 1 - scryptdkLen = 32 + + // n,r,p = 2^18, 8, 1 uses 256MB memory and approx 1s CPU time on a modern CPU. + StandardScryptN = 1 << 18 + StandardScryptP = 1 + + // n,r,p = 2^12, 8, 6 uses 4MB memory and approx 100ms CPU time on a modern CPU. + LightScryptN = 1 << 12 + LightScryptP = 6 + + scryptR = 8 + scryptDKLen = 32 ) type keyStorePassphrase struct { keysDirPath string + scryptN int + scryptP int + scryptR int + scryptDKLen int } -func NewKeyStorePassphrase(path string) KeyStore { - return &keyStorePassphrase{path} +func NewKeyStorePassphrase(path string, scryptN int, scryptP int) KeyStore { + return &keyStorePassphrase{path, scryptN, scryptP, scryptR, scryptDKLen} } func (ks keyStorePassphrase) GenerateNewKey(rand io.Reader, auth string) (key *Key, err error) { @@ -87,11 +97,10 @@ func (ks keyStorePassphrase) GetKeyAddresses() (addresses []common.Address, err func (ks keyStorePassphrase) StoreKey(key *Key, auth string) (err error) { authArray := []byte(auth) salt := randentropy.GetEntropyCSPRNG(32) - derivedKey, err := scrypt.Key(authArray, salt, scryptN, scryptr, scryptp, scryptdkLen) + derivedKey, err := scrypt.Key(authArray, salt, ks.scryptN, ks.scryptR, ks.scryptP, ks.scryptDKLen) if err != nil { return err } - encryptKey := derivedKey[:16] keyBytes := FromECDSA(key.PrivateKey) @@ -104,10 +113,10 @@ func (ks keyStorePassphrase) StoreKey(key *Key, auth string) (err error) { mac := Sha3(derivedKey[16:32], cipherText) scryptParamsJSON := make(map[string]interface{}, 5) - scryptParamsJSON["n"] = scryptN - scryptParamsJSON["r"] = scryptr - scryptParamsJSON["p"] = scryptp - scryptParamsJSON["dklen"] = scryptdkLen + scryptParamsJSON["n"] = ks.scryptN + scryptParamsJSON["r"] = ks.scryptR + scryptParamsJSON["p"] = ks.scryptP + scryptParamsJSON["dklen"] = ks.scryptDKLen scryptParamsJSON["salt"] = hex.EncodeToString(salt) cipherParamsJSON := cipherparamsJSON{ diff --git a/crypto/key_store_test.go b/crypto/key_store_test.go index de4a21dcf..5a44a6026 100644 --- a/crypto/key_store_test.go +++ b/crypto/key_store_test.go @@ -56,7 +56,7 @@ func TestKeyStorePlain(t *testing.T) { } func TestKeyStorePassphrase(t *testing.T) { - ks := NewKeyStorePassphrase(common.DefaultDataDir()) + ks := NewKeyStorePassphrase(common.DefaultDataDir(), LightScryptN, LightScryptP) pass := "foo" k1, err := ks.GenerateNewKey(randentropy.Reader, pass) if err != nil { @@ -82,7 +82,7 @@ func TestKeyStorePassphrase(t *testing.T) { } func TestKeyStorePassphraseDecryptionFail(t *testing.T) { - ks := NewKeyStorePassphrase(common.DefaultDataDir()) + ks := NewKeyStorePassphrase(common.DefaultDataDir(), LightScryptN, LightScryptP) pass := "foo" k1, err := ks.GenerateNewKey(randentropy.Reader, pass) if err != nil { @@ -110,7 +110,7 @@ func TestImportPreSaleKey(t *testing.T) { // python pyethsaletool.py genwallet // with password "foo" fileContent := "{\"encseed\": \"26d87f5f2bf9835f9a47eefae571bc09f9107bb13d54ff12a4ec095d01f83897494cf34f7bed2ed34126ecba9db7b62de56c9d7cd136520a0427bfb11b8954ba7ac39b90d4650d3448e31185affcd74226a68f1e94b1108e6e0a4a91cdd83eba\", \"ethaddr\": \"d4584b5f6229b7be90727b0fc8c6b91bb427821f\", \"email\": \"gustav.simonsson@gmail.com\", \"btcaddr\": \"1EVknXyFC68kKNLkh6YnKzW41svSRoaAcx\"}" - ks := NewKeyStorePassphrase(common.DefaultDataDir()) + ks := NewKeyStorePassphrase(common.DefaultDataDir(), LightScryptN, LightScryptP) pass := "foo" _, err := ImportPreSaleKey(ks, []byte(fileContent), pass) if err != nil { @@ -168,7 +168,7 @@ func TestV1_1(t *testing.T) { } func TestV1_2(t *testing.T) { - ks := NewKeyStorePassphrase("tests/v1") + ks := NewKeyStorePassphrase("tests/v1", LightScryptN, LightScryptP) addr := common.HexToAddress("cb61d5a9c4896fb9658090b597ef0e7be6f7b67e") k, err := ks.GetKey(addr, "g") if err != nil { diff --git a/tests/block_test_util.go b/tests/block_test_util.go index 4c329631a..6a2eb96a4 100644 --- a/tests/block_test_util.go +++ b/tests/block_test_util.go @@ -162,7 +162,7 @@ func runBlockTests(bt map[string]*BlockTest, skipTests []string) error { } func runBlockTest(test *BlockTest) error { - ks := crypto.NewKeyStorePassphrase(filepath.Join(common.DefaultDataDir(), "keystore")) + ks := crypto.NewKeyStorePassphrase(filepath.Join(common.DefaultDataDir(), "keystore"), crypto.StandardScryptN, crypto.StandardScryptP) am := accounts.NewManager(ks) db, _ := ethdb.NewMemDatabase() cfg := ð.Config{