钱包地址的生成过程
第一步,随机选取一个32字节的数,大小介于1~0xFFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFE BAAE DCE6 AF48 A03B BFD2 5E8C D036 4141之间,作为私钥
18e14a7b6a307f426a94f8114701e7c8e774e7f9a47e2c2035db29a206321725
第二步,使用椭圆曲线加密算法(ECDSA-SECP256k1)计算私钥所对应的非压缩公钥(共65字节,1字节0x04,32字节为x坐标,32字节为y坐标)。
0450863AD64A87AE8A2FE83C1AF1A8403CB53F53E486D8511DAD8A04887E5B23522CD470243453A299FA9E77237716103ABC11A1DF38855ED6F2EE187E9C582BA6
第三步,计算公钥的SHA-256哈希值
600FFE422B4E00731A59557A5CCA46CC183944191006324A447BDB2D98D4B408
第四步,计算上一步哈希值的RIPEMD-160哈希值
010966776006953D5567439E5E39F86A0D273BEE
第五步,在上一步结果之间加入地址版本号(如比特币主网版本号"0x00")
00010966776006953D5567439E5E39F86A0D273BEE
第六步,计算上一步结果的SHA-256哈希值
445C7A8007A93D8733188288BB320A8FE2DEBD2AE1B47F0F50BC10BAE845C094
第七步,再次计算上一步结果的SHA-256哈希值
D61967F63C7DD183914A4AE452C9F6AD5D462CE3D277798075B107615C1A8A30
第八步,取上一步结果的前4个字节(8位十六进制数)D61967F6,把这4个字节加在第五步结果的后面,作为校验(这就是比特币地址的16进制形态)
00010966776006953D5567439E5E39F86A0D273BEED61967F6
第九步,用base58表示法变换一下地址(这就是最常见的比特币地址形态)
16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM
验证地址
如果给你个地址你只要:
base58->二进制-> 这时是第8步,
如果我们把后面4个字节拿掉,
就是第5步的结果,你只要重复以上步骤到第8步
取前4个和地址后4位比较就可以得到答案了
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
/**
* 代码来自:https://blog.csdn.net/qq_26917447/article/details/81299136
* 参考博文:https://blog.csdn.net/wypeng2010/article/details/81325743
*/
public class CoinValidationUtil {
private final static String ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
public static void main(String[] args) {
System.out.println(bitCoinAddressValidate("16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM"));//true
System.out.println();
System.out.println(bitCoinAddressValidate("1MkX4opviJKBBrqr1coykedYKp2DBJPC7z"));//true
System.out.println();
System.out.println(bitCoinAddressValidate("1Mkx4opviJKBBrqr1coykedYKp2DBJPC7z"));//false
}
/**
* btc(bch,usdt)地址是否有效
*
* return: true有效,false无效
*/
public static boolean bitCoinAddressValidate(String addr) {
System.out.println(addr);
if (addr.length() < 26 || addr.length() > 35)
return false;
byte[] decoded = decodeBase58To25Bytes(addr);
if (decoded == null)
return false;
byte[] hash1 = sha256(Arrays.copyOfRange(decoded, 0, 21));
byte[] hash2 = sha256(hash1);
// for (byte b : Arrays.copyOfRange(decoded, 0, 21)) { System.out.print(b); }System.out.println();
// for (byte b : hash1) { System.out.print(b); }System.out.println();
// for (byte b : Arrays.copyOfRange(hash2, 0, 4)) { System.out.print(b); }System.out.println();
// for (byte b : Arrays.copyOfRange(decoded, 21, 25)) { System.out.print(b); }System.out.println();
//先把地址base58解码成字节数组,然后把数组分成两个字节数组,一个是后4字节数组(字节数组1),一个是减去后4字节的数组(字节数组2),然后把字节数组2两次Sha256Hash,然后取其前4位,跟字节数组1比较,是相同的,就校验通过。
//博文地址生成的逆过程
/**
* 第五步,取上一步结果,前面加入地址版本号(比特币主网版本号“0x00”)
* 00010966776006953D5567439E5E39F86A0D273BEE
*
* 第六步,取上一步结果,计算 SHA-256 哈希值
* 445C7A8007A93D8733188288BB320A8FE2DEBD2AE1B47F0F50BC10BAE845C094
*
* 第七步,取上一步结果,再计算一下 SHA-256 哈希值(哈哈)
* D61967F63C7DD183914A4AE452C9F6AD5D462CE3D277798075B107615C1A8A30
*
* 第八步,取上一步结果的前4个字节(8位十六进制)
* D61967F6
*
* 第九步,把这4个字节加在第五步的结果后面,作为校验(这就是比特币地址的16进制形态)。
* 00010966776006953D5567439E5E39F86A0D273BEED61967F6
*
* 所以,地址是第5步的东西+验证,我们只要重复该步骤就可以验证比特币地址是否正确!!,即判断是不是相同的字符串
*
*/
return Arrays.equals(Arrays.copyOfRange(hash2, 0, 4), Arrays.copyOfRange(decoded, 21, 25));
}
/**
* 把地址 58位变成 25位的byte数组
*
* 这个步骤相当于把 base58换成2进制数组,58进制-》2进制,简单粗暴。//前面不足补前面,超过长度就报错。
*
* @param input
* @return
*/
private static byte[] decodeBase58To25Bytes(String input) {
BigInteger num = BigInteger.ZERO;
for (char t : input.toCharArray()) {
int p = ALPHABET.indexOf(t);
if (p == -1)
return null;
num = num.multiply(BigInteger.valueOf(58)).add(BigInteger.valueOf(p));
}//58进制转换 10进制
// System.out.println(num);
byte[] result = new byte[25];
byte[] numBytes = num.toByteArray();//toByteArray()将大整数转换成二进制反码保存在byte数组中
System.arraycopy(numBytes, 0, result, result.length - numBytes.length, numBytes.length);
return result;
}
/**
* sha256
* @param data
* @return
*/
private static byte[] sha256(byte[] data) {
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(data);
return md.digest();
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException(e);
}
}
}
网友评论