簡體   English   中英

使用 HSM 作為 NBitcoin 的外部簽名者

[英]Using HSM as an external signer with NBitcoin

我已經使用 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));

    }

我怎樣才能使這項工作? 非常感謝

終於解決了,感謝 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);

        }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM