在数字货币的世界中,密码学扮演着至关重要的角色。它不仅能证明秘密知识而不泄露秘密(如数字签名),还能验证数据的真实性(如数字指纹)。这些加密证明是比特币等区块链系统的数学基石,用于确保资金所有权的安全性与不可篡改性。本文将深入探讨如何利用密码学工具实现密钥、地址与钱包的核心功能,并基于 LaravelZero 框架提供具体实现方案。
密码学在区块链中的核心作用
比特币系统并不存储任何个人账户信息,而是通过数字密钥、比特币地址和数字签名来确认所有权。这些元素共同构成了一套去中心化的信任机制,无需依赖中央权威或网络验证即可实现资金控制与交易认证。
公钥加密体系简介
公钥加密算法使用成对的密钥:私钥及其衍生的唯一公钥。私钥是一个随机选出的数字,必须严格保密并妥善备份,因为它用于生成支付比特币所需的数字签名,一旦丢失即无法恢复对应资金。公钥则通过椭圆曲线乘法从私钥计算得出,这一过程不可逆,无法从公钥反推私钥。
比特币地址是由公钥经过哈希运算、添加版本前缀并经 Base58Check 编码后生成的字符串,例如以“1”开头的地址“1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa”。用户可安全地将地址分享给他人以接收资金。
数字签名的工作机制
数字签名算法保障了三大核心特性:
- 数据在传输过程中不被篡改;
- 数据由特定发送方创建;
- 发送方无法否认发送行为。
生成签名需使用私钥和被签名的数据,而验证签名则需公钥、签名和数据本身。在比特币交易中,每个输入都需由发送方签名,网络节点在验证交易时会检查签名正确性及公钥哈希匹配性,确保交易合法性。
钱包与地址的具体实现
钱包的核心功能是生成并管理密钥对。以下代码展示了基于 PHP 的密钥对生成与地址计算实现:
class Wallet
{
public $privateKey;
public $publicKey;
public function __construct()
{
list($privateKey, $publicKey) = $this->newKeyPair();
$this->privateKey = $privateKey;
$this->publicKey = $publicKey;
}
public function getAddress(): string
{
$addrCreator = new AddressCreator();
$factory = new P2pkhScriptDataFactory();
$scriptPubKey = $factory->convertKey((new PublicKeyFactory())->fromHex($this->publicKey))->getScriptPubKey();
$address = $addrCreator->fromOutputScript($scriptPubKey);
return $address->getAddress(Bitcoin::getNetwork());
}
private function newKeyPair(): array
{
$privateKeyFactory = new PrivateKeyFactory();
$privateKey = $privateKeyFactory->generateCompressed(new Random());
$publicKey = $privateKey->getPublicKey();
return [$privateKey->getHex(), $publicKey->getHex()];
}
}Wallets 类负责管理多个钱包实例,提供持久化存储与检索功能:
class Wallets
{
public $wallets;
public function __construct()
{
$this->loadFromFile();
}
public function createWallet(): string
{
$wallet = new Wallet();
$address = $wallet->getAddress();
$this->wallets[$address] = $wallet;
return $address;
}
public function saveToFile()
{
$walletsSer = serialize($this->wallets);
file_put_contents(storage_path() . '/walletFile', $walletsSer);
}
public function getWallet(string $from)
{
if (isset($this->wallets[$from])) {
return $this->wallets[$from];
}
exit("钱包不存在该地址");
}
}交易输入输出的密码学升级
为简化实现,我们移除了脚本语言相关字段,将 scriptSig 拆分为 signature 和 pubKey,并将 scriptPubKey 重命名为 pubKeyHash。关键修改如下:
class TXInput
{
public $txId;
public $vOut;
public $signature;
public $pubKey;
public function usesKey(string $pubKeyHash): bool
{
$pubKeyIns = (new PublicKeyFactory())->fromHex($this->pubKey);
return $pubKeyIns->getPubKeyHash()->getHex() == $pubKeyHash;
}
}
class TXOutput
{
public $value;
public $pubKeyHash;
public static function NewTxOutput(int $value, string $address)
{
$txOut = new TXOutput($value, '');
$pubKeyHash = $txOut->lock($address);
$txOut->pubKeyHash = $pubKeyHash;
return $txOut;
}
private function lock(string $address): string
{
$addCreator = new AddressCreator();
$addInstance = $addCreator->fromString($address);
$pubKeyHash = $addInstance->getScriptPubKey()->getHex();
return substr($pubKeyHash, 6, mb_strlen($pubKeyHash) - 10);
}
}usesKey 方法验证输入是否使用指定密钥解锁输出,而 lock 方法通过地址解码提取公钥哈希以实现输出锁定。
交易签名与验证机制
交易签名过程需构建修剪后的交易副本,避免循环依赖:
class Transaction
{
public function sign(string $privateKey, array $prevTXs)
{
if ($this->isCoinbase()) return;
$txCopy = $this->trimmedCopy();
foreach ($txCopy->txInputs as $inId => $txInput) {
$prevTx = $prevTXs[$txInput->txId];
$txCopy->txInputs[$inId]->signature = '';
$txCopy->txInputs[$inId]->pubKey = $prevTx->txOutputs[$txInput->vOut]->pubKeyHash;
$txCopy->setId();
$txCopy->txInputs[$inId]->pubKey = '';
$signature = (new PrivateKeyFactory())->fromHexCompressed($privateKey)->sign(new Buffer($txCopy->id))->getHex();
$this->txInputs[$inId]->signature = $signature;
}
}
public function verify(array $prevTXs): bool
{
$txCopy = $this->trimmedCopy();
foreach ($this->txInputs as $inId => $txInput) {
$prevTx = $prevTXs[$txInput->txId];
$txCopy->txInputs[$inId]->signature = '';
$txCopy->txInputs[$inId]->pubKey = $prevTx->txOutputs[$txInput->vOut]->pubKeyHash;
$txCopy->setId();
$txCopy->txInputs[$inId]->pubKey = '';
$signatureInstance = SignatureFactory::fromHex($txInput->signature);
$pubKeyInstance = (new PublicKeyFactory())->fromHex($txInput->pubKey);
if (!$pubKeyInstance->verify(new Buffer($txCopy->id), $signatureInstance)) {
return false;
}
}
return true;
}
}区块链层面对交易验证的集成:
class BlockChain
{
public function mineBlock(array $transactions)
{
foreach ($transactions as $tx) {
if (!$this->verifyTransaction($tx)) {
exit("交易验证失败");
}
}
// 挖矿逻辑
}
public function signTransaction(Transaction $tx, string $privateKey)
{
$prevTXs = [];
foreach ($tx->txInputs as $txInput) {
$prevTx = $this->findTransaction($txInput->txId);
$prevTXs[$prevTx->id] = $prevTx;
}
$tx->sign($privateKey, $prevTXs);
}
}命令行工具与功能测试
新增钱包创建与地址列表命令:
class CreateWallet extends Command
{
protected $signature = 'createwallet';
protected $description = '创建一个钱包';
public function handle()
{
$wallets = new Wallets();
$address = $wallets->createWallet();
$wallets->saveToFile();
$this->info("Your new address: {$address}");
}
}
class ListAddresses extends Command
{
protected $signature = 'listaddresses';
protected $description = '钱包所有地址';
public function handle()
{
$wallets = new Wallets();
$addresses = $wallets->getAddresses();
foreach ($addresses as $address) {
$this->info($address);
}
}
}通过以下测试流程验证功能完整性:
- 创建钱包并初始化区块链
- 生成第二个钱包地址
- 发起转账交易
- 查询余额及地址列表
测试结果证实了密钥管理、交易签名与验证机制的正确性。👉 查看实时区块链工具
常见问题
私钥丢失后能否恢复?
私钥一旦丢失即无法恢复,其控制的资金将永久锁定。务必通过多重备份保障私钥安全,例如使用硬件钱包或纸质存储。
地址生成过程中为何需要哈希运算?
哈希运算将公钥转换为固定长度字符串,增强隐私性与安全性。同时缩短地址长度便于日常使用,并通过校验和减少输入错误风险。
交易签名为何需要构建副本?
修剪交易副本移除可变字段(如签名本身),确保每次签名数据一致。防止第三方在验证过程中篡改交易内容,保障签名有效性。
为何要验证交易输入的所有权?
验证确保输入引用的未花费输出确实由当前签名者拥有。防止双重支付与未经授权的资金转移,维护网络共识与资产安全。
非对称加密在区块链中还有哪些应用?
除交易签名的核心作用外,非对称加密还用于节点身份验证、加密通信通道及智能合约访问控制等场景,构建全方位安全体系。
总结
本文详细阐述了区块链中钱包、地址与密钥的密码学原理与实践方法,通过代码实例演示了密钥对生成、地址计算、交易签名与验证的关键流程。这套机制不仅保障了数字货币所有权控制的可靠性与安全性,也为去中心化应用奠定了信任基础。下一步将继续优化交易结构,使其更贴近真实区块链系统的实现标准。