From dda703032020b34e05c4bbec6070c859dac44be1 Mon Sep 17 00:00:00 2001
From: wonjoon <wnjoon@gmail.com>
Date: Fri, 10 Jan 2025 20:06:08 +0900
Subject: [PATCH 1/8] feat: add erc2335 structure

---
 crypto/erc2335/erc2335.go      | 65 ++++++++++++++++++++++++++++++++++
 crypto/erc2335/erc2335_test.go | 37 +++++++++++++++++++
 go.mod                         |  2 ++
 go.sum                         |  4 +++
 4 files changed, 108 insertions(+)
 create mode 100644 crypto/erc2335/erc2335.go
 create mode 100644 crypto/erc2335/erc2335_test.go

diff --git a/crypto/erc2335/erc2335.go b/crypto/erc2335/erc2335.go
new file mode 100644
index 000000000..9096a4530
--- /dev/null
+++ b/crypto/erc2335/erc2335.go
@@ -0,0 +1,65 @@
+package erc2335
+
+import (
+	"encoding/json"
+	"fmt"
+
+	"github.com/babylonlabs-io/babylon/crypto/bls12381"
+	"github.com/pkg/errors"
+	keystorev4 "github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4"
+)
+
+type Erc2335KeyStore struct {
+	Crypto  map[string]interface{} `json:"crypto"`
+	Version uint                   `json:"version"`
+	UUID    string                 `json:"uuid"`
+	Path    string                 `json:"path"`
+	Pubkey  string                 `json:"pubkey"`
+}
+
+// Encrypt encrypts a BLS private key using the EIP-2335 format
+func EncryptBLS(privKey *bls12381.PrivateKey, password string) ([]byte, error) {
+	if privKey == nil {
+		return nil, errors.New("private key cannot be nil")
+	}
+
+	encryptor := keystorev4.New()
+	cryptoFields, err := encryptor.Encrypt(*privKey, password)
+	if err != nil {
+		return nil, errors.Wrap(err, "failed to encrypt private key")
+	}
+
+	pubKey := privKey.PubKey().Bytes()
+
+	// Create the keystore json structure
+	keystoreJSON := Erc2335KeyStore{
+		Crypto:  cryptoFields,
+		Version: 4,
+		Pubkey:  fmt.Sprintf("%x", pubKey),
+	}
+
+	return json.Marshal(keystoreJSON)
+}
+
+// Decrypt decrypts an EIP-2335 keystore JSON and returns the BLS private key
+func DecryptBLS(keystoreJSON []byte, password string) (bls12381.PrivateKey, error) {
+	// Parse the keystore json
+	var keystore Erc2335KeyStore
+
+	if err := json.Unmarshal(keystoreJSON, &keystore); err != nil {
+		return nil, errors.Wrap(err, "failed to parse keystore json")
+	}
+
+	// Verify version
+	if keystore.Version != 4 {
+		return nil, fmt.Errorf("invalid keystore version: %d", keystore.Version)
+	}
+
+	encryptor := keystorev4.New()
+	privateKeyBytes, err := encryptor.Decrypt(keystore.Crypto, password)
+	if err != nil {
+		return nil, errors.Wrap(err, "failed to decrypt keystore")
+	}
+	return bls12381.PrivateKey(privateKeyBytes), nil
+
+}
diff --git a/crypto/erc2335/erc2335_test.go b/crypto/erc2335/erc2335_test.go
new file mode 100644
index 000000000..a53459798
--- /dev/null
+++ b/crypto/erc2335/erc2335_test.go
@@ -0,0 +1,37 @@
+package erc2335
+
+import (
+	"testing"
+
+	"github.com/babylonlabs-io/babylon/crypto/bls12381"
+	"github.com/test-go/testify/require"
+)
+
+func TestEncryptBLS(t *testing.T) {
+	// TODO
+	t.Run("create bls key", func(t *testing.T) {
+		// TODO
+		blsPrivKey := bls12381.GenPrivKey()
+		password := "password"
+
+		t.Run("encrypt bls key", func(t *testing.T) {
+			// TODO
+			encryptedBlsKey, err := EncryptBLS(&blsPrivKey, password)
+			require.NoError(t, err)
+			t.Logf("encrypted bls key: %s", encryptedBlsKey)
+
+			t.Run("decrypt bls key", func(t *testing.T) {
+				// TODO
+				decryptedBlsKey, err := DecryptBLS(encryptedBlsKey, password)
+				require.NoError(t, err)
+				require.Equal(t, blsPrivKey, decryptedBlsKey)
+			})
+
+			t.Run("decrypt bls key with wrong password", func(t *testing.T) {
+				// TODO
+				_, err := DecryptBLS(encryptedBlsKey, "wrong password")
+				require.Error(t, err)
+			})
+		})
+	})
+}
diff --git a/go.mod b/go.mod
index ad2796aa2..e63d5c966 100644
--- a/go.mod
+++ b/go.mod
@@ -233,9 +233,11 @@ require (
 	github.com/sourcegraph/conc v0.3.0 // indirect
 	github.com/strangelove-ventures/cometbft-client v0.1.0 // indirect
 	github.com/stretchr/objx v0.5.2 // indirect
+	github.com/test-go/testify v1.1.4
 	github.com/tidwall/btree v1.7.0 // indirect
 	github.com/tyler-smith/go-bip39 v1.1.0 // indirect
 	github.com/ulikunitz/xz v0.5.11 // indirect
+	github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.4.1
 	github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
 	github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
 	github.com/xeipuuv/gojsonschema v1.2.0 // indirect
diff --git a/go.sum b/go.sum
index 28eaac7bc..f699c7a91 100644
--- a/go.sum
+++ b/go.sum
@@ -1115,6 +1115,8 @@ github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70
 github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc=
 github.com/tendermint/go-amino v0.16.0 h1:GyhmgQKvqF82e2oZeuMSp9JTN0N09emoSZlb2lyGa2E=
 github.com/tendermint/go-amino v0.16.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME=
+github.com/test-go/testify v1.1.4 h1:Tf9lntrKUMHiXQ07qBScBTSA0dhYQlu83hswqelv1iE=
+github.com/test-go/testify v1.1.4/go.mod h1:rH7cfJo/47vWGdi4GPj16x3/t1xGOj2YxzmNQzk2ghU=
 github.com/tidwall/btree v1.7.0 h1:L1fkJH/AuEh5zBnnBbmTwQ5Lt+bRJ5A8EWecslvo9iI=
 github.com/tidwall/btree v1.7.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY=
 github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
@@ -1137,6 +1139,8 @@ github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijb
 github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
 github.com/vulpine-io/io-test v1.0.0 h1:Ot8vMh+ssm1VWDAwJ3U4C5qG9aRnr5YfQFZPNZBAUGI=
 github.com/vulpine-io/io-test v1.0.0/go.mod h1:X1I+p5GCxVX9m4nFd1HBtr2bVX9v1ZE6x8w+Obt36AU=
+github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.4.1 h1:9j7bpwjT9wmwBb54ZkBhTm1uNIlFFcCJXefd/YskZPw=
+github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.4.1/go.mod h1:+tI1VD76E1WINI+Nstg7RVGpUolL5ql10nu2YztMO/4=
 github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
 github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
 github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=

From 857ab38abf8988a7dfd118fe79ce9654c0a8cda1 Mon Sep 17 00:00:00 2001
From: wonjoon <wnjoon@gmail.com>
Date: Fri, 10 Jan 2025 20:09:18 +0900
Subject: [PATCH 2/8] feat: separate bls structure

---
 app/test_helpers.go                           |   2 +-
 .../cmd/genhelpers/bls_create_test.go         |   4 +-
 crypto/erc2335/erc2335.go                     |  21 +-
 crypto/erc2335/erc2335_test.go                |   5 +-
 go.mod                                        |   2 +-
 go.sum                                        |  23 ++-
 privval/bls.go                                | 166 ++++++++++++++++
 privval/bls_test.go                           |  54 ++++++
 privval/file.go                               | 180 ++++++++++--------
 test/e2e/initialization/config.go             |   6 +-
 test/e2e/initialization/node.go               |   2 +-
 testutil/datagen/genesiskey.go                |   4 +-
 testutil/helper/helper.go                     |   4 +-
 x/checkpointing/vote_ext_test.go              |   2 +-
 14 files changed, 360 insertions(+), 115 deletions(-)
 create mode 100644 privval/bls.go
 create mode 100644 privval/bls_test.go

diff --git a/app/test_helpers.go b/app/test_helpers.go
index a53305374..385a557d8 100644
--- a/app/test_helpers.go
+++ b/app/test_helpers.go
@@ -239,7 +239,7 @@ func SetupWithBitcoinConf(t *testing.T, isCheckTx bool, btcConf bbn.SupportedBtc
 
 	ps, err := signer.SetupTestPrivSigner()
 	require.NoError(t, err)
-	valPubKey := ps.WrappedPV.Key.PubKey
+	valPubKey := ps.WrappedPV.Key.CometPVKey.PubKey
 	// generate genesis account
 	acc := authtypes.NewBaseAccount(valPubKey.Address().Bytes(), &cosmosed.PubKey{Key: valPubKey.Bytes()}, 0, 0)
 	balance := banktypes.Balance{
diff --git a/cmd/babylond/cmd/genhelpers/bls_create_test.go b/cmd/babylond/cmd/genhelpers/bls_create_test.go
index 5b171fa90..c93d38de9 100644
--- a/cmd/babylond/cmd/genhelpers/bls_create_test.go
+++ b/cmd/babylond/cmd/genhelpers/bls_create_test.go
@@ -84,7 +84,7 @@ func Test_CmdCreateBls(t *testing.T) {
 	genKey, err := types.LoadGenesisKeyFromFile(outputFilePath)
 	require.NoError(t, err)
 	require.Equal(t, sdk.ValAddress(addr).String(), genKey.ValidatorAddress)
-	require.True(t, filePV.Key.BlsPubKey.Equal(*genKey.BlsKey.Pubkey))
-	require.Equal(t, filePV.Key.PubKey.Bytes(), genKey.ValPubkey.Bytes())
+	require.True(t, filePV.Key.BlsPVKey.PubKey.Equal(*genKey.BlsKey.Pubkey))
+	require.Equal(t, filePV.Key.CometPVKey.PubKey.Bytes(), genKey.ValPubkey.Bytes())
 	require.True(t, genKey.BlsKey.Pop.IsValid(*genKey.BlsKey.Pubkey, genKey.ValPubkey))
 }
diff --git a/crypto/erc2335/erc2335.go b/crypto/erc2335/erc2335.go
index 9096a4530..9559e4970 100644
--- a/crypto/erc2335/erc2335.go
+++ b/crypto/erc2335/erc2335.go
@@ -4,7 +4,6 @@ import (
 	"encoding/json"
 	"fmt"
 
-	"github.com/babylonlabs-io/babylon/crypto/bls12381"
 	"github.com/pkg/errors"
 	keystorev4 "github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4"
 )
@@ -17,20 +16,19 @@ type Erc2335KeyStore struct {
 	Pubkey  string                 `json:"pubkey"`
 }
 
-// Encrypt encrypts a BLS private key using the EIP-2335 format
-func EncryptBLS(privKey *bls12381.PrivateKey, password string) ([]byte, error) {
+// wonjoon: encrypt key pair to erc2335 keystore
+// available to handle all keys in []byte format
+func EncryptBLS(privKey, pubKey []byte, password string) ([]byte, error) {
 	if privKey == nil {
 		return nil, errors.New("private key cannot be nil")
 	}
 
 	encryptor := keystorev4.New()
-	cryptoFields, err := encryptor.Encrypt(*privKey, password)
+	cryptoFields, err := encryptor.Encrypt(privKey, password)
 	if err != nil {
 		return nil, errors.Wrap(err, "failed to encrypt private key")
 	}
 
-	pubKey := privKey.PubKey().Bytes()
-
 	// Create the keystore json structure
 	keystoreJSON := Erc2335KeyStore{
 		Crypto:  cryptoFields,
@@ -41,8 +39,8 @@ func EncryptBLS(privKey *bls12381.PrivateKey, password string) ([]byte, error) {
 	return json.Marshal(keystoreJSON)
 }
 
-// Decrypt decrypts an EIP-2335 keystore JSON and returns the BLS private key
-func DecryptBLS(keystoreJSON []byte, password string) (bls12381.PrivateKey, error) {
+// decrypt private key from erc2335 keystore
+func DecryptBLS(keystoreJSON []byte, password string) ([]byte, error) {
 	// Parse the keystore json
 	var keystore Erc2335KeyStore
 
@@ -56,10 +54,5 @@ func DecryptBLS(keystoreJSON []byte, password string) (bls12381.PrivateKey, erro
 	}
 
 	encryptor := keystorev4.New()
-	privateKeyBytes, err := encryptor.Decrypt(keystore.Crypto, password)
-	if err != nil {
-		return nil, errors.Wrap(err, "failed to decrypt keystore")
-	}
-	return bls12381.PrivateKey(privateKeyBytes), nil
-
+	return encryptor.Decrypt(keystore.Crypto, password)
 }
diff --git a/crypto/erc2335/erc2335_test.go b/crypto/erc2335/erc2335_test.go
index a53459798..e6ccc1702 100644
--- a/crypto/erc2335/erc2335_test.go
+++ b/crypto/erc2335/erc2335_test.go
@@ -12,11 +12,12 @@ func TestEncryptBLS(t *testing.T) {
 	t.Run("create bls key", func(t *testing.T) {
 		// TODO
 		blsPrivKey := bls12381.GenPrivKey()
+		blsPubKey := blsPrivKey.PubKey().Bytes()
 		password := "password"
 
 		t.Run("encrypt bls key", func(t *testing.T) {
 			// TODO
-			encryptedBlsKey, err := EncryptBLS(&blsPrivKey, password)
+			encryptedBlsKey, err := EncryptBLS(blsPrivKey, blsPubKey, password)
 			require.NoError(t, err)
 			t.Logf("encrypted bls key: %s", encryptedBlsKey)
 
@@ -24,7 +25,7 @@ func TestEncryptBLS(t *testing.T) {
 				// TODO
 				decryptedBlsKey, err := DecryptBLS(encryptedBlsKey, password)
 				require.NoError(t, err)
-				require.Equal(t, blsPrivKey, decryptedBlsKey)
+				require.Equal(t, blsPrivKey, bls12381.PrivateKey(decryptedBlsKey))
 			})
 
 			t.Run("decrypt bls key with wrong password", func(t *testing.T) {
diff --git a/go.mod b/go.mod
index e63d5c966..e3efba2b1 100644
--- a/go.mod
+++ b/go.mod
@@ -237,7 +237,7 @@ require (
 	github.com/tidwall/btree v1.7.0 // indirect
 	github.com/tyler-smith/go-bip39 v1.1.0 // indirect
 	github.com/ulikunitz/xz v0.5.11 // indirect
-	github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.4.1
+	github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.1.3
 	github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
 	github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
 	github.com/xeipuuv/gojsonschema v1.2.0 // indirect
diff --git a/go.sum b/go.sum
index f699c7a91..8788e3f95 100644
--- a/go.sum
+++ b/go.sum
@@ -494,6 +494,9 @@ github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
 github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
 github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
 github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
+github.com/ferranbt/fastssz v0.0.0-20210120143747-11b9eff30ea9/go.mod h1:DyEu2iuLBnb/T51BlsiO3yLYdJC6UbGMrIkqK1KmQxM=
+github.com/ferranbt/fastssz v0.1.2 h1:Dky6dXlngF6Qjc+EfDipAkE83N5I5DE68bY6O0VLNPk=
+github.com/ferranbt/fastssz v0.1.2/go.mod h1:X5UPrE2u1UJjxHA8X54u04SBwdAQjG2sFtWs39YxyWs=
 github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
 github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
 github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
@@ -672,6 +675,7 @@ github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3
 github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
 github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
 github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@@ -766,6 +770,8 @@ github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE
 github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
 github.com/hdevalence/ed25519consensus v0.1.0 h1:jtBwzzcHuTmFrQN6xQZn6CQEO/V9f7HsjsjeEZ6auqU=
 github.com/hdevalence/ed25519consensus v0.1.0/go.mod h1:w3BHWjwJbFU29IRHL1Iqkw3sus+7FctEyM4RqDxYNzo=
+github.com/herumi/bls-eth-go-binary v0.0.0-20210130185500-57372fb27371 h1:LEw2KkKciJEr3eKDLzdZ/rjzSR6Y+BS6xKxdA78Bq6s=
+github.com/herumi/bls-eth-go-binary v0.0.0-20210130185500-57372fb27371/go.mod h1:luAnRm3OsMQeokhGzpYmc0ZKwawY7o87PUEP11Z7r7U=
 github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao=
 github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA=
 github.com/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU=
@@ -828,6 +834,8 @@ github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYs
 github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM=
 github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
 github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
+github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4=
+github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
 github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
 github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
 github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
@@ -877,6 +885,9 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5
 github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
 github.com/minio/highwayhash v1.0.3 h1:kbnuUMoHYyVl7szWjSxJnxw11k2U709jqFPPmIUyD6Q=
 github.com/minio/highwayhash v1.0.3/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ=
+github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
+github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g=
+github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM=
 github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
 github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
 github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
@@ -888,6 +899,8 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4
 github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
 github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
 github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
+github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
 github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
 github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
 github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY=
@@ -1139,8 +1152,12 @@ github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijb
 github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
 github.com/vulpine-io/io-test v1.0.0 h1:Ot8vMh+ssm1VWDAwJ3U4C5qG9aRnr5YfQFZPNZBAUGI=
 github.com/vulpine-io/io-test v1.0.0/go.mod h1:X1I+p5GCxVX9m4nFd1HBtr2bVX9v1ZE6x8w+Obt36AU=
-github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.4.1 h1:9j7bpwjT9wmwBb54ZkBhTm1uNIlFFcCJXefd/YskZPw=
-github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.4.1/go.mod h1:+tI1VD76E1WINI+Nstg7RVGpUolL5ql10nu2YztMO/4=
+github.com/wealdtech/go-eth2-types/v2 v2.5.2 h1:tiA6T88M6XQIbrV5Zz53l1G5HtRERcxQfmET225V4Ls=
+github.com/wealdtech/go-eth2-types/v2 v2.5.2/go.mod h1:8lkNUbgklSQ4LZ2oMSuxSdR7WwJW3L9ge1dcoCVyzws=
+github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.1.3 h1:SxrDVSr+oXuT1x8kZt4uWqNCvv5xXEGV9zd7cuSrZS8=
+github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.1.3/go.mod h1:qiIimacW5NhVRy8o+YxWo9YrecXqDAKKbL0+sOa0SJ4=
+github.com/wealdtech/go-eth2-wallet-types/v2 v2.8.2 h1:264/meVYWt1wFw6Mtn+xwkZkXjID42gNra4rycoiDXI=
+github.com/wealdtech/go-eth2-wallet-types/v2 v2.8.2/go.mod h1:k6kmiKWSWBTd4OxFifTEkPaBLhZspnO2KFD5XJY9nqg=
 github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
 github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
 github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
@@ -1215,6 +1232,7 @@ golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8U
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
 golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
@@ -1461,6 +1479,7 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
 golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
diff --git a/privval/bls.go b/privval/bls.go
new file mode 100644
index 000000000..71118fe25
--- /dev/null
+++ b/privval/bls.go
@@ -0,0 +1,166 @@
+package privval
+
+import (
+	"encoding/json"
+	"fmt"
+	"os"
+	"path/filepath"
+
+	"github.com/babylonlabs-io/babylon/crypto/bls12381"
+	"github.com/babylonlabs-io/babylon/crypto/erc2335"
+	cmtcfg "github.com/cometbft/cometbft/config"
+	cmtos "github.com/cometbft/cometbft/libs/os"
+	"github.com/cometbft/cometbft/libs/tempfile"
+	"github.com/cosmos/go-bip39"
+)
+
+const DefaultBlsKeyName = "bls_key.json"
+
+type BlsPV struct {
+	Key BlsPVKey
+}
+
+type BlsPVKey struct {
+	PubKey   bls12381.PublicKey
+	PrivKey  bls12381.PrivateKey
+	filePath string
+}
+
+// todo: where
+func NewBlsPV(privKey bls12381.PrivateKey, keyFilePath string) *BlsPV {
+	return &BlsPV{
+		Key: BlsPVKey{
+			PubKey:   privKey.PubKey(),
+			PrivKey:  privKey,
+			filePath: keyFilePath,
+		},
+	}
+}
+
+func GenBlsPV(keyFilePath string) *BlsPV {
+	return NewBlsPV(bls12381.GenPrivKey(), keyFilePath)
+}
+
+func LoadBlsPV(keyFilePath, password string) *BlsPV {
+
+	keyJSONBytes, err := os.ReadFile(keyFilePath)
+	if err != nil {
+		cmtos.Exit(fmt.Sprintf("failed to read BLS file: %v", err.Error()))
+	}
+
+	// decrypt bls key from erc2335 type of structure
+	privKey, err := erc2335.DecryptBLS(keyJSONBytes, password)
+	if err != nil {
+		cmtos.Exit(fmt.Sprintf("failed to decrypt BLS key: %v", err.Error()))
+	}
+
+	blsPrivKey := bls12381.PrivateKey(privKey)
+
+	return &BlsPV{
+		Key: BlsPVKey{
+			PubKey:   blsPrivKey.PubKey(),
+			PrivKey:  blsPrivKey,
+			filePath: keyFilePath,
+		},
+	}
+}
+
+func LoadOrGenBlsPV(keyFilePath, password string) *BlsPV {
+
+	var pv *BlsPV
+	if cmtos.FileExists(keyFilePath) {
+		pv = LoadBlsPV(keyFilePath, password)
+	} else {
+		pv = GenBlsPV(keyFilePath)
+		pv.Save(password)
+	}
+	return pv
+}
+
+func (pv *BlsPV) Save(password string) {
+	pv.Key.Save(password)
+}
+
+func (k *BlsPVKey) Save(password string) {
+	outFile := k.filePath
+	if outFile == "" {
+		panic("cannot save PrivValidator BLS key: filePath not set")
+	}
+
+	// encrypt the bls12381 key to erc2335 type
+	erc2335BlsPvKey, err := erc2335.EncryptBLS(k.PrivKey, k.PubKey.Bytes(), password)
+	if err != nil {
+		panic(err)
+	}
+
+	// Parse the encrypted key back to Erc2335KeyStore structure
+	var keystore erc2335.Erc2335KeyStore
+	if err := json.Unmarshal(erc2335BlsPvKey, &keystore); err != nil {
+		panic(err)
+	}
+
+	jsonBytes, err := json.MarshalIndent(keystore, "", "  ")
+	if err != nil {
+		panic(err)
+	}
+
+	if err := tempfile.WriteFileAtomic(outFile, jsonBytes, 0600); err != nil {
+		panic(err)
+	}
+}
+
+func InitializeNodeValidatorBlsFiles(config *BlsConfig, password string) (blsPubKey []byte, err error) {
+	return InitializeNodeValidatorBlsFilesFromMnemonic(config, "", password)
+}
+
+func InitializeNodeValidatorBlsFilesFromMnemonic(config *BlsConfig, mnemonic, password string) (blsPubKey []byte, err error) {
+	if len(mnemonic) > 0 && !bip39.IsMnemonicValid(mnemonic) {
+		return nil, fmt.Errorf("invalid mnemonic")
+	}
+
+	blsKeyFile := config.BlsKeyFile()
+	if err := cmtos.EnsureDir(filepath.Dir(blsKeyFile), 0777); err != nil {
+		return nil, fmt.Errorf("could not create directory %q: %w", filepath.Dir(blsKeyFile), err)
+	}
+
+	var blsPv *BlsPV
+	if len(mnemonic) == 0 {
+		blsPv = LoadOrGenBlsPV(blsKeyFile, password)
+	} else {
+		privKey := bls12381.GenPrivKeyFromSecret([]byte(mnemonic))
+		blsPv = NewBlsPV(privKey, blsKeyFile)
+		blsPv.Save(password)
+	}
+
+	return blsPv.Key.PubKey.Bytes(), nil
+}
+
+// -------------------------------------------------------------------------------
+// ---------------------------- BLS Config ---------------------------------------
+// -------------------------------------------------------------------------------
+
+type BlsConfig struct {
+	RootDir    string `mapstructure:"home"`
+	BlsKeyPath string `mapstructure:"bls_key_file"`
+}
+
+func DefaultBlsConfig() BlsConfig {
+	return BlsConfig{
+		RootDir:    cmtcfg.DefaultDataDir,
+		BlsKeyPath: filepath.Join(cmtcfg.DefaultDataDir, DefaultBlsKeyName),
+	}
+}
+
+func SetBlsConfig(rootDir, blsKeyPath string) BlsConfig {
+	return BlsConfig{
+		RootDir:    rootDir,
+		BlsKeyPath: blsKeyPath,
+	}
+}
+
+func (cfg BlsConfig) BlsKeyFile() string {
+	if filepath.IsAbs(cfg.BlsKeyPath) {
+		return cfg.BlsKeyPath
+	}
+	return filepath.Join(cfg.RootDir, cfg.BlsKeyPath)
+}
diff --git a/privval/bls_test.go b/privval/bls_test.go
new file mode 100644
index 000000000..b86bedade
--- /dev/null
+++ b/privval/bls_test.go
@@ -0,0 +1,54 @@
+package privval
+
+import (
+	"os"
+	"path/filepath"
+	"testing"
+
+	"github.com/babylonlabs-io/babylon/crypto/bls12381"
+	cmtcfg "github.com/cometbft/cometbft/config"
+	"github.com/test-go/testify/assert"
+)
+
+func TestNewBlsPV(t *testing.T) {
+	pv := NewBlsPV(bls12381.GenPrivKey(), "test")
+	assert.NotNil(t, pv)
+}
+
+func TestCleanUp(t *testing.T) {
+	blsKeyFilePath := DefaultBlsConfig().BlsKeyFile()
+	t.Log("bls key file path", blsKeyFilePath)
+	cleanup(blsKeyFilePath)
+}
+
+func TestLoadOrGenBlsPV(t *testing.T) {
+
+	t.Run("clean file path", func(t *testing.T) {
+		blsKeyFilePath := DefaultBlsConfig().BlsKeyFile()
+		t.Log("bls key file path", blsKeyFilePath)
+		cleanup(blsKeyFilePath)
+	})
+
+	t.Run("set default config", func(t *testing.T) {
+		blsCfg := DefaultBlsConfig()
+		assert.NotNil(t, blsCfg)
+		assert.Equal(t, blsCfg.RootDir, cmtcfg.DefaultDataDir)
+		assert.Equal(t, blsCfg.BlsKeyPath, filepath.Join(cmtcfg.DefaultDataDir, DefaultBlsKeyName))
+
+		t.Run("generate key without mnemonic", func(t *testing.T) {
+			blsPubKey, err := InitializeNodeValidatorBlsFiles(&blsCfg, "password")
+			assert.NoError(t, err)
+			assert.NotNil(t, blsPubKey)
+		})
+
+		t.Run("load key with password", func(t *testing.T) {
+			blsPubKey, err := InitializeNodeValidatorBlsFiles(&blsCfg, "password")
+			assert.NoError(t, err)
+			assert.NotNil(t, blsPubKey)
+		})
+	})
+}
+
+func cleanup(blsKeyPath string) {
+	_ = os.RemoveAll(filepath.Dir(blsKeyPath))
+}
diff --git a/privval/file.go b/privval/file.go
index ebfac1314..6b11e9028 100644
--- a/privval/file.go
+++ b/privval/file.go
@@ -13,7 +13,6 @@ import (
 	"github.com/cometbft/cometbft/libs/tempfile"
 	"github.com/cometbft/cometbft/privval"
 	cmtproto "github.com/cometbft/cometbft/proto/tendermint/types"
-	"github.com/cometbft/cometbft/types"
 	"github.com/cosmos/cosmos-sdk/crypto/codec"
 	sdk "github.com/cosmos/cosmos-sdk/types"
 
@@ -47,52 +46,40 @@ func voteToStep(vote *cmtproto.Vote) int8 {
 
 // WrappedFilePVKey wraps FilePVKey with BLS keys.
 type WrappedFilePVKey struct {
-	DelegatorAddress string              `json:"acc_address"`
-	Address          types.Address       `json:"address"`
-	PubKey           cmtcrypto.PubKey    `json:"pub_key"`
-	PrivKey          cmtcrypto.PrivKey   `json:"priv_key"`
-	BlsPubKey        bls12381.PublicKey  `json:"bls_pub_key"`
-	BlsPrivKey       bls12381.PrivateKey `json:"bls_priv_key"`
-
-	filePath string
+	// wonjoon/feat: separate cometPvKey and blsPvKey
+	CometPVKey privval.FilePVKey
+	BlsPVKey   BlsPVKey
+
+	// wonjoon/todo: remove
+	DelegatorAddress string `json:"acc_address"`
 }
 
-// Save persists the FilePVKey to its filePath.
+// wonjoon/todo: remove or refactoring
 func (pvKey WrappedFilePVKey) Save() {
-	outFile := pvKey.filePath
-	if outFile == "" {
-		panic("cannot save PrivValidator key: filePath not set")
-	}
-
-	jsonBytes, err := cmtjson.MarshalIndent(pvKey, "", "  ")
-	if err != nil {
-		panic(err)
-	}
-
-	if err := tempfile.WriteFileAtomic(outFile, jsonBytes, 0600); err != nil {
-		panic(err)
-	}
+	pvKey.CometPVKey.Save()
+	pvKey.BlsPVKey.Save("")
 }
 
-// -------------------------------------------------------------------------------
-
-// WrappedFilePV wraps FilePV with WrappedFilePVKey.
 type WrappedFilePV struct {
 	Key           WrappedFilePVKey
 	LastSignState privval.FilePVLastSignState
 }
 
-// NewWrappedFilePV wraps FilePV
-func NewWrappedFilePV(privKey cmtcrypto.PrivKey, blsPrivKey bls12381.PrivateKey, keyFilePath, stateFilePath string) *WrappedFilePV {
-	filePV := privval.NewFilePV(privKey, keyFilePath, stateFilePath)
+// wonjoon/todo: refactoring
+func NewWrappedFilePV(
+	cometPrivKey cmtcrypto.PrivKey,
+	blsPrivKey bls12381.PrivateKey,
+	cometKeyFilePath, cometStateFilePath string,
+	// blsKeyFilePath string,
+) *WrappedFilePV {
+	filePV := privval.NewFilePV(cometPrivKey, cometKeyFilePath, cometStateFilePath)
 	return &WrappedFilePV{
 		Key: WrappedFilePVKey{
-			Address:    privKey.PubKey().Address(),
-			PubKey:     privKey.PubKey(),
-			PrivKey:    privKey,
-			BlsPubKey:  blsPrivKey.PubKey(),
-			BlsPrivKey: blsPrivKey,
-			filePath:   keyFilePath,
+			CometPVKey: filePV.Key,
+			BlsPVKey: NewBlsPV(
+				blsPrivKey,
+				DefaultBlsConfig().BlsKeyFile(), // blsKeyFilePath,
+			).Key,
 		},
 		LastSignState: filePV.LastSignState,
 	}
@@ -100,88 +87,110 @@ func NewWrappedFilePV(privKey cmtcrypto.PrivKey, blsPrivKey bls12381.PrivateKey,
 
 // GenWrappedFilePV generates a new validator with randomly generated private key
 // and sets the filePaths, but does not call Save().
-func GenWrappedFilePV(keyFilePath, stateFilePath string) *WrappedFilePV {
-	return NewWrappedFilePV(ed25519.GenPrivKey(), bls12381.GenPrivKey(), keyFilePath, stateFilePath)
+// wonjoon/todo: refactoring
+func GenWrappedFilePV(
+	cometKeyFilePath, cometStateFilePath string,
+	//blsKeyFilePath string,
+) *WrappedFilePV {
+	return NewWrappedFilePV(
+		ed25519.GenPrivKey(),
+		bls12381.GenPrivKey(),
+		cometKeyFilePath,
+		cometStateFilePath,
+		//blsKeyFilePath,
+	)
 }
 
 // LoadWrappedFilePV loads a FilePV from the filePaths.  The FilePV handles double
 // signing prevention by persisting data to the stateFilePath.  If either file path
 // does not exist, the program will exit.
-func LoadWrappedFilePV(keyFilePath, stateFilePath string) *WrappedFilePV {
-	return loadWrappedFilePV(keyFilePath, stateFilePath, true)
+// wonjoon/todo: refactoring
+func LoadWrappedFilePV(
+	cometKeyFilePath, cometStateFilePath string,
+	//  blsKeyFilePath, blsPassword string
+) *WrappedFilePV {
+	return loadWrappedFilePV(
+		cometKeyFilePath,
+		cometStateFilePath,
+		DefaultBlsConfig().BlsKeyFile(), // blsKeyFilePath,
+		"",                              // blsPassword,
+		true,
+	)
 }
 
 // LoadWrappedFilePVEmptyState loads a FilePV from the given keyFilePath, with an empty LastSignState.
 // If the keyFilePath does not exist, the program will exit.
-func LoadWrappedFilePVEmptyState(keyFilePath, stateFilePath string) *WrappedFilePV {
-	return loadWrappedFilePV(keyFilePath, stateFilePath, false)
+// wonjoon/todo: refactoring
+func LoadWrappedFilePVEmptyState(
+	cometKeyFilePath, cometStateFilePath string,
+	//  blsKeyFilePath, blsPassword string
+) *WrappedFilePV {
+	return loadWrappedFilePV(
+		cometKeyFilePath,
+		cometStateFilePath,
+		DefaultBlsConfig().BlsKeyFile(), // blsKeyFilePath,
+		"",                              // blsPassword,
+		false,
+	)
 }
 
 // If loadState is true, we load from the stateFilePath. Otherwise, we use an empty LastSignState.
-func loadWrappedFilePV(keyFilePath, stateFilePath string, loadState bool) *WrappedFilePV {
-	keyFilePath = filepath.Clean(keyFilePath)
-	keyJSONBytes, err := os.ReadFile(keyFilePath)
-	if err != nil {
-		cmtos.Exit(err.Error())
-	}
-	pvKey := WrappedFilePVKey{}
-	err = cmtjson.Unmarshal(keyJSONBytes, &pvKey)
-	if err != nil {
-		cmtos.Exit(fmt.Sprintf("Error reading PrivValidator key from %v: %v\n", keyFilePath, err))
-	}
-
-	// overwrite pubkey and address for convenience
-	pvKey.PubKey = pvKey.PrivKey.PubKey()
-	pvKey.Address = pvKey.PubKey.Address()
-	pvKey.BlsPubKey = pvKey.BlsPrivKey.PubKey()
-	pvKey.filePath = keyFilePath
-
-	pvState := privval.FilePVLastSignState{}
+func loadWrappedFilePV(cometKeyFilePath, cometStateFilePath, blsKeyFilePath, blsPassword string, loadState bool) *WrappedFilePV {
 
+	// comet
+	var cometPv *privval.FilePV
 	if loadState {
-		stateFilePath := filepath.Clean(stateFilePath)
-		stateJSONBytes, err := os.ReadFile(stateFilePath)
-		if err != nil {
-			cmtos.Exit(err.Error())
-		}
-		err = cmtjson.Unmarshal(stateJSONBytes, &pvState)
-		if err != nil {
-			cmtos.Exit(fmt.Sprintf("Error reading PrivValidator state from %v: %v\n", stateFilePath, err))
-		}
+		cometPv = privval.LoadFilePV(cometKeyFilePath, cometStateFilePath)
+	} else {
+		cometPv = privval.LoadFilePVEmptyState(cometKeyFilePath, cometStateFilePath)
 	}
 
-	// adding path is not needed
-	// pvState.filePath = stateFilePath
+	// bls
+	blsPv := LoadBlsPV(blsKeyFilePath, blsPassword)
 
 	return &WrappedFilePV{
-		Key:           pvKey,
-		LastSignState: pvState,
+		Key: WrappedFilePVKey{
+			CometPVKey: cometPv.Key,
+			BlsPVKey:   blsPv.Key,
+		},
+		LastSignState: cometPv.LastSignState,
 	}
 }
 
 // LoadOrGenWrappedFilePV loads a FilePV from the given filePaths
 // or else generates a new one and saves it to the filePaths.
-func LoadOrGenWrappedFilePV(keyFilePath, stateFilePath string) *WrappedFilePV {
-	var pv *WrappedFilePV
-	if cmtos.FileExists(keyFilePath) {
-		pv = LoadWrappedFilePV(keyFilePath, stateFilePath)
-	} else {
-		pv = GenWrappedFilePV(keyFilePath, stateFilePath)
-		pv.Save()
+// wonjoon/todo: refactoring
+func LoadOrGenWrappedFilePV(
+	cometKeyFilePath, cometStateFilePath string,
+	// blsKeyFilePath, blsPassword string,
+) *WrappedFilePV {
+	cometPv := privval.LoadOrGenFilePV(cometKeyFilePath, cometStateFilePath)
+	blsPv := LoadOrGenBlsPV(
+		DefaultBlsConfig().BlsKeyFile(), // blsKeyFilePath,
+		"",                              // blsPassword,
+	)
+	return &WrappedFilePV{
+		Key: WrappedFilePVKey{
+			CometPVKey: cometPv.Key,
+			BlsPVKey:   blsPv.Key,
+		},
+		LastSignState: cometPv.LastSignState,
 	}
-	return pv
 }
 
 // ExportGenBls writes a {address, bls_pub_key, pop, and pub_key} into a json file
 func (pv *WrappedFilePV) ExportGenBls(filePath string) (outputFileName string, err error) {
+	// file check
 	if !cmtos.FileExists(filePath) {
 		return outputFileName, errors.New("export file path does not exist")
 	}
 
+	// ---- Should be removed ---//
 	valAddress := pv.GetAddress()
 	if valAddress.Empty() {
 		return outputFileName, errors.New("validator address should not be empty")
 	}
+	//-------------------------//
 
 	validatorKey, err := NewValidatorKeys(pv.GetValPrivKey(), pv.GetBlsPrivKey())
 	if err != nil {
@@ -229,15 +238,15 @@ func (pv *WrappedFilePV) SetAccAddress(addr sdk.AccAddress) {
 // GetPubKey returns the public key of the validator.
 // Implements PrivValidator.
 func (pv *WrappedFilePV) GetPubKey() (cmtcrypto.PubKey, error) {
-	return pv.Key.PubKey, nil
+	return pv.Key.CometPVKey.PubKey, nil
 }
 
 func (pv *WrappedFilePV) GetValPrivKey() cmtcrypto.PrivKey {
-	return pv.Key.PrivKey
+	return pv.Key.CometPVKey.PrivKey
 }
 
 func (pv *WrappedFilePV) GetBlsPrivKey() bls12381.PrivateKey {
-	return pv.Key.BlsPrivKey
+	return pv.Key.BlsPVKey.PrivKey
 }
 
 func (pv *WrappedFilePV) SignMsgWithBls(msg []byte) (bls12381.Signature, error) {
@@ -260,12 +269,15 @@ func (pv *WrappedFilePV) GetValidatorPubkey() (cmtcrypto.PubKey, error) {
 	return pv.GetPubKey()
 }
 
+// ---- Should be removed ---//₩
 // Save persists the FilePV to disk.
 func (pv *WrappedFilePV) Save() {
 	pv.Key.Save()
 	pv.LastSignState.Save()
 }
 
+//-------------------------//
+
 // Reset resets all fields in the FilePV.
 // NOTE: Unsafe!
 func (pv *WrappedFilePV) Reset() {
diff --git a/test/e2e/initialization/config.go b/test/e2e/initialization/config.go
index c1f4da6f7..e61985e7c 100644
--- a/test/e2e/initialization/config.go
+++ b/test/e2e/initialization/config.go
@@ -404,13 +404,13 @@ func updateCheckpointingGenesis(c *internalChain) func(*checkpointingtypes.Genes
 				continue
 			}
 
-			proofOfPossession, err := privval.BuildPoP(node.consensusKey.PrivKey, node.consensusKey.BlsPrivKey)
+			proofOfPossession, err := privval.BuildPoP(node.consensusKey.CometPVKey.PrivKey, node.consensusKey.BlsPVKey.PrivKey)
 
 			if err != nil {
 				panic("It should be possible to build proof of possession from validator private keys")
 			}
 
-			valPubKey, err := cryptocodec.FromCmtPubKeyInterface(node.consensusKey.PubKey)
+			valPubKey, err := cryptocodec.FromCmtPubKeyInterface(node.consensusKey.CometPVKey.PubKey)
 
 			if err != nil {
 				panic("It should be possible to retrieve validator public key")
@@ -427,7 +427,7 @@ func updateCheckpointingGenesis(c *internalChain) func(*checkpointingtypes.Genes
 			genKey := &checkpointingtypes.GenesisKey{
 				ValidatorAddress: va.String(),
 				BlsKey: &checkpointingtypes.BlsKey{
-					Pubkey: &node.consensusKey.BlsPubKey,
+					Pubkey: &node.consensusKey.BlsPVKey.PubKey,
 					Pop:    proofOfPossession,
 				},
 				ValPubkey: valPubKey.(*ed25519.PubKey),
diff --git a/test/e2e/initialization/node.go b/test/e2e/initialization/node.go
index 7452bdd58..0c710c46e 100644
--- a/test/e2e/initialization/node.go
+++ b/test/e2e/initialization/node.go
@@ -90,7 +90,7 @@ func (n *internalNode) buildCreateValidatorMsg(amount sdk.Coin) (sdk.Msg, error)
 	// get the initial validator min self delegation
 	minSelfDelegation, _ := math.NewIntFromString("1")
 
-	valPubKey, err := cryptocodec.FromCmtPubKeyInterface(n.consensusKey.PubKey)
+	valPubKey, err := cryptocodec.FromCmtPubKeyInterface(n.consensusKey.CometPVKey.PubKey)
 	if err != nil {
 		return nil, err
 	}
diff --git a/testutil/datagen/genesiskey.go b/testutil/datagen/genesiskey.go
index dbc39dda2..aa77c8be8 100644
--- a/testutil/datagen/genesiskey.go
+++ b/testutil/datagen/genesiskey.go
@@ -99,8 +99,8 @@ func GenesisValidatorSetWithPrivSigner(numVals int) (*GenesisValidators, *appsig
 	}
 	signerVal := &GenesisKeyWithBLS{
 		GenesisKey: *signerGenesisKey,
-		PrivateKey: ps.WrappedPV.Key.BlsPrivKey,
-		PrivKey:    ps.WrappedPV.Key.PrivKey,
+		PrivateKey: ps.WrappedPV.Key.BlsPVKey.PrivKey,
+		PrivKey:    ps.WrappedPV.Key.CometPVKey.PrivKey,
 	}
 	genesisVals, err := GenesisValidatorSet(numVals)
 	if err != nil {
diff --git a/testutil/helper/helper.go b/testutil/helper/helper.go
index 46ba8d9dd..dd6eab288 100644
--- a/testutil/helper/helper.go
+++ b/testutil/helper/helper.go
@@ -59,7 +59,7 @@ func NewHelper(t *testing.T) *Helper {
 // the privSigner is the 0th validator in valSet
 func NewHelperWithValSet(t *testing.T, valSet *datagen.GenesisValidators, privSigner *signer.PrivSigner) *Helper {
 	// generate the genesis account
-	signerPubKey := privSigner.WrappedPV.Key.PubKey
+	signerPubKey := privSigner.WrappedPV.Key.CometPVKey.PubKey
 	acc := authtypes.NewBaseAccount(signerPubKey.Address().Bytes(), &cosmosed.PubKey{Key: signerPubKey.Bytes()}, 0, 0)
 	privSigner.WrappedPV.Key.DelegatorAddress = acc.Address
 	valSet.Keys[0].ValidatorAddress = privSigner.WrappedPV.GetAddress().String()
@@ -97,7 +97,7 @@ func NewHelperWithValSet(t *testing.T, valSet *datagen.GenesisValidators, privSi
 // included in the validator set
 func NewHelperWithValSetNoSigner(t *testing.T, valSet *datagen.GenesisValidators, privSigner *signer.PrivSigner) *Helper {
 	// generate the genesis account
-	signerPubKey := privSigner.WrappedPV.Key.PubKey
+	signerPubKey := privSigner.WrappedPV.Key.CometPVKey.PubKey
 	acc := authtypes.NewBaseAccount(signerPubKey.Address().Bytes(), &cosmosed.PubKey{Key: signerPubKey.Bytes()}, 0, 0)
 	privSigner.WrappedPV.Key.DelegatorAddress = acc.Address
 	// set a random validator address instead of the privSigner's
diff --git a/x/checkpointing/vote_ext_test.go b/x/checkpointing/vote_ext_test.go
index 90c57342f..81ecdbe00 100644
--- a/x/checkpointing/vote_ext_test.go
+++ b/x/checkpointing/vote_ext_test.go
@@ -188,7 +188,7 @@ func FuzzExtendVote_EmptyBLSPrivKey(f *testing.F) {
 		require.NoError(t, err)
 
 		// set the BLS private key to be nil to trigger panic
-		ps.WrappedPV.Key.BlsPrivKey = nil
+		ps.WrappedPV.Key.BlsPVKey.PrivKey = nil
 		helper := testhelper.NewHelperWithValSet(t, genesisValSet, ps)
 		ek := helper.App.EpochingKeeper
 

From 255d25c8f663b28d9ca13d278e5d0948eacd8e6c Mon Sep 17 00:00:00 2001
From: wonjoon <wnjoon@gmail.com>
Date: Fri, 10 Jan 2025 20:11:27 +0900
Subject: [PATCH 3/8] fix: get bls password from prompt and create bls
 structure in create-bls-key

---
 app/signer/private.go              |  30 ++++-
 client/flags/flags.go              |   5 +
 cmd/babylond/cmd/create_bls_key.go |  38 +++---
 cmd/babylond/cmd/init.go           | 195 +++++++++++++++++++++++++++++
 cmd/babylond/cmd/init_test.go      |  21 ++++
 cmd/babylond/cmd/root.go           |   3 +-
 crypto/erc2335/erc2335.go          |  25 +++-
 crypto/erc2335/erc2335_test.go     |  65 ++++++++--
 privval/bls.go                     | 104 ++++++++++++---
 privval/bls_test.go                |  57 +++++++--
 10 files changed, 479 insertions(+), 64 deletions(-)
 create mode 100644 client/flags/flags.go
 create mode 100644 cmd/babylond/cmd/init.go
 create mode 100644 cmd/babylond/cmd/init_test.go

diff --git a/app/signer/private.go b/app/signer/private.go
index 8fcd1f217..46061677e 100644
--- a/app/signer/private.go
+++ b/app/signer/private.go
@@ -7,6 +7,7 @@ import (
 	cmtos "github.com/cometbft/cometbft/libs/os"
 
 	"github.com/babylonlabs-io/babylon/privval"
+	cmtprivval "github.com/cometbft/cometbft/privval"
 )
 
 type PrivSigner struct {
@@ -14,6 +15,8 @@ type PrivSigner struct {
 }
 
 func InitPrivSigner(nodeDir string) (*PrivSigner, error) {
+
+	// cometPv
 	nodeCfg := cmtconfig.DefaultConfig()
 	pvKeyFile := filepath.Join(nodeDir, nodeCfg.PrivValidatorKeyFile())
 	err := cmtos.EnsureDir(filepath.Dir(pvKeyFile), 0777)
@@ -25,9 +28,32 @@ func InitPrivSigner(nodeDir string) (*PrivSigner, error) {
 	if err != nil {
 		return nil, err
 	}
-	wrappedPV := privval.LoadOrGenWrappedFilePV(pvKeyFile, pvStateFile)
+	cometPv := cmtprivval.LoadOrGenFilePV(pvKeyFile, pvStateFile)
+
+	// blsPv
+	blsCfg := privval.DefaultBlsConfig()
+	blsCfg.RootDir = nodeCfg.RootDir
+	blsKeyFile := filepath.Join(nodeDir, blsCfg.BlsKeyFile())
+	err = cmtos.EnsureDir(filepath.Dir(blsKeyFile), 0777)
+	if err != nil {
+		return nil, err
+	}
+	blsPasswordFile := filepath.Join(nodeDir, blsCfg.BlsPasswordFile())
+	err = cmtos.EnsureDir(filepath.Dir(blsPasswordFile), 0777)
+	if err != nil {
+		return nil, err
+	}
+
+	password := privval.LoadOrGenBlsPassword(blsPasswordFile)
+	blsPv := privval.LoadOrGenBlsPV(blsKeyFile, password)
 
 	return &PrivSigner{
-		WrappedPV: wrappedPV,
+		WrappedPV: &privval.WrappedFilePV{
+			Key: privval.WrappedFilePVKey{
+				CometPVKey: cometPv.Key,
+				BlsPVKey:   blsPv.Key,
+			},
+			LastSignState: cometPv.LastSignState,
+		},
 	}, nil
 }
diff --git a/client/flags/flags.go b/client/flags/flags.go
new file mode 100644
index 000000000..5e58fe954
--- /dev/null
+++ b/client/flags/flags.go
@@ -0,0 +1,5 @@
+package flags
+
+const (
+	FlagBlsPassword = "bls-password"
+)
diff --git a/cmd/babylond/cmd/create_bls_key.go b/cmd/babylond/cmd/create_bls_key.go
index 37e4f4be4..46e747919 100644
--- a/cmd/babylond/cmd/create_bls_key.go
+++ b/cmd/babylond/cmd/create_bls_key.go
@@ -1,21 +1,19 @@
 package cmd
 
 import (
-	"errors"
 	"fmt"
 	"path/filepath"
 	"strings"
 
 	cmtconfig "github.com/cometbft/cometbft/config"
-	cmtos "github.com/cometbft/cometbft/libs/os"
 	"github.com/cosmos/cosmos-sdk/client/flags"
 	sdk "github.com/cosmos/cosmos-sdk/types"
 	"github.com/spf13/cobra"
 
 	"github.com/babylonlabs-io/babylon/app"
 	appparams "github.com/babylonlabs-io/babylon/app/params"
-	"github.com/babylonlabs-io/babylon/crypto/bls12381"
 	"github.com/babylonlabs-io/babylon/privval"
+	cmtprivval "github.com/cometbft/cometbft/privval"
 )
 
 func CreateBlsKeyCmd() *cobra.Command {
@@ -57,28 +55,28 @@ $ babylond create-bls-key %s1f5tnl46mk4dfp4nx3n2vnrvyw2h2ydz6ykhk3r --home ./
 }
 
 func CreateBlsKey(home string, addr sdk.AccAddress) error {
+	// comet
 	nodeCfg := cmtconfig.DefaultConfig()
 	keyPath := filepath.Join(home, nodeCfg.PrivValidatorKeyFile())
 	statePath := filepath.Join(home, nodeCfg.PrivValidatorStateFile())
 
-	pv, err := LoadWrappedFilePV(keyPath, statePath)
-	if err != nil {
-		return err
-	}
-
-	wrappedPV := privval.NewWrappedFilePV(pv.GetValPrivKey(), bls12381.GenPrivKey(), keyPath, statePath)
-	wrappedPV.SetAccAddress(addr)
+	// bls
+	blsCfg := privval.DefaultBlsConfig()
+	blsKeyFilePath := filepath.Join(home, blsCfg.BlsKeyFile())
+	blsPasswordPath := filepath.Join(home, blsCfg.BlsPasswordFile())
 
-	return nil
-}
+	cometPv := cmtprivval.LoadOrGenFilePV(keyPath, statePath)
+	blsPv := privval.LoadOrGenBlsPV(blsKeyFilePath, blsPasswordPath)
 
-// LoadWrappedFilePV loads the wrapped file private key from the file path.
-func LoadWrappedFilePV(keyPath, statePath string) (*privval.WrappedFilePV, error) {
-	if !cmtos.FileExists(keyPath) {
-		return nil, errors.New("validator key file does not exist")
-	}
-	if !cmtos.FileExists(statePath) {
-		return nil, errors.New("validator state file does not exist")
+	// wrappedFilePv
+	wrappedFilePv := privval.WrappedFilePV{
+		Key: privval.WrappedFilePVKey{
+			CometPVKey: cometPv.Key,
+			BlsPVKey:   blsPv.Key,
+		},
+		LastSignState: cometPv.LastSignState,
 	}
-	return privval.LoadWrappedFilePV(keyPath, statePath), nil
+	wrappedFilePv.SetAccAddress(addr)
+
+	return nil
 }
diff --git a/cmd/babylond/cmd/init.go b/cmd/babylond/cmd/init.go
new file mode 100644
index 000000000..4d9ef56c5
--- /dev/null
+++ b/cmd/babylond/cmd/init.go
@@ -0,0 +1,195 @@
+package cmd
+
+import (
+	"bufio"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"os"
+	"path/filepath"
+
+	"cosmossdk.io/math/unsafe"
+	"github.com/babylonlabs-io/babylon/privval"
+	"github.com/spf13/cobra"
+
+	errorsmod "cosmossdk.io/errors"
+	cfg "github.com/cometbft/cometbft/config"
+	"github.com/cosmos/cosmos-sdk/client"
+	"github.com/cosmos/cosmos-sdk/client/flags"
+	"github.com/cosmos/cosmos-sdk/client/input"
+	"github.com/cosmos/cosmos-sdk/server"
+	sdk "github.com/cosmos/cosmos-sdk/types"
+	"github.com/cosmos/cosmos-sdk/types/module"
+	"github.com/cosmos/cosmos-sdk/version"
+	"github.com/cosmos/cosmos-sdk/x/genutil"
+	cmtcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli"
+	"github.com/cosmos/cosmos-sdk/x/genutil/types"
+	"github.com/cosmos/go-bip39"
+)
+
+// wonjoon
+// copied from "https://github.com/cosmos/cosmos-sdk/x/genutil/client/cli/init.go"
+func InitCmd(mbm module.BasicManager, defaultNodeHome string) *cobra.Command {
+	cmd := &cobra.Command{
+		Use:   "init [moniker]",
+		Short: "Initialize private validator, p2p, genesis, and application configuration files",
+		Long:  `Initialize validators's and node's configuration files.`,
+		Args:  cobra.ExactArgs(1),
+		RunE: func(cmd *cobra.Command, args []string) error {
+			clientCtx := client.GetClientContextFromCmd(cmd)
+			cdc := clientCtx.Codec
+
+			serverCtx := server.GetServerContextFromCmd(cmd)
+			config := serverCtx.Config
+			config.SetRoot(clientCtx.HomeDir)
+
+			chainID, _ := cmd.Flags().GetString(flags.FlagChainID)
+			switch {
+			case chainID != "":
+			case clientCtx.ChainID != "":
+				chainID = clientCtx.ChainID
+			default:
+				chainID = fmt.Sprintf("test-chain-%v", unsafe.Str(6))
+			}
+
+			// Get bip39 mnemonic
+			var mnemonic string
+			recover, _ := cmd.Flags().GetBool(cmtcli.FlagRecover)
+			if recover {
+				inBuf := bufio.NewReader(cmd.InOrStdin())
+				value, err := input.GetString("Enter your bip39 mnemonic", inBuf)
+				if err != nil {
+					return err
+				}
+
+				mnemonic = value
+				if !bip39.IsMnemonicValid(mnemonic) {
+					return errors.New("invalid mnemonic")
+				}
+			}
+
+			// wonjoon: make config for bls
+			blsCfg := privval.BlsConfig{
+				RootDir:         config.RootDir,
+				BlsKeyPath:      filepath.Join(config.RootDir, cfg.DefaultConfigDir, privval.DefaultBlsKeyName),
+				BlsPasswordPath: filepath.Join(config.RootDir, cfg.DefaultConfigDir, privval.DefaultBlsPasswordName),
+			}
+
+			// Get BLS password
+			blsPassword := privval.LoadOrGenBlsPassword(blsCfg.BlsPasswordFile())
+
+			// Get initial height
+			initHeight, _ := cmd.Flags().GetInt64(flags.FlagInitHeight)
+			if initHeight < 1 {
+				initHeight = 1
+			}
+
+			// InitializeNodeValidatorFilesFromMnemonic from cosmos-sdk/x/genutil/utils.go
+			nodeID, _, err := genutil.InitializeNodeValidatorFilesFromMnemonic(config, mnemonic)
+			if err != nil {
+				return err
+			}
+
+			// InitializeNodeValidatorBlsFilesFromMnemonic from babylon/x/privval/bls.go
+			_, err = privval.InitializeNodeValidatorBlsFilesFromMnemonic(&blsCfg, mnemonic, blsPassword)
+			if err != nil {
+				return err
+			}
+
+			config.Moniker = args[0]
+
+			genFile := config.GenesisFile()
+			overwrite, _ := cmd.Flags().GetBool(cmtcli.FlagOverwrite)
+			defaultDenom, _ := cmd.Flags().GetString(cmtcli.FlagDefaultBondDenom)
+
+			// use os.Stat to check if the file exists
+			_, err = os.Stat(genFile)
+			if !overwrite && !os.IsNotExist(err) {
+				return fmt.Errorf("genesis.json file already exists: %v", genFile)
+			}
+
+			// Overwrites the SDK default denom for side-effects
+			if defaultDenom != "" {
+				sdk.DefaultBondDenom = defaultDenom
+			}
+			appGenState := mbm.DefaultGenesis(cdc)
+
+			appState, err := json.MarshalIndent(appGenState, "", " ")
+			if err != nil {
+				return errorsmod.Wrap(err, "Failed to marshal default genesis state")
+			}
+
+			appGenesis := &types.AppGenesis{}
+			if _, err := os.Stat(genFile); err != nil {
+				if !os.IsNotExist(err) {
+					return err
+				}
+			} else {
+				appGenesis, err = types.AppGenesisFromFile(genFile)
+				if err != nil {
+					return errorsmod.Wrap(err, "Failed to read genesis doc from file")
+				}
+			}
+
+			appGenesis.AppName = version.AppName
+			appGenesis.AppVersion = version.Version
+			appGenesis.ChainID = chainID
+			appGenesis.AppState = appState
+			appGenesis.InitialHeight = initHeight
+			appGenesis.Consensus = &types.ConsensusGenesis{
+				Validators: nil,
+			}
+
+			if err = genutil.ExportGenesisFile(appGenesis, genFile); err != nil {
+				return errorsmod.Wrap(err, "Failed to export genesis file")
+			}
+
+			toPrint := newPrintInfo(config.Moniker, chainID, nodeID, "", appState)
+
+			cfg.WriteConfigFile(filepath.Join(config.RootDir, "config", "config.toml"), config)
+			return displayInfo(toPrint)
+		},
+	}
+
+	cmd.Flags().String(flags.FlagHome, defaultNodeHome, "node's home directory")
+	cmd.Flags().BoolP(cmtcli.FlagOverwrite, "o", false, "overwrite the genesis.json file")
+	cmd.Flags().Bool(cmtcli.FlagRecover, false, "provide seed phrase to recover existing key instead of creating")
+	cmd.Flags().String(flags.FlagChainID, "", "genesis file chain-id, if left blank will be randomly created")
+	cmd.Flags().String(cmtcli.FlagDefaultBondDenom, "", "genesis file default denomination, if left blank default value is 'stake'")
+	cmd.Flags().Int64(flags.FlagInitHeight, 1, "specify the initial block height at genesis")
+	cmd.Flags().String("bls-password", "", "BLS key password (if not provided, will prompt for input)")
+
+	return cmd
+}
+
+// copied from "https://github.com/cosmos/cosmos-sdk/x/genutil/client/cli/init.go"
+type printInfo struct {
+	Moniker    string          `json:"moniker" yaml:"moniker"`
+	ChainID    string          `json:"chain_id" yaml:"chain_id"`
+	NodeID     string          `json:"node_id" yaml:"node_id"`
+	GenTxsDir  string          `json:"gentxs_dir" yaml:"gentxs_dir"`
+	AppMessage json.RawMessage `json:"app_message" yaml:"app_message"`
+}
+
+// copied from "https://github.com/cosmos/cosmos-sdk/x/genutil/client/cli/init.go"
+func newPrintInfo(moniker, chainID, nodeID, genTxsDir string, appMessage json.RawMessage) printInfo {
+	return printInfo{
+		Moniker:    moniker,
+		ChainID:    chainID,
+		NodeID:     nodeID,
+		GenTxsDir:  genTxsDir,
+		AppMessage: appMessage,
+	}
+}
+
+// copied from "https://github.com/cosmos/cosmos-sdk/x/genutil/client/cli/init.go"
+func displayInfo(info printInfo) error {
+	out, err := json.MarshalIndent(info, "", " ")
+	if err != nil {
+		return err
+	}
+
+	_, err = fmt.Fprintf(os.Stderr, "%s\n", out)
+
+	return err
+}
diff --git a/cmd/babylond/cmd/init_test.go b/cmd/babylond/cmd/init_test.go
new file mode 100644
index 000000000..1f7441912
--- /dev/null
+++ b/cmd/babylond/cmd/init_test.go
@@ -0,0 +1,21 @@
+package cmd
+
+import (
+	"path/filepath"
+	"testing"
+
+	"github.com/babylonlabs-io/babylon/privval"
+	cfg "github.com/cometbft/cometbft/config"
+)
+
+func TestSaveFiles(t *testing.T) {
+
+	// clientCtx := client.GetClientContextFromCmd(&cobra.Command{})
+	homeDir := "test"
+	blsCfg := privval.BlsConfig{
+		RootDir:         homeDir,
+		BlsKeyPath:      filepath.Join(homeDir, cfg.DefaultConfigDir, privval.DefaultBlsKeyName),
+		BlsPasswordPath: filepath.Join(homeDir, cfg.DefaultConfigDir, privval.DefaultBlsPasswordName),
+	}
+	t.Log(blsCfg)
+}
diff --git a/cmd/babylond/cmd/root.go b/cmd/babylond/cmd/root.go
index 7687ab268..cf78b1beb 100644
--- a/cmd/babylond/cmd/root.go
+++ b/cmd/babylond/cmd/root.go
@@ -167,7 +167,8 @@ func initRootCmd(rootCmd *cobra.Command, txConfig client.TxEncodingConfig, basic
 	gentxModule := basicManager[genutiltypes.ModuleName].(genutil.AppModuleBasic)
 
 	rootCmd.AddCommand(
-		genutilcli.InitCmd(basicManager, app.DefaultNodeHome),
+		// genutilcli.InitCmd(basicManager, app.DefaultNodeHome),
+		InitCmd(basicManager, app.DefaultNodeHome),
 		genutilcli.CollectGenTxsCmd(banktypes.GenesisBalancesIterator{}, app.DefaultNodeHome, gentxModule.GenTxValidator, authcodec.NewBech32Codec(params.Bech32PrefixValAddr)),
 		genutilcli.MigrateGenesisCmd(genutilcli.MigrationMap),
 		genutilcli.GenTxCmd(basicManager, txConfig, banktypes.GenesisBalancesIterator{}, app.DefaultNodeHome, authcodec.NewBech32Codec(params.Bech32PrefixValAddr)),
diff --git a/crypto/erc2335/erc2335.go b/crypto/erc2335/erc2335.go
index 9559e4970..4c78aa3ce 100644
--- a/crypto/erc2335/erc2335.go
+++ b/crypto/erc2335/erc2335.go
@@ -1,8 +1,11 @@
 package erc2335
 
 import (
+	"crypto/rand"
+	"encoding/hex"
 	"encoding/json"
 	"fmt"
+	"os"
 
 	"github.com/pkg/errors"
 	keystorev4 "github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4"
@@ -18,7 +21,7 @@ type Erc2335KeyStore struct {
 
 // wonjoon: encrypt key pair to erc2335 keystore
 // available to handle all keys in []byte format
-func EncryptBLS(privKey, pubKey []byte, password string) ([]byte, error) {
+func Encrypt(privKey, pubKey []byte, password string) ([]byte, error) {
 	if privKey == nil {
 		return nil, errors.New("private key cannot be nil")
 	}
@@ -40,7 +43,7 @@ func EncryptBLS(privKey, pubKey []byte, password string) ([]byte, error) {
 }
 
 // decrypt private key from erc2335 keystore
-func DecryptBLS(keystoreJSON []byte, password string) ([]byte, error) {
+func Decrypt(keystoreJSON []byte, password string) ([]byte, error) {
 	// Parse the keystore json
 	var keystore Erc2335KeyStore
 
@@ -56,3 +59,21 @@ func DecryptBLS(keystoreJSON []byte, password string) ([]byte, error) {
 	encryptor := keystorev4.New()
 	return encryptor.Decrypt(keystore.Crypto, password)
 }
+
+func SavePasswordToFile(password, filePath string) error {
+	return os.WriteFile(filePath, []byte(password), 0600)
+}
+
+func LoadPaswordFromFile(filePath string) (string, error) {
+	password, err := os.ReadFile(filePath)
+	return string(password), err
+}
+
+func CreateRandomPassword() string {
+	password := make([]byte, 32)
+	_, err := rand.Read(password)
+	if err != nil {
+		panic(err)
+	}
+	return hex.EncodeToString(password)
+}
diff --git a/crypto/erc2335/erc2335_test.go b/crypto/erc2335/erc2335_test.go
index e6ccc1702..c6c51d4b3 100644
--- a/crypto/erc2335/erc2335_test.go
+++ b/crypto/erc2335/erc2335_test.go
@@ -1,6 +1,7 @@
 package erc2335
 
 import (
+	"os"
 	"testing"
 
 	"github.com/babylonlabs-io/babylon/crypto/bls12381"
@@ -10,29 +11,77 @@ import (
 func TestEncryptBLS(t *testing.T) {
 	// TODO
 	t.Run("create bls key", func(t *testing.T) {
-		// TODO
+
 		blsPrivKey := bls12381.GenPrivKey()
 		blsPubKey := blsPrivKey.PubKey().Bytes()
-		password := "password"
 
 		t.Run("encrypt bls key", func(t *testing.T) {
-			// TODO
-			encryptedBlsKey, err := EncryptBLS(blsPrivKey, blsPubKey, password)
+
+			password := CreateRandomPassword()
+			t.Logf("password: %s", password)
+
+			encryptedBlsKey, err := Encrypt(blsPrivKey, blsPubKey, password)
 			require.NoError(t, err)
 			t.Logf("encrypted bls key: %s", encryptedBlsKey)
 
 			t.Run("decrypt bls key", func(t *testing.T) {
-				// TODO
-				decryptedBlsKey, err := DecryptBLS(encryptedBlsKey, password)
+
+				decryptedBlsKey, err := Decrypt(encryptedBlsKey, password)
 				require.NoError(t, err)
 				require.Equal(t, blsPrivKey, bls12381.PrivateKey(decryptedBlsKey))
 			})
 
 			t.Run("decrypt bls key with wrong password", func(t *testing.T) {
-				// TODO
-				_, err := DecryptBLS(encryptedBlsKey, "wrong password")
+
+				_, err := Decrypt(encryptedBlsKey, "wrong password")
+				require.Error(t, err)
+			})
+		})
+
+		t.Run("save password and encrypt bls key", func(t *testing.T) {
+
+			password := CreateRandomPassword()
+			t.Logf("password: %s", password)
+
+			encryptedBlsKey, err := Encrypt(blsPrivKey, blsPubKey, password)
+			require.NoError(t, err)
+			t.Logf("encrypted bls key: %s", encryptedBlsKey)
+			err = SavePasswordToFile(password, "password.txt")
+			require.NoError(t, err)
+
+			t.Run("load password and decrypt bls key", func(t *testing.T) {
+
+				password, err := LoadPaswordFromFile("password.txt")
+				require.NoError(t, err)
+				decryptedBlsKey, err := Decrypt(encryptedBlsKey, password)
+				require.NoError(t, err)
+				require.Equal(t, blsPrivKey, bls12381.PrivateKey(decryptedBlsKey))
+			})
+
+			t.Run("save new password into same file", func(t *testing.T) {
+
+				newPassword := CreateRandomPassword()
+				t.Logf("new password: %s", newPassword)
+				err = SavePasswordToFile(newPassword, "password.txt")
+				require.NoError(t, err)
+			})
+
+			t.Run("failed when load different password and decrypt bls key", func(t *testing.T) {
+
+				password, err := LoadPaswordFromFile("password.txt")
+				require.NoError(t, err)
+				_, err = Decrypt(encryptedBlsKey, password)
+				require.Error(t, err)
+			})
+
+			t.Run("failed when password file don't exist", func(t *testing.T) {
+				_, err := LoadPaswordFromFile("nopassword.txt")
 				require.Error(t, err)
 			})
 		})
+
+		t.Run("clean test files", func(t *testing.T) {
+			_ = os.RemoveAll("password.txt")
+		})
 	})
 }
diff --git a/privval/bls.go b/privval/bls.go
index 71118fe25..a435ab200 100644
--- a/privval/bls.go
+++ b/privval/bls.go
@@ -1,8 +1,10 @@
 package privval
 
 import (
+	"bufio"
 	"encoding/json"
 	"fmt"
+	"log"
 	"os"
 	"path/filepath"
 
@@ -11,10 +13,14 @@ import (
 	cmtcfg "github.com/cometbft/cometbft/config"
 	cmtos "github.com/cometbft/cometbft/libs/os"
 	"github.com/cometbft/cometbft/libs/tempfile"
+	"github.com/cosmos/cosmos-sdk/client/input"
 	"github.com/cosmos/go-bip39"
 )
 
-const DefaultBlsKeyName = "bls_key.json"
+const (
+	DefaultBlsKeyName      = "bls_key.json"
+	DefaultBlsPasswordName = "bls_password.txt"
+)
 
 type BlsPV struct {
 	Key BlsPVKey
@@ -49,7 +55,7 @@ func LoadBlsPV(keyFilePath, password string) *BlsPV {
 	}
 
 	// decrypt bls key from erc2335 type of structure
-	privKey, err := erc2335.DecryptBLS(keyJSONBytes, password)
+	privKey, err := erc2335.Decrypt(keyJSONBytes, password)
 	if err != nil {
 		cmtos.Exit(fmt.Sprintf("failed to decrypt BLS key: %v", err.Error()))
 	}
@@ -77,18 +83,59 @@ func LoadOrGenBlsPV(keyFilePath, password string) *BlsPV {
 	return pv
 }
 
+func LoadOrGenBlsPassword(passwordFilePath string) string {
+	password, isExist, err := LoadBlsPassword(passwordFilePath)
+	if err != nil {
+		cmtos.Exit(fmt.Sprintf("failed to read BLS password file: %v", err.Error()))
+	}
+
+	if !isExist {
+		newPassword, err := GenBlsPassword()
+		if err != nil {
+			cmtos.Exit(fmt.Sprintf("failed to generate BLS password: %v", err.Error()))
+		}
+		err = erc2335.SavePasswordToFile(newPassword, passwordFilePath)
+		if err != nil {
+			cmtos.Exit(fmt.Sprintf("failed to save BLS password file: %v", err.Error()))
+		}
+		log.Print("BLS password saved to ", passwordFilePath)
+		return newPassword
+	}
+	return password
+}
+
+func LoadBlsPassword(passwordFilePath string) (string, bool, error) {
+	if cmtos.FileExists(passwordFilePath) {
+		password, err := os.ReadFile(passwordFilePath)
+		if err != nil {
+			return "", true, fmt.Errorf("failed to read BLS password file: %v", err.Error())
+		}
+		return string(password), true, nil
+	}
+	return "", false, nil
+}
+
+func GenRandomBlsPassword() string {
+	return erc2335.CreateRandomPassword()
+}
+
+func GenBlsPassword() (string, error) {
+	inBuf := bufio.NewReader(os.Stdin)
+	return input.GetString("Enter your bls password", inBuf)
+}
+
 func (pv *BlsPV) Save(password string) {
 	pv.Key.Save(password)
 }
 
-func (k *BlsPVKey) Save(password string) {
-	outFile := k.filePath
+func (pvKey *BlsPVKey) Save(password string) {
+	outFile := pvKey.filePath
 	if outFile == "" {
 		panic("cannot save PrivValidator BLS key: filePath not set")
 	}
 
 	// encrypt the bls12381 key to erc2335 type
-	erc2335BlsPvKey, err := erc2335.EncryptBLS(k.PrivKey, k.PubKey.Bytes(), password)
+	erc2335BlsPvKey, err := erc2335.Encrypt(pvKey.PrivKey, pvKey.PubKey.Bytes(), password)
 	if err != nil {
 		panic(err)
 	}
@@ -109,17 +156,29 @@ func (k *BlsPVKey) Save(password string) {
 	}
 }
 
-func InitializeNodeValidatorBlsFiles(config *BlsConfig, password string) (blsPubKey []byte, err error) {
+// initialize node validator bls key with random password
+func InitializeNodeValidatorBlsFiles(config *BlsConfig) (blsPubKey []byte, err error) {
+	password := erc2335.CreateRandomPassword()
 	return InitializeNodeValidatorBlsFilesFromMnemonic(config, "", password)
 }
 
+// initialize node validator bls key with specific password
+// if you want to generate a random password,
+// use 'CreateRandomBlsPassword' to generate a random password and pass it to this function
+func InitializeNodeValidatorBlsFilesWithPassword(config *BlsConfig, password string) (blsPubKey []byte, err error) {
+	return InitializeNodeValidatorBlsFilesFromMnemonic(config, "", password)
+}
+
+// initialize node validator bls key with mnemonic and specific password
+// if you want to generate a random password,
+// use 'CreateRandomBlsPassword' to generate a random password and pass it to this function
 func InitializeNodeValidatorBlsFilesFromMnemonic(config *BlsConfig, mnemonic, password string) (blsPubKey []byte, err error) {
 	if len(mnemonic) > 0 && !bip39.IsMnemonicValid(mnemonic) {
 		return nil, fmt.Errorf("invalid mnemonic")
 	}
 
 	blsKeyFile := config.BlsKeyFile()
-	if err := cmtos.EnsureDir(filepath.Dir(blsKeyFile), 0777); err != nil {
+	if err := os.MkdirAll(filepath.Dir(blsKeyFile), 0o777); err != nil {
 		return nil, fmt.Errorf("could not create directory %q: %w", filepath.Dir(blsKeyFile), err)
 	}
 
@@ -140,27 +199,32 @@ func InitializeNodeValidatorBlsFilesFromMnemonic(config *BlsConfig, mnemonic, pa
 // -------------------------------------------------------------------------------
 
 type BlsConfig struct {
-	RootDir    string `mapstructure:"home"`
-	BlsKeyPath string `mapstructure:"bls_key_file"`
+	RootDir         string `mapstructure:"home"`
+	BlsKeyPath      string `mapstructure:"bls_key_file"`
+	BlsPasswordPath string `mapstructure:"bls_password_file"`
 }
 
 func DefaultBlsConfig() BlsConfig {
 	return BlsConfig{
-		RootDir:    cmtcfg.DefaultDataDir,
-		BlsKeyPath: filepath.Join(cmtcfg.DefaultDataDir, DefaultBlsKeyName),
+		RootDir:         cmtcfg.DefaultConfigDir,
+		BlsKeyPath:      filepath.Join(cmtcfg.DefaultConfigDir, DefaultBlsKeyName),
+		BlsPasswordPath: filepath.Join(cmtcfg.DefaultConfigDir, DefaultBlsPasswordName),
 	}
 }
 
-func SetBlsConfig(rootDir, blsKeyPath string) BlsConfig {
-	return BlsConfig{
-		RootDir:    rootDir,
-		BlsKeyPath: blsKeyPath,
-	}
+func (cfg BlsConfig) BlsKeyFile() string {
+	return rootify(cfg.BlsKeyPath, cfg.RootDir)
 }
 
-func (cfg BlsConfig) BlsKeyFile() string {
-	if filepath.IsAbs(cfg.BlsKeyPath) {
-		return cfg.BlsKeyPath
+func (cfg BlsConfig) BlsPasswordFile() string {
+	return rootify(cfg.BlsPasswordPath, cfg.RootDir)
+}
+
+// helper function to make config creation independent of root dir
+// copied from https://github.com/cometbft/cometbft/blob/v0.38.15/config/config.go
+func rootify(path, root string) string {
+	if filepath.IsAbs(path) {
+		return path
 	}
-	return filepath.Join(cfg.RootDir, cfg.BlsKeyPath)
+	return filepath.Join(root, path)
 }
diff --git a/privval/bls_test.go b/privval/bls_test.go
index b86bedade..302d1562f 100644
--- a/privval/bls_test.go
+++ b/privval/bls_test.go
@@ -6,6 +6,7 @@ import (
 	"testing"
 
 	"github.com/babylonlabs-io/babylon/crypto/bls12381"
+	"github.com/babylonlabs-io/babylon/crypto/erc2335"
 	cmtcfg "github.com/cometbft/cometbft/config"
 	"github.com/test-go/testify/assert"
 )
@@ -21,31 +22,65 @@ func TestCleanUp(t *testing.T) {
 	cleanup(blsKeyFilePath)
 }
 
-func TestLoadOrGenBlsPV(t *testing.T) {
-
-	t.Run("clean file path", func(t *testing.T) {
-		blsKeyFilePath := DefaultBlsConfig().BlsKeyFile()
-		t.Log("bls key file path", blsKeyFilePath)
-		cleanup(blsKeyFilePath)
-	})
+func TestInitializeNodeValidatorBlsFiles(t *testing.T) {
 
 	t.Run("set default config", func(t *testing.T) {
 		blsCfg := DefaultBlsConfig()
 		assert.NotNil(t, blsCfg)
-		assert.Equal(t, blsCfg.RootDir, cmtcfg.DefaultDataDir)
-		assert.Equal(t, blsCfg.BlsKeyPath, filepath.Join(cmtcfg.DefaultDataDir, DefaultBlsKeyName))
+		assert.Equal(t, blsCfg.RootDir, cmtcfg.DefaultConfigDir)
+		assert.Equal(t, blsCfg.BlsKeyPath, filepath.Join(cmtcfg.DefaultConfigDir, DefaultBlsKeyName))
+
+		password := erc2335.CreateRandomPassword()
+		t.Log("password", password)
 
 		t.Run("generate key without mnemonic", func(t *testing.T) {
-			blsPubKey, err := InitializeNodeValidatorBlsFiles(&blsCfg, "password")
+			blsPubKey, err := InitializeNodeValidatorBlsFilesWithPassword(&blsCfg, password)
 			assert.NoError(t, err)
 			assert.NotNil(t, blsPubKey)
 		})
 
 		t.Run("load key with password", func(t *testing.T) {
-			blsPubKey, err := InitializeNodeValidatorBlsFiles(&blsCfg, "password")
+			blsPubKey, err := InitializeNodeValidatorBlsFilesWithPassword(&blsCfg, password)
 			assert.NoError(t, err)
 			assert.NotNil(t, blsPubKey)
 		})
+
+		t.Run("clean file path", func(t *testing.T) {
+			blsKeyFilePath := DefaultBlsConfig().BlsKeyFile()
+			t.Log("bls key file path", blsKeyFilePath)
+			cleanup(blsKeyFilePath)
+		})
+	})
+}
+
+func TestSavePasswordToFile(t *testing.T) {
+
+	blsCfg := DefaultBlsConfig()
+
+	t.Run("failed to load unsaved file", func(t *testing.T) {
+		_, err := erc2335.LoadPaswordFromFile(blsCfg.BlsPasswordFile())
+		assert.Error(t, err)
+	})
+
+	t.Run("create password file", func(t *testing.T) {
+		password := erc2335.CreateRandomPassword()
+		t.Log("password", password)
+
+		err := erc2335.SavePasswordToFile(password, blsCfg.BlsPasswordFile())
+		assert.NoError(t, err)
+
+		t.Run("load password file", func(t *testing.T) {
+
+			loadPassword, err := erc2335.LoadPaswordFromFile(blsCfg.BlsPasswordFile())
+			assert.NoError(t, err)
+			assert.Equal(t, password, loadPassword)
+		})
+	})
+
+	t.Run("clean file path", func(t *testing.T) {
+		blsPasswordFilePath := DefaultBlsConfig().BlsPasswordFile()
+		t.Log("bls passwordd file path", blsPasswordFilePath)
+		cleanup(blsPasswordFilePath)
 	})
 }
 

From 6138f622a88b6fe2a55f85479186abade26c4d06 Mon Sep 17 00:00:00 2001
From: wonjoon <wnjoon@gmail.com>
Date: Fri, 10 Jan 2025 20:13:00 +0900
Subject: [PATCH 4/8] fix: move delegator address to bls structure and save to
 bls_key.json in erc2335 description

---
 app/signer/private.go                         |  66 +++-
 cmd/babylond/cmd/create_bls_key.go            |  45 ++-
 cmd/babylond/cmd/genhelpers/bls_add_test.go   |   9 +-
 cmd/babylond/cmd/genhelpers/bls_create.go     |  13 +-
 .../cmd/genhelpers/bls_create_test.go         |   8 +-
 cmd/babylond/cmd/init.go                      |  32 +-
 crypto/erc2335/erc2335.go                     |  11 +-
 privval/bls.go                                | 187 +++++-------
 privval/bls_test.go                           |  21 +-
 privval/file.go                               | 285 +++++++++---------
 privval/file_test.go                          |  74 +++++
 test/e2e/initialization/node.go               |  25 +-
 testutil/datagen/init_val.go                  |  12 +-
 testutil/signer/private.go                    |   2 +-
 x/checkpointing/client/cli/tx_test.go         |  11 +-
 x/checkpointing/client/cli/utils.go           |   9 +-
 16 files changed, 471 insertions(+), 339 deletions(-)
 create mode 100644 privval/file_test.go

diff --git a/app/signer/private.go b/app/signer/private.go
index 46061677e..22012963c 100644
--- a/app/signer/private.go
+++ b/app/signer/private.go
@@ -1,6 +1,7 @@
 package signer
 
 import (
+	"fmt"
 	"path/filepath"
 
 	cmtconfig "github.com/cometbft/cometbft/config"
@@ -15,8 +16,56 @@ type PrivSigner struct {
 }
 
 func InitPrivSigner(nodeDir string) (*PrivSigner, error) {
+	nodeCfg := cmtconfig.DefaultConfig()
+	pvKeyFile := filepath.Join(nodeDir, nodeCfg.PrivValidatorKeyFile())
+	err := cmtos.EnsureDir(filepath.Dir(pvKeyFile), 0777)
+	if err != nil {
+		return nil, err
+	}
+	pvStateFile := filepath.Join(nodeDir, nodeCfg.PrivValidatorStateFile())
+	err = cmtos.EnsureDir(filepath.Dir(pvStateFile), 0777)
+	if err != nil {
+		return nil, err
+	}
+
+	blsCfg := privval.DefaultBlsConfig()
+	blsCfg.SetRoot(nodeCfg.RootDir)
+	blsKeyFile := filepath.Join(nodeDir, blsCfg.BlsKeyFile())
+	err = cmtos.EnsureDir(filepath.Dir(blsKeyFile), 0777)
+	if err != nil {
+		return nil, err
+	}
+	blsPasswordFile := filepath.Join(nodeDir, blsCfg.BlsPasswordFile())
+	err = cmtos.EnsureDir(filepath.Dir(blsPasswordFile), 0777)
+	if err != nil {
+		return nil, err
+	}
+
+	if !cmtos.FileExists(blsKeyFile) {
+		return nil, fmt.Errorf("BLS key file does not exist: %v", blsKeyFile)
+	}
+
+	if !cmtos.FileExists(blsPasswordFile) {
+		return nil, fmt.Errorf("BLS password file does not exist: %v", blsPasswordFile)
+	}
+
+	blsPv := privval.LoadBlsPV(blsKeyFile, blsPasswordFile)
+	cmtPv := cmtprivval.LoadFilePV(pvKeyFile, pvStateFile)
+	wrappedPvKey := privval.WrappedFilePVKey{
+		CometPVKey: cmtPv.Key,
+		BlsPVKey:   blsPv.Key,
+	}
+	wrappedPV := &privval.WrappedFilePV{
+		Key:           wrappedPvKey,
+		LastSignState: cmtPv.LastSignState,
+	}
+
+	return &PrivSigner{
+		WrappedPV: wrappedPV,
+	}, nil
+}
 
-	// cometPv
+func InitTestPrivSigner(nodeDir string) (*PrivSigner, error) {
 	nodeCfg := cmtconfig.DefaultConfig()
 	pvKeyFile := filepath.Join(nodeDir, nodeCfg.PrivValidatorKeyFile())
 	err := cmtos.EnsureDir(filepath.Dir(pvKeyFile), 0777)
@@ -28,11 +77,9 @@ func InitPrivSigner(nodeDir string) (*PrivSigner, error) {
 	if err != nil {
 		return nil, err
 	}
-	cometPv := cmtprivval.LoadOrGenFilePV(pvKeyFile, pvStateFile)
 
-	// blsPv
 	blsCfg := privval.DefaultBlsConfig()
-	blsCfg.RootDir = nodeCfg.RootDir
+	blsCfg.SetRoot(nodeCfg.RootDir)
 	blsKeyFile := filepath.Join(nodeDir, blsCfg.BlsKeyFile())
 	err = cmtos.EnsureDir(filepath.Dir(blsKeyFile), 0777)
 	if err != nil {
@@ -44,16 +91,9 @@ func InitPrivSigner(nodeDir string) (*PrivSigner, error) {
 		return nil, err
 	}
 
-	password := privval.LoadOrGenBlsPassword(blsPasswordFile)
-	blsPv := privval.LoadOrGenBlsPV(blsKeyFile, password)
+	wrappedPV := privval.LoadOrGenWrappedFilePV(pvKeyFile, pvStateFile, blsKeyFile, blsPasswordFile)
 
 	return &PrivSigner{
-		WrappedPV: &privval.WrappedFilePV{
-			Key: privval.WrappedFilePVKey{
-				CometPVKey: cometPv.Key,
-				BlsPVKey:   blsPv.Key,
-			},
-			LastSignState: cometPv.LastSignState,
-		},
+		WrappedPV: wrappedPV,
 	}, nil
 }
diff --git a/cmd/babylond/cmd/create_bls_key.go b/cmd/babylond/cmd/create_bls_key.go
index 46e747919..ac500cf8a 100644
--- a/cmd/babylond/cmd/create_bls_key.go
+++ b/cmd/babylond/cmd/create_bls_key.go
@@ -1,17 +1,24 @@
 package cmd
 
 import (
+	"bufio"
 	"fmt"
+	"log"
+	"os"
 	"path/filepath"
 	"strings"
 
 	cmtconfig "github.com/cometbft/cometbft/config"
+	cmtos "github.com/cometbft/cometbft/libs/os"
 	"github.com/cosmos/cosmos-sdk/client/flags"
+	"github.com/cosmos/cosmos-sdk/client/input"
 	sdk "github.com/cosmos/cosmos-sdk/types"
 	"github.com/spf13/cobra"
 
 	"github.com/babylonlabs-io/babylon/app"
 	appparams "github.com/babylonlabs-io/babylon/app/params"
+	"github.com/babylonlabs-io/babylon/crypto/bls12381"
+	"github.com/babylonlabs-io/babylon/crypto/erc2335"
 	"github.com/babylonlabs-io/babylon/privval"
 	cmtprivval "github.com/cometbft/cometbft/privval"
 )
@@ -55,28 +62,42 @@ $ babylond create-bls-key %s1f5tnl46mk4dfp4nx3n2vnrvyw2h2ydz6ykhk3r --home ./
 }
 
 func CreateBlsKey(home string, addr sdk.AccAddress) error {
-	// comet
 	nodeCfg := cmtconfig.DefaultConfig()
 	keyPath := filepath.Join(home, nodeCfg.PrivValidatorKeyFile())
 	statePath := filepath.Join(home, nodeCfg.PrivValidatorStateFile())
+	cmtPv := cmtprivval.LoadFilePV(keyPath, statePath)
 
-	// bls
 	blsCfg := privval.DefaultBlsConfig()
-	blsKeyFilePath := filepath.Join(home, blsCfg.BlsKeyFile())
-	blsPasswordPath := filepath.Join(home, blsCfg.BlsPasswordFile())
-
-	cometPv := cmtprivval.LoadOrGenFilePV(keyPath, statePath)
-	blsPv := privval.LoadOrGenBlsPV(blsKeyFilePath, blsPasswordPath)
+	blsKeyPath := filepath.Join(home, blsCfg.BlsKeyFile())
+	blsPasswordFile := filepath.Join(home, blsCfg.BlsPasswordFile())
+
+	var blsPassword string
+	var err error
+	if !cmtos.FileExists(blsPasswordFile) {
+		log.Printf("BLS password file don't exists in file: %v", blsPasswordFile)
+		inBuf := bufio.NewReader(os.Stdin)
+		blsPassword, err = input.GetString("Enter your bls password", inBuf)
+		if err != nil {
+			return err
+		}
+		err = erc2335.SavePasswordToFile(blsPassword, blsPasswordFile)
+		if err != nil {
+			return err
+		}
+	}
+	blsPv := privval.NewBlsPV(bls12381.GenPrivKey(), blsKeyPath, blsPasswordFile)
+	blsPv.Key.Save(blsPassword)
 
-	// wrappedFilePv
-	wrappedFilePv := privval.WrappedFilePV{
+	wrappedPv := privval.WrappedFilePV{
 		Key: privval.WrappedFilePVKey{
-			CometPVKey: cometPv.Key,
+			CometPVKey: cmtPv.Key,
 			BlsPVKey:   blsPv.Key,
 		},
-		LastSignState: cometPv.LastSignState,
+		LastSignState: cmtPv.LastSignState,
 	}
-	wrappedFilePv.SetAccAddress(addr)
 
+	wrappedPv.SetAccAddress(addr)
+	log.Printf("Saved delegator address: %s", addr.String())
+	log.Printf("Saved delegator address in wrapperPv: %s", wrappedPv.Key.DelegatorAddress)
 	return nil
 }
diff --git a/cmd/babylond/cmd/genhelpers/bls_add_test.go b/cmd/babylond/cmd/genhelpers/bls_add_test.go
index 52e50dfcc..817e77937 100644
--- a/cmd/babylond/cmd/genhelpers/bls_add_test.go
+++ b/cmd/babylond/cmd/genhelpers/bls_add_test.go
@@ -152,7 +152,12 @@ func Test_CmdAddBlsWithGentx(t *testing.T) {
 		nodeCfg.SetRoot(homeDir)
 		keyPath := nodeCfg.PrivValidatorKeyFile()
 		statePath := nodeCfg.PrivValidatorStateFile()
-		filePV := privval.GenWrappedFilePV(keyPath, statePath)
+
+		blsCfg := privval.DefaultBlsConfig()
+		blsCfg.SetRoot(homeDir)
+		blsKeyFile := blsCfg.BlsKeyFile()
+		blsPasswordFile := blsCfg.BlsPasswordFile()
+		filePV := privval.GenWrappedFilePV(keyPath, statePath, blsKeyFile, blsPasswordFile)
 		filePV.SetAccAddress(v.Address)
 		_, err = cli.ExecTestCLICmd(v.ClientCtx, genBlsCmd, []string{fmt.Sprintf("--%s=%s", flags.FlagHome, homeDir)})
 		require.NoError(t, err)
@@ -175,6 +180,6 @@ func Test_CmdAddBlsWithGentx(t *testing.T) {
 		require.NotEmpty(t, checkpointingGenState.GenesisKeys)
 		gks := checkpointingGenState.GetGenesisKeys()
 		require.Equal(t, genKey, gks[i])
-		filePV.Clean(keyPath, statePath)
+		filePV.Clean(keyPath, statePath, blsKeyFile, blsPasswordFile)
 	}
 }
diff --git a/cmd/babylond/cmd/genhelpers/bls_create.go b/cmd/babylond/cmd/genhelpers/bls_create.go
index ac1ab7882..5c20b8f65 100644
--- a/cmd/babylond/cmd/genhelpers/bls_create.go
+++ b/cmd/babylond/cmd/genhelpers/bls_create.go
@@ -1,12 +1,11 @@
 package genhelpers
 
 import (
-	"errors"
+	"log"
 	"path/filepath"
 	"strings"
 
 	cmtconfig "github.com/cometbft/cometbft/config"
-	cmtos "github.com/cometbft/cometbft/libs/os"
 	"github.com/cosmos/cosmos-sdk/client/flags"
 	"github.com/spf13/cobra"
 
@@ -35,13 +34,15 @@ $ babylond genbls --home ./
 			homeDir, _ := cmd.Flags().GetString(flags.FlagHome)
 
 			nodeCfg := cmtconfig.DefaultConfig()
+			blsCfg := privval.DefaultBlsConfig()
 			keyPath := filepath.Join(homeDir, nodeCfg.PrivValidatorKeyFile())
 			statePath := filepath.Join(homeDir, nodeCfg.PrivValidatorStateFile())
-			if !cmtos.FileExists(keyPath) {
-				return errors.New("validator key file does not exist")
-			}
+			blsKeyPath := filepath.Join(homeDir, blsCfg.BlsKeyFile())
+			blsPasswordPath := filepath.Join(homeDir, blsCfg.BlsPasswordFile())
+
+			wrappedPV := privval.LoadWrappedFilePV(keyPath, statePath, blsKeyPath, blsPasswordPath)
 
-			wrappedPV := privval.LoadWrappedFilePV(keyPath, statePath)
+			log.Printf("Loaded delegator address in wrapperPv: %s", wrappedPV.Key.DelegatorAddress)
 
 			outputFileName, err := wrappedPV.ExportGenBls(filepath.Dir(keyPath))
 			if err != nil {
diff --git a/cmd/babylond/cmd/genhelpers/bls_create_test.go b/cmd/babylond/cmd/genhelpers/bls_create_test.go
index c93d38de9..58c29176d 100644
--- a/cmd/babylond/cmd/genhelpers/bls_create_test.go
+++ b/cmd/babylond/cmd/genhelpers/bls_create_test.go
@@ -72,8 +72,12 @@ func Test_CmdCreateBls(t *testing.T) {
 	nodeCfg := cmtconfig.DefaultConfig()
 	keyPath := filepath.Join(home, nodeCfg.PrivValidatorKeyFile())
 	statePath := filepath.Join(home, nodeCfg.PrivValidatorStateFile())
-	filePV := privval.GenWrappedFilePV(keyPath, statePath)
-	defer filePV.Clean(keyPath, statePath)
+
+	blsCfg := privval.DefaultBlsConfig()
+	blsKeyFile := filepath.Join(home, blsCfg.BlsKeyFile())
+	blsPasswordFile := filepath.Join(home, blsCfg.BlsPasswordFile())
+	filePV := privval.GenWrappedFilePV(keyPath, statePath, blsKeyFile, blsPasswordFile)
+	defer filePV.Clean(keyPath, statePath, blsKeyFile, blsPasswordFile)
 	filePV.SetAccAddress(addr)
 
 	// execute the gen-bls cmd
diff --git a/cmd/babylond/cmd/init.go b/cmd/babylond/cmd/init.go
index 4d9ef56c5..7322d04e9 100644
--- a/cmd/babylond/cmd/init.go
+++ b/cmd/babylond/cmd/init.go
@@ -68,30 +68,34 @@ func InitCmd(mbm module.BasicManager, defaultNodeHome string) *cobra.Command {
 				}
 			}
 
-			// wonjoon: make config for bls
-			blsCfg := privval.BlsConfig{
-				RootDir:         config.RootDir,
-				BlsKeyPath:      filepath.Join(config.RootDir, cfg.DefaultConfigDir, privval.DefaultBlsKeyName),
-				BlsPasswordPath: filepath.Join(config.RootDir, cfg.DefaultConfigDir, privval.DefaultBlsPasswordName),
-			}
-
-			// Get BLS password
-			blsPassword := privval.LoadOrGenBlsPassword(blsCfg.BlsPasswordFile())
-
 			// Get initial height
 			initHeight, _ := cmd.Flags().GetInt64(flags.FlagInitHeight)
 			if initHeight < 1 {
 				initHeight = 1
 			}
 
-			// InitializeNodeValidatorFilesFromMnemonic from cosmos-sdk/x/genutil/utils.go
-			nodeID, _, err := genutil.InitializeNodeValidatorFilesFromMnemonic(config, mnemonic)
+			// Get bls password
+			inBuf := bufio.NewReader(cmd.InOrStdin())
+			blsPassword, err := input.GetString("Enter your bls password", inBuf)
 			if err != nil {
 				return err
 			}
 
-			// InitializeNodeValidatorBlsFilesFromMnemonic from babylon/x/privval/bls.go
-			_, err = privval.InitializeNodeValidatorBlsFilesFromMnemonic(&blsCfg, mnemonic, blsPassword)
+			// Initialize bls key
+			blsCfg := privval.BlsConfig{
+				RootDir:         config.RootDir,
+				BlsKeyPath:      filepath.Join(config.RootDir, cfg.DefaultConfigDir, privval.DefaultBlsKeyName),
+				BlsPasswordPath: filepath.Join(config.RootDir, cfg.DefaultConfigDir, privval.DefaultBlsPasswordName),
+			}
+
+			// Initialize BLS key and save to file
+			_, err = privval.InitializeBlsFileFromMnemonic(&blsCfg, blsPassword, mnemonic)
+			if err != nil {
+				return err
+			}
+
+			// InitializeNodeValidatorFilesFromMnemonic from cosmos-sdk/x/genutil/utils.go
+			nodeID, _, err := genutil.InitializeNodeValidatorFilesFromMnemonic(config, mnemonic)
 			if err != nil {
 				return err
 			}
diff --git a/crypto/erc2335/erc2335.go b/crypto/erc2335/erc2335.go
index 4c78aa3ce..673588e46 100644
--- a/crypto/erc2335/erc2335.go
+++ b/crypto/erc2335/erc2335.go
@@ -12,11 +12,12 @@ import (
 )
 
 type Erc2335KeyStore struct {
-	Crypto  map[string]interface{} `json:"crypto"`
-	Version uint                   `json:"version"`
-	UUID    string                 `json:"uuid"`
-	Path    string                 `json:"path"`
-	Pubkey  string                 `json:"pubkey"`
+	Crypto      map[string]interface{} `json:"crypto"`
+	Version     uint                   `json:"version"`
+	UUID        string                 `json:"uuid"`
+	Path        string                 `json:"path"`
+	Pubkey      string                 `json:"pubkey"`
+	Description string                 `json:"description"`
 }
 
 // wonjoon: encrypt key pair to erc2335 keystore
diff --git a/privval/bls.go b/privval/bls.go
index a435ab200..05da75790 100644
--- a/privval/bls.go
+++ b/privval/bls.go
@@ -1,10 +1,8 @@
 package privval
 
 import (
-	"bufio"
 	"encoding/json"
 	"fmt"
-	"log"
 	"os"
 	"path/filepath"
 
@@ -13,7 +11,6 @@ import (
 	cmtcfg "github.com/cometbft/cometbft/config"
 	cmtos "github.com/cometbft/cometbft/libs/os"
 	"github.com/cometbft/cometbft/libs/tempfile"
-	"github.com/cosmos/cosmos-sdk/client/input"
 	"github.com/cosmos/go-bip39"
 )
 
@@ -27,101 +24,56 @@ type BlsPV struct {
 }
 
 type BlsPVKey struct {
-	PubKey   bls12381.PublicKey
-	PrivKey  bls12381.PrivateKey
-	filePath string
-}
+	PubKey  bls12381.PublicKey  `json:"bls_pub_key"`
+	PrivKey bls12381.PrivateKey `json:"bls_priv_key"`
 
-// todo: where
-func NewBlsPV(privKey bls12381.PrivateKey, keyFilePath string) *BlsPV {
-	return &BlsPV{
-		Key: BlsPVKey{
-			PubKey:   privKey.PubKey(),
-			PrivKey:  privKey,
-			filePath: keyFilePath,
-		},
-	}
+	filePath     string
+	passwordPath string
 }
 
-func GenBlsPV(keyFilePath string) *BlsPV {
-	return NewBlsPV(bls12381.GenPrivKey(), keyFilePath)
+// initialize node validator bls key with password
+func InitializeBlsFile(config *BlsConfig, password string) (blsPubKey []byte, err error) {
+	return InitializeBlsFileFromMnemonic(config, password, "")
 }
 
-func LoadBlsPV(keyFilePath, password string) *BlsPV {
-
-	keyJSONBytes, err := os.ReadFile(keyFilePath)
-	if err != nil {
-		cmtos.Exit(fmt.Sprintf("failed to read BLS file: %v", err.Error()))
+// initialize node validator bls key with mnemonic and password
+func InitializeBlsFileFromMnemonic(config *BlsConfig, password, mnemonic string) (blsPubKey []byte, err error) {
+	if len(mnemonic) > 0 && !bip39.IsMnemonicValid(mnemonic) {
+		return nil, fmt.Errorf("invalid mnemonic")
 	}
 
-	// decrypt bls key from erc2335 type of structure
-	privKey, err := erc2335.Decrypt(keyJSONBytes, password)
-	if err != nil {
-		cmtos.Exit(fmt.Sprintf("failed to decrypt BLS key: %v", err.Error()))
+	blsKeyFile := config.BlsKeyFile()
+	if err := os.MkdirAll(filepath.Dir(blsKeyFile), 0o777); err != nil {
+		return nil, fmt.Errorf("could not create directory for bls key %q: %w", filepath.Dir(blsKeyFile), err)
 	}
 
-	blsPrivKey := bls12381.PrivateKey(privKey)
-
-	return &BlsPV{
-		Key: BlsPVKey{
-			PubKey:   blsPrivKey.PubKey(),
-			PrivKey:  blsPrivKey,
-			filePath: keyFilePath,
-		},
+	blsPasswordFile := config.BlsPasswordFile()
+	if err := os.MkdirAll(filepath.Dir(blsPasswordFile), 0o777); err != nil {
+		return nil, fmt.Errorf("could not create directory for bls password %q: %w", filepath.Dir(blsPasswordFile), err)
 	}
-}
-
-func LoadOrGenBlsPV(keyFilePath, password string) *BlsPV {
 
-	var pv *BlsPV
-	if cmtos.FileExists(keyFilePath) {
-		pv = LoadBlsPV(keyFilePath, password)
+	// var blsPv *BlsPV
+	var privKey bls12381.PrivateKey
+	if len(mnemonic) == 0 {
+		privKey = bls12381.GenPrivKey()
 	} else {
-		pv = GenBlsPV(keyFilePath)
-		pv.Save(password)
+		privKey = bls12381.GenPrivKeyFromSecret([]byte(mnemonic))
 	}
-	return pv
-}
 
-func LoadOrGenBlsPassword(passwordFilePath string) string {
-	password, isExist, err := LoadBlsPassword(passwordFilePath)
-	if err != nil {
-		cmtos.Exit(fmt.Sprintf("failed to read BLS password file: %v", err.Error()))
-	}
-
-	if !isExist {
-		newPassword, err := GenBlsPassword()
-		if err != nil {
-			cmtos.Exit(fmt.Sprintf("failed to generate BLS password: %v", err.Error()))
-		}
-		err = erc2335.SavePasswordToFile(newPassword, passwordFilePath)
-		if err != nil {
-			cmtos.Exit(fmt.Sprintf("failed to save BLS password file: %v", err.Error()))
-		}
-		log.Print("BLS password saved to ", passwordFilePath)
-		return newPassword
-	}
-	return password
+	blsPv := NewBlsPV(privKey, blsKeyFile, blsPasswordFile)
+	blsPv.Save(password)
+	return privKey.PubKey().Bytes(), nil
 }
 
-func LoadBlsPassword(passwordFilePath string) (string, bool, error) {
-	if cmtos.FileExists(passwordFilePath) {
-		password, err := os.ReadFile(passwordFilePath)
-		if err != nil {
-			return "", true, fmt.Errorf("failed to read BLS password file: %v", err.Error())
-		}
-		return string(password), true, nil
+func NewBlsPV(privKey bls12381.PrivateKey, keyFilePath, passwordFilePath string) *BlsPV {
+	return &BlsPV{
+		Key: BlsPVKey{
+			PubKey:       privKey.PubKey(),
+			PrivKey:      privKey,
+			filePath:     keyFilePath,
+			passwordPath: passwordFilePath,
+		},
 	}
-	return "", false, nil
-}
-
-func GenRandomBlsPassword() string {
-	return erc2335.CreateRandomPassword()
-}
-
-func GenBlsPassword() (string, error) {
-	inBuf := bufio.NewReader(os.Stdin)
-	return input.GetString("Enter your bls password", inBuf)
 }
 
 func (pv *BlsPV) Save(password string) {
@@ -129,8 +81,20 @@ func (pv *BlsPV) Save(password string) {
 }
 
 func (pvKey *BlsPVKey) Save(password string) {
-	outFile := pvKey.filePath
-	if outFile == "" {
+
+	passwordOutFile := pvKey.passwordPath
+	if passwordOutFile == "" {
+		panic("cannot save PrivValidator BLS key: password filePath not set")
+	}
+
+	// save password to file
+	err := erc2335.SavePasswordToFile(password, passwordOutFile)
+	if err != nil {
+		panic(err)
+	}
+
+	keyOutFile := pvKey.filePath
+	if keyOutFile == "" {
 		panic("cannot save PrivValidator BLS key: filePath not set")
 	}
 
@@ -151,47 +115,38 @@ func (pvKey *BlsPVKey) Save(password string) {
 		panic(err)
 	}
 
-	if err := tempfile.WriteFileAtomic(outFile, jsonBytes, 0600); err != nil {
+	if err := tempfile.WriteFileAtomic(keyOutFile, jsonBytes, 0600); err != nil {
 		panic(err)
 	}
 }
 
-// initialize node validator bls key with random password
-func InitializeNodeValidatorBlsFiles(config *BlsConfig) (blsPubKey []byte, err error) {
-	password := erc2335.CreateRandomPassword()
-	return InitializeNodeValidatorBlsFilesFromMnemonic(config, "", password)
-}
-
-// initialize node validator bls key with specific password
-// if you want to generate a random password,
-// use 'CreateRandomBlsPassword' to generate a random password and pass it to this function
-func InitializeNodeValidatorBlsFilesWithPassword(config *BlsConfig, password string) (blsPubKey []byte, err error) {
-	return InitializeNodeValidatorBlsFilesFromMnemonic(config, "", password)
-}
+func LoadBlsPV(keyFilePath, passwordFilePath string) *BlsPV {
 
-// initialize node validator bls key with mnemonic and specific password
-// if you want to generate a random password,
-// use 'CreateRandomBlsPassword' to generate a random password and pass it to this function
-func InitializeNodeValidatorBlsFilesFromMnemonic(config *BlsConfig, mnemonic, password string) (blsPubKey []byte, err error) {
-	if len(mnemonic) > 0 && !bip39.IsMnemonicValid(mnemonic) {
-		return nil, fmt.Errorf("invalid mnemonic")
+	password, err := erc2335.LoadPaswordFromFile(passwordFilePath)
+	if err != nil {
+		cmtos.Exit(fmt.Sprintf("failed to read BLS password file: %v", err.Error()))
 	}
 
-	blsKeyFile := config.BlsKeyFile()
-	if err := os.MkdirAll(filepath.Dir(blsKeyFile), 0o777); err != nil {
-		return nil, fmt.Errorf("could not create directory %q: %w", filepath.Dir(blsKeyFile), err)
+	keyJSONBytes, err := os.ReadFile(keyFilePath)
+	if err != nil {
+		cmtos.Exit(fmt.Sprintf("failed to read BLS file: %v", err.Error()))
 	}
 
-	var blsPv *BlsPV
-	if len(mnemonic) == 0 {
-		blsPv = LoadOrGenBlsPV(blsKeyFile, password)
-	} else {
-		privKey := bls12381.GenPrivKeyFromSecret([]byte(mnemonic))
-		blsPv = NewBlsPV(privKey, blsKeyFile)
-		blsPv.Save(password)
+	// decrypt bls key from erc2335 type of structure
+	privKey, err := erc2335.Decrypt(keyJSONBytes, password)
+	if err != nil {
+		cmtos.Exit(fmt.Sprintf("failed to decrypt BLS key: %v", err.Error()))
 	}
 
-	return blsPv.Key.PubKey.Bytes(), nil
+	blsPrivKey := bls12381.PrivateKey(privKey)
+
+	return &BlsPV{
+		Key: BlsPVKey{
+			PubKey:   blsPrivKey.PubKey(),
+			PrivKey:  blsPrivKey,
+			filePath: keyFilePath,
+		},
+	}
 }
 
 // -------------------------------------------------------------------------------
@@ -206,12 +161,16 @@ type BlsConfig struct {
 
 func DefaultBlsConfig() BlsConfig {
 	return BlsConfig{
-		RootDir:         cmtcfg.DefaultConfigDir,
 		BlsKeyPath:      filepath.Join(cmtcfg.DefaultConfigDir, DefaultBlsKeyName),
 		BlsPasswordPath: filepath.Join(cmtcfg.DefaultConfigDir, DefaultBlsPasswordName),
 	}
 }
 
+func (cfg *BlsConfig) SetRoot(root string) *BlsConfig {
+	cfg.RootDir = root
+	return cfg
+}
+
 func (cfg BlsConfig) BlsKeyFile() string {
 	return rootify(cfg.BlsKeyPath, cfg.RootDir)
 }
diff --git a/privval/bls_test.go b/privval/bls_test.go
index 302d1562f..03248ca6c 100644
--- a/privval/bls_test.go
+++ b/privval/bls_test.go
@@ -5,16 +5,15 @@ import (
 	"path/filepath"
 	"testing"
 
-	"github.com/babylonlabs-io/babylon/crypto/bls12381"
 	"github.com/babylonlabs-io/babylon/crypto/erc2335"
 	cmtcfg "github.com/cometbft/cometbft/config"
 	"github.com/test-go/testify/assert"
 )
 
-func TestNewBlsPV(t *testing.T) {
-	pv := NewBlsPV(bls12381.GenPrivKey(), "test")
-	assert.NotNil(t, pv)
-}
+// func TestNewBlsPV(t *testing.T) {
+// 	pv := NewBlsPV(bls12381.GenPrivKey(), "test")
+// 	assert.NotNil(t, pv)
+// }
 
 func TestCleanUp(t *testing.T) {
 	blsKeyFilePath := DefaultBlsConfig().BlsKeyFile()
@@ -22,25 +21,24 @@ func TestCleanUp(t *testing.T) {
 	cleanup(blsKeyFilePath)
 }
 
-func TestInitializeNodeValidatorBlsFiles(t *testing.T) {
+func TestInitializeBlsFile(t *testing.T) {
 
 	t.Run("set default config", func(t *testing.T) {
 		blsCfg := DefaultBlsConfig()
 		assert.NotNil(t, blsCfg)
-		assert.Equal(t, blsCfg.RootDir, cmtcfg.DefaultConfigDir)
 		assert.Equal(t, blsCfg.BlsKeyPath, filepath.Join(cmtcfg.DefaultConfigDir, DefaultBlsKeyName))
 
 		password := erc2335.CreateRandomPassword()
 		t.Log("password", password)
 
 		t.Run("generate key without mnemonic", func(t *testing.T) {
-			blsPubKey, err := InitializeNodeValidatorBlsFilesWithPassword(&blsCfg, password)
+			blsPubKey, err := InitializeBlsFile(&blsCfg, password)
 			assert.NoError(t, err)
 			assert.NotNil(t, blsPubKey)
 		})
 
 		t.Run("load key with password", func(t *testing.T) {
-			blsPubKey, err := InitializeNodeValidatorBlsFilesWithPassword(&blsCfg, password)
+			blsPubKey, err := InitializeBlsFile(&blsCfg, password)
 			assert.NoError(t, err)
 			assert.NotNil(t, blsPubKey)
 		})
@@ -66,7 +64,10 @@ func TestSavePasswordToFile(t *testing.T) {
 		password := erc2335.CreateRandomPassword()
 		t.Log("password", password)
 
-		err := erc2335.SavePasswordToFile(password, blsCfg.BlsPasswordFile())
+		err := os.MkdirAll(filepath.Dir(blsCfg.BlsPasswordFile()), 0o777)
+		assert.NoError(t, err)
+
+		err = erc2335.SavePasswordToFile(password, blsCfg.BlsPasswordFile())
 		assert.NoError(t, err)
 
 		t.Run("load password file", func(t *testing.T) {
diff --git a/privval/file.go b/privval/file.go
index 6b11e9028..879f94e64 100644
--- a/privval/file.go
+++ b/privval/file.go
@@ -1,6 +1,7 @@
 package privval
 
 import (
+	"encoding/json"
 	"errors"
 	"fmt"
 	"os"
@@ -14,10 +15,11 @@ import (
 	"github.com/cometbft/cometbft/privval"
 	cmtproto "github.com/cometbft/cometbft/proto/tendermint/types"
 	"github.com/cosmos/cosmos-sdk/crypto/codec"
-	sdk "github.com/cosmos/cosmos-sdk/types"
 
 	"github.com/babylonlabs-io/babylon/crypto/bls12381"
+	"github.com/babylonlabs-io/babylon/crypto/erc2335"
 	checkpointingtypes "github.com/babylonlabs-io/babylon/x/checkpointing/types"
+	sdk "github.com/cosmos/cosmos-sdk/types"
 )
 
 // copied from github.com/cometbft/cometbft/privval/file.go"
@@ -46,108 +48,34 @@ func voteToStep(vote *cmtproto.Vote) int8 {
 
 // WrappedFilePVKey wraps FilePVKey with BLS keys.
 type WrappedFilePVKey struct {
-	// wonjoon/feat: separate cometPvKey and blsPvKey
-	CometPVKey privval.FilePVKey
-	BlsPVKey   BlsPVKey
-
-	// wonjoon/todo: remove
-	DelegatorAddress string `json:"acc_address"`
-}
-
-// wonjoon/todo: remove or refactoring
-func (pvKey WrappedFilePVKey) Save() {
-	pvKey.CometPVKey.Save()
-	pvKey.BlsPVKey.Save("")
+	CometPVKey       privval.FilePVKey
+	BlsPVKey         BlsPVKey
+	DelegatorAddress string
 }
 
+// WrappedFilePV wraps FilePV with WrappedFilePVKey.
 type WrappedFilePV struct {
 	Key           WrappedFilePVKey
 	LastSignState privval.FilePVLastSignState
 }
 
-// wonjoon/todo: refactoring
-func NewWrappedFilePV(
-	cometPrivKey cmtcrypto.PrivKey,
-	blsPrivKey bls12381.PrivateKey,
-	cometKeyFilePath, cometStateFilePath string,
-	// blsKeyFilePath string,
-) *WrappedFilePV {
-	filePV := privval.NewFilePV(cometPrivKey, cometKeyFilePath, cometStateFilePath)
+// GenWrappedFilePV generates a new validator with randomly generated private key
+// and sets the filePaths, but does not call Save().
+func GenWrappedFilePV(cmtKeyFilePath, cmtStateFilePath, blsKeyFilePath, blsPasswordFilePath string) *WrappedFilePV {
+	cometPv := privval.NewFilePV(ed25519.GenPrivKey(), cmtKeyFilePath, cmtStateFilePath)
+	blsPv := NewBlsPV(bls12381.GenPrivKey(), blsKeyFilePath, blsPasswordFilePath)
 	return &WrappedFilePV{
 		Key: WrappedFilePVKey{
-			CometPVKey: filePV.Key,
-			BlsPVKey: NewBlsPV(
-				blsPrivKey,
-				DefaultBlsConfig().BlsKeyFile(), // blsKeyFilePath,
-			).Key,
+			CometPVKey: cometPv.Key,
+			BlsPVKey:   blsPv.Key,
 		},
-		LastSignState: filePV.LastSignState,
+		LastSignState: cometPv.LastSignState,
 	}
 }
 
-// GenWrappedFilePV generates a new validator with randomly generated private key
-// and sets the filePaths, but does not call Save().
-// wonjoon/todo: refactoring
-func GenWrappedFilePV(
-	cometKeyFilePath, cometStateFilePath string,
-	//blsKeyFilePath string,
-) *WrappedFilePV {
-	return NewWrappedFilePV(
-		ed25519.GenPrivKey(),
-		bls12381.GenPrivKey(),
-		cometKeyFilePath,
-		cometStateFilePath,
-		//blsKeyFilePath,
-	)
-}
-
-// LoadWrappedFilePV loads a FilePV from the filePaths.  The FilePV handles double
-// signing prevention by persisting data to the stateFilePath.  If either file path
-// does not exist, the program will exit.
-// wonjoon/todo: refactoring
-func LoadWrappedFilePV(
-	cometKeyFilePath, cometStateFilePath string,
-	//  blsKeyFilePath, blsPassword string
-) *WrappedFilePV {
-	return loadWrappedFilePV(
-		cometKeyFilePath,
-		cometStateFilePath,
-		DefaultBlsConfig().BlsKeyFile(), // blsKeyFilePath,
-		"",                              // blsPassword,
-		true,
-	)
-}
-
-// LoadWrappedFilePVEmptyState loads a FilePV from the given keyFilePath, with an empty LastSignState.
-// If the keyFilePath does not exist, the program will exit.
-// wonjoon/todo: refactoring
-func LoadWrappedFilePVEmptyState(
-	cometKeyFilePath, cometStateFilePath string,
-	//  blsKeyFilePath, blsPassword string
-) *WrappedFilePV {
-	return loadWrappedFilePV(
-		cometKeyFilePath,
-		cometStateFilePath,
-		DefaultBlsConfig().BlsKeyFile(), // blsKeyFilePath,
-		"",                              // blsPassword,
-		false,
-	)
-}
-
-// If loadState is true, we load from the stateFilePath. Otherwise, we use an empty LastSignState.
-func loadWrappedFilePV(cometKeyFilePath, cometStateFilePath, blsKeyFilePath, blsPassword string, loadState bool) *WrappedFilePV {
-
-	// comet
-	var cometPv *privval.FilePV
-	if loadState {
-		cometPv = privval.LoadFilePV(cometKeyFilePath, cometStateFilePath)
-	} else {
-		cometPv = privval.LoadFilePVEmptyState(cometKeyFilePath, cometStateFilePath)
-	}
-
-	// bls
-	blsPv := LoadBlsPV(blsKeyFilePath, blsPassword)
-
+func GenWrappedFilePVWithMnemonic(mnemonic, cmtKeyFilePath, cmtStateFilePath, blsKeyFilePath, blsPasswordFilePath string) *WrappedFilePV {
+	cometPv := privval.NewFilePV(ed25519.GenPrivKeyFromSecret([]byte(mnemonic)), cmtKeyFilePath, cmtStateFilePath)
+	blsPv := NewBlsPV(bls12381.GenPrivKeyFromSecret([]byte(mnemonic)), blsKeyFilePath, blsPasswordFilePath)
 	return &WrappedFilePV{
 		Key: WrappedFilePVKey{
 			CometPVKey: cometPv.Key,
@@ -159,20 +87,66 @@ func loadWrappedFilePV(cometKeyFilePath, cometStateFilePath, blsKeyFilePath, bls
 
 // LoadOrGenWrappedFilePV loads a FilePV from the given filePaths
 // or else generates a new one and saves it to the filePaths.
-// wonjoon/todo: refactoring
-func LoadOrGenWrappedFilePV(
-	cometKeyFilePath, cometStateFilePath string,
-	// blsKeyFilePath, blsPassword string,
-) *WrappedFilePV {
-	cometPv := privval.LoadOrGenFilePV(cometKeyFilePath, cometStateFilePath)
-	blsPv := LoadOrGenBlsPV(
-		DefaultBlsConfig().BlsKeyFile(), // blsKeyFilePath,
-		"",                              // blsPassword,
-	)
+func LoadOrGenWrappedFilePV(cmtKeyFilePath, cmtStateFilePath, blsKeyFilePath, blsPasswordFilePath string) *WrappedFilePV {
+
+	var blsPV *BlsPV
+
+	if !cmtos.FileExists(blsKeyFilePath) {
+		var blsPassword string
+		var err error
+		if cmtos.FileExists(blsPasswordFilePath) {
+			blsPassword, err = erc2335.LoadPaswordFromFile(blsPasswordFilePath)
+			if err != nil {
+				cmtos.Exit(fmt.Sprintf("failed to read BLS password file: %v", err.Error()))
+			}
+		} else {
+			blsPassword = erc2335.CreateRandomPassword()
+		}
+
+		blsPV = NewBlsPV(bls12381.GenPrivKey(), blsKeyFilePath, blsPassword)
+		blsPV.Save(blsPassword)
+	} else {
+		blsPV = LoadBlsPV(blsKeyFilePath, blsPasswordFilePath)
+	}
+
+	var cometPV *privval.FilePV
+	if cmtos.FileExists(cmtKeyFilePath) {
+		cometPV = privval.LoadFilePV(cmtKeyFilePath, cmtStateFilePath)
+	} else {
+		cometPV = privval.GenFilePV(cmtKeyFilePath, cmtStateFilePath)
+		cometPV.Key.Save()
+	}
+
+	wrappedFilePV := &WrappedFilePV{
+		Key: WrappedFilePVKey{
+			CometPVKey: cometPV.Key,
+			BlsPVKey:   blsPV.Key,
+		},
+		LastSignState: cometPV.LastSignState,
+	}
+
+	return wrappedFilePV
+}
+
+func LoadWrappedFilePV(keyFilePath, stateFilePath, blsKeyFilePath, blsPasswordFilePath string) *WrappedFilePV {
+
+	if !cmtos.FileExists(blsKeyFilePath) {
+		cmtos.Exit(fmt.Sprintf("BLS key file does not exist: %v", blsKeyFilePath))
+	}
+
+	blsPv := LoadBlsPV(blsKeyFilePath, blsPasswordFilePath)
+
+	if !cmtos.FileExists(keyFilePath) {
+		cmtos.Exit(fmt.Sprintf("validator key file does not exist: %v", keyFilePath))
+	}
+
+	cometPv := privval.LoadFilePV(keyFilePath, stateFilePath)
+
 	return &WrappedFilePV{
 		Key: WrappedFilePVKey{
-			CometPVKey: cometPv.Key,
-			BlsPVKey:   blsPv.Key,
+			CometPVKey:       cometPv.Key,
+			BlsPVKey:         blsPv.Key,
+			DelegatorAddress: ReadDelegatorAddressFromFile(blsKeyFilePath),
 		},
 		LastSignState: cometPv.LastSignState,
 	}
@@ -180,17 +154,14 @@ func LoadOrGenWrappedFilePV(
 
 // ExportGenBls writes a {address, bls_pub_key, pop, and pub_key} into a json file
 func (pv *WrappedFilePV) ExportGenBls(filePath string) (outputFileName string, err error) {
-	// file check
 	if !cmtos.FileExists(filePath) {
 		return outputFileName, errors.New("export file path does not exist")
 	}
 
-	// ---- Should be removed ---//
 	valAddress := pv.GetAddress()
 	if valAddress.Empty() {
 		return outputFileName, errors.New("validator address should not be empty")
 	}
-	//-------------------------//
 
 	validatorKey, err := NewValidatorKeys(pv.GetValPrivKey(), pv.GetBlsPrivKey())
 	if err != nil {
@@ -232,31 +203,69 @@ func (pv *WrappedFilePV) GetAddress() sdk.ValAddress {
 
 func (pv *WrappedFilePV) SetAccAddress(addr sdk.AccAddress) {
 	pv.Key.DelegatorAddress = addr.String()
-	pv.Key.Save()
+	// pv.Key.Save()
+	SaveDelegatorAddressToFile(pv.Key.DelegatorAddress, pv.Key.BlsPVKey.filePath)
+}
+
+func SaveDelegatorAddressToFile(delegatorAddress, filePath string) {
+
+	var data map[string]interface{}
+	if err := ReadJSON(filePath, &data); err != nil {
+		cmtos.Exit(fmt.Sprintf("Failed to read JSON file: %v\n", err))
+	}
+
+	data["description"] = delegatorAddress
+	if err := WriteJSON(filePath, data); err != nil {
+		cmtos.Exit(fmt.Sprintf("Failed to write to JSON file: %v\n", err))
+	}
+}
+
+func ReadDelegatorAddressFromFile(filePath string) string {
+
+	var data map[string]interface{}
+	if err := ReadJSON(filePath, &data); err != nil {
+		cmtos.Exit(fmt.Sprintf("Failed to read JSON file: %v\n", err))
+	}
+	return data["description"].(string)
+}
+
+func WriteJSON(filePath string, v interface{}) error {
+	jsonBytes, err := json.MarshalIndent(v, "", "  ")
+	if err != nil {
+		return err
+	}
+	return os.WriteFile(filePath, jsonBytes, 0644)
+}
+
+func ReadJSON(filePath string, v interface{}) error {
+	file, err := os.Open(filePath)
+	if err != nil {
+		if os.IsNotExist(err) {
+			*v.(*map[string]interface{}) = make(map[string]interface{})
+			return nil
+		}
+		return err
+	}
+	defer file.Close()
+	return json.NewDecoder(file).Decode(v)
 }
 
 // GetPubKey returns the public key of the validator.
-// Implements PrivValidator.
 func (pv *WrappedFilePV) GetPubKey() (cmtcrypto.PubKey, error) {
 	return pv.Key.CometPVKey.PubKey, nil
 }
 
+// GetValPrivKey returns the private key of the validator.
 func (pv *WrappedFilePV) GetValPrivKey() cmtcrypto.PrivKey {
 	return pv.Key.CometPVKey.PrivKey
 }
 
+// GetBlsPrivKey returns the private key of the BLS.
 func (pv *WrappedFilePV) GetBlsPrivKey() bls12381.PrivateKey {
 	return pv.Key.BlsPVKey.PrivKey
 }
 
-func (pv *WrappedFilePV) SignMsgWithBls(msg []byte) (bls12381.Signature, error) {
-	blsPrivKey := pv.GetBlsPrivKey()
-	if blsPrivKey == nil {
-		return nil, checkpointingtypes.ErrBlsPrivKeyDoesNotExist
-	}
-	return bls12381.Sign(blsPrivKey, msg), nil
-}
-
+// GetBlsPubkey returns the public key of the BLS
 func (pv *WrappedFilePV) GetBlsPubkey() (bls12381.PublicKey, error) {
 	blsPrivKey := pv.GetBlsPrivKey()
 	if blsPrivKey == nil {
@@ -269,40 +278,24 @@ func (pv *WrappedFilePV) GetValidatorPubkey() (cmtcrypto.PubKey, error) {
 	return pv.GetPubKey()
 }
 
-// ---- Should be removed ---//₩
-// Save persists the FilePV to disk.
-func (pv *WrappedFilePV) Save() {
-	pv.Key.Save()
-	pv.LastSignState.Save()
-}
-
-//-------------------------//
-
-// Reset resets all fields in the FilePV.
-// NOTE: Unsafe!
-func (pv *WrappedFilePV) Reset() {
-	var sig []byte
-	pv.LastSignState.Height = 0
-	pv.LastSignState.Round = 0
-	pv.LastSignState.Step = 0
-	pv.LastSignState.Signature = sig
-	pv.LastSignState.SignBytes = nil
-	pv.Save()
+// SignMsgWithBls signs a message with BLS
+func (pv *WrappedFilePV) SignMsgWithBls(msg []byte) (bls12381.Signature, error) {
+	blsPrivKey := pv.GetBlsPrivKey()
+	if blsPrivKey == nil {
+		return nil, checkpointingtypes.ErrBlsPrivKeyDoesNotExist
+	}
+	return bls12381.Sign(blsPrivKey, msg), nil
 }
 
 // Clean removes PVKey file and PVState file
-func (pv *WrappedFilePV) Clean(keyFilePath, stateFilePath string) {
-	_ = os.RemoveAll(filepath.Dir(keyFilePath))
-	_ = os.RemoveAll(filepath.Dir(stateFilePath))
+func (pv *WrappedFilePV) Clean(paths ...string) {
+	for _, path := range paths {
+		_ = os.RemoveAll(filepath.Dir(path))
+	}
 }
 
-// String returns a string representation of the FilePV.
-func (pv *WrappedFilePV) String() string {
-	return fmt.Sprintf(
-		"PrivValidator{%v LH:%v, LR:%v, LS:%v}",
-		pv.GetAddress(),
-		pv.LastSignState.Height,
-		pv.LastSignState.Round,
-		pv.LastSignState.Step,
-	)
+func (pv *WrappedFilePV) Save(password string) {
+	pv.Key.CometPVKey.Save()
+	pv.Key.BlsPVKey.Save(password)
+	pv.LastSignState.Save()
 }
diff --git a/privval/file_test.go b/privval/file_test.go
new file mode 100644
index 000000000..4afcb9d35
--- /dev/null
+++ b/privval/file_test.go
@@ -0,0 +1,74 @@
+package privval
+
+import (
+	"encoding/json"
+	"os"
+	"path/filepath"
+	"testing"
+
+	"github.com/babylonlabs-io/babylon/crypto/erc2335"
+	cmtcfg "github.com/cometbft/cometbft/config"
+	cmtos "github.com/cometbft/cometbft/libs/os"
+
+	"github.com/cosmos/cosmos-sdk/types"
+	"github.com/test-go/testify/assert"
+)
+
+func TestSaveDelegatorAddressToFile(t *testing.T) {
+
+	tempDir := t.TempDir()
+	defer os.RemoveAll(tempDir)
+
+	ccfg := cmtcfg.DefaultConfig()
+	ccfg.SetRoot(tempDir)
+	bcfg := DefaultBlsConfig()
+	bcfg.SetRoot(tempDir)
+
+	pvKeyFile := filepath.Join(tempDir, ccfg.PrivValidatorKeyFile())
+	pvStateFile := filepath.Join(tempDir, ccfg.PrivValidatorStateFile())
+	blsKeyFile := filepath.Join(tempDir, bcfg.BlsKeyFile())
+	blsPasswordFile := filepath.Join(tempDir, bcfg.BlsPasswordFile())
+
+	err := cmtos.EnsureDir(filepath.Dir(pvKeyFile), 0777)
+	assert.Nil(t, err)
+	err = cmtos.EnsureDir(filepath.Dir(pvStateFile), 0777)
+	assert.Nil(t, err)
+	err = cmtos.EnsureDir(filepath.Dir(blsKeyFile), 0777)
+	assert.Nil(t, err)
+	err = cmtos.EnsureDir(filepath.Dir(blsPasswordFile), 0777)
+	assert.Nil(t, err)
+
+	pv := GenWrappedFilePV(
+		pvKeyFile,
+		pvStateFile,
+		blsKeyFile,
+		blsPasswordFile,
+	)
+
+	pv.Save("test")
+
+	t.Run("save delegator address", func(t *testing.T) {
+		delegatorAddress := pv.Key.CometPVKey.PubKey.Address()
+		t.Log("delegatorAddress: ", delegatorAddress)
+
+		// addr, err := sdk.AccAddressFromBech32(delegatorAddress.String())
+		// assert.NoError(t, err)
+		// t.Log("sdk.AccAddressFromBech32(delegatorAddress.String()): ", addr)
+
+		pv.SetAccAddress(types.AccAddress(delegatorAddress))
+
+		var keystore erc2335.Erc2335KeyStore
+		keyJSONBytes, err := os.ReadFile(blsKeyFile)
+		assert.NoError(t, err)
+		err = json.Unmarshal(keyJSONBytes, &keystore)
+		assert.NoError(t, err)
+
+		// t.Log(keystore)
+		t.Log(keystore.Description)
+	})
+
+	t.Run("load delegator address", func(t *testing.T) {
+		delegatorAddress := ReadDelegatorAddressFromFile(blsKeyFile)
+		assert.Equal(t, delegatorAddress, pv.Key.DelegatorAddress)
+	})
+}
diff --git a/test/e2e/initialization/node.go b/test/e2e/initialization/node.go
index 0c710c46e..3e674f5fb 100644
--- a/test/e2e/initialization/node.go
+++ b/test/e2e/initialization/node.go
@@ -10,7 +10,6 @@ import (
 
 	"cosmossdk.io/math"
 	cmtconfig "github.com/cometbft/cometbft/config"
-	cmted25519 "github.com/cometbft/cometbft/crypto/ed25519"
 	cmtos "github.com/cometbft/cometbft/libs/os"
 	"github.com/cometbft/cometbft/p2p"
 	cmttypes "github.com/cometbft/cometbft/types"
@@ -34,7 +33,7 @@ import (
 	babylonApp "github.com/babylonlabs-io/babylon/app"
 	appparams "github.com/babylonlabs-io/babylon/app/params"
 	"github.com/babylonlabs-io/babylon/cmd/babylond/cmd"
-	"github.com/babylonlabs-io/babylon/crypto/bls12381"
+	"github.com/babylonlabs-io/babylon/crypto/erc2335"
 	"github.com/babylonlabs-io/babylon/privval"
 	"github.com/babylonlabs-io/babylon/test/e2e/util"
 )
@@ -173,12 +172,26 @@ func (n *internalNode) createConsensusKey() error {
 		return err
 	}
 
-	privKey := cmted25519.GenPrivKeyFromSecret([]byte(n.mnemonic))
-	blsPrivKey := bls12381.GenPrivKeyFromSecret([]byte(n.mnemonic))
-	filePV := privval.NewWrappedFilePV(privKey, blsPrivKey, pvKeyFile, pvStateFile)
+	blsCfg := privval.DefaultBlsConfig()
+	blsCfg.SetRoot(config.RootDir)
+	blsKeyFile := blsCfg.BlsKeyFile()
+	if err := cmtos.EnsureDir(filepath.Dir(blsKeyFile), 0o777); err != nil {
+		return err
+	}
+
+	blsPasswordFile := blsCfg.BlsPasswordFile()
+	if err := cmtos.EnsureDir(filepath.Dir(blsPasswordFile), 0o777); err != nil {
+		return err
+	}
+
+	// for test e2e
+	// bls-password is random generated
+	blsPassword := erc2335.CreateRandomPassword()
+
+	filePV := privval.GenWrappedFilePVWithMnemonic(n.mnemonic, pvKeyFile, pvStateFile, blsKeyFile, blsPasswordFile)
+	filePV.Save(blsPassword)
 
 	accAddress, _ := n.keyInfo.GetAddress()
-	filePV.Save()
 	filePV.SetAccAddress(accAddress)
 
 	n.consensusKey = filePV.Key
diff --git a/testutil/datagen/init_val.go b/testutil/datagen/init_val.go
index 46e883b46..827a9ca4f 100644
--- a/testutil/datagen/init_val.go
+++ b/testutil/datagen/init_val.go
@@ -5,13 +5,11 @@ import (
 	"path/filepath"
 
 	cfg "github.com/cometbft/cometbft/config"
-	cmted25519 "github.com/cometbft/cometbft/crypto/ed25519"
 	cmtos "github.com/cometbft/cometbft/libs/os"
 	"github.com/cometbft/cometbft/p2p"
 	sdk "github.com/cosmos/cosmos-sdk/types"
 	"github.com/cosmos/go-bip39"
 
-	"github.com/babylonlabs-io/babylon/crypto/bls12381"
 	"github.com/babylonlabs-io/babylon/privval"
 )
 
@@ -42,13 +40,15 @@ func InitializeNodeValidatorFilesFromMnemonic(config *cfg.Config, mnemonic strin
 		return "", nil, err
 	}
 
+	// add bls config and set root same as config
+	blsCfg := privval.DefaultBlsConfig()
+	blsCfg.SetRoot(config.RootDir)
+
 	var filePV *privval.WrappedFilePV
 	if len(mnemonic) == 0 {
-		filePV = privval.LoadOrGenWrappedFilePV(pvKeyFile, pvStateFile)
+		filePV = privval.LoadOrGenWrappedFilePV(pvKeyFile, pvStateFile, blsCfg.BlsKeyFile(), blsCfg.BlsPasswordFile())
 	} else {
-		privKey := cmted25519.GenPrivKeyFromSecret([]byte(mnemonic))
-		blsPrivKey := bls12381.GenPrivKeyFromSecret([]byte(mnemonic))
-		filePV = privval.NewWrappedFilePV(privKey, blsPrivKey, pvKeyFile, pvStateFile)
+		filePV = privval.GenWrappedFilePVWithMnemonic(mnemonic, pvKeyFile, pvStateFile, blsCfg.BlsKeyFile(), blsCfg.BlsPasswordFile())
 	}
 	filePV.SetAccAddress(addr)
 
diff --git a/testutil/signer/private.go b/testutil/signer/private.go
index a4f39cb3a..a46f3e862 100644
--- a/testutil/signer/private.go
+++ b/testutil/signer/private.go
@@ -21,7 +21,7 @@ func SetupTestPrivSigner() (*signer.PrivSigner, error) {
 	defer func() {
 		_ = os.RemoveAll(nodeDir)
 	}()
-	privSigner, _ := signer.InitPrivSigner(nodeDir)
+	privSigner, _ := signer.InitTestPrivSigner(nodeDir)
 	return privSigner, nil
 }
 
diff --git a/x/checkpointing/client/cli/tx_test.go b/x/checkpointing/client/cli/tx_test.go
index bee75d842..24c37771d 100644
--- a/x/checkpointing/client/cli/tx_test.go
+++ b/x/checkpointing/client/cli/tx_test.go
@@ -110,7 +110,16 @@ func (s *CLITestSuite) TestCmdWrappedCreateValidator() {
 	pvStateFile := filepath.Join(homeDir, nodeCfg.PrivValidatorStateFile())
 	err = cmtos.EnsureDir(filepath.Dir(pvStateFile), 0777)
 	require.NoError(err)
-	wrappedPV := privval.LoadOrGenWrappedFilePV(pvKeyFile, pvStateFile)
+
+	blsCfg := privval.DefaultBlsConfig()
+	blsKeyFile := filepath.Join(homeDir, blsCfg.BlsKeyFile())
+	err = cmtos.EnsureDir(filepath.Dir(blsKeyFile), 0777)
+	require.NoError(err)
+	blsPasswordFile := filepath.Join(homeDir, blsCfg.BlsPasswordFile())
+	err = cmtos.EnsureDir(filepath.Dir(blsPasswordFile), 0777)
+	require.NoError(err)
+
+	wrappedPV := privval.LoadOrGenWrappedFilePV(pvKeyFile, pvStateFile, blsKeyFile, blsPasswordFile)
 	cmd := checkpointcli.CmdWrappedCreateValidator(authcodec.NewBech32Codec("cosmosvaloper"))
 
 	consPrivKey := wrappedPV.GetValPrivKey()
diff --git a/x/checkpointing/client/cli/utils.go b/x/checkpointing/client/cli/utils.go
index c30ad96dd..7d4161390 100644
--- a/x/checkpointing/client/cli/utils.go
+++ b/x/checkpointing/client/cli/utils.go
@@ -209,7 +209,14 @@ func getValKeyFromFile(homeDir string) (*privval.ValidatorKeys, error) {
 	if !cmtos.FileExists(keyPath) {
 		return nil, errors.New("validator key file does not exist")
 	}
-	wrappedPV := privval.LoadWrappedFilePV(keyPath, statePath)
+
+	blsCfg := privval.DefaultBlsConfig()
+	blsKeyPath := filepath.Join(homeDir, blsCfg.BlsKeyFile())
+	blsPasswordPath := filepath.Join(homeDir, blsCfg.BlsPasswordFile())
+	if !cmtos.FileExists(blsKeyPath) {
+		return nil, errors.New("validator bls key file does not exist")
+	}
+	wrappedPV := privval.LoadWrappedFilePV(keyPath, statePath, blsKeyPath, blsPasswordPath)
 
 	return privval.NewValidatorKeys(wrappedPV.GetValPrivKey(), wrappedPV.GetBlsPrivKey())
 }

From f6dd2c1ac2b1387b39bd86aecaac053d811253b0 Mon Sep 17 00:00:00 2001
From: wonjoon <wnjoon@gmail.com>
Date: Fri, 10 Jan 2025 20:15:05 +0900
Subject: [PATCH 5/8] refactor: refactoring codes related to bls and test code

---
 app/signer/private.go                         |  78 +------
 app/test_helpers.go                           |   2 +-
 cmd/babylond/cmd/create_bls_key.go            |  46 +---
 cmd/babylond/cmd/genhelpers/bls_add_test.go   |  31 ++-
 cmd/babylond/cmd/genhelpers/bls_create.go     |  18 +-
 .../cmd/genhelpers/bls_create_test.go         |  23 +-
 cmd/babylond/cmd/init.go                      | 199 ------------------
 cmd/babylond/cmd/init_test.go                 |  21 --
 cmd/babylond/cmd/root.go                      |   3 +-
 crypto/erc2335/erc2335.go                     |  19 +-
 crypto/erc2335/erc2335_test.go                |  34 +--
 privval/bls.go                                | 134 +++++-------
 privval/bls_test.go                           |  91 +++-----
 privval/file.go                               | 193 +----------------
 privval/file_test.go                          |  74 -------
 privval/util.go                               |  21 ++
 test/e2e/initialization/config.go             |   2 +-
 test/e2e/initialization/node.go               |  56 ++---
 testutil/datagen/init_val.go                  |  54 +++--
 testutil/helper/helper.go                     |   4 +-
 testutil/signer/private.go                    |  32 ++-
 x/checkpointing/client/cli/tx_test.go         |  27 +--
 x/checkpointing/client/cli/utils.go           |  20 +-
 23 files changed, 342 insertions(+), 840 deletions(-)
 delete mode 100644 cmd/babylond/cmd/init.go
 delete mode 100644 cmd/babylond/cmd/init_test.go
 delete mode 100644 privval/file_test.go
 create mode 100644 privval/util.go

diff --git a/app/signer/private.go b/app/signer/private.go
index 22012963c..d95fdc910 100644
--- a/app/signer/private.go
+++ b/app/signer/private.go
@@ -1,11 +1,9 @@
 package signer
 
 import (
-	"fmt"
 	"path/filepath"
 
 	cmtconfig "github.com/cometbft/cometbft/config"
-	cmtos "github.com/cometbft/cometbft/libs/os"
 
 	"github.com/babylonlabs-io/babylon/privval"
 	cmtprivval "github.com/cometbft/cometbft/privval"
@@ -17,83 +15,29 @@ type PrivSigner struct {
 
 func InitPrivSigner(nodeDir string) (*PrivSigner, error) {
 	nodeCfg := cmtconfig.DefaultConfig()
+	blsCfg := privval.DefaultBlsConfig()
+
 	pvKeyFile := filepath.Join(nodeDir, nodeCfg.PrivValidatorKeyFile())
-	err := cmtos.EnsureDir(filepath.Dir(pvKeyFile), 0777)
-	if err != nil {
-		return nil, err
-	}
 	pvStateFile := filepath.Join(nodeDir, nodeCfg.PrivValidatorStateFile())
-	err = cmtos.EnsureDir(filepath.Dir(pvStateFile), 0777)
-	if err != nil {
-		return nil, err
-	}
-
-	blsCfg := privval.DefaultBlsConfig()
-	blsCfg.SetRoot(nodeCfg.RootDir)
 	blsKeyFile := filepath.Join(nodeDir, blsCfg.BlsKeyFile())
-	err = cmtos.EnsureDir(filepath.Dir(blsKeyFile), 0777)
-	if err != nil {
-		return nil, err
-	}
 	blsPasswordFile := filepath.Join(nodeDir, blsCfg.BlsPasswordFile())
-	err = cmtos.EnsureDir(filepath.Dir(blsPasswordFile), 0777)
-	if err != nil {
+
+	if err := privval.IsValidFilePath(pvKeyFile, pvStateFile, blsKeyFile, blsPasswordFile); err != nil {
 		return nil, err
 	}
 
-	if !cmtos.FileExists(blsKeyFile) {
-		return nil, fmt.Errorf("BLS key file does not exist: %v", blsKeyFile)
-	}
+	cometPV := cmtprivval.LoadFilePV(pvKeyFile, pvStateFile)
+	blsPV := privval.LoadBlsPV(blsKeyFile, blsPasswordFile)
 
-	if !cmtos.FileExists(blsPasswordFile) {
-		return nil, fmt.Errorf("BLS password file does not exist: %v", blsPasswordFile)
-	}
-
-	blsPv := privval.LoadBlsPV(blsKeyFile, blsPasswordFile)
-	cmtPv := cmtprivval.LoadFilePV(pvKeyFile, pvStateFile)
-	wrappedPvKey := privval.WrappedFilePVKey{
-		CometPVKey: cmtPv.Key,
-		BlsPVKey:   blsPv.Key,
-	}
 	wrappedPV := &privval.WrappedFilePV{
-		Key:           wrappedPvKey,
-		LastSignState: cmtPv.LastSignState,
+		Key: privval.WrappedFilePVKey{
+			CometPVKey: cometPV.Key,
+			BlsPVKey:   blsPV.Key,
+		},
+		LastSignState: cometPV.LastSignState,
 	}
 
 	return &PrivSigner{
 		WrappedPV: wrappedPV,
 	}, nil
 }
-
-func InitTestPrivSigner(nodeDir string) (*PrivSigner, error) {
-	nodeCfg := cmtconfig.DefaultConfig()
-	pvKeyFile := filepath.Join(nodeDir, nodeCfg.PrivValidatorKeyFile())
-	err := cmtos.EnsureDir(filepath.Dir(pvKeyFile), 0777)
-	if err != nil {
-		return nil, err
-	}
-	pvStateFile := filepath.Join(nodeDir, nodeCfg.PrivValidatorStateFile())
-	err = cmtos.EnsureDir(filepath.Dir(pvStateFile), 0777)
-	if err != nil {
-		return nil, err
-	}
-
-	blsCfg := privval.DefaultBlsConfig()
-	blsCfg.SetRoot(nodeCfg.RootDir)
-	blsKeyFile := filepath.Join(nodeDir, blsCfg.BlsKeyFile())
-	err = cmtos.EnsureDir(filepath.Dir(blsKeyFile), 0777)
-	if err != nil {
-		return nil, err
-	}
-	blsPasswordFile := filepath.Join(nodeDir, blsCfg.BlsPasswordFile())
-	err = cmtos.EnsureDir(filepath.Dir(blsPasswordFile), 0777)
-	if err != nil {
-		return nil, err
-	}
-
-	wrappedPV := privval.LoadOrGenWrappedFilePV(pvKeyFile, pvStateFile, blsKeyFile, blsPasswordFile)
-
-	return &PrivSigner{
-		WrappedPV: wrappedPV,
-	}, nil
-}
diff --git a/app/test_helpers.go b/app/test_helpers.go
index 385a557d8..6bdcb4eda 100644
--- a/app/test_helpers.go
+++ b/app/test_helpers.go
@@ -246,7 +246,7 @@ func SetupWithBitcoinConf(t *testing.T, isCheckTx bool, btcConf bbn.SupportedBtc
 		Address: acc.GetAddress().String(),
 		Coins:   sdk.NewCoins(sdk.NewCoin(appparams.DefaultBondDenom, math.NewInt(100000000000000))),
 	}
-	ps.WrappedPV.Key.DelegatorAddress = acc.GetAddress().String()
+	ps.WrappedPV.Key.BlsPVKey.DelegatorAddress = acc.GetAddress().String()
 	// create validator set with single validator
 	genesisKey, err := signer.GenesisKeyFromPrivSigner(ps)
 	require.NoError(t, err)
diff --git a/cmd/babylond/cmd/create_bls_key.go b/cmd/babylond/cmd/create_bls_key.go
index ac500cf8a..6a6b62ea8 100644
--- a/cmd/babylond/cmd/create_bls_key.go
+++ b/cmd/babylond/cmd/create_bls_key.go
@@ -1,26 +1,17 @@
 package cmd
 
 import (
-	"bufio"
 	"fmt"
-	"log"
-	"os"
 	"path/filepath"
 	"strings"
 
-	cmtconfig "github.com/cometbft/cometbft/config"
-	cmtos "github.com/cometbft/cometbft/libs/os"
 	"github.com/cosmos/cosmos-sdk/client/flags"
-	"github.com/cosmos/cosmos-sdk/client/input"
 	sdk "github.com/cosmos/cosmos-sdk/types"
 	"github.com/spf13/cobra"
 
 	"github.com/babylonlabs-io/babylon/app"
 	appparams "github.com/babylonlabs-io/babylon/app/params"
-	"github.com/babylonlabs-io/babylon/crypto/bls12381"
-	"github.com/babylonlabs-io/babylon/crypto/erc2335"
 	"github.com/babylonlabs-io/babylon/privval"
-	cmtprivval "github.com/cometbft/cometbft/privval"
 )
 
 func CreateBlsKeyCmd() *cobra.Command {
@@ -62,42 +53,13 @@ $ babylond create-bls-key %s1f5tnl46mk4dfp4nx3n2vnrvyw2h2ydz6ykhk3r --home ./
 }
 
 func CreateBlsKey(home string, addr sdk.AccAddress) error {
-	nodeCfg := cmtconfig.DefaultConfig()
-	keyPath := filepath.Join(home, nodeCfg.PrivValidatorKeyFile())
-	statePath := filepath.Join(home, nodeCfg.PrivValidatorStateFile())
-	cmtPv := cmtprivval.LoadFilePV(keyPath, statePath)
 
 	blsCfg := privval.DefaultBlsConfig()
-	blsKeyPath := filepath.Join(home, blsCfg.BlsKeyFile())
-	blsPasswordFile := filepath.Join(home, blsCfg.BlsPasswordFile())
-
-	var blsPassword string
-	var err error
-	if !cmtos.FileExists(blsPasswordFile) {
-		log.Printf("BLS password file don't exists in file: %v", blsPasswordFile)
-		inBuf := bufio.NewReader(os.Stdin)
-		blsPassword, err = input.GetString("Enter your bls password", inBuf)
-		if err != nil {
-			return err
-		}
-		err = erc2335.SavePasswordToFile(blsPassword, blsPasswordFile)
-		if err != nil {
-			return err
-		}
-	}
-	blsPv := privval.NewBlsPV(bls12381.GenPrivKey(), blsKeyPath, blsPasswordFile)
-	blsPv.Key.Save(blsPassword)
+	keyPath := filepath.Join(home, blsCfg.BlsKeyFile())
+	passwordPath := filepath.Join(home, blsCfg.BlsPasswordFile())
 
-	wrappedPv := privval.WrappedFilePV{
-		Key: privval.WrappedFilePVKey{
-			CometPVKey: cmtPv.Key,
-			BlsPVKey:   blsPv.Key,
-		},
-		LastSignState: cmtPv.LastSignState,
-	}
+	password := privval.GetBlsPassword()
 
-	wrappedPv.SetAccAddress(addr)
-	log.Printf("Saved delegator address: %s", addr.String())
-	log.Printf("Saved delegator address in wrapperPv: %s", wrappedPv.Key.DelegatorAddress)
+	privval.GenBlsPV(keyPath, passwordPath, password, addr.String())
 	return nil
 }
diff --git a/cmd/babylond/cmd/genhelpers/bls_add_test.go b/cmd/babylond/cmd/genhelpers/bls_add_test.go
index 817e77937..4c7b8f21e 100644
--- a/cmd/babylond/cmd/genhelpers/bls_add_test.go
+++ b/cmd/babylond/cmd/genhelpers/bls_add_test.go
@@ -3,6 +3,7 @@ package genhelpers_test
 import (
 	"context"
 	"fmt"
+	"os"
 	"path/filepath"
 	"testing"
 
@@ -20,6 +21,7 @@ import (
 	cmtconfig "github.com/cometbft/cometbft/config"
 	tmjson "github.com/cometbft/cometbft/libs/json"
 	"github.com/cometbft/cometbft/libs/tempfile"
+	cmtprivval "github.com/cometbft/cometbft/privval"
 	"github.com/cosmos/cosmos-sdk/client"
 	"github.com/cosmos/cosmos-sdk/client/flags"
 	"github.com/cosmos/cosmos-sdk/server"
@@ -147,18 +149,26 @@ func Test_CmdAddBlsWithGentx(t *testing.T) {
 		v := testNetwork.Validators[i]
 		// build and create genesis BLS key
 		genBlsCmd := genhelpers.CmdCreateBls()
-		nodeCfg := cmtconfig.DefaultConfig()
 		homeDir := filepath.Join(v.Dir, "simd")
-		nodeCfg.SetRoot(homeDir)
-		keyPath := nodeCfg.PrivValidatorKeyFile()
-		statePath := nodeCfg.PrivValidatorStateFile()
 
+		nodeCfg := cmtconfig.DefaultConfig()
+		nodeCfg.SetRoot(homeDir)
 		blsCfg := privval.DefaultBlsConfig()
 		blsCfg.SetRoot(homeDir)
+
+		keyPath := nodeCfg.PrivValidatorKeyFile()
+		statePath := nodeCfg.PrivValidatorStateFile()
 		blsKeyFile := blsCfg.BlsKeyFile()
 		blsPasswordFile := blsCfg.BlsPasswordFile()
-		filePV := privval.GenWrappedFilePV(keyPath, statePath, blsKeyFile, blsPasswordFile)
-		filePV.SetAccAddress(v.Address)
+
+		err := privval.IsValidFilePath(keyPath, statePath, blsKeyFile, blsPasswordFile)
+		require.NoError(t, err)
+
+		filePV := cmtprivval.GenFilePV(keyPath, statePath)
+		filePV.Key.Save()
+		filePV.LastSignState.Save()
+		privval.GenBlsPV(blsKeyFile, blsPasswordFile, "password", v.Address.String())
+
 		_, err = cli.ExecTestCLICmd(v.ClientCtx, genBlsCmd, []string{fmt.Sprintf("--%s=%s", flags.FlagHome, homeDir)})
 		require.NoError(t, err)
 		genKeyFileName := filepath.Join(filepath.Dir(keyPath), fmt.Sprintf("gen-bls-%s.json", v.ValAddress))
@@ -180,6 +190,13 @@ func Test_CmdAddBlsWithGentx(t *testing.T) {
 		require.NotEmpty(t, checkpointingGenState.GenesisKeys)
 		gks := checkpointingGenState.GetGenesisKeys()
 		require.Equal(t, genKey, gks[i])
-		filePV.Clean(keyPath, statePath, blsKeyFile, blsPasswordFile)
+		Clean(keyPath, statePath, blsKeyFile, blsPasswordFile)
+	}
+}
+
+// Clean removes PVKey file and PVState file
+func Clean(paths ...string) {
+	for _, path := range paths {
+		_ = os.RemoveAll(filepath.Dir(path))
 	}
 }
diff --git a/cmd/babylond/cmd/genhelpers/bls_create.go b/cmd/babylond/cmd/genhelpers/bls_create.go
index 5c20b8f65..357139863 100644
--- a/cmd/babylond/cmd/genhelpers/bls_create.go
+++ b/cmd/babylond/cmd/genhelpers/bls_create.go
@@ -1,7 +1,6 @@
 package genhelpers
 
 import (
-	"log"
 	"path/filepath"
 	"strings"
 
@@ -11,6 +10,7 @@ import (
 
 	"github.com/babylonlabs-io/babylon/app"
 	"github.com/babylonlabs-io/babylon/privval"
+	cmtprivval "github.com/cometbft/cometbft/privval"
 )
 
 // CmdCreateBls CLI command to create BLS file with proof of possession.
@@ -35,14 +35,26 @@ $ babylond genbls --home ./
 
 			nodeCfg := cmtconfig.DefaultConfig()
 			blsCfg := privval.DefaultBlsConfig()
+
 			keyPath := filepath.Join(homeDir, nodeCfg.PrivValidatorKeyFile())
 			statePath := filepath.Join(homeDir, nodeCfg.PrivValidatorStateFile())
 			blsKeyPath := filepath.Join(homeDir, blsCfg.BlsKeyFile())
 			blsPasswordPath := filepath.Join(homeDir, blsCfg.BlsPasswordFile())
 
-			wrappedPV := privval.LoadWrappedFilePV(keyPath, statePath, blsKeyPath, blsPasswordPath)
+			if err := privval.IsValidFilePath(keyPath, statePath, blsKeyPath, blsPasswordPath); err != nil {
+				return err
+			}
 
-			log.Printf("Loaded delegator address in wrapperPv: %s", wrappedPV.Key.DelegatorAddress)
+			filePV := cmtprivval.LoadFilePV(keyPath, statePath)
+			blsPV := privval.LoadBlsPV(blsKeyPath, blsPasswordPath)
+
+			wrappedPV := &privval.WrappedFilePV{
+				Key: privval.WrappedFilePVKey{
+					CometPVKey: filePV.Key,
+					BlsPVKey:   blsPV.Key,
+				},
+				LastSignState: filePV.LastSignState,
+			}
 
 			outputFileName, err := wrappedPV.ExportGenBls(filepath.Dir(keyPath))
 			if err != nil {
diff --git a/cmd/babylond/cmd/genhelpers/bls_create_test.go b/cmd/babylond/cmd/genhelpers/bls_create_test.go
index 58c29176d..b80f1bbad 100644
--- a/cmd/babylond/cmd/genhelpers/bls_create_test.go
+++ b/cmd/babylond/cmd/genhelpers/bls_create_test.go
@@ -27,6 +27,7 @@ import (
 	"github.com/babylonlabs-io/babylon/privval"
 	"github.com/babylonlabs-io/babylon/testutil/signer"
 	"github.com/babylonlabs-io/babylon/x/checkpointing/types"
+	cmtprivval "github.com/cometbft/cometbft/privval"
 )
 
 func Test_CmdCreateBls(t *testing.T) {
@@ -70,15 +71,21 @@ func Test_CmdCreateBls(t *testing.T) {
 
 	// create BLS keys
 	nodeCfg := cmtconfig.DefaultConfig()
+	blsCfg := privval.DefaultBlsConfig()
+
 	keyPath := filepath.Join(home, nodeCfg.PrivValidatorKeyFile())
 	statePath := filepath.Join(home, nodeCfg.PrivValidatorStateFile())
-
-	blsCfg := privval.DefaultBlsConfig()
 	blsKeyFile := filepath.Join(home, blsCfg.BlsKeyFile())
 	blsPasswordFile := filepath.Join(home, blsCfg.BlsPasswordFile())
-	filePV := privval.GenWrappedFilePV(keyPath, statePath, blsKeyFile, blsPasswordFile)
-	defer filePV.Clean(keyPath, statePath, blsKeyFile, blsPasswordFile)
-	filePV.SetAccAddress(addr)
+
+	err = privval.IsValidFilePath(keyPath, statePath, blsKeyFile, blsPasswordFile)
+	require.NoError(t, err)
+
+	filePV := cmtprivval.GenFilePV(keyPath, statePath)
+	filePV.Key.Save()
+
+	blsPV := privval.GenBlsPV(blsKeyFile, blsPasswordFile, "password", addr.String())
+	defer Clean(keyPath, statePath, blsKeyFile, blsPasswordFile)
 
 	// execute the gen-bls cmd
 	err = genBlsCmd.ExecuteContext(ctx)
@@ -86,9 +93,11 @@ func Test_CmdCreateBls(t *testing.T) {
 	outputFilePath := filepath.Join(filepath.Dir(keyPath), fmt.Sprintf("gen-bls-%s.json", sdk.ValAddress(addr).String()))
 	require.NoError(t, err)
 	genKey, err := types.LoadGenesisKeyFromFile(outputFilePath)
+
 	require.NoError(t, err)
 	require.Equal(t, sdk.ValAddress(addr).String(), genKey.ValidatorAddress)
-	require.True(t, filePV.Key.BlsPVKey.PubKey.Equal(*genKey.BlsKey.Pubkey))
-	require.Equal(t, filePV.Key.CometPVKey.PubKey.Bytes(), genKey.ValPubkey.Bytes())
+	require.Equal(t, filePV.Key.PubKey.Bytes(), genKey.ValPubkey.Bytes())
+	require.True(t, blsPV.Key.PubKey.Equal(*genKey.BlsKey.Pubkey))
+
 	require.True(t, genKey.BlsKey.Pop.IsValid(*genKey.BlsKey.Pubkey, genKey.ValPubkey))
 }
diff --git a/cmd/babylond/cmd/init.go b/cmd/babylond/cmd/init.go
deleted file mode 100644
index 7322d04e9..000000000
--- a/cmd/babylond/cmd/init.go
+++ /dev/null
@@ -1,199 +0,0 @@
-package cmd
-
-import (
-	"bufio"
-	"encoding/json"
-	"errors"
-	"fmt"
-	"os"
-	"path/filepath"
-
-	"cosmossdk.io/math/unsafe"
-	"github.com/babylonlabs-io/babylon/privval"
-	"github.com/spf13/cobra"
-
-	errorsmod "cosmossdk.io/errors"
-	cfg "github.com/cometbft/cometbft/config"
-	"github.com/cosmos/cosmos-sdk/client"
-	"github.com/cosmos/cosmos-sdk/client/flags"
-	"github.com/cosmos/cosmos-sdk/client/input"
-	"github.com/cosmos/cosmos-sdk/server"
-	sdk "github.com/cosmos/cosmos-sdk/types"
-	"github.com/cosmos/cosmos-sdk/types/module"
-	"github.com/cosmos/cosmos-sdk/version"
-	"github.com/cosmos/cosmos-sdk/x/genutil"
-	cmtcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli"
-	"github.com/cosmos/cosmos-sdk/x/genutil/types"
-	"github.com/cosmos/go-bip39"
-)
-
-// wonjoon
-// copied from "https://github.com/cosmos/cosmos-sdk/x/genutil/client/cli/init.go"
-func InitCmd(mbm module.BasicManager, defaultNodeHome string) *cobra.Command {
-	cmd := &cobra.Command{
-		Use:   "init [moniker]",
-		Short: "Initialize private validator, p2p, genesis, and application configuration files",
-		Long:  `Initialize validators's and node's configuration files.`,
-		Args:  cobra.ExactArgs(1),
-		RunE: func(cmd *cobra.Command, args []string) error {
-			clientCtx := client.GetClientContextFromCmd(cmd)
-			cdc := clientCtx.Codec
-
-			serverCtx := server.GetServerContextFromCmd(cmd)
-			config := serverCtx.Config
-			config.SetRoot(clientCtx.HomeDir)
-
-			chainID, _ := cmd.Flags().GetString(flags.FlagChainID)
-			switch {
-			case chainID != "":
-			case clientCtx.ChainID != "":
-				chainID = clientCtx.ChainID
-			default:
-				chainID = fmt.Sprintf("test-chain-%v", unsafe.Str(6))
-			}
-
-			// Get bip39 mnemonic
-			var mnemonic string
-			recover, _ := cmd.Flags().GetBool(cmtcli.FlagRecover)
-			if recover {
-				inBuf := bufio.NewReader(cmd.InOrStdin())
-				value, err := input.GetString("Enter your bip39 mnemonic", inBuf)
-				if err != nil {
-					return err
-				}
-
-				mnemonic = value
-				if !bip39.IsMnemonicValid(mnemonic) {
-					return errors.New("invalid mnemonic")
-				}
-			}
-
-			// Get initial height
-			initHeight, _ := cmd.Flags().GetInt64(flags.FlagInitHeight)
-			if initHeight < 1 {
-				initHeight = 1
-			}
-
-			// Get bls password
-			inBuf := bufio.NewReader(cmd.InOrStdin())
-			blsPassword, err := input.GetString("Enter your bls password", inBuf)
-			if err != nil {
-				return err
-			}
-
-			// Initialize bls key
-			blsCfg := privval.BlsConfig{
-				RootDir:         config.RootDir,
-				BlsKeyPath:      filepath.Join(config.RootDir, cfg.DefaultConfigDir, privval.DefaultBlsKeyName),
-				BlsPasswordPath: filepath.Join(config.RootDir, cfg.DefaultConfigDir, privval.DefaultBlsPasswordName),
-			}
-
-			// Initialize BLS key and save to file
-			_, err = privval.InitializeBlsFileFromMnemonic(&blsCfg, blsPassword, mnemonic)
-			if err != nil {
-				return err
-			}
-
-			// InitializeNodeValidatorFilesFromMnemonic from cosmos-sdk/x/genutil/utils.go
-			nodeID, _, err := genutil.InitializeNodeValidatorFilesFromMnemonic(config, mnemonic)
-			if err != nil {
-				return err
-			}
-
-			config.Moniker = args[0]
-
-			genFile := config.GenesisFile()
-			overwrite, _ := cmd.Flags().GetBool(cmtcli.FlagOverwrite)
-			defaultDenom, _ := cmd.Flags().GetString(cmtcli.FlagDefaultBondDenom)
-
-			// use os.Stat to check if the file exists
-			_, err = os.Stat(genFile)
-			if !overwrite && !os.IsNotExist(err) {
-				return fmt.Errorf("genesis.json file already exists: %v", genFile)
-			}
-
-			// Overwrites the SDK default denom for side-effects
-			if defaultDenom != "" {
-				sdk.DefaultBondDenom = defaultDenom
-			}
-			appGenState := mbm.DefaultGenesis(cdc)
-
-			appState, err := json.MarshalIndent(appGenState, "", " ")
-			if err != nil {
-				return errorsmod.Wrap(err, "Failed to marshal default genesis state")
-			}
-
-			appGenesis := &types.AppGenesis{}
-			if _, err := os.Stat(genFile); err != nil {
-				if !os.IsNotExist(err) {
-					return err
-				}
-			} else {
-				appGenesis, err = types.AppGenesisFromFile(genFile)
-				if err != nil {
-					return errorsmod.Wrap(err, "Failed to read genesis doc from file")
-				}
-			}
-
-			appGenesis.AppName = version.AppName
-			appGenesis.AppVersion = version.Version
-			appGenesis.ChainID = chainID
-			appGenesis.AppState = appState
-			appGenesis.InitialHeight = initHeight
-			appGenesis.Consensus = &types.ConsensusGenesis{
-				Validators: nil,
-			}
-
-			if err = genutil.ExportGenesisFile(appGenesis, genFile); err != nil {
-				return errorsmod.Wrap(err, "Failed to export genesis file")
-			}
-
-			toPrint := newPrintInfo(config.Moniker, chainID, nodeID, "", appState)
-
-			cfg.WriteConfigFile(filepath.Join(config.RootDir, "config", "config.toml"), config)
-			return displayInfo(toPrint)
-		},
-	}
-
-	cmd.Flags().String(flags.FlagHome, defaultNodeHome, "node's home directory")
-	cmd.Flags().BoolP(cmtcli.FlagOverwrite, "o", false, "overwrite the genesis.json file")
-	cmd.Flags().Bool(cmtcli.FlagRecover, false, "provide seed phrase to recover existing key instead of creating")
-	cmd.Flags().String(flags.FlagChainID, "", "genesis file chain-id, if left blank will be randomly created")
-	cmd.Flags().String(cmtcli.FlagDefaultBondDenom, "", "genesis file default denomination, if left blank default value is 'stake'")
-	cmd.Flags().Int64(flags.FlagInitHeight, 1, "specify the initial block height at genesis")
-	cmd.Flags().String("bls-password", "", "BLS key password (if not provided, will prompt for input)")
-
-	return cmd
-}
-
-// copied from "https://github.com/cosmos/cosmos-sdk/x/genutil/client/cli/init.go"
-type printInfo struct {
-	Moniker    string          `json:"moniker" yaml:"moniker"`
-	ChainID    string          `json:"chain_id" yaml:"chain_id"`
-	NodeID     string          `json:"node_id" yaml:"node_id"`
-	GenTxsDir  string          `json:"gentxs_dir" yaml:"gentxs_dir"`
-	AppMessage json.RawMessage `json:"app_message" yaml:"app_message"`
-}
-
-// copied from "https://github.com/cosmos/cosmos-sdk/x/genutil/client/cli/init.go"
-func newPrintInfo(moniker, chainID, nodeID, genTxsDir string, appMessage json.RawMessage) printInfo {
-	return printInfo{
-		Moniker:    moniker,
-		ChainID:    chainID,
-		NodeID:     nodeID,
-		GenTxsDir:  genTxsDir,
-		AppMessage: appMessage,
-	}
-}
-
-// copied from "https://github.com/cosmos/cosmos-sdk/x/genutil/client/cli/init.go"
-func displayInfo(info printInfo) error {
-	out, err := json.MarshalIndent(info, "", " ")
-	if err != nil {
-		return err
-	}
-
-	_, err = fmt.Fprintf(os.Stderr, "%s\n", out)
-
-	return err
-}
diff --git a/cmd/babylond/cmd/init_test.go b/cmd/babylond/cmd/init_test.go
deleted file mode 100644
index 1f7441912..000000000
--- a/cmd/babylond/cmd/init_test.go
+++ /dev/null
@@ -1,21 +0,0 @@
-package cmd
-
-import (
-	"path/filepath"
-	"testing"
-
-	"github.com/babylonlabs-io/babylon/privval"
-	cfg "github.com/cometbft/cometbft/config"
-)
-
-func TestSaveFiles(t *testing.T) {
-
-	// clientCtx := client.GetClientContextFromCmd(&cobra.Command{})
-	homeDir := "test"
-	blsCfg := privval.BlsConfig{
-		RootDir:         homeDir,
-		BlsKeyPath:      filepath.Join(homeDir, cfg.DefaultConfigDir, privval.DefaultBlsKeyName),
-		BlsPasswordPath: filepath.Join(homeDir, cfg.DefaultConfigDir, privval.DefaultBlsPasswordName),
-	}
-	t.Log(blsCfg)
-}
diff --git a/cmd/babylond/cmd/root.go b/cmd/babylond/cmd/root.go
index cf78b1beb..7687ab268 100644
--- a/cmd/babylond/cmd/root.go
+++ b/cmd/babylond/cmd/root.go
@@ -167,8 +167,7 @@ func initRootCmd(rootCmd *cobra.Command, txConfig client.TxEncodingConfig, basic
 	gentxModule := basicManager[genutiltypes.ModuleName].(genutil.AppModuleBasic)
 
 	rootCmd.AddCommand(
-		// genutilcli.InitCmd(basicManager, app.DefaultNodeHome),
-		InitCmd(basicManager, app.DefaultNodeHome),
+		genutilcli.InitCmd(basicManager, app.DefaultNodeHome),
 		genutilcli.CollectGenTxsCmd(banktypes.GenesisBalancesIterator{}, app.DefaultNodeHome, gentxModule.GenTxValidator, authcodec.NewBech32Codec(params.Bech32PrefixValAddr)),
 		genutilcli.MigrateGenesisCmd(genutilcli.MigrationMap),
 		genutilcli.GenTxCmd(basicManager, txConfig, banktypes.GenesisBalancesIterator{}, app.DefaultNodeHome, authcodec.NewBech32Codec(params.Bech32PrefixValAddr)),
diff --git a/crypto/erc2335/erc2335.go b/crypto/erc2335/erc2335.go
index 673588e46..6933500b5 100644
--- a/crypto/erc2335/erc2335.go
+++ b/crypto/erc2335/erc2335.go
@@ -43,20 +43,23 @@ func Encrypt(privKey, pubKey []byte, password string) ([]byte, error) {
 	return json.Marshal(keystoreJSON)
 }
 
-// decrypt private key from erc2335 keystore
-func Decrypt(keystoreJSON []byte, password string) ([]byte, error) {
-	// Parse the keystore json
+func LoadKeyStore(filePath string) (Erc2335KeyStore, error) {
 	var keystore Erc2335KeyStore
 
-	if err := json.Unmarshal(keystoreJSON, &keystore); err != nil {
-		return nil, errors.Wrap(err, "failed to parse keystore json")
+	keyJSONBytes, err := os.ReadFile(filePath)
+	if err != nil {
+		return Erc2335KeyStore{}, err
 	}
 
-	// Verify version
-	if keystore.Version != 4 {
-		return nil, fmt.Errorf("invalid keystore version: %d", keystore.Version)
+	if err := json.Unmarshal(keyJSONBytes, &keystore); err != nil {
+		return Erc2335KeyStore{}, err
 	}
 
+	return keystore, nil
+}
+
+// decrypt private key from erc2335 keystore
+func Decrypt(keystore Erc2335KeyStore, password string) ([]byte, error) {
 	encryptor := keystorev4.New()
 	return encryptor.Decrypt(keystore.Crypto, password)
 }
diff --git a/crypto/erc2335/erc2335_test.go b/crypto/erc2335/erc2335_test.go
index c6c51d4b3..aa56f650e 100644
--- a/crypto/erc2335/erc2335_test.go
+++ b/crypto/erc2335/erc2335_test.go
@@ -1,6 +1,7 @@
 package erc2335
 
 import (
+	"encoding/json"
 	"os"
 	"testing"
 
@@ -9,37 +10,37 @@ import (
 )
 
 func TestEncryptBLS(t *testing.T) {
-	// TODO
 	t.Run("create bls key", func(t *testing.T) {
-
 		blsPrivKey := bls12381.GenPrivKey()
 		blsPubKey := blsPrivKey.PubKey().Bytes()
 
 		t.Run("encrypt bls key", func(t *testing.T) {
-
 			password := CreateRandomPassword()
 			t.Logf("password: %s", password)
-
 			encryptedBlsKey, err := Encrypt(blsPrivKey, blsPubKey, password)
 			require.NoError(t, err)
 			t.Logf("encrypted bls key: %s", encryptedBlsKey)
 
 			t.Run("decrypt bls key", func(t *testing.T) {
+				var keystore Erc2335KeyStore
+				err = json.Unmarshal(encryptedBlsKey, &keystore)
+				require.NoError(t, err)
 
-				decryptedBlsKey, err := Decrypt(encryptedBlsKey, password)
+				decryptedBlsKey, err := Decrypt(keystore, password)
 				require.NoError(t, err)
 				require.Equal(t, blsPrivKey, bls12381.PrivateKey(decryptedBlsKey))
 			})
 
 			t.Run("decrypt bls key with wrong password", func(t *testing.T) {
-
-				_, err := Decrypt(encryptedBlsKey, "wrong password")
+				var keystore Erc2335KeyStore
+				err = json.Unmarshal(encryptedBlsKey, &keystore)
+				require.NoError(t, err)
+				_, err := Decrypt(keystore, "wrong password")
 				require.Error(t, err)
 			})
 		})
 
 		t.Run("save password and encrypt bls key", func(t *testing.T) {
-
 			password := CreateRandomPassword()
 			t.Logf("password: %s", password)
 
@@ -50,16 +51,19 @@ func TestEncryptBLS(t *testing.T) {
 			require.NoError(t, err)
 
 			t.Run("load password and decrypt bls key", func(t *testing.T) {
-
 				password, err := LoadPaswordFromFile("password.txt")
 				require.NoError(t, err)
-				decryptedBlsKey, err := Decrypt(encryptedBlsKey, password)
+
+				var keystore Erc2335KeyStore
+				err = json.Unmarshal(encryptedBlsKey, &keystore)
+				require.NoError(t, err)
+
+				decryptedBlsKey, err := Decrypt(keystore, password)
 				require.NoError(t, err)
 				require.Equal(t, blsPrivKey, bls12381.PrivateKey(decryptedBlsKey))
 			})
 
 			t.Run("save new password into same file", func(t *testing.T) {
-
 				newPassword := CreateRandomPassword()
 				t.Logf("new password: %s", newPassword)
 				err = SavePasswordToFile(newPassword, "password.txt")
@@ -67,10 +71,14 @@ func TestEncryptBLS(t *testing.T) {
 			})
 
 			t.Run("failed when load different password and decrypt bls key", func(t *testing.T) {
-
 				password, err := LoadPaswordFromFile("password.txt")
 				require.NoError(t, err)
-				_, err = Decrypt(encryptedBlsKey, password)
+
+				var keystore Erc2335KeyStore
+				err = json.Unmarshal(encryptedBlsKey, &keystore)
+				require.NoError(t, err)
+
+				_, err = Decrypt(keystore, password)
 				require.Error(t, err)
 			})
 
diff --git a/privval/bls.go b/privval/bls.go
index 05da75790..e990db8e3 100644
--- a/privval/bls.go
+++ b/privval/bls.go
@@ -1,6 +1,7 @@
 package privval
 
 import (
+	"bufio"
 	"encoding/json"
 	"fmt"
 	"os"
@@ -11,7 +12,7 @@ import (
 	cmtcfg "github.com/cometbft/cometbft/config"
 	cmtos "github.com/cometbft/cometbft/libs/os"
 	"github.com/cometbft/cometbft/libs/tempfile"
-	"github.com/cosmos/go-bip39"
+	"github.com/cosmos/cosmos-sdk/client/input"
 )
 
 const (
@@ -27,79 +28,78 @@ type BlsPVKey struct {
 	PubKey  bls12381.PublicKey  `json:"bls_pub_key"`
 	PrivKey bls12381.PrivateKey `json:"bls_priv_key"`
 
+	DelegatorAddress string
+
 	filePath     string
 	passwordPath string
 }
 
-// initialize node validator bls key with password
-func InitializeBlsFile(config *BlsConfig, password string) (blsPubKey []byte, err error) {
-	return InitializeBlsFileFromMnemonic(config, password, "")
+func NewBlsPV(privKey bls12381.PrivateKey, keyFilePath, passwordFilePath, delegatorAddress string) *BlsPV {
+	return &BlsPV{
+		Key: BlsPVKey{
+			PubKey:           privKey.PubKey(),
+			PrivKey:          privKey,
+			DelegatorAddress: delegatorAddress,
+			filePath:         keyFilePath,
+			passwordPath:     passwordFilePath,
+		},
+	}
 }
 
-// initialize node validator bls key with mnemonic and password
-func InitializeBlsFileFromMnemonic(config *BlsConfig, password, mnemonic string) (blsPubKey []byte, err error) {
-	if len(mnemonic) > 0 && !bip39.IsMnemonicValid(mnemonic) {
-		return nil, fmt.Errorf("invalid mnemonic")
-	}
+func GenBlsPV(keyFilePath, passwordFilePath, password, delegatorAddress string) *BlsPV {
+	pv := NewBlsPV(bls12381.GenPrivKey(), keyFilePath, passwordFilePath, delegatorAddress)
+	pv.Key.Save(password, delegatorAddress)
+	return pv
+}
 
-	blsKeyFile := config.BlsKeyFile()
-	if err := os.MkdirAll(filepath.Dir(blsKeyFile), 0o777); err != nil {
-		return nil, fmt.Errorf("could not create directory for bls key %q: %w", filepath.Dir(blsKeyFile), err)
+func LoadBlsPV(keyFilePath, passwordFilePath string) *BlsPV {
+	password, err := erc2335.LoadPaswordFromFile(passwordFilePath)
+	if err != nil {
+		cmtos.Exit(fmt.Sprintf("failed to read BLS password file: %v", err.Error()))
 	}
 
-	blsPasswordFile := config.BlsPasswordFile()
-	if err := os.MkdirAll(filepath.Dir(blsPasswordFile), 0o777); err != nil {
-		return nil, fmt.Errorf("could not create directory for bls password %q: %w", filepath.Dir(blsPasswordFile), err)
+	keystore, err := erc2335.LoadKeyStore(keyFilePath)
+	if err != nil {
+		cmtos.Exit(fmt.Sprintf("failed to read erc2335 keystore: %v", err.Error()))
 	}
 
-	// var blsPv *BlsPV
-	var privKey bls12381.PrivateKey
-	if len(mnemonic) == 0 {
-		privKey = bls12381.GenPrivKey()
-	} else {
-		privKey = bls12381.GenPrivKeyFromSecret([]byte(mnemonic))
+	// decrypt bls key from erc2335 type of structure
+	privKey, err := erc2335.Decrypt(keystore, password)
+	if err != nil {
+		cmtos.Exit(fmt.Sprintf("failed to decrypt BLS key: %v", err.Error()))
 	}
 
-	blsPv := NewBlsPV(privKey, blsKeyFile, blsPasswordFile)
-	blsPv.Save(password)
-	return privKey.PubKey().Bytes(), nil
-}
-
-func NewBlsPV(privKey bls12381.PrivateKey, keyFilePath, passwordFilePath string) *BlsPV {
+	blsPrivKey := bls12381.PrivateKey(privKey)
 	return &BlsPV{
 		Key: BlsPVKey{
-			PubKey:       privKey.PubKey(),
-			PrivKey:      privKey,
-			filePath:     keyFilePath,
-			passwordPath: passwordFilePath,
+			PubKey:           blsPrivKey.PubKey(),
+			PrivKey:          blsPrivKey,
+			DelegatorAddress: keystore.Description,
+			filePath:         keyFilePath,
+			passwordPath:     passwordFilePath,
 		},
 	}
 }
 
-func (pv *BlsPV) Save(password string) {
-	pv.Key.Save(password)
-}
-
-func (pvKey *BlsPVKey) Save(password string) {
-
-	passwordOutFile := pvKey.passwordPath
-	if passwordOutFile == "" {
-		panic("cannot save PrivValidator BLS key: password filePath not set")
-	}
-
-	// save password to file
-	err := erc2335.SavePasswordToFile(password, passwordOutFile)
+func GetBlsPassword() string {
+	inBuf := bufio.NewReader(os.Stdin)
+	password, err := input.GetString("Enter your bls password", inBuf)
 	if err != nil {
-		panic(err)
+		cmtos.Exit("failed to get BLS password")
 	}
+	return password
+}
 
-	keyOutFile := pvKey.filePath
-	if keyOutFile == "" {
-		panic("cannot save PrivValidator BLS key: filePath not set")
+// Save bls key using password
+// Check both paths of bls key and password inside function
+func (k *BlsPVKey) Save(password, addr string) {
+	// check file path is valid
+	if err := IsValidFilePath(k.filePath, k.passwordPath); err != nil {
+		panic(err)
 	}
 
 	// encrypt the bls12381 key to erc2335 type
-	erc2335BlsPvKey, err := erc2335.Encrypt(pvKey.PrivKey, pvKey.PubKey.Bytes(), password)
+	erc2335BlsPvKey, err := erc2335.Encrypt(k.PrivKey, k.PubKey.Bytes(), password)
 	if err != nil {
 		panic(err)
 	}
@@ -110,42 +110,24 @@ func (pvKey *BlsPVKey) Save(password string) {
 		panic(err)
 	}
 
+	// save the delegator address to description field
+	keystore.Description = addr
+
+	// convert keystore to json
 	jsonBytes, err := json.MarshalIndent(keystore, "", "  ")
 	if err != nil {
 		panic(err)
 	}
 
-	if err := tempfile.WriteFileAtomic(keyOutFile, jsonBytes, 0600); err != nil {
+	// write generated erc2335 keystore to file
+	if err := tempfile.WriteFileAtomic(k.filePath, jsonBytes, 0600); err != nil {
 		panic(err)
 	}
-}
-
-func LoadBlsPV(keyFilePath, passwordFilePath string) *BlsPV {
-
-	password, err := erc2335.LoadPaswordFromFile(passwordFilePath)
-	if err != nil {
-		cmtos.Exit(fmt.Sprintf("failed to read BLS password file: %v", err.Error()))
-	}
-
-	keyJSONBytes, err := os.ReadFile(keyFilePath)
-	if err != nil {
-		cmtos.Exit(fmt.Sprintf("failed to read BLS file: %v", err.Error()))
-	}
 
-	// decrypt bls key from erc2335 type of structure
-	privKey, err := erc2335.Decrypt(keyJSONBytes, password)
+	// save used password to file
+	err = erc2335.SavePasswordToFile(password, k.passwordPath)
 	if err != nil {
-		cmtos.Exit(fmt.Sprintf("failed to decrypt BLS key: %v", err.Error()))
-	}
-
-	blsPrivKey := bls12381.PrivateKey(privKey)
-
-	return &BlsPV{
-		Key: BlsPVKey{
-			PubKey:   blsPrivKey.PubKey(),
-			PrivKey:  blsPrivKey,
-			filePath: keyFilePath,
-		},
+		panic(err)
 	}
 }
 
diff --git a/privval/bls_test.go b/privval/bls_test.go
index 03248ca6c..6e6c134e5 100644
--- a/privval/bls_test.go
+++ b/privval/bls_test.go
@@ -5,86 +5,55 @@ import (
 	"path/filepath"
 	"testing"
 
+	"github.com/cometbft/cometbft/crypto/ed25519"
+
+	"github.com/babylonlabs-io/babylon/crypto/bls12381"
 	"github.com/babylonlabs-io/babylon/crypto/erc2335"
-	cmtcfg "github.com/cometbft/cometbft/config"
+	"github.com/cosmos/cosmos-sdk/types"
 	"github.com/test-go/testify/assert"
 )
 
-// func TestNewBlsPV(t *testing.T) {
-// 	pv := NewBlsPV(bls12381.GenPrivKey(), "test")
-// 	assert.NotNil(t, pv)
-// }
+func TestNewBlsPV(t *testing.T) {
+	tempDir := t.TempDir()
+	defer os.RemoveAll(tempDir)
 
-func TestCleanUp(t *testing.T) {
-	blsKeyFilePath := DefaultBlsConfig().BlsKeyFile()
-	t.Log("bls key file path", blsKeyFilePath)
-	cleanup(blsKeyFilePath)
-}
+	cfg := DefaultBlsConfig()
 
-func TestInitializeBlsFile(t *testing.T) {
+	keyFilePath := filepath.Join(tempDir, cfg.BlsKeyFile())
+	passwordFilePath := filepath.Join(tempDir, cfg.BlsPasswordFile())
 
-	t.Run("set default config", func(t *testing.T) {
-		blsCfg := DefaultBlsConfig()
-		assert.NotNil(t, blsCfg)
-		assert.Equal(t, blsCfg.BlsKeyPath, filepath.Join(cmtcfg.DefaultConfigDir, DefaultBlsKeyName))
+	t.Run("save bls key to file without delegator address", func(t *testing.T) {
+		pv := NewBlsPV(bls12381.GenPrivKey(), keyFilePath, passwordFilePath, "")
+		assert.NotNil(t, pv)
 
 		password := erc2335.CreateRandomPassword()
-		t.Log("password", password)
+		pv.Key.Save(password, "")
 
-		t.Run("generate key without mnemonic", func(t *testing.T) {
-			blsPubKey, err := InitializeBlsFile(&blsCfg, password)
-			assert.NoError(t, err)
-			assert.NotNil(t, blsPubKey)
-		})
+		t.Run("load bls key from file", func(t *testing.T) {
+			loadedPv := LoadBlsPV(keyFilePath, passwordFilePath)
+			assert.NotNil(t, loadedPv)
 
-		t.Run("load key with password", func(t *testing.T) {
-			blsPubKey, err := InitializeBlsFile(&blsCfg, password)
-			assert.NoError(t, err)
-			assert.NotNil(t, blsPubKey)
-		})
-
-		t.Run("clean file path", func(t *testing.T) {
-			blsKeyFilePath := DefaultBlsConfig().BlsKeyFile()
-			t.Log("bls key file path", blsKeyFilePath)
-			cleanup(blsKeyFilePath)
+			assert.Equal(t, pv.Key.PrivKey, loadedPv.Key.PrivKey)
+			assert.Equal(t, pv.Key.PubKey.Bytes(), loadedPv.Key.PubKey.Bytes())
 		})
 	})
-}
-
-func TestSavePasswordToFile(t *testing.T) {
 
-	blsCfg := DefaultBlsConfig()
+	t.Run("save bls key to file with delegator address", func(t *testing.T) {
+		pv := NewBlsPV(bls12381.GenPrivKey(), keyFilePath, passwordFilePath, "")
+		assert.NotNil(t, pv)
 
-	t.Run("failed to load unsaved file", func(t *testing.T) {
-		_, err := erc2335.LoadPaswordFromFile(blsCfg.BlsPasswordFile())
-		assert.Error(t, err)
-	})
-
-	t.Run("create password file", func(t *testing.T) {
 		password := erc2335.CreateRandomPassword()
-		t.Log("password", password)
 
-		err := os.MkdirAll(filepath.Dir(blsCfg.BlsPasswordFile()), 0o777)
-		assert.NoError(t, err)
+		delegatorAddress := types.AccAddress(ed25519.GenPrivKey().PubKey().Address()).String()
+		pv.Key.Save(password, delegatorAddress)
 
-		err = erc2335.SavePasswordToFile(password, blsCfg.BlsPasswordFile())
-		assert.NoError(t, err)
+		t.Run("load bls key from file", func(t *testing.T) {
+			loadedPv := LoadBlsPV(keyFilePath, passwordFilePath)
+			assert.NotNil(t, loadedPv)
 
-		t.Run("load password file", func(t *testing.T) {
-
-			loadPassword, err := erc2335.LoadPaswordFromFile(blsCfg.BlsPasswordFile())
-			assert.NoError(t, err)
-			assert.Equal(t, password, loadPassword)
+			assert.Equal(t, pv.Key.PrivKey, loadedPv.Key.PrivKey)
+			assert.Equal(t, pv.Key.PubKey.Bytes(), loadedPv.Key.PubKey.Bytes())
+			assert.Equal(t, delegatorAddress, loadedPv.Key.DelegatorAddress)
 		})
 	})
-
-	t.Run("clean file path", func(t *testing.T) {
-		blsPasswordFilePath := DefaultBlsConfig().BlsPasswordFile()
-		t.Log("bls passwordd file path", blsPasswordFilePath)
-		cleanup(blsPasswordFilePath)
-	})
-}
-
-func cleanup(blsKeyPath string) {
-	_ = os.RemoveAll(filepath.Dir(blsKeyPath))
 }
diff --git a/privval/file.go b/privval/file.go
index 879f94e64..dbdffdd71 100644
--- a/privval/file.go
+++ b/privval/file.go
@@ -1,56 +1,26 @@
 package privval
 
 import (
-	"encoding/json"
 	"errors"
 	"fmt"
-	"os"
 	"path/filepath"
 
 	cmtcrypto "github.com/cometbft/cometbft/crypto"
-	"github.com/cometbft/cometbft/crypto/ed25519"
 	cmtjson "github.com/cometbft/cometbft/libs/json"
 	cmtos "github.com/cometbft/cometbft/libs/os"
 	"github.com/cometbft/cometbft/libs/tempfile"
 	"github.com/cometbft/cometbft/privval"
-	cmtproto "github.com/cometbft/cometbft/proto/tendermint/types"
 	"github.com/cosmos/cosmos-sdk/crypto/codec"
 
 	"github.com/babylonlabs-io/babylon/crypto/bls12381"
-	"github.com/babylonlabs-io/babylon/crypto/erc2335"
 	checkpointingtypes "github.com/babylonlabs-io/babylon/x/checkpointing/types"
 	sdk "github.com/cosmos/cosmos-sdk/types"
 )
 
-// copied from github.com/cometbft/cometbft/privval/file.go"
-//
-//nolint:unused
-const (
-	stepNone      int8 = 0 // Used to distinguish the initial state
-	stepPropose   int8 = 1
-	stepPrevote   int8 = 2
-	stepPrecommit int8 = 3
-)
-
-// copied from github.com/cometbft/cometbft/privval/file.go"
-//
-//nolint:unused
-func voteToStep(vote *cmtproto.Vote) int8 {
-	switch vote.Type {
-	case cmtproto.PrevoteType:
-		return stepPrevote
-	case cmtproto.PrecommitType:
-		return stepPrecommit
-	default:
-		panic(fmt.Sprintf("Unknown vote type: %v", vote.Type))
-	}
-}
-
 // WrappedFilePVKey wraps FilePVKey with BLS keys.
 type WrappedFilePVKey struct {
-	CometPVKey       privval.FilePVKey
-	BlsPVKey         BlsPVKey
-	DelegatorAddress string
+	CometPVKey privval.FilePVKey
+	BlsPVKey   BlsPVKey
 }
 
 // WrappedFilePV wraps FilePV with WrappedFilePVKey.
@@ -59,99 +29,6 @@ type WrappedFilePV struct {
 	LastSignState privval.FilePVLastSignState
 }
 
-// GenWrappedFilePV generates a new validator with randomly generated private key
-// and sets the filePaths, but does not call Save().
-func GenWrappedFilePV(cmtKeyFilePath, cmtStateFilePath, blsKeyFilePath, blsPasswordFilePath string) *WrappedFilePV {
-	cometPv := privval.NewFilePV(ed25519.GenPrivKey(), cmtKeyFilePath, cmtStateFilePath)
-	blsPv := NewBlsPV(bls12381.GenPrivKey(), blsKeyFilePath, blsPasswordFilePath)
-	return &WrappedFilePV{
-		Key: WrappedFilePVKey{
-			CometPVKey: cometPv.Key,
-			BlsPVKey:   blsPv.Key,
-		},
-		LastSignState: cometPv.LastSignState,
-	}
-}
-
-func GenWrappedFilePVWithMnemonic(mnemonic, cmtKeyFilePath, cmtStateFilePath, blsKeyFilePath, blsPasswordFilePath string) *WrappedFilePV {
-	cometPv := privval.NewFilePV(ed25519.GenPrivKeyFromSecret([]byte(mnemonic)), cmtKeyFilePath, cmtStateFilePath)
-	blsPv := NewBlsPV(bls12381.GenPrivKeyFromSecret([]byte(mnemonic)), blsKeyFilePath, blsPasswordFilePath)
-	return &WrappedFilePV{
-		Key: WrappedFilePVKey{
-			CometPVKey: cometPv.Key,
-			BlsPVKey:   blsPv.Key,
-		},
-		LastSignState: cometPv.LastSignState,
-	}
-}
-
-// LoadOrGenWrappedFilePV loads a FilePV from the given filePaths
-// or else generates a new one and saves it to the filePaths.
-func LoadOrGenWrappedFilePV(cmtKeyFilePath, cmtStateFilePath, blsKeyFilePath, blsPasswordFilePath string) *WrappedFilePV {
-
-	var blsPV *BlsPV
-
-	if !cmtos.FileExists(blsKeyFilePath) {
-		var blsPassword string
-		var err error
-		if cmtos.FileExists(blsPasswordFilePath) {
-			blsPassword, err = erc2335.LoadPaswordFromFile(blsPasswordFilePath)
-			if err != nil {
-				cmtos.Exit(fmt.Sprintf("failed to read BLS password file: %v", err.Error()))
-			}
-		} else {
-			blsPassword = erc2335.CreateRandomPassword()
-		}
-
-		blsPV = NewBlsPV(bls12381.GenPrivKey(), blsKeyFilePath, blsPassword)
-		blsPV.Save(blsPassword)
-	} else {
-		blsPV = LoadBlsPV(blsKeyFilePath, blsPasswordFilePath)
-	}
-
-	var cometPV *privval.FilePV
-	if cmtos.FileExists(cmtKeyFilePath) {
-		cometPV = privval.LoadFilePV(cmtKeyFilePath, cmtStateFilePath)
-	} else {
-		cometPV = privval.GenFilePV(cmtKeyFilePath, cmtStateFilePath)
-		cometPV.Key.Save()
-	}
-
-	wrappedFilePV := &WrappedFilePV{
-		Key: WrappedFilePVKey{
-			CometPVKey: cometPV.Key,
-			BlsPVKey:   blsPV.Key,
-		},
-		LastSignState: cometPV.LastSignState,
-	}
-
-	return wrappedFilePV
-}
-
-func LoadWrappedFilePV(keyFilePath, stateFilePath, blsKeyFilePath, blsPasswordFilePath string) *WrappedFilePV {
-
-	if !cmtos.FileExists(blsKeyFilePath) {
-		cmtos.Exit(fmt.Sprintf("BLS key file does not exist: %v", blsKeyFilePath))
-	}
-
-	blsPv := LoadBlsPV(blsKeyFilePath, blsPasswordFilePath)
-
-	if !cmtos.FileExists(keyFilePath) {
-		cmtos.Exit(fmt.Sprintf("validator key file does not exist: %v", keyFilePath))
-	}
-
-	cometPv := privval.LoadFilePV(keyFilePath, stateFilePath)
-
-	return &WrappedFilePV{
-		Key: WrappedFilePVKey{
-			CometPVKey:       cometPv.Key,
-			BlsPVKey:         blsPv.Key,
-			DelegatorAddress: ReadDelegatorAddressFromFile(blsKeyFilePath),
-		},
-		LastSignState: cometPv.LastSignState,
-	}
-}
-
 // ExportGenBls writes a {address, bls_pub_key, pop, and pub_key} into a json file
 func (pv *WrappedFilePV) ExportGenBls(filePath string) (outputFileName string, err error) {
 	if !cmtos.FileExists(filePath) {
@@ -191,65 +68,16 @@ func (pv *WrappedFilePV) ExportGenBls(filePath string) (outputFileName string, e
 // GetAddress returns the delegator address of the validator.
 // Implements PrivValidator.
 func (pv *WrappedFilePV) GetAddress() sdk.ValAddress {
-	if pv.Key.DelegatorAddress == "" {
+	if pv.Key.BlsPVKey.DelegatorAddress == "" {
 		return sdk.ValAddress{}
 	}
-	addr, err := sdk.AccAddressFromBech32(pv.Key.DelegatorAddress)
+	addr, err := sdk.AccAddressFromBech32(pv.Key.BlsPVKey.DelegatorAddress)
 	if err != nil {
 		cmtos.Exit(err.Error())
 	}
 	return sdk.ValAddress(addr)
 }
 
-func (pv *WrappedFilePV) SetAccAddress(addr sdk.AccAddress) {
-	pv.Key.DelegatorAddress = addr.String()
-	// pv.Key.Save()
-	SaveDelegatorAddressToFile(pv.Key.DelegatorAddress, pv.Key.BlsPVKey.filePath)
-}
-
-func SaveDelegatorAddressToFile(delegatorAddress, filePath string) {
-
-	var data map[string]interface{}
-	if err := ReadJSON(filePath, &data); err != nil {
-		cmtos.Exit(fmt.Sprintf("Failed to read JSON file: %v\n", err))
-	}
-
-	data["description"] = delegatorAddress
-	if err := WriteJSON(filePath, data); err != nil {
-		cmtos.Exit(fmt.Sprintf("Failed to write to JSON file: %v\n", err))
-	}
-}
-
-func ReadDelegatorAddressFromFile(filePath string) string {
-
-	var data map[string]interface{}
-	if err := ReadJSON(filePath, &data); err != nil {
-		cmtos.Exit(fmt.Sprintf("Failed to read JSON file: %v\n", err))
-	}
-	return data["description"].(string)
-}
-
-func WriteJSON(filePath string, v interface{}) error {
-	jsonBytes, err := json.MarshalIndent(v, "", "  ")
-	if err != nil {
-		return err
-	}
-	return os.WriteFile(filePath, jsonBytes, 0644)
-}
-
-func ReadJSON(filePath string, v interface{}) error {
-	file, err := os.Open(filePath)
-	if err != nil {
-		if os.IsNotExist(err) {
-			*v.(*map[string]interface{}) = make(map[string]interface{})
-			return nil
-		}
-		return err
-	}
-	defer file.Close()
-	return json.NewDecoder(file).Decode(v)
-}
-
 // GetPubKey returns the public key of the validator.
 func (pv *WrappedFilePV) GetPubKey() (cmtcrypto.PubKey, error) {
 	return pv.Key.CometPVKey.PubKey, nil
@@ -286,16 +114,3 @@ func (pv *WrappedFilePV) SignMsgWithBls(msg []byte) (bls12381.Signature, error)
 	}
 	return bls12381.Sign(blsPrivKey, msg), nil
 }
-
-// Clean removes PVKey file and PVState file
-func (pv *WrappedFilePV) Clean(paths ...string) {
-	for _, path := range paths {
-		_ = os.RemoveAll(filepath.Dir(path))
-	}
-}
-
-func (pv *WrappedFilePV) Save(password string) {
-	pv.Key.CometPVKey.Save()
-	pv.Key.BlsPVKey.Save(password)
-	pv.LastSignState.Save()
-}
diff --git a/privval/file_test.go b/privval/file_test.go
deleted file mode 100644
index 4afcb9d35..000000000
--- a/privval/file_test.go
+++ /dev/null
@@ -1,74 +0,0 @@
-package privval
-
-import (
-	"encoding/json"
-	"os"
-	"path/filepath"
-	"testing"
-
-	"github.com/babylonlabs-io/babylon/crypto/erc2335"
-	cmtcfg "github.com/cometbft/cometbft/config"
-	cmtos "github.com/cometbft/cometbft/libs/os"
-
-	"github.com/cosmos/cosmos-sdk/types"
-	"github.com/test-go/testify/assert"
-)
-
-func TestSaveDelegatorAddressToFile(t *testing.T) {
-
-	tempDir := t.TempDir()
-	defer os.RemoveAll(tempDir)
-
-	ccfg := cmtcfg.DefaultConfig()
-	ccfg.SetRoot(tempDir)
-	bcfg := DefaultBlsConfig()
-	bcfg.SetRoot(tempDir)
-
-	pvKeyFile := filepath.Join(tempDir, ccfg.PrivValidatorKeyFile())
-	pvStateFile := filepath.Join(tempDir, ccfg.PrivValidatorStateFile())
-	blsKeyFile := filepath.Join(tempDir, bcfg.BlsKeyFile())
-	blsPasswordFile := filepath.Join(tempDir, bcfg.BlsPasswordFile())
-
-	err := cmtos.EnsureDir(filepath.Dir(pvKeyFile), 0777)
-	assert.Nil(t, err)
-	err = cmtos.EnsureDir(filepath.Dir(pvStateFile), 0777)
-	assert.Nil(t, err)
-	err = cmtos.EnsureDir(filepath.Dir(blsKeyFile), 0777)
-	assert.Nil(t, err)
-	err = cmtos.EnsureDir(filepath.Dir(blsPasswordFile), 0777)
-	assert.Nil(t, err)
-
-	pv := GenWrappedFilePV(
-		pvKeyFile,
-		pvStateFile,
-		blsKeyFile,
-		blsPasswordFile,
-	)
-
-	pv.Save("test")
-
-	t.Run("save delegator address", func(t *testing.T) {
-		delegatorAddress := pv.Key.CometPVKey.PubKey.Address()
-		t.Log("delegatorAddress: ", delegatorAddress)
-
-		// addr, err := sdk.AccAddressFromBech32(delegatorAddress.String())
-		// assert.NoError(t, err)
-		// t.Log("sdk.AccAddressFromBech32(delegatorAddress.String()): ", addr)
-
-		pv.SetAccAddress(types.AccAddress(delegatorAddress))
-
-		var keystore erc2335.Erc2335KeyStore
-		keyJSONBytes, err := os.ReadFile(blsKeyFile)
-		assert.NoError(t, err)
-		err = json.Unmarshal(keyJSONBytes, &keystore)
-		assert.NoError(t, err)
-
-		// t.Log(keystore)
-		t.Log(keystore.Description)
-	})
-
-	t.Run("load delegator address", func(t *testing.T) {
-		delegatorAddress := ReadDelegatorAddressFromFile(blsKeyFile)
-		assert.Equal(t, delegatorAddress, pv.Key.DelegatorAddress)
-	})
-}
diff --git a/privval/util.go b/privval/util.go
new file mode 100644
index 000000000..802240580
--- /dev/null
+++ b/privval/util.go
@@ -0,0 +1,21 @@
+package privval
+
+import (
+	"fmt"
+	"path/filepath"
+
+	cmtos "github.com/cometbft/cometbft/libs/os"
+)
+
+func IsValidFilePath(paths ...string) error {
+	// Check file path of bls key
+	for _, path := range paths {
+		if path == "" {
+			return fmt.Errorf("filePath for bls key not set")
+		}
+		if err := cmtos.EnsureDir(filepath.Dir(path), 0777); err != nil {
+			return fmt.Errorf("failed to ensure key path dir: %w", err)
+		}
+	}
+	return nil
+}
diff --git a/test/e2e/initialization/config.go b/test/e2e/initialization/config.go
index e61985e7c..5a5e2d32c 100644
--- a/test/e2e/initialization/config.go
+++ b/test/e2e/initialization/config.go
@@ -416,7 +416,7 @@ func updateCheckpointingGenesis(c *internalChain) func(*checkpointingtypes.Genes
 				panic("It should be possible to retrieve validator public key")
 			}
 
-			da, err := sdk.AccAddressFromBech32(node.consensusKey.DelegatorAddress)
+			da, err := sdk.AccAddressFromBech32(node.consensusKey.BlsPVKey.DelegatorAddress)
 
 			if err != nil {
 				panic("It should be possible to get validator address from delegator address")
diff --git a/test/e2e/initialization/node.go b/test/e2e/initialization/node.go
index 3e674f5fb..d148c0d00 100644
--- a/test/e2e/initialization/node.go
+++ b/test/e2e/initialization/node.go
@@ -8,9 +8,10 @@ import (
 	"path/filepath"
 	"strings"
 
+	"github.com/cometbft/cometbft/crypto/ed25519"
+
 	"cosmossdk.io/math"
 	cmtconfig "github.com/cometbft/cometbft/config"
-	cmtos "github.com/cometbft/cometbft/libs/os"
 	"github.com/cometbft/cometbft/p2p"
 	cmttypes "github.com/cometbft/cometbft/types"
 	sdkcrypto "github.com/cosmos/cosmos-sdk/crypto"
@@ -33,9 +34,9 @@ import (
 	babylonApp "github.com/babylonlabs-io/babylon/app"
 	appparams "github.com/babylonlabs-io/babylon/app/params"
 	"github.com/babylonlabs-io/babylon/cmd/babylond/cmd"
-	"github.com/babylonlabs-io/babylon/crypto/erc2335"
 	"github.com/babylonlabs-io/babylon/privval"
 	"github.com/babylonlabs-io/babylon/test/e2e/util"
+	cmtprivval "github.com/cometbft/cometbft/privval"
 )
 
 type internalNode struct {
@@ -158,44 +159,45 @@ func (n *internalNode) createNodeKey() error {
 func (n *internalNode) createConsensusKey() error {
 	serverCtx := server.NewDefaultContext()
 	config := serverCtx.Config
-
 	config.SetRoot(n.configDir())
+
 	config.Moniker = n.moniker
 
-	pvKeyFile := config.PrivValidatorKeyFile()
-	if err := cmtos.EnsureDir(filepath.Dir(pvKeyFile), 0o777); err != nil {
-		return err
-	}
+	blsCfg := privval.DefaultBlsConfig()
+	blsCfg.SetRoot(n.configDir())
 
+	pvKeyFile := config.PrivValidatorKeyFile()
 	pvStateFile := config.PrivValidatorStateFile()
-	if err := cmtos.EnsureDir(filepath.Dir(pvStateFile), 0o777); err != nil {
-		return err
-	}
-
-	blsCfg := privval.DefaultBlsConfig()
-	blsCfg.SetRoot(config.RootDir)
 	blsKeyFile := blsCfg.BlsKeyFile()
-	if err := cmtos.EnsureDir(filepath.Dir(blsKeyFile), 0o777); err != nil {
-		return err
-	}
-
 	blsPasswordFile := blsCfg.BlsPasswordFile()
-	if err := cmtos.EnsureDir(filepath.Dir(blsPasswordFile), 0o777); err != nil {
+
+	if err := privval.IsValidFilePath(pvKeyFile, pvStateFile, blsKeyFile, blsPasswordFile); err != nil {
 		return err
 	}
 
-	// for test e2e
-	// bls-password is random generated
-	blsPassword := erc2335.CreateRandomPassword()
-
-	filePV := privval.GenWrappedFilePVWithMnemonic(n.mnemonic, pvKeyFile, pvStateFile, blsKeyFile, blsPasswordFile)
-	filePV.Save(blsPassword)
-
+	// delegator address
 	accAddress, _ := n.keyInfo.GetAddress()
-	filePV.SetAccAddress(accAddress)
 
-	n.consensusKey = filePV.Key
+	// create new key for consensus
+	// file pv
+	var privKey ed25519.PrivKey
+	if n.mnemonic == "" {
+		privKey = ed25519.GenPrivKey()
+	} else {
+		privKey = ed25519.GenPrivKeyFromSecret([]byte(n.mnemonic))
+	}
+	filePV := cmtprivval.NewFilePV(privKey, pvKeyFile, pvStateFile)
+	filePV.Key.Save()
+	filePV.LastSignState.Save()
 
+	// bls pv
+	blsPV := privval.GenBlsPV(blsKeyFile, blsPasswordFile, "password", accAddress.String())
+
+	// n.consensusKey = filePV.Key
+	n.consensusKey = privval.WrappedFilePVKey{
+		CometPVKey: filePV.Key,
+		BlsPVKey:   blsPV.Key,
+	}
 	return nil
 }
 
diff --git a/testutil/datagen/init_val.go b/testutil/datagen/init_val.go
index 827a9ca4f..10ee141c9 100644
--- a/testutil/datagen/init_val.go
+++ b/testutil/datagen/init_val.go
@@ -2,15 +2,16 @@ package datagen
 
 import (
 	"fmt"
-	"path/filepath"
 
 	cfg "github.com/cometbft/cometbft/config"
-	cmtos "github.com/cometbft/cometbft/libs/os"
+	"github.com/cometbft/cometbft/crypto/ed25519"
 	"github.com/cometbft/cometbft/p2p"
 	sdk "github.com/cosmos/cosmos-sdk/types"
 	"github.com/cosmos/go-bip39"
 
 	"github.com/babylonlabs-io/babylon/privval"
+	cmtos "github.com/cometbft/cometbft/libs/os"
+	cmtprivval "github.com/cometbft/cometbft/privval"
 )
 
 // InitializeNodeValidatorFiles creates private validator and p2p configuration files.
@@ -31,30 +32,51 @@ func InitializeNodeValidatorFilesFromMnemonic(config *cfg.Config, mnemonic strin
 	nodeID = string(nodeKey.ID())
 
 	pvKeyFile := config.PrivValidatorKeyFile()
-	if err := cmtos.EnsureDir(filepath.Dir(pvKeyFile), 0777); err != nil {
-		return "", nil, err
-	}
-
 	pvStateFile := config.PrivValidatorStateFile()
-	if err := cmtos.EnsureDir(filepath.Dir(pvStateFile), 0777); err != nil {
+
+	if err := privval.IsValidFilePath(pvKeyFile, pvStateFile); err != nil {
 		return "", nil, err
 	}
 
-	// add bls config and set root same as config
+	// bls config
 	blsCfg := privval.DefaultBlsConfig()
 	blsCfg.SetRoot(config.RootDir)
 
-	var filePV *privval.WrappedFilePV
-	if len(mnemonic) == 0 {
-		filePV = privval.LoadOrGenWrappedFilePV(pvKeyFile, pvStateFile, blsCfg.BlsKeyFile(), blsCfg.BlsPasswordFile())
+	blsKeyFile := blsCfg.BlsKeyFile()
+	blsPasswordFile := blsCfg.BlsPasswordFile()
+	if err := privval.IsValidFilePath(blsKeyFile, blsPasswordFile); err != nil {
+		return "", nil, err
+	}
+
+	// load or generate private validator
+	var filePV *cmtprivval.FilePV
+	if cmtos.FileExists(pvKeyFile) {
+		filePV = cmtprivval.LoadFilePV(pvKeyFile, pvStateFile)
+	} else {
+		var privKey ed25519.PrivKey
+		if len(mnemonic) == 0 {
+			privKey = ed25519.GenPrivKey()
+		} else {
+			privKey = ed25519.GenPrivKeyFromSecret([]byte(mnemonic))
+		}
+		filePV = cmtprivval.NewFilePV(privKey, pvKeyFile, pvStateFile)
+		filePV.Key.Save()
+		filePV.LastSignState.Save()
+	}
+
+	// load or generate BLS private validator
+	var blsPV *privval.BlsPV
+	if cmtos.FileExists(blsKeyFile) {
+		// if key file exists but password file does not exist -> error
+		if !cmtos.FileExists(blsPasswordFile) {
+			cmtos.Exit(fmt.Sprintf("BLS password file does not exist: %v", blsPasswordFile))
+		}
+		blsPV = privval.LoadBlsPV(blsKeyFile, blsPasswordFile)
 	} else {
-		filePV = privval.GenWrappedFilePVWithMnemonic(mnemonic, pvKeyFile, pvStateFile, blsCfg.BlsKeyFile(), blsCfg.BlsPasswordFile())
+		blsPV = privval.GenBlsPV(blsKeyFile, blsPasswordFile, "password", addr.String())
 	}
-	filePV.SetAccAddress(addr)
 
-	valPrivkey := filePV.GetValPrivKey()
-	blsPrivkey := filePV.GetBlsPrivKey()
-	valKeys, err = privval.NewValidatorKeys(valPrivkey, blsPrivkey)
+	valKeys, err = privval.NewValidatorKeys(filePV.Key.PrivKey, blsPV.Key.PrivKey)
 	if err != nil {
 		return "", nil, err
 	}
diff --git a/testutil/helper/helper.go b/testutil/helper/helper.go
index dd6eab288..4423d0866 100644
--- a/testutil/helper/helper.go
+++ b/testutil/helper/helper.go
@@ -61,7 +61,7 @@ func NewHelperWithValSet(t *testing.T, valSet *datagen.GenesisValidators, privSi
 	// generate the genesis account
 	signerPubKey := privSigner.WrappedPV.Key.CometPVKey.PubKey
 	acc := authtypes.NewBaseAccount(signerPubKey.Address().Bytes(), &cosmosed.PubKey{Key: signerPubKey.Bytes()}, 0, 0)
-	privSigner.WrappedPV.Key.DelegatorAddress = acc.Address
+	privSigner.WrappedPV.Key.BlsPVKey.DelegatorAddress = acc.Address
 	valSet.Keys[0].ValidatorAddress = privSigner.WrappedPV.GetAddress().String()
 	// ensure the genesis account has a sufficient amount of tokens
 	balance := banktypes.Balance{
@@ -99,7 +99,7 @@ func NewHelperWithValSetNoSigner(t *testing.T, valSet *datagen.GenesisValidators
 	// generate the genesis account
 	signerPubKey := privSigner.WrappedPV.Key.CometPVKey.PubKey
 	acc := authtypes.NewBaseAccount(signerPubKey.Address().Bytes(), &cosmosed.PubKey{Key: signerPubKey.Bytes()}, 0, 0)
-	privSigner.WrappedPV.Key.DelegatorAddress = acc.Address
+	privSigner.WrappedPV.Key.BlsPVKey.DelegatorAddress = acc.Address
 	// set a random validator address instead of the privSigner's
 	valSet.Keys[0].ValidatorAddress = datagen.GenRandomValidatorAddress().String()
 	// ensure the genesis account has a sufficient amount of tokens
diff --git a/testutil/signer/private.go b/testutil/signer/private.go
index a46f3e862..8d1d4538e 100644
--- a/testutil/signer/private.go
+++ b/testutil/signer/private.go
@@ -2,6 +2,7 @@ package signer
 
 import (
 	"os"
+	"path/filepath"
 
 	cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
 	cosmosed "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
@@ -9,6 +10,8 @@ import (
 	"github.com/babylonlabs-io/babylon/app/signer"
 	"github.com/babylonlabs-io/babylon/privval"
 	checkpointingtypes "github.com/babylonlabs-io/babylon/x/checkpointing/types"
+	cmtconfig "github.com/cometbft/cometbft/config"
+	cmtprivval "github.com/cometbft/cometbft/privval"
 )
 
 // SetupTestPrivSigner sets up a PrivSigner for testing
@@ -21,7 +24,13 @@ func SetupTestPrivSigner() (*signer.PrivSigner, error) {
 	defer func() {
 		_ = os.RemoveAll(nodeDir)
 	}()
-	privSigner, _ := signer.InitTestPrivSigner(nodeDir)
+
+	// generate a privSigner
+	if err := GeneratePrivSigner(nodeDir); err != nil {
+		return nil, err
+	}
+
+	privSigner, _ := signer.InitPrivSigner(nodeDir)
 	return privSigner, nil
 }
 
@@ -41,3 +50,24 @@ func GenesisKeyFromPrivSigner(ps *signer.PrivSigner) (*checkpointingtypes.Genesi
 		&cosmosed.PubKey{Key: valPubkey.Bytes()},
 	)
 }
+
+func GeneratePrivSigner(nodeDir string) error {
+	nodeCfg := cmtconfig.DefaultConfig()
+	blsCfg := privval.DefaultBlsConfig()
+
+	pvKeyFile := filepath.Join(nodeDir, nodeCfg.PrivValidatorKeyFile())
+	pvStateFile := filepath.Join(nodeDir, nodeCfg.PrivValidatorStateFile())
+	blsKeyFile := filepath.Join(nodeDir, blsCfg.BlsKeyFile())
+	blsPasswordFile := filepath.Join(nodeDir, blsCfg.BlsPasswordFile())
+
+	if err := privval.IsValidFilePath(pvKeyFile, pvStateFile, blsKeyFile, blsPasswordFile); err != nil {
+		return err
+	}
+
+	cometPV := cmtprivval.GenFilePV(pvKeyFile, pvStateFile)
+	cometPV.Key.Save()
+	cometPV.LastSignState.Save()
+
+	privval.GenBlsPV(blsKeyFile, blsPasswordFile, "password", "")
+	return nil
+}
diff --git a/x/checkpointing/client/cli/tx_test.go b/x/checkpointing/client/cli/tx_test.go
index 24c37771d..5cccefdaf 100644
--- a/x/checkpointing/client/cli/tx_test.go
+++ b/x/checkpointing/client/cli/tx_test.go
@@ -11,7 +11,6 @@ import (
 	abci "github.com/cometbft/cometbft/abci/types"
 	cmtconfig "github.com/cometbft/cometbft/config"
 	cmtbytes "github.com/cometbft/cometbft/libs/bytes"
-	cmtos "github.com/cometbft/cometbft/libs/os"
 	rpcclient "github.com/cometbft/cometbft/rpc/client"
 	rpcclientmock "github.com/cometbft/cometbft/rpc/client/mock"
 	coretypes "github.com/cometbft/cometbft/rpc/core/types"
@@ -31,6 +30,7 @@ import (
 	"github.com/babylonlabs-io/babylon/privval"
 	testutilcli "github.com/babylonlabs-io/babylon/testutil/cli"
 	checkpointcli "github.com/babylonlabs-io/babylon/x/checkpointing/client/cli"
+	cmtprivval "github.com/cometbft/cometbft/privval"
 )
 
 type mockCometRPC struct {
@@ -103,26 +103,27 @@ func (s *CLITestSuite) SetupSuite() {
 func (s *CLITestSuite) TestCmdWrappedCreateValidator() {
 	require := s.Require()
 	homeDir := s.T().TempDir()
-	nodeCfg := cmtconfig.DefaultConfig()
-	pvKeyFile := filepath.Join(homeDir, nodeCfg.PrivValidatorKeyFile())
-	err := cmtos.EnsureDir(filepath.Dir(pvKeyFile), 0777)
-	require.NoError(err)
-	pvStateFile := filepath.Join(homeDir, nodeCfg.PrivValidatorStateFile())
-	err = cmtos.EnsureDir(filepath.Dir(pvStateFile), 0777)
-	require.NoError(err)
 
+	// create BLS keys
+	nodeCfg := cmtconfig.DefaultConfig()
 	blsCfg := privval.DefaultBlsConfig()
+
+	keyPath := filepath.Join(homeDir, nodeCfg.PrivValidatorKeyFile())
+	statePath := filepath.Join(homeDir, nodeCfg.PrivValidatorStateFile())
 	blsKeyFile := filepath.Join(homeDir, blsCfg.BlsKeyFile())
-	err = cmtos.EnsureDir(filepath.Dir(blsKeyFile), 0777)
-	require.NoError(err)
 	blsPasswordFile := filepath.Join(homeDir, blsCfg.BlsPasswordFile())
-	err = cmtos.EnsureDir(filepath.Dir(blsPasswordFile), 0777)
+
+	err := privval.IsValidFilePath(keyPath, statePath, blsKeyFile, blsPasswordFile)
 	require.NoError(err)
 
-	wrappedPV := privval.LoadOrGenWrappedFilePV(pvKeyFile, pvStateFile, blsKeyFile, blsPasswordFile)
+	filePV := cmtprivval.GenFilePV(keyPath, statePath)
+	filePV.Key.Save()
+	filePV.LastSignState.Save()
+
+	privval.GenBlsPV(blsKeyFile, blsPasswordFile, "password", "")
 	cmd := checkpointcli.CmdWrappedCreateValidator(authcodec.NewBech32Codec("cosmosvaloper"))
 
-	consPrivKey := wrappedPV.GetValPrivKey()
+	consPrivKey := filePV.Key.PrivKey
 	consPubKey, err := cryptocodec.FromCmtPubKeyInterface(consPrivKey.PubKey())
 	require.NoError(err)
 	consPubKeyBz, err := s.clientCtx.Codec.MarshalInterfaceJSON(consPubKey)
diff --git a/x/checkpointing/client/cli/utils.go b/x/checkpointing/client/cli/utils.go
index 7d4161390..e25bbc750 100644
--- a/x/checkpointing/client/cli/utils.go
+++ b/x/checkpointing/client/cli/utils.go
@@ -11,7 +11,6 @@ import (
 	errorsmod "cosmossdk.io/errors"
 	sdkmath "cosmossdk.io/math"
 	cmtconfig "github.com/cometbft/cometbft/config"
-	cmtos "github.com/cometbft/cometbft/libs/os"
 	"github.com/cosmos/cosmos-sdk/client"
 	"github.com/cosmos/cosmos-sdk/client/flags"
 	"github.com/cosmos/cosmos-sdk/client/tx"
@@ -25,6 +24,7 @@ import (
 
 	"github.com/babylonlabs-io/babylon/privval"
 	"github.com/babylonlabs-io/babylon/x/checkpointing/types"
+	cmtprivval "github.com/cometbft/cometbft/privval"
 )
 
 // validator struct to define the fields of the validator
@@ -204,19 +204,19 @@ func buildCommissionRates(rateStr, maxRateStr, maxChangeRateStr string) (commiss
 
 func getValKeyFromFile(homeDir string) (*privval.ValidatorKeys, error) {
 	nodeCfg := cmtconfig.DefaultConfig()
+	blsCfg := privval.DefaultBlsConfig()
+
 	keyPath := filepath.Join(homeDir, nodeCfg.PrivValidatorKeyFile())
 	statePath := filepath.Join(homeDir, nodeCfg.PrivValidatorStateFile())
-	if !cmtos.FileExists(keyPath) {
-		return nil, errors.New("validator key file does not exist")
-	}
-
-	blsCfg := privval.DefaultBlsConfig()
 	blsKeyPath := filepath.Join(homeDir, blsCfg.BlsKeyFile())
 	blsPasswordPath := filepath.Join(homeDir, blsCfg.BlsPasswordFile())
-	if !cmtos.FileExists(blsKeyPath) {
-		return nil, errors.New("validator bls key file does not exist")
+
+	if err := privval.IsValidFilePath(keyPath, statePath, blsKeyPath, blsPasswordPath); err != nil {
+		return nil, err
 	}
-	wrappedPV := privval.LoadWrappedFilePV(keyPath, statePath, blsKeyPath, blsPasswordPath)
 
-	return privval.NewValidatorKeys(wrappedPV.GetValPrivKey(), wrappedPV.GetBlsPrivKey())
+	filePV := cmtprivval.LoadFilePV(keyPath, statePath)
+	blsPV := privval.LoadBlsPV(blsKeyPath, blsPasswordPath)
+
+	return privval.NewValidatorKeys(filePV.Key.PrivKey, blsPV.Key.PrivKey)
 }

From 80375689ff5727c2c030a631ec24f01e8fb18294 Mon Sep 17 00:00:00 2001
From: wonjoon <wnjoon@gmail.com>
Date: Fri, 10 Jan 2025 21:16:16 +0900
Subject: [PATCH 6/8] feat: update CHANGELOG

---
 CHANGELOG.md | 1 +
 1 file changed, 1 insertion(+)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 46f39ee45..d355fd273 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -39,6 +39,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
 
 ### Improvements
 
+- [#396](https://github.com/babylonlabs-io/babylon/pull/396) BLS Key Separation and ERC2335 Implementation
 - [#391](https://github.com/babylonlabs-io/babylon/pull/391) Fix e2e `TestBTCRewardsDistribution` flunky
 check of rewards
 

From 1f14b31db3dc3aef8655e416aae90ca12e0e8557 Mon Sep 17 00:00:00 2001
From: wonjoon <wnjoon@gmail.com>
Date: Tue, 14 Jan 2025 21:48:13 +0900
Subject: [PATCH 7/8] feat: add bls password flag option, refactor comments and
 fix lint

---
 app/signer/private.go                         | 14 +++--
 client/flags/flags.go                         |  5 --
 cmd/babylond/cmd/create_bls_key.go            | 30 ++++++-----
 cmd/babylond/cmd/genhelpers/bls_add_test.go   |  8 ++-
 cmd/babylond/cmd/genhelpers/bls_create.go     | 34 ++++++++-----
 .../cmd/genhelpers/bls_create_test.go         | 12 ++---
 privval/bls.go                                | 51 ++++---------------
 privval/bls_test.go                           |  8 +--
 privval/util.go                               |  2 +-
 test/e2e/initialization/node.go               | 18 ++-----
 testutil/datagen/btc_blockchain.go            |  2 +-
 testutil/datagen/init_val.go                  | 27 +++-------
 testutil/signer/private.go                    | 15 +++---
 x/checkpointing/client/cli/tx_test.go         | 15 +++---
 x/checkpointing/client/cli/utils.go           | 14 ++---
 15 files changed, 104 insertions(+), 151 deletions(-)
 delete mode 100644 client/flags/flags.go

diff --git a/app/signer/private.go b/app/signer/private.go
index d95fdc910..c2839a673 100644
--- a/app/signer/private.go
+++ b/app/signer/private.go
@@ -1,8 +1,6 @@
 package signer
 
 import (
-	"path/filepath"
-
 	cmtconfig "github.com/cometbft/cometbft/config"
 
 	"github.com/babylonlabs-io/babylon/privval"
@@ -15,14 +13,14 @@ type PrivSigner struct {
 
 func InitPrivSigner(nodeDir string) (*PrivSigner, error) {
 	nodeCfg := cmtconfig.DefaultConfig()
-	blsCfg := privval.DefaultBlsConfig()
+	nodeCfg.SetRoot(nodeDir)
 
-	pvKeyFile := filepath.Join(nodeDir, nodeCfg.PrivValidatorKeyFile())
-	pvStateFile := filepath.Join(nodeDir, nodeCfg.PrivValidatorStateFile())
-	blsKeyFile := filepath.Join(nodeDir, blsCfg.BlsKeyFile())
-	blsPasswordFile := filepath.Join(nodeDir, blsCfg.BlsPasswordFile())
+	pvKeyFile := nodeCfg.PrivValidatorKeyFile()
+	pvStateFile := nodeCfg.PrivValidatorStateFile()
+	blsKeyFile := privval.DefaultBlsKeyFile(nodeDir)
+	blsPasswordFile := privval.DefaultBlsPasswordFile(nodeDir)
 
-	if err := privval.IsValidFilePath(pvKeyFile, pvStateFile, blsKeyFile, blsPasswordFile); err != nil {
+	if err := privval.EnsureDirs(pvKeyFile, pvStateFile, blsKeyFile, blsPasswordFile); err != nil {
 		return nil, err
 	}
 
diff --git a/client/flags/flags.go b/client/flags/flags.go
deleted file mode 100644
index 5e58fe954..000000000
--- a/client/flags/flags.go
+++ /dev/null
@@ -1,5 +0,0 @@
-package flags
-
-const (
-	FlagBlsPassword = "bls-password"
-)
diff --git a/cmd/babylond/cmd/create_bls_key.go b/cmd/babylond/cmd/create_bls_key.go
index 6a6b62ea8..a3f8c755a 100644
--- a/cmd/babylond/cmd/create_bls_key.go
+++ b/cmd/babylond/cmd/create_bls_key.go
@@ -2,7 +2,6 @@ package cmd
 
 import (
 	"fmt"
-	"path/filepath"
 	"strings"
 
 	"github.com/cosmos/cosmos-sdk/client/flags"
@@ -14,6 +13,10 @@ import (
 	"github.com/babylonlabs-io/babylon/privval"
 )
 
+const (
+	FlagPassword = "bls-password"
+)
+
 func CreateBlsKeyCmd() *cobra.Command {
 	bech32PrefixAccAddr := appparams.Bech32PrefixAccAddr
 
@@ -43,23 +46,26 @@ $ babylond create-bls-key %s1f5tnl46mk4dfp4nx3n2vnrvyw2h2ydz6ykhk3r --home ./
 				return err
 			}
 
-			return CreateBlsKey(homeDir, addr)
+			var password string
+			password, _ = cmd.Flags().GetString(FlagPassword)
+			if password == "" {
+				password = privval.NewBlsPassword()
+			}
+			return CreateBlsKey(homeDir, password, addr)
 		},
 	}
 
 	cmd.Flags().String(flags.FlagHome, app.DefaultNodeHome, "The node home directory")
-
+	cmd.Flags().String(FlagPassword, "", "The password for the BLS key. If a flag is set, the non-empty password should be provided. If a flag is not set, the password will be read from the prompt.")
 	return cmd
 }
 
-func CreateBlsKey(home string, addr sdk.AccAddress) error {
-
-	blsCfg := privval.DefaultBlsConfig()
-	keyPath := filepath.Join(home, blsCfg.BlsKeyFile())
-	passwordPath := filepath.Join(home, blsCfg.BlsPasswordFile())
-
-	password := privval.GetBlsPassword()
-
-	privval.GenBlsPV(keyPath, passwordPath, password, addr.String())
+func CreateBlsKey(home, password string, addr sdk.AccAddress) error {
+	privval.GenBlsPV(
+		privval.DefaultBlsKeyFile(home),
+		privval.DefaultBlsPasswordFile(home),
+		password,
+		addr.String(),
+	)
 	return nil
 }
diff --git a/cmd/babylond/cmd/genhelpers/bls_add_test.go b/cmd/babylond/cmd/genhelpers/bls_add_test.go
index 4c7b8f21e..12bb9b85f 100644
--- a/cmd/babylond/cmd/genhelpers/bls_add_test.go
+++ b/cmd/babylond/cmd/genhelpers/bls_add_test.go
@@ -153,15 +153,13 @@ func Test_CmdAddBlsWithGentx(t *testing.T) {
 
 		nodeCfg := cmtconfig.DefaultConfig()
 		nodeCfg.SetRoot(homeDir)
-		blsCfg := privval.DefaultBlsConfig()
-		blsCfg.SetRoot(homeDir)
 
 		keyPath := nodeCfg.PrivValidatorKeyFile()
 		statePath := nodeCfg.PrivValidatorStateFile()
-		blsKeyFile := blsCfg.BlsKeyFile()
-		blsPasswordFile := blsCfg.BlsPasswordFile()
+		blsKeyFile := privval.DefaultBlsKeyFile(homeDir)
+		blsPasswordFile := privval.DefaultBlsPasswordFile(homeDir)
 
-		err := privval.IsValidFilePath(keyPath, statePath, blsKeyFile, blsPasswordFile)
+		err := privval.EnsureDirs(keyPath, statePath, blsKeyFile, blsPasswordFile)
 		require.NoError(t, err)
 
 		filePV := cmtprivval.GenFilePV(keyPath, statePath)
diff --git a/cmd/babylond/cmd/genhelpers/bls_create.go b/cmd/babylond/cmd/genhelpers/bls_create.go
index 357139863..2bdfcc29a 100644
--- a/cmd/babylond/cmd/genhelpers/bls_create.go
+++ b/cmd/babylond/cmd/genhelpers/bls_create.go
@@ -1,10 +1,12 @@
 package genhelpers
 
 import (
+	"fmt"
 	"path/filepath"
 	"strings"
 
 	cmtconfig "github.com/cometbft/cometbft/config"
+	cmtos "github.com/cometbft/cometbft/libs/os"
 	"github.com/cosmos/cosmos-sdk/client/flags"
 	"github.com/spf13/cobra"
 
@@ -34,29 +36,35 @@ $ babylond genbls --home ./
 			homeDir, _ := cmd.Flags().GetString(flags.FlagHome)
 
 			nodeCfg := cmtconfig.DefaultConfig()
-			blsCfg := privval.DefaultBlsConfig()
-
-			keyPath := filepath.Join(homeDir, nodeCfg.PrivValidatorKeyFile())
-			statePath := filepath.Join(homeDir, nodeCfg.PrivValidatorStateFile())
-			blsKeyPath := filepath.Join(homeDir, blsCfg.BlsKeyFile())
-			blsPasswordPath := filepath.Join(homeDir, blsCfg.BlsPasswordFile())
-
-			if err := privval.IsValidFilePath(keyPath, statePath, blsKeyPath, blsPasswordPath); err != nil {
+			nodeCfg.SetRoot(homeDir)
+			cmtPvKeyFile := nodeCfg.PrivValidatorKeyFile()
+			cmtPvStateFile := nodeCfg.PrivValidatorStateFile()
+			blsKeyFile := privval.DefaultBlsKeyFile(homeDir)
+			blsPasswordFile := privval.DefaultBlsPasswordFile(homeDir)
+
+			if err := func(paths ...string) error {
+				for _, path := range paths {
+					if !cmtos.FileExists(path) {
+						return fmt.Errorf("file does not exist in %s", path)
+					}
+				}
+				return nil
+			}(cmtPvKeyFile, cmtPvStateFile, blsKeyFile, blsPasswordFile); err != nil {
 				return err
 			}
 
-			filePV := cmtprivval.LoadFilePV(keyPath, statePath)
-			blsPV := privval.LoadBlsPV(blsKeyPath, blsPasswordPath)
+			cmtPV := cmtprivval.LoadFilePV(cmtPvKeyFile, cmtPvStateFile)
+			blsPV := privval.LoadBlsPV(blsKeyFile, blsPasswordFile)
 
 			wrappedPV := &privval.WrappedFilePV{
 				Key: privval.WrappedFilePVKey{
-					CometPVKey: filePV.Key,
+					CometPVKey: cmtPV.Key,
 					BlsPVKey:   blsPV.Key,
 				},
-				LastSignState: filePV.LastSignState,
+				LastSignState: cmtPV.LastSignState,
 			}
 
-			outputFileName, err := wrappedPV.ExportGenBls(filepath.Dir(keyPath))
+			outputFileName, err := wrappedPV.ExportGenBls(filepath.Dir(cmtPvKeyFile))
 			if err != nil {
 				return err
 			}
diff --git a/cmd/babylond/cmd/genhelpers/bls_create_test.go b/cmd/babylond/cmd/genhelpers/bls_create_test.go
index b80f1bbad..ea157304e 100644
--- a/cmd/babylond/cmd/genhelpers/bls_create_test.go
+++ b/cmd/babylond/cmd/genhelpers/bls_create_test.go
@@ -71,14 +71,14 @@ func Test_CmdCreateBls(t *testing.T) {
 
 	// create BLS keys
 	nodeCfg := cmtconfig.DefaultConfig()
-	blsCfg := privval.DefaultBlsConfig()
+	nodeCfg.SetRoot(home)
 
-	keyPath := filepath.Join(home, nodeCfg.PrivValidatorKeyFile())
-	statePath := filepath.Join(home, nodeCfg.PrivValidatorStateFile())
-	blsKeyFile := filepath.Join(home, blsCfg.BlsKeyFile())
-	blsPasswordFile := filepath.Join(home, blsCfg.BlsPasswordFile())
+	keyPath := nodeCfg.PrivValidatorKeyFile()
+	statePath := nodeCfg.PrivValidatorStateFile()
+	blsKeyFile := privval.DefaultBlsKeyFile(home)
+	blsPasswordFile := privval.DefaultBlsPasswordFile(home)
 
-	err = privval.IsValidFilePath(keyPath, statePath, blsKeyFile, blsPasswordFile)
+	err = privval.EnsureDirs(keyPath, statePath, blsKeyFile, blsPasswordFile)
 	require.NoError(t, err)
 
 	filePV := cmtprivval.GenFilePV(keyPath, statePath)
diff --git a/privval/bls.go b/privval/bls.go
index e990db8e3..b68884ab9 100644
--- a/privval/bls.go
+++ b/privval/bls.go
@@ -20,6 +20,11 @@ const (
 	DefaultBlsPasswordName = "bls_password.txt"
 )
 
+var (
+	defaultBlsKeyFilePath  = filepath.Join(cmtcfg.DefaultConfigDir, DefaultBlsKeyName)
+	defaultBlsPasswordPath = filepath.Join(cmtcfg.DefaultConfigDir, DefaultBlsPasswordName)
+)
+
 type BlsPV struct {
 	Key BlsPVKey
 }
@@ -81,7 +86,7 @@ func LoadBlsPV(keyFilePath, passwordFilePath string) *BlsPV {
 	}
 }
 
-func GetBlsPassword() string {
+func NewBlsPassword() string {
 	inBuf := bufio.NewReader(os.Stdin)
 	password, err := input.GetString("Enter your bls password", inBuf)
 	if err != nil {
@@ -93,11 +98,6 @@ func GetBlsPassword() string {
 // Save bls key using password
 // Check both paths of bls key and password inside function
 func (k *BlsPVKey) Save(password, addr string) {
-	// check file path is valid
-	if err := IsValidFilePath(k.filePath, k.passwordPath); err != nil {
-		panic(err)
-	}
-
 	// encrypt the bls12381 key to erc2335 type
 	erc2335BlsPvKey, err := erc2335.Encrypt(k.PrivKey, k.PubKey.Bytes(), password)
 	if err != nil {
@@ -131,41 +131,10 @@ func (k *BlsPVKey) Save(password, addr string) {
 	}
 }
 
-// -------------------------------------------------------------------------------
-// ---------------------------- BLS Config ---------------------------------------
-// -------------------------------------------------------------------------------
-
-type BlsConfig struct {
-	RootDir         string `mapstructure:"home"`
-	BlsKeyPath      string `mapstructure:"bls_key_file"`
-	BlsPasswordPath string `mapstructure:"bls_password_file"`
-}
-
-func DefaultBlsConfig() BlsConfig {
-	return BlsConfig{
-		BlsKeyPath:      filepath.Join(cmtcfg.DefaultConfigDir, DefaultBlsKeyName),
-		BlsPasswordPath: filepath.Join(cmtcfg.DefaultConfigDir, DefaultBlsPasswordName),
-	}
-}
-
-func (cfg *BlsConfig) SetRoot(root string) *BlsConfig {
-	cfg.RootDir = root
-	return cfg
-}
-
-func (cfg BlsConfig) BlsKeyFile() string {
-	return rootify(cfg.BlsKeyPath, cfg.RootDir)
-}
-
-func (cfg BlsConfig) BlsPasswordFile() string {
-	return rootify(cfg.BlsPasswordPath, cfg.RootDir)
+func DefaultBlsKeyFile(home string) string {
+	return filepath.Join(home, defaultBlsKeyFilePath)
 }
 
-// helper function to make config creation independent of root dir
-// copied from https://github.com/cometbft/cometbft/blob/v0.38.15/config/config.go
-func rootify(path, root string) string {
-	if filepath.IsAbs(path) {
-		return path
-	}
-	return filepath.Join(root, path)
+func DefaultBlsPasswordFile(home string) string {
+	return filepath.Join(home, defaultBlsPasswordPath)
 }
diff --git a/privval/bls_test.go b/privval/bls_test.go
index 6e6c134e5..f88417140 100644
--- a/privval/bls_test.go
+++ b/privval/bls_test.go
@@ -2,7 +2,6 @@ package privval
 
 import (
 	"os"
-	"path/filepath"
 	"testing"
 
 	"github.com/cometbft/cometbft/crypto/ed25519"
@@ -17,10 +16,11 @@ func TestNewBlsPV(t *testing.T) {
 	tempDir := t.TempDir()
 	defer os.RemoveAll(tempDir)
 
-	cfg := DefaultBlsConfig()
+	keyFilePath := DefaultBlsKeyFile(tempDir)
+	passwordFilePath := DefaultBlsPasswordFile(tempDir)
 
-	keyFilePath := filepath.Join(tempDir, cfg.BlsKeyFile())
-	passwordFilePath := filepath.Join(tempDir, cfg.BlsPasswordFile())
+	err := EnsureDirs(keyFilePath, passwordFilePath)
+	assert.NoError(t, err)
 
 	t.Run("save bls key to file without delegator address", func(t *testing.T) {
 		pv := NewBlsPV(bls12381.GenPrivKey(), keyFilePath, passwordFilePath, "")
diff --git a/privval/util.go b/privval/util.go
index 802240580..3535c4056 100644
--- a/privval/util.go
+++ b/privval/util.go
@@ -7,7 +7,7 @@ import (
 	cmtos "github.com/cometbft/cometbft/libs/os"
 )
 
-func IsValidFilePath(paths ...string) error {
+func EnsureDirs(paths ...string) error {
 	// Check file path of bls key
 	for _, path := range paths {
 		if path == "" {
diff --git a/test/e2e/initialization/node.go b/test/e2e/initialization/node.go
index d148c0d00..eb894ae28 100644
--- a/test/e2e/initialization/node.go
+++ b/test/e2e/initialization/node.go
@@ -160,26 +160,19 @@ func (n *internalNode) createConsensusKey() error {
 	serverCtx := server.NewDefaultContext()
 	config := serverCtx.Config
 	config.SetRoot(n.configDir())
-
 	config.Moniker = n.moniker
 
-	blsCfg := privval.DefaultBlsConfig()
-	blsCfg.SetRoot(n.configDir())
-
 	pvKeyFile := config.PrivValidatorKeyFile()
 	pvStateFile := config.PrivValidatorStateFile()
-	blsKeyFile := blsCfg.BlsKeyFile()
-	blsPasswordFile := blsCfg.BlsPasswordFile()
+	blsKeyFile := privval.DefaultBlsKeyFile(n.configDir())
+	blsPasswordFile := privval.DefaultBlsPasswordFile(n.configDir())
 
-	if err := privval.IsValidFilePath(pvKeyFile, pvStateFile, blsKeyFile, blsPasswordFile); err != nil {
+	if err := privval.EnsureDirs(pvKeyFile, pvStateFile, blsKeyFile, blsPasswordFile); err != nil {
 		return err
 	}
-
-	// delegator address
 	accAddress, _ := n.keyInfo.GetAddress()
 
-	// create new key for consensus
-	// file pv
+	// create file pv
 	var privKey ed25519.PrivKey
 	if n.mnemonic == "" {
 		privKey = ed25519.GenPrivKey()
@@ -190,10 +183,9 @@ func (n *internalNode) createConsensusKey() error {
 	filePV.Key.Save()
 	filePV.LastSignState.Save()
 
-	// bls pv
+	// create bls pv
 	blsPV := privval.GenBlsPV(blsKeyFile, blsPasswordFile, "password", accAddress.String())
 
-	// n.consensusKey = filePV.Key
 	n.consensusKey = privval.WrappedFilePVKey{
 		CometPVKey: filePV.Key,
 		BlsPVKey:   blsPV.Key,
diff --git a/testutil/datagen/btc_blockchain.go b/testutil/datagen/btc_blockchain.go
index d963e50e1..da0a207da 100644
--- a/testutil/datagen/btc_blockchain.go
+++ b/testutil/datagen/btc_blockchain.go
@@ -104,7 +104,7 @@ func GenRandomBtcdBlockWithTransactions(
 
 	var proofs []*btcctypes.BTCSpvProof
 
-	for i, _ := range msgTxs {
+	for i := range msgTxs {
 		headerBytes := bbn.NewBTCHeaderBytesFromBlockHeader(header)
 		proof, err := btcctypes.SpvProofFromHeaderAndTransactions(&headerBytes, txBytes, uint(i))
 		if err != nil {
diff --git a/testutil/datagen/init_val.go b/testutil/datagen/init_val.go
index 10ee141c9..ac33ea596 100644
--- a/testutil/datagen/init_val.go
+++ b/testutil/datagen/init_val.go
@@ -31,27 +31,17 @@ func InitializeNodeValidatorFilesFromMnemonic(config *cfg.Config, mnemonic strin
 
 	nodeID = string(nodeKey.ID())
 
-	pvKeyFile := config.PrivValidatorKeyFile()
-	pvStateFile := config.PrivValidatorStateFile()
-
-	if err := privval.IsValidFilePath(pvKeyFile, pvStateFile); err != nil {
-		return "", nil, err
-	}
-
-	// bls config
-	blsCfg := privval.DefaultBlsConfig()
-	blsCfg.SetRoot(config.RootDir)
-
-	blsKeyFile := blsCfg.BlsKeyFile()
-	blsPasswordFile := blsCfg.BlsPasswordFile()
-	if err := privval.IsValidFilePath(blsKeyFile, blsPasswordFile); err != nil {
+	cmtKeyFile := config.PrivValidatorKeyFile()
+	cmtStateFile := config.PrivValidatorStateFile()
+	blsKeyFile := privval.DefaultBlsKeyFile(config.RootDir)
+	blsPasswordFile := privval.DefaultBlsPasswordFile(config.RootDir)
+	if err := privval.EnsureDirs(cmtKeyFile, cmtStateFile, blsKeyFile, blsPasswordFile); err != nil {
 		return "", nil, err
 	}
 
-	// load or generate private validator
 	var filePV *cmtprivval.FilePV
-	if cmtos.FileExists(pvKeyFile) {
-		filePV = cmtprivval.LoadFilePV(pvKeyFile, pvStateFile)
+	if cmtos.FileExists(cmtKeyFile) {
+		filePV = cmtprivval.LoadFilePV(cmtKeyFile, cmtStateFile)
 	} else {
 		var privKey ed25519.PrivKey
 		if len(mnemonic) == 0 {
@@ -59,12 +49,11 @@ func InitializeNodeValidatorFilesFromMnemonic(config *cfg.Config, mnemonic strin
 		} else {
 			privKey = ed25519.GenPrivKeyFromSecret([]byte(mnemonic))
 		}
-		filePV = cmtprivval.NewFilePV(privKey, pvKeyFile, pvStateFile)
+		filePV = cmtprivval.NewFilePV(privKey, cmtKeyFile, cmtStateFile)
 		filePV.Key.Save()
 		filePV.LastSignState.Save()
 	}
 
-	// load or generate BLS private validator
 	var blsPV *privval.BlsPV
 	if cmtos.FileExists(blsKeyFile) {
 		// if key file exists but password file does not exist -> error
diff --git a/testutil/signer/private.go b/testutil/signer/private.go
index 8d1d4538e..c1589ddae 100644
--- a/testutil/signer/private.go
+++ b/testutil/signer/private.go
@@ -2,7 +2,6 @@ package signer
 
 import (
 	"os"
-	"path/filepath"
 
 	cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
 	cosmosed "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
@@ -53,18 +52,18 @@ func GenesisKeyFromPrivSigner(ps *signer.PrivSigner) (*checkpointingtypes.Genesi
 
 func GeneratePrivSigner(nodeDir string) error {
 	nodeCfg := cmtconfig.DefaultConfig()
-	blsCfg := privval.DefaultBlsConfig()
+	nodeCfg.SetRoot(nodeDir)
 
-	pvKeyFile := filepath.Join(nodeDir, nodeCfg.PrivValidatorKeyFile())
-	pvStateFile := filepath.Join(nodeDir, nodeCfg.PrivValidatorStateFile())
-	blsKeyFile := filepath.Join(nodeDir, blsCfg.BlsKeyFile())
-	blsPasswordFile := filepath.Join(nodeDir, blsCfg.BlsPasswordFile())
+	cmtKeyFile := nodeCfg.PrivValidatorKeyFile()
+	cmtStateFile := nodeCfg.PrivValidatorStateFile()
+	blsKeyFile := privval.DefaultBlsKeyFile(nodeDir)
+	blsPasswordFile := privval.DefaultBlsPasswordFile(nodeDir)
 
-	if err := privval.IsValidFilePath(pvKeyFile, pvStateFile, blsKeyFile, blsPasswordFile); err != nil {
+	if err := privval.EnsureDirs(cmtKeyFile, cmtStateFile, blsKeyFile, blsPasswordFile); err != nil {
 		return err
 	}
 
-	cometPV := cmtprivval.GenFilePV(pvKeyFile, pvStateFile)
+	cometPV := cmtprivval.GenFilePV(cmtKeyFile, cmtStateFile)
 	cometPV.Key.Save()
 	cometPV.LastSignState.Save()
 
diff --git a/x/checkpointing/client/cli/tx_test.go b/x/checkpointing/client/cli/tx_test.go
index 5cccefdaf..3a12e687f 100644
--- a/x/checkpointing/client/cli/tx_test.go
+++ b/x/checkpointing/client/cli/tx_test.go
@@ -4,7 +4,6 @@ import (
 	"context"
 	"fmt"
 	"io"
-	"path/filepath"
 	"testing"
 
 	sdkmath "cosmossdk.io/math"
@@ -106,17 +105,17 @@ func (s *CLITestSuite) TestCmdWrappedCreateValidator() {
 
 	// create BLS keys
 	nodeCfg := cmtconfig.DefaultConfig()
-	blsCfg := privval.DefaultBlsConfig()
+	nodeCfg.SetRoot(homeDir)
 
-	keyPath := filepath.Join(homeDir, nodeCfg.PrivValidatorKeyFile())
-	statePath := filepath.Join(homeDir, nodeCfg.PrivValidatorStateFile())
-	blsKeyFile := filepath.Join(homeDir, blsCfg.BlsKeyFile())
-	blsPasswordFile := filepath.Join(homeDir, blsCfg.BlsPasswordFile())
+	cmtKeyPath := nodeCfg.PrivValidatorKeyFile()
+	cmtStatePath := nodeCfg.PrivValidatorStateFile()
+	blsKeyFile := privval.DefaultBlsKeyFile(homeDir)
+	blsPasswordFile := privval.DefaultBlsPasswordFile(homeDir)
 
-	err := privval.IsValidFilePath(keyPath, statePath, blsKeyFile, blsPasswordFile)
+	err := privval.EnsureDirs(cmtKeyPath, cmtStatePath, blsKeyFile, blsPasswordFile)
 	require.NoError(err)
 
-	filePV := cmtprivval.GenFilePV(keyPath, statePath)
+	filePV := cmtprivval.GenFilePV(cmtKeyPath, cmtStatePath)
 	filePV.Key.Save()
 	filePV.LastSignState.Save()
 
diff --git a/x/checkpointing/client/cli/utils.go b/x/checkpointing/client/cli/utils.go
index e25bbc750..f29998631 100644
--- a/x/checkpointing/client/cli/utils.go
+++ b/x/checkpointing/client/cli/utils.go
@@ -204,18 +204,18 @@ func buildCommissionRates(rateStr, maxRateStr, maxChangeRateStr string) (commiss
 
 func getValKeyFromFile(homeDir string) (*privval.ValidatorKeys, error) {
 	nodeCfg := cmtconfig.DefaultConfig()
-	blsCfg := privval.DefaultBlsConfig()
+	nodeCfg.SetRoot(homeDir)
 
-	keyPath := filepath.Join(homeDir, nodeCfg.PrivValidatorKeyFile())
-	statePath := filepath.Join(homeDir, nodeCfg.PrivValidatorStateFile())
-	blsKeyPath := filepath.Join(homeDir, blsCfg.BlsKeyFile())
-	blsPasswordPath := filepath.Join(homeDir, blsCfg.BlsPasswordFile())
+	cmtKeyPath := nodeCfg.PrivValidatorKeyFile()
+	cmtStatePath := nodeCfg.PrivValidatorStateFile()
+	blsKeyPath := privval.DefaultBlsKeyFile(homeDir)
+	blsPasswordPath := privval.DefaultBlsPasswordFile(homeDir)
 
-	if err := privval.IsValidFilePath(keyPath, statePath, blsKeyPath, blsPasswordPath); err != nil {
+	if err := privval.EnsureDirs(cmtKeyPath, cmtStatePath, blsKeyPath, blsPasswordPath); err != nil {
 		return nil, err
 	}
 
-	filePV := cmtprivval.LoadFilePV(keyPath, statePath)
+	filePV := cmtprivval.LoadFilePV(cmtKeyPath, cmtStatePath)
 	blsPV := privval.LoadBlsPV(blsKeyPath, blsPasswordPath)
 
 	return privval.NewValidatorKeys(filePV.Key.PrivKey, blsPV.Key.PrivKey)

From 9dd45f35b08314b5c93bc2fdcd541344ffefc3db Mon Sep 17 00:00:00 2001
From: wonjoon <wnjoon@gmail.com>
Date: Wed, 15 Jan 2025 15:31:05 +0900
Subject: [PATCH 8/8] fix: add comments, wrapping errors and remove unused
 functions

---
 app/signer/private.go               |  4 +-
 crypto/erc2335/erc2335.go           | 59 ++++++++++-------------------
 crypto/erc2335/erc2335_test.go      | 23 ++++++-----
 privval/bls.go                      | 43 +++++++++++++--------
 privval/bls_test.go                 |  5 +--
 test/e2e/initialization/node.go     |  2 +-
 testutil/datagen/init_val.go        |  2 +-
 testutil/signer/private.go          |  3 +-
 x/checkpointing/client/cli/utils.go |  2 +-
 9 files changed, 67 insertions(+), 76 deletions(-)

diff --git a/app/signer/private.go b/app/signer/private.go
index c2839a673..491658b36 100644
--- a/app/signer/private.go
+++ b/app/signer/private.go
@@ -1,6 +1,8 @@
 package signer
 
 import (
+	"fmt"
+
 	cmtconfig "github.com/cometbft/cometbft/config"
 
 	"github.com/babylonlabs-io/babylon/privval"
@@ -21,7 +23,7 @@ func InitPrivSigner(nodeDir string) (*PrivSigner, error) {
 	blsPasswordFile := privval.DefaultBlsPasswordFile(nodeDir)
 
 	if err := privval.EnsureDirs(pvKeyFile, pvStateFile, blsKeyFile, blsPasswordFile); err != nil {
-		return nil, err
+		return nil, fmt.Errorf("failed to ensure dirs: %w", err)
 	}
 
 	cometPV := cmtprivval.LoadFilePV(pvKeyFile, pvStateFile)
diff --git a/crypto/erc2335/erc2335.go b/crypto/erc2335/erc2335.go
index 6933500b5..e018f7250 100644
--- a/crypto/erc2335/erc2335.go
+++ b/crypto/erc2335/erc2335.go
@@ -1,39 +1,35 @@
 package erc2335
 
 import (
-	"crypto/rand"
-	"encoding/hex"
 	"encoding/json"
 	"fmt"
 	"os"
 
-	"github.com/pkg/errors"
 	keystorev4 "github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4"
 )
 
+// Erc2335KeyStore represents an ERC-2335 compatible keystore used in keystorev4.
 type Erc2335KeyStore struct {
-	Crypto      map[string]interface{} `json:"crypto"`
-	Version     uint                   `json:"version"`
-	UUID        string                 `json:"uuid"`
-	Path        string                 `json:"path"`
-	Pubkey      string                 `json:"pubkey"`
-	Description string                 `json:"description"`
+	Crypto      map[string]interface{} `json:"crypto"`      // Map containing the encryption details for the keystore such as checksum, cipher, and kdf.
+	Version     uint                   `json:"version"`     // Version of the keystore format (e.g., 4 for keystorev4).
+	UUID        string                 `json:"uuid"`        // Unique identifier for the keystore.
+	Path        string                 `json:"path"`        // File path where the keystore is stored.
+	Pubkey      string                 `json:"pubkey"`      // Public key associated with the keystore, stored as a hexadecimal string.
+	Description string                 `json:"description"` // Optional description of the keystore, currently used to store the delegator address.
 }
 
-// wonjoon: encrypt key pair to erc2335 keystore
-// available to handle all keys in []byte format
+// Encrypt encrypts the private key using the keystorev4 encryptor.
 func Encrypt(privKey, pubKey []byte, password string) ([]byte, error) {
 	if privKey == nil {
-		return nil, errors.New("private key cannot be nil")
+		return nil, fmt.Errorf("private key cannot be nil")
 	}
 
 	encryptor := keystorev4.New()
 	cryptoFields, err := encryptor.Encrypt(privKey, password)
 	if err != nil {
-		return nil, errors.Wrap(err, "failed to encrypt private key")
+		return nil, fmt.Errorf("failed to encrypt private key: %w", err)
 	}
 
-	// Create the keystore json structure
 	keystoreJSON := Erc2335KeyStore{
 		Crypto:  cryptoFields,
 		Version: 4,
@@ -43,41 +39,24 @@ func Encrypt(privKey, pubKey []byte, password string) ([]byte, error) {
 	return json.Marshal(keystoreJSON)
 }
 
+// Decrypt decrypts the private key from the keystore using the given password.
+func Decrypt(keystore Erc2335KeyStore, password string) ([]byte, error) {
+	encryptor := keystorev4.New()
+	return encryptor.Decrypt(keystore.Crypto, password)
+}
+
+// LoadKeyStore loads a keystore from a file.
 func LoadKeyStore(filePath string) (Erc2335KeyStore, error) {
 	var keystore Erc2335KeyStore
 
 	keyJSONBytes, err := os.ReadFile(filePath)
 	if err != nil {
-		return Erc2335KeyStore{}, err
+		return Erc2335KeyStore{}, fmt.Errorf("failed to read keystore file: %w", err)
 	}
 
 	if err := json.Unmarshal(keyJSONBytes, &keystore); err != nil {
-		return Erc2335KeyStore{}, err
+		return Erc2335KeyStore{}, fmt.Errorf("failed to unmarshal keystore: %w", err)
 	}
 
 	return keystore, nil
 }
-
-// decrypt private key from erc2335 keystore
-func Decrypt(keystore Erc2335KeyStore, password string) ([]byte, error) {
-	encryptor := keystorev4.New()
-	return encryptor.Decrypt(keystore.Crypto, password)
-}
-
-func SavePasswordToFile(password, filePath string) error {
-	return os.WriteFile(filePath, []byte(password), 0600)
-}
-
-func LoadPaswordFromFile(filePath string) (string, error) {
-	password, err := os.ReadFile(filePath)
-	return string(password), err
-}
-
-func CreateRandomPassword() string {
-	password := make([]byte, 32)
-	_, err := rand.Read(password)
-	if err != nil {
-		panic(err)
-	}
-	return hex.EncodeToString(password)
-}
diff --git a/crypto/erc2335/erc2335_test.go b/crypto/erc2335/erc2335_test.go
index aa56f650e..9706b599a 100644
--- a/crypto/erc2335/erc2335_test.go
+++ b/crypto/erc2335/erc2335_test.go
@@ -6,17 +6,18 @@ import (
 	"testing"
 
 	"github.com/babylonlabs-io/babylon/crypto/bls12381"
+	"github.com/cometbft/cometbft/libs/tempfile"
 	"github.com/test-go/testify/require"
 )
 
+const password string = "password"
+
 func TestEncryptBLS(t *testing.T) {
 	t.Run("create bls key", func(t *testing.T) {
 		blsPrivKey := bls12381.GenPrivKey()
 		blsPubKey := blsPrivKey.PubKey().Bytes()
 
 		t.Run("encrypt bls key", func(t *testing.T) {
-			password := CreateRandomPassword()
-			t.Logf("password: %s", password)
 			encryptedBlsKey, err := Encrypt(blsPrivKey, blsPubKey, password)
 			require.NoError(t, err)
 			t.Logf("encrypted bls key: %s", encryptedBlsKey)
@@ -41,18 +42,16 @@ func TestEncryptBLS(t *testing.T) {
 		})
 
 		t.Run("save password and encrypt bls key", func(t *testing.T) {
-			password := CreateRandomPassword()
-			t.Logf("password: %s", password)
-
 			encryptedBlsKey, err := Encrypt(blsPrivKey, blsPubKey, password)
 			require.NoError(t, err)
 			t.Logf("encrypted bls key: %s", encryptedBlsKey)
-			err = SavePasswordToFile(password, "password.txt")
+			err = tempfile.WriteFileAtomic("password.txt", []byte(password), 0600)
 			require.NoError(t, err)
 
 			t.Run("load password and decrypt bls key", func(t *testing.T) {
-				password, err := LoadPaswordFromFile("password.txt")
+				passwordBytes, err := os.ReadFile("password.txt")
 				require.NoError(t, err)
+				password := string(passwordBytes)
 
 				var keystore Erc2335KeyStore
 				err = json.Unmarshal(encryptedBlsKey, &keystore)
@@ -64,15 +63,15 @@ func TestEncryptBLS(t *testing.T) {
 			})
 
 			t.Run("save new password into same file", func(t *testing.T) {
-				newPassword := CreateRandomPassword()
-				t.Logf("new password: %s", newPassword)
-				err = SavePasswordToFile(newPassword, "password.txt")
+				newPassword := "new password"
+				err = tempfile.WriteFileAtomic("password.txt", []byte(newPassword), 0600)
 				require.NoError(t, err)
 			})
 
 			t.Run("failed when load different password and decrypt bls key", func(t *testing.T) {
-				password, err := LoadPaswordFromFile("password.txt")
+				passwordBytes, err := os.ReadFile("password.txt")
 				require.NoError(t, err)
+				password := string(passwordBytes)
 
 				var keystore Erc2335KeyStore
 				err = json.Unmarshal(encryptedBlsKey, &keystore)
@@ -83,7 +82,7 @@ func TestEncryptBLS(t *testing.T) {
 			})
 
 			t.Run("failed when password file don't exist", func(t *testing.T) {
-				_, err := LoadPaswordFromFile("nopassword.txt")
+				_, err := os.ReadFile("nopassword.txt")
 				require.Error(t, err)
 			})
 		})
diff --git a/privval/bls.go b/privval/bls.go
index b68884ab9..1621865ba 100644
--- a/privval/bls.go
+++ b/privval/bls.go
@@ -16,29 +16,34 @@ import (
 )
 
 const (
-	DefaultBlsKeyName      = "bls_key.json"
-	DefaultBlsPasswordName = "bls_password.txt"
+	DefaultBlsKeyName      = "bls_key.json"     // Default file name for BLS key
+	DefaultBlsPasswordName = "bls_password.txt" // Default file name for BLS password
 )
 
 var (
-	defaultBlsKeyFilePath  = filepath.Join(cmtcfg.DefaultConfigDir, DefaultBlsKeyName)
-	defaultBlsPasswordPath = filepath.Join(cmtcfg.DefaultConfigDir, DefaultBlsPasswordName)
+	defaultBlsKeyFilePath  = filepath.Join(cmtcfg.DefaultConfigDir, DefaultBlsKeyName)      // Default file path for BLS key
+	defaultBlsPasswordPath = filepath.Join(cmtcfg.DefaultConfigDir, DefaultBlsPasswordName) // Default file path for BLS password
 )
 
+// BlsPV is a wrapper around BlsPVKey
 type BlsPV struct {
+	// Key is a structure containing bls12381 keys,
+	// paths of both key and password files,
+	// and delegator address
 	Key BlsPVKey
 }
 
+// BlsPVKey is a wrapper containing bls12381 keys,
+// paths of both key and password files, and delegator address.
 type BlsPVKey struct {
-	PubKey  bls12381.PublicKey  `json:"bls_pub_key"`
-	PrivKey bls12381.PrivateKey `json:"bls_priv_key"`
-
-	DelegatorAddress string
-
-	filePath     string
-	passwordPath string
+	PubKey           bls12381.PublicKey  `json:"bls_pub_key"`       // Public Key of BLS
+	PrivKey          bls12381.PrivateKey `json:"bls_priv_key"`      // Private Key of BLS
+	DelegatorAddress string              `json:"delegator_address"` // Delegate Address
+	filePath         string              // File Path of BLS Key
+	passwordPath     string              // File Path of BLS Password
 }
 
+// NewBlsPV returns a new BlsPV.
 func NewBlsPV(privKey bls12381.PrivateKey, keyFilePath, passwordFilePath, delegatorAddress string) *BlsPV {
 	return &BlsPV{
 		Key: BlsPVKey{
@@ -51,17 +56,21 @@ func NewBlsPV(privKey bls12381.PrivateKey, keyFilePath, passwordFilePath, delega
 	}
 }
 
+// GenBlsPV returns a new BlsPV after saving it to the file.
 func GenBlsPV(keyFilePath, passwordFilePath, password, delegatorAddress string) *BlsPV {
 	pv := NewBlsPV(bls12381.GenPrivKey(), keyFilePath, passwordFilePath, delegatorAddress)
 	pv.Key.Save(password, delegatorAddress)
 	return pv
 }
 
+// LoadBlsPV returns a BlsPV after loading the erc2335 type of structure
+// from the file and decrypt it using a password.
 func LoadBlsPV(keyFilePath, passwordFilePath string) *BlsPV {
-	password, err := erc2335.LoadPaswordFromFile(passwordFilePath)
+	passwordBytes, err := os.ReadFile(passwordFilePath)
 	if err != nil {
 		cmtos.Exit(fmt.Sprintf("failed to read BLS password file: %v", err.Error()))
 	}
+	password := string(passwordBytes)
 
 	keystore, err := erc2335.LoadKeyStore(keyFilePath)
 	if err != nil {
@@ -86,6 +95,7 @@ func LoadBlsPV(keyFilePath, passwordFilePath string) *BlsPV {
 	}
 }
 
+// NewBlsPassword returns a password from the user prompt.
 func NewBlsPassword() string {
 	inBuf := bufio.NewReader(os.Stdin)
 	password, err := input.GetString("Enter your bls password", inBuf)
@@ -95,8 +105,8 @@ func NewBlsPassword() string {
 	return password
 }
 
-// Save bls key using password
-// Check both paths of bls key and password inside function
+// Save saves the bls12381 key to the file.
+// The file stores an erc2335 structure containing the encrypted bls private key.
 func (k *BlsPVKey) Save(password, addr string) {
 	// encrypt the bls12381 key to erc2335 type
 	erc2335BlsPvKey, err := erc2335.Encrypt(k.PrivKey, k.PubKey.Bytes(), password)
@@ -125,16 +135,17 @@ func (k *BlsPVKey) Save(password, addr string) {
 	}
 
 	// save used password to file
-	err = erc2335.SavePasswordToFile(password, k.passwordPath)
-	if err != nil {
+	if err := tempfile.WriteFileAtomic(k.passwordPath, []byte(password), 0600); err != nil {
 		panic(err)
 	}
 }
 
+// DefaultBlsKeyFile returns the default BLS key file path.
 func DefaultBlsKeyFile(home string) string {
 	return filepath.Join(home, defaultBlsKeyFilePath)
 }
 
+// DefaultBlsPasswordFile returns the default BLS password file path.
 func DefaultBlsPasswordFile(home string) string {
 	return filepath.Join(home, defaultBlsPasswordPath)
 }
diff --git a/privval/bls_test.go b/privval/bls_test.go
index f88417140..829747713 100644
--- a/privval/bls_test.go
+++ b/privval/bls_test.go
@@ -7,7 +7,6 @@ import (
 	"github.com/cometbft/cometbft/crypto/ed25519"
 
 	"github.com/babylonlabs-io/babylon/crypto/bls12381"
-	"github.com/babylonlabs-io/babylon/crypto/erc2335"
 	"github.com/cosmos/cosmos-sdk/types"
 	"github.com/test-go/testify/assert"
 )
@@ -26,7 +25,7 @@ func TestNewBlsPV(t *testing.T) {
 		pv := NewBlsPV(bls12381.GenPrivKey(), keyFilePath, passwordFilePath, "")
 		assert.NotNil(t, pv)
 
-		password := erc2335.CreateRandomPassword()
+		password := "password"
 		pv.Key.Save(password, "")
 
 		t.Run("load bls key from file", func(t *testing.T) {
@@ -42,7 +41,7 @@ func TestNewBlsPV(t *testing.T) {
 		pv := NewBlsPV(bls12381.GenPrivKey(), keyFilePath, passwordFilePath, "")
 		assert.NotNil(t, pv)
 
-		password := erc2335.CreateRandomPassword()
+		password := "password"
 
 		delegatorAddress := types.AccAddress(ed25519.GenPrivKey().PubKey().Address()).String()
 		pv.Key.Save(password, delegatorAddress)
diff --git a/test/e2e/initialization/node.go b/test/e2e/initialization/node.go
index eb894ae28..808ad3bb5 100644
--- a/test/e2e/initialization/node.go
+++ b/test/e2e/initialization/node.go
@@ -168,7 +168,7 @@ func (n *internalNode) createConsensusKey() error {
 	blsPasswordFile := privval.DefaultBlsPasswordFile(n.configDir())
 
 	if err := privval.EnsureDirs(pvKeyFile, pvStateFile, blsKeyFile, blsPasswordFile); err != nil {
-		return err
+		return fmt.Errorf("failed to ensure dirs: %w", err)
 	}
 	accAddress, _ := n.keyInfo.GetAddress()
 
diff --git a/testutil/datagen/init_val.go b/testutil/datagen/init_val.go
index ac33ea596..b7fb30c5b 100644
--- a/testutil/datagen/init_val.go
+++ b/testutil/datagen/init_val.go
@@ -36,7 +36,7 @@ func InitializeNodeValidatorFilesFromMnemonic(config *cfg.Config, mnemonic strin
 	blsKeyFile := privval.DefaultBlsKeyFile(config.RootDir)
 	blsPasswordFile := privval.DefaultBlsPasswordFile(config.RootDir)
 	if err := privval.EnsureDirs(cmtKeyFile, cmtStateFile, blsKeyFile, blsPasswordFile); err != nil {
-		return "", nil, err
+		return "", nil, fmt.Errorf("failed to ensure dirs: %w", err)
 	}
 
 	var filePV *cmtprivval.FilePV
diff --git a/testutil/signer/private.go b/testutil/signer/private.go
index c1589ddae..98f4852fe 100644
--- a/testutil/signer/private.go
+++ b/testutil/signer/private.go
@@ -1,6 +1,7 @@
 package signer
 
 import (
+	"fmt"
 	"os"
 
 	cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
@@ -60,7 +61,7 @@ func GeneratePrivSigner(nodeDir string) error {
 	blsPasswordFile := privval.DefaultBlsPasswordFile(nodeDir)
 
 	if err := privval.EnsureDirs(cmtKeyFile, cmtStateFile, blsKeyFile, blsPasswordFile); err != nil {
-		return err
+		return fmt.Errorf("failed to ensure dirs: %w", err)
 	}
 
 	cometPV := cmtprivval.GenFilePV(cmtKeyFile, cmtStateFile)
diff --git a/x/checkpointing/client/cli/utils.go b/x/checkpointing/client/cli/utils.go
index f29998631..695a57f99 100644
--- a/x/checkpointing/client/cli/utils.go
+++ b/x/checkpointing/client/cli/utils.go
@@ -212,7 +212,7 @@ func getValKeyFromFile(homeDir string) (*privval.ValidatorKeys, error) {
 	blsPasswordPath := privval.DefaultBlsPasswordFile(homeDir)
 
 	if err := privval.EnsureDirs(cmtKeyPath, cmtStatePath, blsKeyPath, blsPasswordPath); err != nil {
-		return nil, err
+		return nil, fmt.Errorf("failed to ensure dirs: %w", err)
 	}
 
 	filePV := cmtprivval.LoadFilePV(cmtKeyPath, cmtStatePath)