比特币学习(一):私钥与地址

对于比特币而言,公钥对应着btc地址,私钥相当于密码,拥有私钥意味着掌握了这个地址,所以了解私钥是非常重要的。

我希望通过代码实现比特币私钥、地址的生成来学习了解这方面的知识。本文的代码很多来自开源项目bitcoinj,实现的语言为java。

一、私钥与公钥的关系

通过椭圆曲线算法,我们可以得到一个密钥对,一个为私钥,一个为公钥。私钥和公钥都是256位32个字节的byte数组。

下面通过代码来实现:

ECKey key = new ECKey();

byte[] privKeyBytes = key.getPrivKeyBytes();

byte[] pubKeyBytes = key.getPubKey();

ECKey封装了椭圆曲线算法,初始化ECKey,即可获得一个密钥对。

二、公钥转换为btc地址

由于数组不便于使用,所以公钥需要进行格式化,格式化后的结果即为btc地址。

先说下原理:

下面通过代码实现:

/**

* ripemd160(sha256(in))

* 双hash,计算比特币地址时使用

*/

public static byte[] sha256hash160(byte[] input) {

try {

byte[] sha256 = MessageDigest.getInstance("SHA-256").digest(input);

RIPEMD160Digest digest = new RIPEMD160Digest();

digest.update(sha256, 0, sha256.length);

byte[] out = new byte[20];

digest.doFinal(out, 0);

return out;

} catch (NoSuchAlgorithmException e) {

throw new RuntimeException(e); // Cannot happen.

}

}

/**

* 从公钥计算出地址

* @param pubKeyBytes

* @return

*/

public static String getBtcAddress (byte[] pubKeyBytes) {

byte[] hash160 = sha256hash160(pubKeyBytes);

byte version = 0x00;

return Base58Check.encode(version, hash160);

}

三、base58及base58check编码

base58介绍:

base58在base64的基础上,去除了几个看起来会产生歧义的字符,如 0 (零), O (大写字母O), I (大写的字母i) and l (小写的字母L) ,和几个影响双击选择的字符,如/, +。结果字符集正好58个字符(包括9个数字,24个大写字母,25个小写字母)。

base58check介绍:

Base58 导出的字符串没有校验机制,这样,在传播过程中,如果漏写了几个字符,会检测不出来。所以使用了改进版的算法 Base58Check。

实现是:在encode前,在输入流尾部加入输入内容的hash值(4个字节)。然后再对输入流进行 Base58Encode。

参考代码:

info.block123.btc.kit.Base58

info.block123.btc.kit.Base58Check

四、私钥格式化

为了方便存储和使用,私钥必须要进行格式化输出。

btc私钥格式介绍:

种类版本描述

Hex   16进制byte数组16进制byte数组

WIF    5开头Base58Check编码

WIF-compressed   K or L开头Base58Check编码前,在byte数组后加0x01字节

代码实现:

/**

* 未加工的密钥格式化

*/

@Override

public String format(byte[] keyBytes) {

if ( PRIV_KEY_HEX.equals(keyType)) {

return BtcKit.toHexString(keyBytes);

}

if ( PRIV_KEY_WIF.equals(keyType)) {

byte version = (byte)0x80;

return Base58Check.encode(version, keyBytes);

}

if ( PRIV_KEY_WIFC.equals(keyType)) {

byte[] cBytes = new byte[ keyBytes.length + 1];

System.arraycopy(keyBytes, 0, cBytes, 0, keyBytes.length);

cBytes[ cBytes.length - 1] = 0x01;

byte version = (byte)0x80;

return Base58Check.encode(version, cBytes);

}

return null;

}

@Override

public byte[] parse(String src) {

if ( PRIV_KEY_HEX.equals(keyType)) {

return BtcKit.hexStringToByte(src);

}

if ( PRIV_KEY_WIF.equals(keyType)) {

return Base58Check.decode(src);

}

if (PRIV_KEY_WIFC.equals(keyType)) {

byte[] rawBytes = Base58Check.decode(src);

byte[] result = new byte[rawBytes.length-1];

System.arraycopy(rawBytes, 0, result, 0, result.length);

return result;

}

return null;

}

五、私钥推算出比特币地址

比特币地址可以由私钥推算出来。下面为代码实现:

@Test

public void testPrivKeyToAddress() {

    String formatPrivKey = "5JG9hT3beGTJuUAmCQEmNaxAuMacCTfXuw1R3FCXig23RQHMr4K";

    KeyFormat format = new PrivKeyFormat(KeyFormat.PRIV_KEY_WIF);

   byte[] privKeyBytes = format.parse(formatPrivKey);

   byte[] pubKeyBytes = ECKey.publicKeyFromPrivate(BtcKit.byte32toBigInteger(privKeyBytes), false);

    String address = BtcKit.getBtcAddress(pubKeyBytes);

    System.out.println("计算后的地址:" + address);

Assert.assertEquals(address, "1thMirt546nngXqyPEz532S8fLwbozud8");

}

PS:如果觉得对你有帮助,欢迎打赏

btc地址:1BYgnJ1Xv561L3qFrFJasVzEGs1JC93QV1

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 在比特币中,经常出现三个词:私钥,公钥和地址。他们是什么意思呢?他们之间又有什么样的关系呢?搞清楚他们之间的关系和...
    0xSen阅读 45,565评论 3 48
  • /**ios常见的几种加密方法: 普通的加密方法是讲密码进行加密后保存到用户偏好设置( [NSUserDefaul...
    彬至睢阳阅读 3,076评论 0 7
  • 作者 Kevin 简介:“比特币技术进阶”由知名比特币技术专家Kevin原创的三篇文章《比特币交易构成》、《时间...
    西部之歌阅读 1,335评论 0 0
  • 她原本只是一个安静的女子, 细雨飘来朦胧了她的眼睛。 你却绅士的向她打了一个喷嚏, 说,遇见她,你已病的不轻。
    简村小吹阅读 259评论 2 4
  • 文/叶老巫 本文关键词:新手、长篇小说、拆解式阅读、多写、东野圭吾 1、 昨天晚上,无聊中打开某直播app,半小时...
    叶两步阅读 1,002评论 9 43