3

I’m trying to use a Hardware Security Module (HSM) to manually sign a Hedera transaction, but the Hedera JavaScript SDK requires me to pass my private key to the SDK for signing. Since my private key cannot leave the HSM and I can only use the HSM to sign transactions, I’m not sure how to proceed. Could someone please let me know how to do this? I couldn’t find any example code.

The flow I need to follow is:

  1. Create a transaction

  2. Serialize the transaction into transaction bytes

  3. Pass the transaction bytes to the HSM for signing

  4. Deserialize the signed transaction bytes back into a transaction object

  5. Submit the signed transaction to the network

I tried running the following code but got INVALID_SIGNATURE error. I have made sure that the key is the correct one.

const { Client, AccountId, PrivateKey, TransferTransaction, Hbar, Transaction, } = require("@hashgraph/sdk"); async function main() { const client = Client.forTestnet(); const operatorPrivateKeyHex = "0xXXX"; const operatorId = AccountId.fromString("0.0.XXX"); const operatorKey = PrivateKey.fromString(operatorPrivateKeyHex); client.setOperator(operatorId, operatorPrivateKeyHex); let transaction = await new TransferTransaction() .addHbarTransfer(operatorId, Hbar.fromTinybars(-100)) .addHbarTransfer(AccountId.fromString("0.0.3"), Hbar.fromTinybars(100)) .setNodeAccountIds([AccountId.fromString("0.0.5")]) .freezeWith(client); const txByte = transaction.toBytes(); const signature = operatorKey.sign(txByte); transaction = Transaction.fromBytes(txByte); transaction.addSignature(operatorKey.publicKey, signature); const txResponse = await transaction.execute(client); const receipt = await txResponse.getReceipt(client); } main();

1 Answer 1

2

Yes, you can sign a Hedera transaction using an HSM by manually handling the signing process outside the SDK. This is useful when your private key cannot leave a secure environment like an HSM.

const { Client, AccountId, TransferTransaction, Hbar, Transaction, PublicKey, } = require("@hashgraph/sdk"); const crypto = require("crypto"); async function main() { const operatorId = AccountId.fromString("0.0.1234"); const publicKey = PublicKey.fromString("302a..."); const client = Client.forTestnet(); client.setOperator(operatorId, { sign: async () => { throw new Error("External signing only"); }, publicKey, }); let tx = await new TransferTransaction() .addHbarTransfer(operatorId, Hbar.fromTinybars(-1000)) .addHbarTransfer("0.0.3", Hbar.fromTinybars(1000)) .setNodeAccountIds(["0.0.5"]) .freezeWith(client); const txBytes = tx.toBytes(); const sha384Hash = crypto.createHash("sha384").update(txBytes).digest(); const signature = yourHSM.sign(sha384Hash); const txSigned = Transaction.fromBytes(txBytes); txSigned.addSignature(publicKey, signature); const txResponse = await txSigned.execute(client); const receipt = await txResponse.getReceipt(client); console.log("Transaction status:", receipt.status.toString()); } main(); 
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.