比特币地址类似于银行的收款账户,用来接收来自他人的转账。
地址对应的密钥对,决定了该地址上的比特币的所有权。掌握了密钥,就掌握了地址上的比特币资产。
比特币钱包里有一系列的密钥对。每个密钥对包括公钥和私钥。私钥是一个数字,通常是随机选出来的。有了私钥,可以通过单向加密啊函数生成一个公钥。注意这里是单向,即是可以通过私钥生成公钥,但很难通过公钥逆向计算出私钥。
利用私钥生成公钥之后,再经过一系列的计算、转换、编码,生成密钥对所对应的比特币地址。这里面,私钥是最为关键的,私钥泄露,则会被他人很容易就偷走自己的比特币资产,因此要保护好自己的私钥。
本文将通过代码,演示在比特币系统中是如何生成密钥对及比特币地址。
首先第一步是利用操作系统底层的随机数生成器产生一个256位二进制的随机数,然后使用椭圆形加密算法从私钥计算出公钥。上面说过,私钥计算出公钥,这是一个不可逆的计算过程。
(1)生成密钥对的过程是:
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp256k1");
keyGen.initialize(ecSpec);
KeyPair kp = keyGen.generateKeyPair();
(2)私钥的随机生成:
PrivateKey pvt = kp.getPrivate();
ECPrivateKey epvt = (ECPrivateKey)pvt;
String sepvt = adjustTo64(epvt.getS().toString(16)).toUpperCase();
System.out.println("s[" + sepvt.length() + "]: " + sepvt);
(3)计算出公钥:
PublicKey pub=kp.getPublic();
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);
return bcPub;
(4)计算公钥的哈希值(SHA-256算法):
MessageDigest sha = MessageDigest.getInstance("SHA-256");
byte[] s1 = sha.digest(bcPub.getBytes("UTF-8"));
System.out.println(" sha: " + bytesToHex(s1).toUpperCase());
(5)对上一步的哈希值,通过RIPEMD-160算法再次取哈希值:
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
MessageDigest rmd = MessageDigest.getInstance("RipeMD160", "BC");
byte[] r1 = rmd.digest(s1);
(6)对上一步的结果,加入地址版本号(比特币主网的版本号是“0x00”):
byte[] r2 = new byte[r1.length + 1];
r2[0] = 0;
for (int i = 0 ; i
(7)对上一步结果连续两次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());
(8) 取第7步的结果的前4个字节,作为校验码加在第5步结果的后面:
byte[] a1 = new byte[25];
for (int i = 0 ; i
(9)最后,用Base58变换一下上一步的结果,得到最常见形态的比特币地址:
String address =Base58.encode(a1);
System.out.println(" adr: " + address);