• 48501

    文章

  • 446

    评论

  • 37

    友链

  • 最近新加了换肤功能,大家多来逛逛吧~~~~
  • 喜欢这个网站的朋友可以加一下QQ群,我们一起交流技术。

比特币地址是怎样生成的

喜欢本站的朋友可以收藏本站,或者加入QQ群:172816590Web网页设计师,我们大家一起来交流技术!

欢迎来到梁钟霖个人博客网站。本个人博客网站提供最新的站长新闻,各种互联网资讯。 还提供个人博客模板,最新最全的java教程,java面试题。在此我将尽我最大所能将此个人博客网站做的最好! 谢谢大家,愿大家一起进步!

首先得到 ECDSA private key, 再得到 ECDSA public key,,然后再计算出钱包地址。ECDSA是Elliptic Curve Digital Signature Algorithm的缩写, 即椭圆曲线数字签名算法。


1、ECDSA private key:执行openssl命令, bitcoin要用到secp256k1

openssl ecparam -name secp256k1 -genkey > priv.pem

# DER格式
openssl ec -in priv.pem -outform DER | tail -c +8 | head -c 32 | xxd -p -c 32

# 输出
read EC key
writing EC key
ccea9c5a20e2b78c2e0fbdd8ae2d2b67e6b1894ccb7a55fc1de08bd53994ea64

得到秘钥文件priv.pem, 输出DER格式, 长度是 64
ccea9c5a20e2b78c2e0fbdd8ae2d2b67e6b1894ccb7a55fc1de08bd53994ea64

 

2、ECDSA public key: priv.pem 生成 pub_key

openssl ec -in priv.pem -pubout -outform DER | tail -c 65 | xxd -p -c 65

# 输出
read EC key
writing EC key
04d061e9c5891f579fd548cfd22ff29f5c642714cc7e7a9215f0071ef5a5723f691757b28e31be71f09f24673eed52348e58d53bcfd26f4d96ec6bf1489eab429d

同样输出DER格式, 长度是130
pub_key = 04d061e9c5891f579fd548cfd22ff29f5c642714cc7e7a9215f0071ef5a5723f691757b28e31be71f09f24673eed52348e58d53bcfd26f4d96ec6bf1489eab429d

3、第2步结果进行hash160运算:hash160运算就是先进行SHA256, 再进行RMD160

bytes = [pub_key].pack("H*") # 转为16进制
hash160_val = Digest::RMD160.hexdigest(Digest::SHA256.digest(bytes) )

hash160_val = 2b6f3b9e337cedbb7c40839523fb1100709c12f7

4、第3步结果加上前缀符

前缀符一般是00, 会生成普通的主网地址
bitcoin address 前缀符有好几种, 具体看https://en.bitcoin.it/wiki/List_of_address_prefixes

'00'+ '2b6f3b9e337cedbb7c40839523fb1100709c12f7'

result_04 = 002b6f3b9e337cedbb7c40839523fb1100709c12f7

bitcoin地址的前缀列表列出了几种钱包地址的类型

十进制 16进制 作用 首字母 例子
0 00 P2PKH address 1 17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYhem
5 05 P2SH address 3 3EktnHQD7RiAE6uzMj2ZifT9YgRrkSgzQX
111 6F Testnet pub key m or n mipcBbFg9gMiCh81Kj8tqqdgoZub1ZJRfn

5、第4步结果, 执行2次SHA256, 取前8位作为校验和

hex_str = [result_04].pack("H*")
checksum = Digest::SHA256.hexdigest(Digest::SHA256.digest(hex_str) )[0...8]

checksum = 86b2e90c

6、第4步结果 跟 第5步结果合并

'002b6f3b9e337cedbb7c40839523fb1100709c12f7' + '86b2e90c'
# result_04 + checksum

result_06 = 002b6f3b9e337cedbb7c40839523fb1100709c12f786b2e90c

7、第6步结果进行base58编码

Base58是一种独特的编码方式, 是Base64的变形, 主要用于Bitcoin的钱包地址.
相比Base64, Base58去掉了数字0, 大写字母O, 大写字母I, 小写字母l+/, 避免引起视觉混淆。

result_06 = "002b6f3b9e337cedbb7c40839523fb1100709c12f786b2e90c"
leading_zero_bytes = (step_06.match(/^([0]+)/) ? $1 : '').size / 2
# leading_zero_bytes的作用是字母填充, 待研究下

address = ("1" * leading_zero_bytes) + encode_base58(step_06.to_i(16) )

得到 14xfJr1DArtYR156XBs28FoYk6sQqirT2s, 这就是了一个标准的bitcoin地址。

在bitcoin系统中,私钥能得公钥, 公钥能得到钱包地址,
私钥=>公钥=>钱包地址, 而反向是不可能的。

 

How to create Bitcoin Address

 

Java Base58算法


public class Base58 {
    public static final char[] ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".toCharArray();
    private static final char ENCODED_ZERO;
    private static final int[] INDEXES;

    public Base58() {
    }

    public static String encode(byte[] input) {
        if (input.length == 0) {
            return "";
        } else {
            int zeros;
            for(zeros = 0; zeros < input.length && input[zeros] == 0; ++zeros) {
                ;
            }

            input = Arrays.copyOf(input, input.length);
            char[] encoded = new char[input.length * 2];
            int outputStart = encoded.length;
            int inputStart = zeros;

            while(inputStart < input.length) {
                --outputStart;
                encoded[outputStart] = ALPHABET[divmod(input, inputStart, 256, 58)];
                if (input[inputStart] == 0) {
                    ++inputStart;
                }
            }

            while(outputStart < encoded.length && encoded[outputStart] == ENCODED_ZERO) {
                ++outputStart;
            }

            while(true) {
                --zeros;
                if (zeros < 0) {
                    return new String(encoded, outputStart, encoded.length - outputStart);
                }

                --outputStart;
                encoded[outputStart] = ENCODED_ZERO;
            }
        }
    }

    public static byte[] decode(String input) throws AddressFormatException {
        if (input.length() == 0) {
            return new byte[0];
        } else {
            byte[] input58 = new byte[input.length()];

            int zeros;
            int outputStart;
            for(zeros = 0; zeros < input.length(); ++zeros) {
                char c = input.charAt(zeros);
                outputStart = c < 128 ? INDEXES[c] : -1;
                if (outputStart < 0) {
                    throw new AddressFormatException("Illegal character " + c + " at position " + zeros);
                }

                input58[zeros] = (byte)outputStart;
            }

            for(zeros = 0; zeros < input58.length && input58[zeros] == 0; ++zeros) {
                ;
            }

            byte[] decoded = new byte[input.length()];
            outputStart = decoded.length;
            int inputStart = zeros;

            while(inputStart < input58.length) {
                --outputStart;
                decoded[outputStart] = divmod(input58, inputStart, 58, 256);
                if (input58[inputStart] == 0) {
                    ++inputStart;
                }
            }

            while(outputStart < decoded.length && decoded[outputStart] == 0) {
                ++outputStart;
            }

            return Arrays.copyOfRange(decoded, outputStart - zeros, decoded.length);
        }
    }

    public static BigInteger decodeToBigInteger(String input) throws AddressFormatException {
        return new BigInteger(1, decode(input));
    }

    public static byte[] decodeChecked(String input) throws AddressFormatException {
        byte[] decoded = decode(input);
        if (decoded.length < 4) {
            throw new AddressFormatException("Input too short");
        } else {
            byte[] data = Arrays.copyOfRange(decoded, 0, decoded.length - 4);
            byte[] checksum = Arrays.copyOfRange(decoded, decoded.length - 4, decoded.length);
            byte[] actualChecksum = Arrays.copyOfRange(Sha256Hash.hashTwice(data), 0, 4);
            if (!Arrays.equals(checksum, actualChecksum)) {
                throw new AddressFormatException("Checksum does not validate");
            } else {
                return data;
            }
        }
    }

    private static byte divmod(byte[] number, int firstDigit, int base, int divisor) {
        int remainder = 0;

        for(int i = firstDigit; i < number.length; ++i) {
            int digit = number[i] & 255;
            int temp = remainder * base + digit;
            number[i] = (byte)(temp / divisor);
            remainder = temp % divisor;
        }

        return (byte)remainder;
    }

    static {
        ENCODED_ZERO = ALPHABET[0];
        INDEXES = new int[128];
        Arrays.fill(INDEXES, -1);

        for(int i = 0; i < ALPHABET.length; INDEXES[ALPHABET[i]] = i++) {
            ;
        }

    }
}

 


 转载至链接:https://my.oschina.net/u/574036/blog/1933019



转载原创文章请注明出处,转载至: 梁钟霖个人博客www.liangzl.com

您觉喜欢本网站,或者觉得本文章对您有帮助,那么可以选择打赏。
打赏多少,您高兴就行,谢谢您对梁钟霖这小子的支持! ~(@^_^@)~

  • 微信扫一扫

  • 支付宝扫一扫

    支付宝打赏

0条评论

Loading...


发表评论

电子邮件地址不会被公开。 必填项已用*标注

自定义皮肤
注册梁钟霖个人博客