【问题标题】:Using HSM as an external signer with NBitcoin使用 HSM 作为 NBitcoin 的外部签名者
【发布时间】:2022-08-14 15:22:06
【问题描述】:

我已经使用 HSM 作为私钥存储实现了签名交易, 但我遇到了一些错误!

        var network = Network.TestNet;

        var destination = BitcoinAddress.Create(receiverAddress, network);
        var sender = BitcoinAddress.Create(senderAddress, network);

        var unspentCoins = (await GetUnSpentCoins(senderAddress, network));
        var builder = network.CreateTransactionBuilder();
        var tx = builder
            .AddCoins(unspentCoins)
            .Send(destination, Money.Coins(0.00001M))
            .SubtractFees()
            .SendEstimatedFees(new FeeRate(1m))
            .SetChange(sender.ScriptPubKey)
            .BuildTransaction(false);

        var wallet = HSMWallet.Load(walletName);
        var signedTx = wallet.SignTransaction(tx.ToHex());

        var pubKey = new NBitcoin.PubKey(wallet.PubKey.RawPubKey);
        var signature = new TransactionSignature(Encoders.Hex.DecodeData(signedTx));
        builder
            .AddKnownSignature(pubKey, signature, unspentCoins[0].Outpoint)
            .SetSigningOptions(SigHash.All);

        builder.SignTransactionInPlace(tx);

        var error = builder.Check(tx);

        var verify = builder.Verify(tx);
        if (verify)
        {
            var result = await BroadcastTransaction(tx.ToHex(), Settings.BlockcypherToken, network);
            return result;

        }

在检查方法(builder.Check(tx)) 我得到两个错误:

  1. {输入 0 (SigHashType) 上的脚本错误}
  2. {费用太低,实际为 0.00000226,保单最低为 0.00000258}

我使用 PKCS11Introp.Net 并连接到 Utimaco HSM 以生成密钥对和签名操作:

public string SignTransaction(string hex)

    {
        var mechanism = Session.Factories.MechanismFactory.Create(CKM.CKM_ECDSA);

        var dataHash = Digest(Digest(Convert.FromHexString(hex), CKM.CKM_SHA256), CKM.CKM_SHA256);

        var signature = Session.Sign(mechanism, PrivateKeyHandle, dataHash);

        Session.Verify(mechanism, PublicKeyHandle, dataHash, signature, out bool isValid);

        if (isValid == false)
            throw new Exception(\"error in signing transaction!\");

        return ConvertUtils.BytesToHexString(ConstructEcdsaSigValue(signature));

    }

我怎样才能使这项工作? 非常感谢

    标签: c# bitcoin sign pkcs#11 hsm


    【解决方案1】:

    终于解决了,感谢 NBitcoin。 分享我的解决方案:

    public async Task<string> MakePayment(string walletName, string receiverAddress, decimal amount)
            {
                var network = Settings.Network == BitcoinNetwork.TestNet ? Network.TestNet : Network.Main;
                var hsmWallet = HSMWallet.Load(walletName, Session);
                var pubKey = new NBitcoin.PubKey(hsmWallet.PubKey.RawPubKey);
    
                var destination = BitcoinAddress.Create(receiverAddress, network);
                var sender = pubKey.GetAddress(ScriptPubKeyType.Legacy, network).ToString();
    
                var unspentCoins = GetUnSpentCoins(sender, network) ?? throw new Exception("no more mony to spend!");
    
                var builder = network.CreateTransactionBuilder();
                var unsignedTx = builder
                    .AddCoins(unspentCoins)
                    .Send(destination.ScriptPubKey, Money.Coins(amount))
                    .SendEstimatedFees(new FeeRate(2m))
                    .SetChange(pubKey)
                    .BuildTransaction(sign: false);
    
                var rebuild = network.CreateTransactionBuilder();
                rebuild.AddCoins(unspentCoins);
    
                foreach (var coin in unspentCoins)
                {
                    var indexedIn = unsignedTx.Inputs.FindIndexedInput(coin.Outpoint);
                    if (indexedIn == null) continue;
                    var signHash = indexedIn.GetSignatureHash(coin, SigHash.All);
                    var sign = hsmWallet.SignTransaction(signHash.ToBytes());
    
                    var signature = new TransactionSignature(sign, SigHash.All).MakeCanonical();
    
                    rebuild.AddKnownSignature(pubKey, signature, coin.Outpoint);
                }
    
                var signedTx = rebuild.SignTransaction(unsignedTx);
    
                var error = rebuild.Check(signedTx);
    
                var verify = rebuild.Verify(signedTx);
                if (verify)
                {
                    var result = await BroadcastTransaction(signedTx.ToHex(), Settings.BlockcypherToken, network);
                    return signedTx.GetHash().ToString();
    
                }
    
                return string.Concat(error.Select(e => e.ToString()), ",");
            }
    

    签到方法:

    public byte[] SignTransaction(byte[] signHash)
            {
                var mechanism = Session.Factories.MechanismFactory.Create(CKM.CKM_ECDSA);
    
                var signature = Session.Sign(mechanism, PrivateKeyHandle, signHash);
    
                Session.Verify(mechanism, PublicKeyHandle, signHash, signature, out bool isValid);
    
                if (isValid == false)
                    throw new Exception("error in signing transaction!");
    
                return ConstructEcdsaSigValue(signature);
    
            }
    

    【讨论】:

      猜你喜欢
      • 2017-10-27
      • 1970-01-01
      • 2020-11-25
      • 2015-03-08
      • 2019-04-22
      • 2020-03-04
      • 2022-06-10
      • 2020-03-06
      • 2021-01-06
      相关资源
      最近更新 更多