让我们通过学习比特币(Bitcoin)如何实施该技术的各个方面来工作,好吗?该技术包括以下几个方面:
警告的提示——这里的代码仅用于学习。如果你试图将比特币发送到由该代码生成的地址,你可能会损失金钱。
比特币地址是一个随机查找的十六进制字符串,在比特币网络中用于发送和接收比特币。它是公私不对称 ECDSA
密钥的公共部分。相应的私钥用于签署比特币交易,作为交易时来自你的确认和证明。
从技术上讲,比特币地址是从 ECDSA
密钥的公共部分生成的,使用 SHA-256
和 RIPEMD-160
进行hash,如下文所述,处理得到的结果hash,最后使用 Base58
校验编码对密钥进行编码。
让我们看看如何使用 JCE(java加密扩展) , Bouncy Castle(RIPEMD-160) 以及最后在 bitcoinj 库中使用Base58编码功能来完成所有这些工作。
我们之前已经介绍过生成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();
你可以只存储密钥的私有部分,因为公钥可以从私钥派生。
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密钥由椭圆曲线上的点表示。该点的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
。
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哈希。
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];
我们现在使用 bitcoinj
库中的 Base58.encode()
方法来获得最终的比特币地址。
System.out.println(" adr: " + Base58.encode(a1)); # prints adr: 1K3pg1JFPtW7NvKNA77YCVghZRq2s1LwVF
这是比特币应在交易中发送到的地址。
这是一个如何在java中生成比特币地址的演示文稿。我们生成一个 ECDSA
密钥对,使用 SHA256
和 RIPEMD160
哈希密钥的公共部分。最后,我们通过执行 SHA256
两次并选取前4个字节来计算校验和,该字节附加到上面的 RIPEMD160
哈希。结果使用 Base58
编码进行编码。
觉得有点复杂,也可以看这个 Java离线生成比特币地址
建议你浏览我们汇智网的各种编程语言的区块链教程和区块链技术博客,更深入了解区块链,比特币,加密货币,以太坊,和智能合约。
汇智网原创翻译,转载请标明出处。这里是 原文