65.9K
CodeProject 正在变化。 阅读更多。
Home

HBitcoin:高级 C# 比特币钱包库 - 保护您的硬币安全

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.80/5 (17投票s)

2016年4月28日

MIT

5分钟阅读

viewsIcon

61343

HBitcoin 是一个专注于隐私的比特币库,建立在 NBitcoin 之上,支持 .NET Core

背景

几年前,我曾尝试编写一个钱包库,那是我的第一个、学习比特币的项目,叫做 HiddenBitcoin。虽然我没能发布稳定版本,但多年来我复用并打磨了其中很多代码。 HBitcoin 可以看作是它的继承者,但《HiddenBitcoin》的动机是为了学习,而《HBitcoin》的动机则源于一个实际需求。我一直在不同的《Bitcoin》项目中复用我的代码。以至于我将在这里介绍的主要类,曾经有过 6 个不同的版本。因此,是时候一次性把事情做对,并将它们打包成一个《Bitcoin》库,我可以通过一个简单的 NuGet 包随时使用。

引言

《HBitcoin》库建立在 NBitcoin 之上。可以将《HBitcoin》理解为介于《NBitcoin》和《Blockchain.info》API 之间。它比后者提供了更多的灵活性,但不如前者。想真正深入了解《Bitcoin》,您需要查阅 《C# 比特币编程》

到这个三部分教程的结尾,您将能够构建一个《Bitcoin》钱包。

引用

虽然对 API 进行编程可以帮助快速启动应用程序,但开发人员受到针对 API 进行创新的限制。

Nicolas Dorier,《Bitcoin》核心开发者,也是 C# 《Bitcoin》库 《NBitcoin》的创建者。
在使用我的库时,请牢记这句话。

比特币钱包做什么?

一个《Bitcoin》钱包有三个主要功能

  1. 安全地存储密钥并管理对它们的访问
  2. 监控与这些密钥相关的交易
  3. 构建交易并将其广播到网络

如何存储密钥?

比特币地址、私钥

您可能熟悉《Bitcoin》地址,可以将比特币发送到这些地址,并知道通过相应的私钥,您可以花费您的资金。

找零地址

您可能也熟悉《Bitcoin》钱包,并且知道它们会为不同的交易生成不同的找零地址。您可能会问,为什么它们不只使用一个《Bitcoin》地址?出于隐私原因。《Bitcoin》区块链是一个公开账本,任何人都可以轻松看到进出某个地址的资金。因此,避免地址重复使用是更好的做法,尽管这并不能完全解决隐私问题,但肯定会改善它。

HD 钱包

现在我们遇到了一个新问题,如何管理这么多密钥?存储、监控和花费它们?
请注意,引入多个密钥极大地增加了我们钱包的复杂性。

幸运的是,HD 钱包结构使我们只需要存储一个密钥就可以派生出其他密钥。为了与《NBitcoin》的术语保持一致,我们称之为 `BitcoinExtKey`。

关于密钥管理的比特币改进提案

这里有四个 BIPs 与我们相关:BIP32、BIP38、BIP43、BIP44。为简单起见,我希望您将 BIP32 和 BIP38 视为相同的 BIPs。它们定义了底层的东西,例如如何派生和加密密钥。这些由《NBitcoin》实现。BIP43 和 BIP44 基于 BIP32-38,定义了密钥应如何组织和使用的更多结构。BIP43-44 已被一些钱包实现。我曾尝试自己实现它们,但很快就放弃了,因为它们不仅会极大地增加我对象使用的复杂性,而且我无法将一些我计划在未来处理的边缘情况纳入其中。这样,我就可以提供一个更简单的接口。

光说不练,给我过一遍代码!

项目设置

  1. 创建一个新的 .NET Core 项目
  2. 添加 《HBitcoin》NuGet 包
// First specify the network youll be working on
var network = Network.Main;
// Next choose a super strong password, like "password"
var password = "password";

// Create a safe at the specified path with a password on the specified network
// The Safe class helps you mange your seed properly
// The Safe will handle the serialization automatically
// By creating a Safe, it also saves itself to the specified path
Mnemonic mnemonic;
Safe safe = Safe.Create(out mnemonic, password, @"Wallets\Wallet.json", network);

// Safe creation has created a mnemonic, too, you can use it to recover (or duplicate) the safe
// You will only encounter this mnemonic at creation time
Console.WriteLine(mnemonic);

// Rrecover the safe into another file
Safe recoveredSafe = Safe.Recover(mnemonic, password, @"Wallets\SameWallet.json", network);

// Decrypt/load an existing safe/walletfile
Safe loadedSafe = Safe.Load(password, @"Wallets\hiddenWallet.hid");

// After we load a safe it is not a bad idea to check if it is on our expected network
if (network != loadedSafe.Network)
	throw new Exception("Wrong network");

// List out the first 10 addresses
for (var i = 0; i < 10; i++)
{
	Console.WriteLine(safe.GetAddress(i));
}

如何破解钱包?

您只需要获取(password mnemonicpassword 钱包文件)。

然后,您就可以直接调用 `Recover` 或 `Load`。

谁知道 `password`?用户。
谁知道 `mnemonic`?理想情况下,它应该写在用户的纸上作为备份。
谁知道钱包文件?理想情况下,它存储在用户的硬盘上。

其他钱包

通常,仅凭助记词恢复另一个钱包就足够了。我不认为这是一个好方法,因此这个钱包不这样工作。

CreationTime

var safe2 = Safe.Recover(mnemonic, password, "Wallet.json", network,
	creationTime: DateTimeOffset.ParseExact("2017-02-20", 
	"yyyy-MM-dd", CultureInfo.InvariantCulture));
Console.WriteLine(safe.CreationTime);

当您创建一个钱包时,它会自动保存其创建时间,这在编写 SPV 钱包时非常有用。因此,在恢复钱包时,您也可以传入创建时间,如果您不传入,它将默认为最早的可能创建时间,这是硬编码的。

public static DateTimeOffset EarliestPossibleCreationTime
	=> DateTimeOffset.ParseExact("2017-02-19", 
	"yyyy-MM-dd", CultureInfo.InvariantCulture);

这是我首次引入创建时间概念的日期。如果您尝试使用更早的创建时间恢复它,它将使用 `EarliestPossibleCreationTime`。

SafeAccounts 和 HdPathType

var alice = new SafeAccount(id: 2);
safe.GetAddress(index: 1, hdPathType: HdPathType.Receive, account: alice);
safe.GetPrivateKey(index: 1, hdPathType: HdPathType.Receive, account: alice);

如果您愿意,可以创建账户。在上面的代码中,我创建了 ID 为 2 的 Alice 的账户,并获取了她的一些密钥。

您还可以注意到我将 `HdPathType` 指定为 `receive`。这是默认的 `HdPathType`,如果您不指定任何内容。请注意,一些术语使用“external”和“internal”来表示接收地址和找零地址。这在您接收和花费钱包资金时会变得很重要。始终将资金接收到 `HdPathType.Receive`,当您花费这些资金时,始终将找零款项接收到 `HdPathType.Change`。这为您的钱包增加了更多隐私。另一种选择是,当您花费一个接收地址时,将找零款项退还到同一个地址。我绝对不建议这样做。

结束

除非您真的知道自己在做什么,否则我不建议您自己实现密钥存储方案。如果由于某种原因,我的 Safe 对您来说不够灵活,请在 GitHub 上提交一个 issue,我会看看我能做些什么。

如果您喜欢这个教程并希望看到更多,请给我打赏:1LYLuYMXkCXDxSfsNoDp8FCb2mA36r29u7。

许可协议

如果您不喜欢我的教程,那么通过阅读这一行,您同意进行一次瑟曦·兰尼斯特式的公开游行。
此外,在您死后,我将有权取走您的灵魂。

更新

  • 2017.02.21
    • 调整 《HiddenBitcoin》教程到其继任者:《HBitcoin》
© . All rights reserved.