讓我們通過學習比特幣(Bitcoin)如何實施該技術的各個方面來工作,好嗎?該技術包括以下幾個方面:
- 比特幣地址bitcoin address是用來傳送和接收比特幣的。
- 交易transaction是比特幣從一個地址轉移到另一個地址。
- 幾個交易被分組成一個區塊block。一個區塊被處理,因此它可以被提交到比特幣網路中。這個過程被稱為挖礦mining。
- 區塊被收集在區塊鏈blockchain中,並由網路中的節點共享。
警告的提示——這裡的程式碼僅用於學習。如果你試圖將比特幣傳送到由該程式碼生成的地址,你可能會損失金錢。
什麼是比特幣地址?
<!–more–>
比特幣地址是一個隨機查詢的十六進位制字串,在比特幣網路中用於傳送和接收比特幣。它是公私不對稱ECDSA
金鑰的公共部分。相應的私鑰用於簽署比特幣交易,作為交易時來自你的確認和證明。
從技術上講,比特幣地址是從ECDSA
金鑰的公共部分生成的,使用SHA-256
和RIPEMD-160
進行hash,如下文所述,處理得到的結果hash,最後使用Base58
校驗編碼對金鑰進行編碼。
讓我們看看如何使用JCE(java加密擴充套件),Bouncy Castle(RIPEMD-160)以及最後在bitcoinj庫中使用Base58編碼功能來完成所有這些工作。
生成ECDSA金鑰對
我們之前已經介紹過生成RSA公鑰和私鑰。比特幣使用ECDSA
代替RSA
作為關鍵演算法。它生成如下:
為Elliptic Curve
演算法建立KeyPairGenerator
。
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
使用指定橢圓曲線是secp256k1。
ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp256k1");
keyGen.initialize(ecSpec);
一旦獲得KeyPairGenerator
後,你可以建立KeyPair
即金鑰對,從中可以獲取公鑰和私鑰。
KeyPair kp = keyGen.generateKeyPair();
PublicKey pub = kp.getPublic();
PrivateKey pvt = kp.getPrivate();
ECDSA私鑰
你可以只儲存金鑰的私有部分,因為公鑰可以從私鑰派生。
ECPrivateKey epvt = (ECPrivateKey)pvt;
String sepvt = adjustTo64(epvt.getS().toString(16)).toUpperCase();
System.out.println("s[" + sepvt.length() + "]: " + sepvt);
靜態方法adjustTo64()
僅填充帶有前導0的十六進位制字串,因此總長度為64個字元。
static private String adjustTo64(String s) {
switch(s.length()) {
case 62: return "00" + s;
case 63: return "0" + s;
case 64: return s;
default:
throw new IllegalArgumentException("not a valid key: " + s);
}
}
這是由上面的程式碼生成的示例私鑰。
s[64]: 024C8E05018319CED4BB04E184C307BFF115976A05F974C7D945B5151E490ADE
這個值通常是由數字錢包儲存的值。
ECDSA公鑰
上面生成的金鑰的公共部分被編碼為比特幣地址。首先,ECDSA金鑰由橢圓曲線上的點表示。該點的X和Y座標包括公鑰。它們在開頭與“04”連線在一起代表公鑰。
ECPublicKey epub = (ECPublicKey)pub;
ECPoint pt = epub.getW();
String sx = adjustTo64(pt.getAffineX().toString(16)).toUpperCase();
String sy = adjustTo64(pt.getAffineY().toString(16)).toUpperCase();
String bcPub = "04" + sx + sy;
System.out.println("bcPub: " + bcPub);
# prints
bcPub: 04CAAA5C0BDDAA22C9D3C0DDAEC8550791891BB2C2FB0F9084D02F927537DE4F443ACED7DEB488E9BFE60D6C68596E6C78D95E20622CC05474FD962392BDC6AF29
執行SHA-256和RIPEMD-160雜湊
我們現在需要在公鑰上執行SHA-256
,然後是RIPEMD-160
。
MessageDigest sha = MessageDigest.getInstance("SHA-256");
byte[] s1 = sha.digest(bcPub.getBytes("UTF-8"));
System.out.println(" sha: " + bytesToHex(s1).toUpperCase());
# prints
sha: 7524DC35AEB4B62A0F1C90425ADC6732A7C5DF51A72E8B90983629A7AEC656A0
我們使用Bouncy Castle
提供程式來執行RIPEMD-160
,因為JCE
沒有實現此演算法。
MessageDigest rmd = MessageDigest.getInstance("RipeMD160", "BC");
byte[] r1 = rmd.digest(s1);
接下來,我們需要在雜湊開頭新增一個0x00的版本位元組。
byte[] r2 = new byte[r1.length + 1];
r2[0] = 0;
for (int i = 0 ; i < r1.length ; i++) r2[i+1] = r1[i];
System.out.println(" rmd: " + bytesToHex(r2).toUpperCase());
# prints
rmd: 00C5FAE41AB21FA56CFBAFA3AE7FB5784441D11CEC
重複SHA-256雜湊兩次
我們現在需要對上面的結果執行兩次SHA-256雜湊。
byte[] s2 = sha.digest(r2);
System.out.println(" sha: " + bytesToHex(s2).toUpperCase());
byte[] s3 = sha.digest(s2);
System.out.println(" sha: " + bytesToHex(s3).toUpperCase());
第二次雜湊結果的前4個位元組用作地址校驗和。它附加到上面的RIPEMD160
雜湊。這是25位元組的比特幣地址。
byte[] a1 = new byte[25];
for (int i = 0 ; i < r2.length ; i++) a1[i] = r2[i];
for (int i = 0 ; i < 5 ; i++) a1[20 + i] = s3[i];
使用Base58對地址進行編碼
我們現在使用bitcoinj
庫中的Base58.encode()
方法來獲得最終的比特幣地址。
System.out.println(" adr: " + Base58.encode(a1));
# prints
adr: 1K3pg1JFPtW7NvKNA77YCVghZRq2s1LwVF
這是比特幣應在交易中傳送到的地址。
這是一個如何在java中生成比特幣地址的簡報。我們生成一個ECDSA
金鑰對,使用SHA256
和RIPEMD160
雜湊金鑰的公共部分。最後,我們通過執行SHA256
兩次並選取前4個位元組來計算校驗和,該位元組附加到上面的RIPEMD160
雜湊。結果使用Base58
編碼進行編碼。
覺得有點複雜,也可以看這個Java離線生成比特幣地址
建議你瀏覽我們的各種程式語言的區塊鏈教程和區塊鏈技術部落格,更深入瞭解區塊鏈,比特幣,加密貨幣,以太坊,和智慧合約。
- java比特幣開發教程,本課程面向初學者,內容即涵蓋比特幣的核心概念,例如區塊鏈儲存、去中心化共識機制、金鑰與指令碼、交易與UTXO等,同時也詳細講解如何在Java程式碼中整合比特幣支援功能,例如建立地址、管理錢包、構造裸交易等,是Java工程師不可多得的比特幣開發學習課程。
- php比特幣開發教程,本課程面向初學者,內容即涵蓋比特幣的核心概念,例如區塊鏈儲存、去中心化共識機制、金鑰與指令碼、交易與UTXO等,同時也詳細講解如何在Php程式碼中整合比特幣支援功能,例如建立地址、管理錢包、構造裸交易等,是Php工程師不可多得的比特幣開發學習課程。
匯智網原創翻譯,轉載請標明出處。這裡是原文