美文网首页
【2019-07-12】比特币的钱包地址验证

【2019-07-12】比特币的钱包地址验证

作者: 6g3y | 来源:发表于2019-07-12 21:00 被阅读0次

钱包地址的生成过程

第一步,随机选取一个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);
        }
    }


}

相关文章

网友评论

      本文标题:【2019-07-12】比特币的钱包地址验证

      本文链接:https://www.haomeiwen.com/subject/lrqukctx.html