比特幣學習(一):私鑰與地址

對于比特幣而言,公鑰對應著btc地址,私鑰相當于密碼,擁有私鑰意味著掌握了這個地址,所以了解私鑰是非常重要的。

我希望通過代碼實現(xiàn)比特幣私鑰、地址的生成來學習了解這方面的知識。本文的代碼很多來自開源項目bitcoinj,實現(xiàn)的語言為java。

一、私鑰與公鑰的關系

通過橢圓曲線算法,我們可以得到一個密鑰對,一個為私鑰,一個為公鑰。私鑰和公鑰都是256位32個字節(jié)的byte數(shù)組。

下面通過代碼來實現(xiàn):

ECKey key = new ECKey();

byte[] privKeyBytes = key.getPrivKeyBytes();

byte[] pubKeyBytes = key.getPubKey();

ECKey封裝了橢圓曲線算法,初始化ECKey,即可獲得一個密鑰對。

二、公鑰轉換為btc地址

由于數(shù)組不便于使用,所以公鑰需要進行格式化,格式化后的結果即為btc地址。

先說下原理:

下面通過代碼實現(xiàn):

/**

* ripemd160(sha256(in))

* 雙hash,計算比特幣地址時使用

*/

public static byte[] sha256hash160(byte[] input) {

try {

byte[] sha256 = MessageDigest.getInstance("SHA-256").digest(input);

RIPEMD160Digest digest = new RIPEMD160Digest();

digest.update(sha256, 0, sha256.length);

byte[] out = new byte[20];

digest.doFinal(out, 0);

return out;

} catch (NoSuchAlgorithmException e) {

throw new RuntimeException(e); // Cannot happen.

}

}

/**

* 從公鑰計算出地址

* @param pubKeyBytes

* @return

*/

public static String getBtcAddress (byte[] pubKeyBytes) {

byte[] hash160 = sha256hash160(pubKeyBytes);

byte version = 0x00;

return Base58Check.encode(version, hash160);

}

三、base58及base58check編碼

base58介紹:

base58在base64的基礎上,去除了幾個看起來會產(chǎn)生歧義的字符,如 0 (零), O (大寫字母O), I (大寫的字母i) and l (小寫的字母L) ,和幾個影響雙擊選擇的字符,如/, +。結果字符集正好58個字符(包括9個數(shù)字,24個大寫字母,25個小寫字母)。

base58check介紹:

Base58 導出的字符串沒有校驗機制,這樣,在傳播過程中,如果漏寫了幾個字符,會檢測不出來。所以使用了改進版的算法 Base58Check。

實現(xiàn)是:在encode前,在輸入流尾部加入輸入內容的hash值(4個字節(jié))。然后再對輸入流進行 Base58Encode。

參考代碼:

info.block123.btc.kit.Base58

info.block123.btc.kit.Base58Check

四、私鑰格式化

為了方便存儲和使用,私鑰必須要進行格式化輸出。

btc私鑰格式介紹:

種類版本描述

Hex? ?16進制byte數(shù)組16進制byte數(shù)組

WIF? ? 5開頭Base58Check編碼

WIF-compressed? ?K or L開頭Base58Check編碼前,在byte數(shù)組后加0x01字節(jié)

代碼實現(xiàn):

/**

* 未加工的密鑰格式化

*/

@Override

public String format(byte[] keyBytes) {

if ( PRIV_KEY_HEX.equals(keyType)) {

return BtcKit.toHexString(keyBytes);

}

if ( PRIV_KEY_WIF.equals(keyType)) {

byte version = (byte)0x80;

return Base58Check.encode(version, keyBytes);

}

if ( PRIV_KEY_WIFC.equals(keyType)) {

byte[] cBytes = new byte[ keyBytes.length + 1];

System.arraycopy(keyBytes, 0, cBytes, 0, keyBytes.length);

cBytes[ cBytes.length - 1] = 0x01;

byte version = (byte)0x80;

return Base58Check.encode(version, cBytes);

}

return null;

}

@Override

public byte[] parse(String src) {

if ( PRIV_KEY_HEX.equals(keyType)) {

return BtcKit.hexStringToByte(src);

}

if ( PRIV_KEY_WIF.equals(keyType)) {

return Base58Check.decode(src);

}

if (PRIV_KEY_WIFC.equals(keyType)) {

byte[] rawBytes = Base58Check.decode(src);

byte[] result = new byte[rawBytes.length-1];

System.arraycopy(rawBytes, 0, result, 0, result.length);

return result;

}

return null;

}

五、私鑰推算出比特幣地址

比特幣地址可以由私鑰推算出來。下面為代碼實現(xiàn):

@Test

public void testPrivKeyToAddress() {

? ? String formatPrivKey = "5JG9hT3beGTJuUAmCQEmNaxAuMacCTfXuw1R3FCXig23RQHMr4K";

? ? KeyFormat format = new PrivKeyFormat(KeyFormat.PRIV_KEY_WIF);

? ?byte[] privKeyBytes = format.parse(formatPrivKey);

? ?byte[] pubKeyBytes = ECKey.publicKeyFromPrivate(BtcKit.byte32toBigInteger(privKeyBytes), false);

? ? String address = BtcKit.getBtcAddress(pubKeyBytes);

? ? System.out.println("計算后的地址:" + address);

Assert.assertEquals(address, "1thMirt546nngXqyPEz532S8fLwbozud8");

}

PS:如果覺得對你有幫助,歡迎打賞

btc地址:1BYgnJ1Xv561L3qFrFJasVzEGs1JC93QV1

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 在比特幣中,經(jīng)常出現(xiàn)三個詞:私鑰,公鑰和地址。他們是什么意思呢?他們之間又有什么樣的關系呢?搞清楚他們之間的關系和...
    0xSen閱讀 45,989評論 3 48
  • 作者 Kevin 簡介:“比特幣技術進階”由知名比特幣技術專家Kevin原創(chuàng)的三篇文章《比特幣交易構成》、《時間...
    西部之歌閱讀 1,610評論 0 0
  • 她原本只是一個安靜的女子, 細雨飄來朦朧了她的眼睛。 你卻紳士的向她打了一個噴嚏, 說,遇見她,你已病的不輕。
    簡村小吹閱讀 291評論 2 4
  • 文/葉老巫 本文關鍵詞:新手、長篇小說、拆解式閱讀、多寫、東野圭吾 1、 昨天晚上,無聊中打開某直播app,半小時...
    葉兩步閱讀 1,071評論 9 43
  • 有了好的產(chǎn)品、團隊后,唯一要考慮的事情就是增長了。 那增長最關鍵的因素是什么?留存率,這是唯一的衡量標準。如果一個...
    jorgensen閱讀 176評論 1 1

友情鏈接更多精彩內容