github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/app/crypto/ethkeystore/keystore.go (about)

     1  package ethkeystore
     2  
     3  import (
     4  	"crypto/ecdsa"
     5  	"encoding/hex"
     6  	"fmt"
     7  	"github.com/fibonacci-chain/fbc/app/crypto/hd"
     8  	"io/ioutil"
     9  	"os"
    10  	"path/filepath"
    11  	"time"
    12  
    13  	"github.com/ethereum/go-ethereum/accounts/keystore"
    14  	"github.com/ethereum/go-ethereum/common"
    15  	ethcrypto "github.com/ethereum/go-ethereum/crypto"
    16  	"github.com/fibonacci-chain/fbc/app/crypto/ethsecp256k1"
    17  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/crypto/keys"
    18  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/crypto/keys/mintkey"
    19  	tmcrypto "github.com/fibonacci-chain/fbc/libs/tendermint/crypto"
    20  	"github.com/fibonacci-chain/fbc/libs/tendermint/crypto/secp256k1"
    21  	"github.com/google/uuid"
    22  )
    23  
    24  // EncodeTmKeyToEthKey  transfer tendermint key  to a ethereum key
    25  func EncodeECDSAKeyToTmKey(privateKeyECDSA *ecdsa.PrivateKey, keytype keys.SigningAlgo) (tmcrypto.PrivKey, error) {
    26  	// Converts key to Ethermint secp256 implementation
    27  	ethkey := ethcrypto.FromECDSA(privateKeyECDSA)
    28  	switch keytype {
    29  	case hd.EthSecp256k1:
    30  		key := ethsecp256k1.PrivKey(ethkey)
    31  		return &key, nil
    32  	case keys.Secp256k1:
    33  		secpPk := &secp256k1.PrivKeySecp256k1{}
    34  		copy(secpPk[:], ethkey)
    35  		return secpPk, nil
    36  	default:
    37  		return nil, fmt.Errorf("unknown private key type %s", keytype)
    38  	}
    39  
    40  }
    41  
    42  // ImportKeyStoreFile Export Key to  keystore file
    43  func ImportKeyStoreFile(decryptPassword, password, fileName string, keytype keys.SigningAlgo) (privKetArmor string, err error) {
    44  	filejson, err := ioutil.ReadFile(fileName)
    45  	if err != nil {
    46  		return "", err
    47  	}
    48  
    49  	var decrytKey *keystore.Key
    50  	decrytKey, err = keystore.DecryptKey(filejson, decryptPassword)
    51  	if err != nil {
    52  		decrytKey, err = DecryptKeyForWeb3(filejson, decryptPassword)
    53  		if err != nil {
    54  			return "", fmt.Errorf("failed to encrypt key: %s", err.Error())
    55  		}
    56  	}
    57  
    58  	privkey, err := EncodeECDSAKeyToTmKey(decrytKey.PrivateKey, keytype)
    59  
    60  	armor := mintkey.EncryptArmorPrivKey(privkey, password, string(keytype))
    61  
    62  	return armor, nil
    63  }
    64  
    65  // CreateKeystoreByTmKey  create a eth keystore by accountname from keybase
    66  func CreateKeystoreByTmKey(privKey tmcrypto.PrivKey, dir, encryptPassword string) (string, error) {
    67  	// dir must be absolute
    68  	if !filepath.IsAbs(dir) {
    69  		return "", fmt.Errorf("invalid directory")
    70  	}
    71  	// converts tendermint  key to ethereum key
    72  	ethKey, err := EncodeTmKeyToEthKey(privKey)
    73  	if err != nil {
    74  		return "", fmt.Errorf("invalid private key type, must be Ethereum key: %T", privKey)
    75  	}
    76  
    77  	// export Key to keystore file
    78  	// if filename isn't set ,use default ethereum name
    79  	addr := common.BytesToAddress(privKey.PubKey().Address())
    80  	fileName := filepath.Join(dir, keyFileName(addr))
    81  	err = ExportKeyStoreFile(ethKey, encryptPassword, fileName)
    82  	return fileName, err
    83  }
    84  
    85  // EncodeTmKeyToEthKey  transfer tendermint key  to a ethereum key
    86  func EncodeTmKeyToEthKey(privKey tmcrypto.PrivKey) (*ecdsa.PrivateKey, error) {
    87  	// Converts key to Ethermint secp256 implementation
    88  	emintKey, ok := privKey.(ethsecp256k1.PrivKey)
    89  	if !ok {
    90  		return nil, fmt.Errorf("invalid private key type, must be Ethereum key: %T", privKey)
    91  	}
    92  
    93  	return emintKey.ToECDSA(), nil
    94  }
    95  
    96  // ExportKeyStoreFile Export Key to  keystore file
    97  func ExportKeyStoreFile(privateKeyECDSA *ecdsa.PrivateKey, encryptPassword, fileName string) error {
    98  	//new keystore key
    99  	ethKey, err := newEthKeyFromECDSA(privateKeyECDSA)
   100  	if err != nil {
   101  		return err
   102  	}
   103  	// encrypt Key to get keystore file
   104  	content, err := keystore.EncryptKey(ethKey, encryptPassword, keystore.StandardScryptN, keystore.StandardScryptP)
   105  	if err != nil {
   106  		return fmt.Errorf("failed to encrypt key: %s", err.Error())
   107  	}
   108  
   109  	// write to keystore file
   110  	err = ioutil.WriteFile(fileName, content, os.ModePerm)
   111  	if err != nil {
   112  		return fmt.Errorf("failed to write keystore: %s", err.Error())
   113  	}
   114  	return nil
   115  }
   116  
   117  // newEthKeyFromECDSA new eth.keystore Key
   118  func newEthKeyFromECDSA(privateKeyECDSA *ecdsa.PrivateKey) (*keystore.Key, error) {
   119  	id, err := uuid.NewRandom()
   120  	if err != nil {
   121  		return nil, fmt.Errorf("Could not create random uuid: %v", err)
   122  	}
   123  	key := &keystore.Key{
   124  		Id:         id,
   125  		Address:    ethcrypto.PubkeyToAddress(privateKeyECDSA.PublicKey),
   126  		PrivateKey: privateKeyECDSA,
   127  	}
   128  	return key, nil
   129  }
   130  
   131  // keyFileName return the default keystore file name in the ethereum
   132  func keyFileName(keyAddr common.Address) string {
   133  	ts := time.Now().UTC()
   134  	return fmt.Sprintf("UTC--%s--%s", toISO8601(ts), hex.EncodeToString(keyAddr[:]))
   135  }
   136  
   137  func toISO8601(t time.Time) string {
   138  	var tz string
   139  	name, offset := t.Zone()
   140  	if name == "UTC" {
   141  		tz = "Z"
   142  	} else {
   143  		tz = fmt.Sprintf("%03d00", offset/3600)
   144  	}
   145  	return fmt.Sprintf("%04d-%02d-%02dT%02d-%02d-%02d.%09d%s",
   146  		t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), tz)
   147  }