比特币中用到了密码学中的2个功能:哈希与签名.
哈希
哈希函数主要有3个特性:
- 抗碰撞性(collision resistance).假设输入为x1,哈希值为H(x1),很难找到一个x2,使得H(x2)=H(x1).
- 隐蔽性(Hiding).哈希函数的计算过程是单向的,不可逆的.例如给定一个输入X,可以计算出哈希值H(x),但是不能从H(x)逆向推出X.
- (谜题友好)puzzle friendly。该性质要求哈希值计算事先不可预测,仅仅根据输入很难预测出输出。例如:我们需要一个哈希值,存在于某一个范围内,只能通过不停运算查找出来。该性质保证了比特币系统中,只能通过“挖矿”获得比特币.该性质保证了工作量证明(POW)机制可以运行下去.即”挖矿难,但验证容易”.
比特币中用的哈希函数是SHA-256.区块哈希值是通过通过对区块头(而非整个区块)进行双重SHA-256计算得出的: Block Hash = SHA256(SHA256(Version + Prev Hash + Merkle Root + Timestamp + Difficulty + Nonce)) 矿工不断调整Nonce,直到哈希值满足难度要求(如前导18个0)。
签名

数字签名类似于现实中的手写签名,用于证明“我同意这笔交易”,但它是基于非对称加密算法(主要是 ECDSA,椭圆曲线数字签名算法)来实现的。
数字签名涉及两把密钥:
- 私钥(Private Key):只有用户自己知道,用来“签名”。
- 公钥(Public Key):可以公开,用来“验证签名”。
在现实社会(第三方中心化系统)中,用户申请账号依赖第三方.在去中心化系统里面,申请账号是用户自己处理,即在本地创建一个公钥-私钥对.公私钥的应用确保了”签名”的安全性.在发布交易时,通过自己的私钥签名,其他人通过公钥进行验证,从而确保该交易是由自己发起.
生产公私钥需要一个好的随机源,否则会出现重复的公私钥。
用代码模拟一下签名过程:
const crypto = require('crypto');
// 1. 生成椭圆曲线密钥对(secp256k1 是比特币所用曲线)
const { publicKey, privateKey } = crypto.generateKeyPairSync('ec', {
namedCurve: 'secp256k1', // 和比特币使用的一样
publicKeyEncoding: { type: 'spki', format: 'pem' },
privateKeyEncoding: { type: 'pkcs8', format: 'pem' }
});
const transaction = {
from: 'Alice',
to: 'Bob',
amount: 1.0,
timestamp: Date.now()
};
// 2. 将交易数据转换为字符串并进行哈希处理
const transactionString = JSON.stringify(transaction);
const hash = crypto.createHash('sha256').update(transactionString).digest('hex');
console.log('交易数据哈希:', hash);
// 示例:
// const sign = crypto.createSign('SHA256'); // 创建签名对象
// sign.update('要签名的数据'); // 添加数据
// sign.end(); // 结束输入
// const signature = sign.sign(privateKey); // 使用私钥生成签名
// 3. 使用私钥对哈希值进行签名
const sign = crypto.createSign('SHA256');
sign.update(transactionString);
sign.end();
const signature = sign.sign(privateKey, 'hex');
console.log('\n🔏 签名结果:\n', signature);
// 4. 使用公钥验证签名
const verify = crypto.createVerify('SHA256');
verify.update(transactionString);
verify.end();
const isValid = verify.verify(publicKey, signature, 'hex');
console.log('\n✅ 验证签名是否有效:', isValid);