Android 創建以太坊錢包

創建以太坊HD錢包

HD錢包 分層確定性錢包

先簡單介紹一下錢包的原理和組成:

每一個錢包賬戶包含一份密鑰對,即私鑰與公鑰。私鑰(k)是一個數字,通常是隨機選出的。有了私鑰,我們就可以使用橢圓曲線乘法這個單向加密函數生成一個公鑰(K)。有了公鑰(K),我們就可以使用一個單向加密哈希函數生成該賬戶地址(A)。
當你發生交易時,每筆交易都需要一個有效的簽名纔會被存儲在區塊鏈。只有有效的私鑰才能產生有效的數字簽名,因此擁有錢包賬戶的私鑰就擁有了該賬戶的支配權。

錢包的常見的形態

  • Private Key
  • keystore && Password
  • Mnemonic Seed
    市面上主流的都是第三種 生成助記詞的形式 創建或者導入生成錢包。

先簡單介紹一下錢包生成流程:

  1. 隨機生成128到258位的隨機數,我們這裏叫做熵;
  2. 熵經過一定處理方法,生成助記詞;
  3. 助記詞經過密鑰延伸函數PBKDF2,生成種子;
  4. 種子經過HMAC-SHA512算法,生成母密鑰
  5. 通過CKD(child key derivation)函數,母密鑰生成衆多子密鑰。
  6. 利用私鑰加密生成keystore

ps:私鑰通過橢圓曲線生成公鑰, 公鑰通過哈希函數生成地址,這兩個過程都是單向的

BIP協議

Bitcoin Improvement Proposals 比特幣改進建議

生成錢包,BIP協議我們一定要了解

  1. BIP32 通過一個隨機種子,提出的爲了避免管理一堆私鑰的麻煩提出的分層推導方案。
  2. BIP39 通過定義助記詞讓種子的備份更友好。(單詞總列表爲2048個單詞組成)
  3. BIP32 的分層增強了路徑定義規範,讓同一個 seed 可以支援多幣種、多帳戶

格式: m / purpose’ / coin_type’ / account’ / change / address_index

目前市面上的Ethereum 錢包均採用以上 Bitcoin HD Wallet 的架構,用的都是BIP44:,具體是這樣的m/44’/60’/0’/0/0

好了,上面這麼東西瞭解以後,那可以着手做一個錢包的項目了。

準備工作

創建錢包需要兩個庫
web3j

主要使用它來生成助記詞和seed,後續需要用此庫來進行交易(轉賬,部署合約,加載合約等)

 implementation 'org.web3j:core:4.2.0-android'

bitcoinj

通過前面生成的seed生成支持bip32和bip44的私鑰。

 implementation "org.bitcoinj:bitcoinj-core:0.14.7"

依賴web3j項目安裝時會出現失敗錯誤:
Installation did not succeed.
The application could not be installed: INSTALL_FAILED_NO_MATCHING_ABIS
Installation failed due to: ‘null’

在gradle中android下添加packagingOptions,這樣就剔除了mips,mips64,x86_64架構,也就用不到對應的架構的工具鏈了

 packagingOptions {
        exclude 'lib/x86_64/darwin/libscrypt.dylib'
        exclude 'lib/x86_64/freebsd/libscrypt.so'
        exclude 'lib/x86_64/linux/libscrypt.so'
    }

重點說一下 現在半數以上的文章都是以web3j種創建的方式,沒有采用BIP44,這種方式你創建出來的錢包地址或者導入助記詞產生的錢包地址,你會發現和Imtoken cobo metaMask這些錢包地址不一樣。

你會看到很多這樣的實現方式,但是就是和主流錢包統一不起來


    public static String create(String pwd) {
        StringBuilder sb = new StringBuilder();
        byte[] entropy = new byte[Words.TWELVE.byteLength()];
        new SecureRandom().nextBytes(entropy);
        new MnemonicGenerator(English.INSTANCE).createMnemonic(entropy, sb::append);
        String mnemonics = sb.toString();
        System.out.println("+++助記詞:==" + mnemonics);
        //生成種子
        byte[] seed = MnemonicUtils.generateSeed(mnemonics, pwd);
        //生成ECKeyPair
        ECKeyPair ecKeyPair = ECKeyPair.create(seed);
        String privateKey = Numeric.toHexStringWithPrefix(ecKeyPair.getPrivateKey());
        System.out.println("+++私鑰==" + privateKey);
        String publicKey = Numeric.toHexStringWithPrefix(ecKeyPair.getPublicKey());
        System.out.println("+++公鑰==" + publicKey);
        //根據公鑰和ecKeyPair獲取錢包地址
        String address = Keys.getAddress(publicKey);
        System.out.println("+++地址==" + address);
        return address;
    }

正確姿勢

  1. 生成或者導入助記詞
  2. 生成 seed
  3. 生成 master key
  4. 生成 child key
  5. 我們取第一組child key即m/44’/60’/0’/0/0 得到私鑰,keystore及地址
	/**
     * 產生助記詞
     */
    public static String  generateMnemonics() {
        StringBuilder sb = new StringBuilder();
        byte[] entropy = new byte[Words.TWELVE.byteLength()];
        new SecureRandom().nextBytes(entropy);
        new MnemonicGenerator(English.INSTANCE).createMnemonic(entropy, sb::append);
        String mnemonics = sb.toString();

        return mnemonics;

    }
創建錢包
 /**
     *
     * @param mnemonics 助記詞
     * @param password 密碼(生成私鑰用)
     * @return BabelWallet自己創建bean對象,方法返回
     */
    public static BabelWallet generateBIP44Wallet(String mnemonics, String password) {
        //2.生成種子
        byte[] seed = MnemonicUtils.generateSeed(mnemonics, null);
        //3. 生成根私鑰 root private key 樹頂點的master key ;bip32
        DeterministicKey rootPrivateKey = HDKeyDerivation.createMasterPrivateKey(seed);
        // 4. 由根私鑰生成 第一個HD 錢包
        DeterministicHierarchy dh = new DeterministicHierarchy(rootPrivateKey);

        // 5. 定義父路徑 H則是加強 imtoken中的eth錢包進過測試發現使用的是此方式生成 bip44
        List<ChildNumber> parentPath = HDUtils.parsePath("M/44H/60H/0H/0");
        DeterministicKey child = dh.deriveChild(parentPath, true, true, new ChildNumber(0));
        byte[] privateKeyByte = child.getPrivKeyBytes();
        //7.通過私鑰生成公私鑰對
        ECKeyPair ecKeyPair = ECKeyPair.create(privateKeyByte);
        //8.通過密碼和鑰匙對生成WalletFile也就是keystore的bean類
        WalletFile walletFile = null;
        try {
            walletFile = Wallet.createLight(password, ecKeyPair);
        } catch (CipherException e) {
            e.printStackTrace();
        }
        String privateKey = Numeric.toHexStringWithPrefix(ecKeyPair.getPrivateKey());
        System.out.println("+++私鑰==" + privateKey);
        String publicKey = Numeric.toHexStringWithPrefix(ecKeyPair.getPublicKey());
        System.out.println("+++公鑰==" + publicKey);
        //根據公鑰和ecKeyPair獲取錢包地址
        String address = Keys.getAddress(publicKey);
        System.out.println("+++地址BIP44==" + address);
        return new BabelWallet(mnemonics, address, walletFile);
    }

到這我們的錢包創建就好了,我們可以把助記詞,導入到imtoken或者matemask 測試一下生成是是否相同。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章