比特币学习之密码学
比特币的密码学 在比特币、以太坊等的区块链中,存在着许多密码学相关的知识,如果搞不懂的话,学习比特币将举步
比特币的密码学
在比特币、以太坊等的区块链中,存在着许多密码学相关的知识,如果搞不懂的话,学习比特币将举步维艰。 因此我们要了解以下的密码学知识:
- Hash
- ECC
Hash
哈希函数(Hash):是把任意长度的输入通过散列算法变换成固定长度的输出。 它的输入可以是字符串,可以是数据,可以是任何文件,经过哈希运算后,变成一个固定长度的输出,该输出就是哈希值。
哈希算法有一个很大的特点,就是你不能从结果推算出输入,所以又称为不可逆的算法。
在比特币中用于交易检验和数字签名等的 SHA-256 算法、 RIPEMD160 算法都是 Hash 函数。
- 用 nodejs 实现 SHA-256 算法对 message 进行哈希
// 方法一:(使用 bitcoinjs-lib 包)
const bitcoin = require('bitcoinjs-lib');
let message = 'a secret message!'
hash = bitcoin.crypto.sha256(message)
console.log(hash.toString('hex'))
// 方法二:(使用 scrypto 包)
function ripemd160(name){
var crypto = require('crypto');
var hash = crypto.createHash('ripemd160');
hash.update(name);
return hash.digest('hex')
}
let message = 'a secret message!'
console.log(sha256(message))
- 用 nodejs 实现 RIPEMD160 算法对 message 进行哈希
// 方法一:(使用 bitcoinjs-lib 包)
const bitcoin = require('bitcoinjs-lib');
let message = 'a secret message!'
hash = bitcoin.crypto.ripemd160(message)
console.log(hash.toString('hex'))
// 方法二:(使用 scrypto 包)
function ripemd160(name){
var crypto = require('crypto');
var hash = crypto.createHash('ripemd160');
hash.update(name);
return hash.digest('hex')
}
let message = 'a secret message!'
console.log(ripemd160(message))
ECC
椭圆曲线算法(ECC): 在密码学理论中,椭圆曲线算法是一种非对称密码,也称公钥密码。 公钥加密,可以说它现在是现代网络安全或者网络信任链的基础。公钥加密最大的特征就是通信双方各有一对公私钥。 这一对公私钥有着千丝万缕的数学关系:
- 私钥可以推算出公钥,公钥无法推算出私钥
- 这一对公私钥一方加密,另一方解密(公钥加密,私钥解密 或者私钥加密,公钥解密)
椭圆曲线算法的实现是非常复杂的,本文不关心如何实现,我们的重点是 ECC 可以生成一对公私钥,同时保存私钥,公开公钥。
- 用 nodejs 实现 ECC 算法的一对公私钥
const bitcoin = require('bitcoinjs-lib');
// 随机生成秘钥
const keyPair = bitcoin.ECPair.makeRandom();
// 输出公钥
console.log(keyPair.publicKey.toString('hex'))
// 输出私钥
console.log(keyPair.privateKey.toString('hex'))
在比特币中,我们使用私钥对交易进行签名,可以确保只有持有私钥的人才能花费对用地址的资金。 接下来,我们对交易签名的原理进行简单的实现,比特币的签名只是消息的结构更加复杂一些。 原理:使用私钥进行签名,公钥进行验证,进而可以对一个消息的真伪进行确认。
-
签名 对消息进行签名,实际上是对消息的哈希进行签名,因为上文提到过,哈希可以将任意长度的消息转化成固定长度的哈希值。对哈希值进行签名也保证了原始消息的真伪。
-
- 使用 ECDSA 通过私钥对消息 message 进行签名
const bitcoin = require('bitcoinjs-lib');
let message = 'a secret message!'
// 对消息进行 SHA-256 哈希
let hash = bitcoin.crypto.sha256(message)
// wif 变量是 WIF 结构的私钥
let wif = 'KwdMAjGmerYanjeui5SHS7JkmpZvVipYvB2LJGU1ZxJwYvP98617'
// 将私钥导入
let keyPair = bitcoin.ECPair.fromWIF(wif);
// 用私钥对消息的哈希签名:
let signature = keyPair.sign(hash); // ECSignature对象
// 打印签名:
console.log(signature.toString('hex'));
// 打印公钥以便验证签名:
console.log(keyPair.publicKey.toString('hex'));
// 打印的结果如下:
//5d0b6e817e01e22ba6ab19c0ab9cdbb2dbcd0612c5b8f990431dd0634f5a9653188b989017ee7e83
//0de581d4e0d46aa36bbe79537774d56cbe41993b3fd66686
//02d0de0aaeaefad02b8bdc8a01a1b8b11c696bd3d66a2c5f10780d95b7df42645c
在得到签名、原始消息和公钥的基础上,就可以对签名验证。
- 验证签名真伪
const bitcoin = require('bitcoinjs-lib');
let message = 'a secret message!'
let hash = bitcoin.crypto.sha256(message)
// 将上文得到签名的结果输入进来
let signature =Buffer.from(
'5d0b6e817e01e22ba6ab19c0ab9cdbb2dbcd0612c5b8f990431dd0634f5a9653188b989017ee7e830de581d4e0d46aa36bbe79537774d56cbe41993b3fd66686',
'hex'
);
// 将上文得到公钥的结果输入进来
let publicKey = Buffer.from(
'02d0de0aaeaefad02b8bdc8a01a1b8b11c696bd3d66a2c5f10780d95b7df42645c',
'hex'
);
pubKeyOnly = bitcoin.ECPair.fromPublicKey(publicKey);
// 通过导入公钥,以及原始消息和签名,就可以验证签名的真伪。
let result = pubKeyOnly.verify(hash, signature);
console.log('Verify result: ' + result)
// 打印结果:
// true
当然,我们可以尝试更改原始消息或者导入的签名,运行查看结果,看是否还是 true.
上述的代码非常简单,原理也易懂。在比特币中,会比这更加复杂,对消息的验证有时候会使用公钥的地址进行验证的等等。 公钥和地址的关系是什么,私钥是如何推出公钥的,我们下节再见。
声明:本文中使用的 bitcoinjs-lib 的版本是 5.1.7
参考链接
https://www.npmjs.com/package/bitcoinjs-lib https://www.liaoxuefeng.com/wiki/1207298049439968/1207687429747616 https://blog.csdn.net/u011583927/article/details/81432863