Skip to main content
All articles

From a Key Inside an HSM to a Signed Blockchain Transaction

· 12 min read
Bankware Global Engineering

A server needs to sign a transaction with a private key to send a customer's tokens. If that key stays inside an HSM and the server does not read its value, who builds the transaction, and how does the server obtain the signature?

An HSM, or Hardware Security Module, is a device that protects cryptographic keys and performs cryptographic operations. In a blockchain integration, it signs with a key held inside the device and returns the result. The server still has to construct the transaction, convert the signature into the chain's required format, and check the submission result.

Connecting customer accounts to blockchain signatures examined how customer identifiers, wallets, and key selection fit together. This article follows BXB's HSM integration from selecting a key to producing the actual transaction.

1. Sending 10 tokens starts with a transaction digest​

Suppose A holds 100 units of token T on an EVM network, while B holds none. T has zero decimal places and no separate token transfer fee. A also has enough native coin to pay the network gas fee. The goal is to send 10 units of T from A to B. This example uses neither gas sponsorship nor MPC joint signing.

A's wallet is associated with a key already prepared in the HSM. We will call the label used to find that key K-A. This is an illustrative name, not an actual key name or a production transaction. Assume the requester is authorized to make the transfer and passes the wallet and address checks.

The essential parts of the transaction BXB constructs are as follows. Assume A's next transaction nonce is 42.

Sender: A
Transaction destination: token T's contract
Call: transfer(B, 10)
Transaction nonce: 42

B receives the tokens, but the outer transaction calls T's contract address. The transaction also includes the network identifier, gas limit, and fee conditions. BXB serializes this unsigned transaction and computes a 32-byte Keccak-256 digest from those bytes. It requests a signature by passing this digest and a reference to the selected key to the HSM integration.

The transaction format specification defines what is hashed for the EIP-1559 transaction in this example. The signature covers bytes that include the transaction's execution conditions, not just the recipient and quantity in isolation. Changing the transaction therefore requires computing the signing digest again.

The token balances are still A 100 / B 0. Obtaining a signature and having the chain execute the transaction are separate events.

2. A key label and a key handle are different from a private key value​

In the software signing path, the server's signing code uses the private key value. The HSM path instead uses a label that locates the key. That label is a name identifying which key inside the device to use, rather than an encrypted representation of the private key.

One way for a Java program to communicate with this device is PKCS#11. It is an interface for requesting operations such as key generation, lookup, and signing from a device or module that holds cryptographic keys. The word token in PKCS#11 refers to the component holding those keys; it does not mean a blockchain token such as T.

BXB's EVM path accesses the HSM through a Java cryptography provider, an implementation that performs cryptographic operations. In a configuration using SunPKCS11, the provider connects Java calls to the device's PKCS#11 calls. Oracle's PKCS#11 guide explains this bridge and its relationship to the algorithms the device must provide.

The application looks up the key associated with K-A in an authenticated session. The key handle it obtains is a reference through which it can request operations using that key inside the device. Even when Java exposes it as a PrivateKey, this HSM signing path does not use it to extract the private key's numeric value and perform the calculation itself. It passes the reference to the selected provider to request a signature.

ItemRole in this example
Customer and wallet identifiersConnect the business request to A's wallet
Key label K-ASelect the key to use in the HSM
Key handleRequest an operation with that key in a session
Public key and address AIdentify the signer

Knowing the label does not, by itself, let someone use the key inside the device. Device access, authentication, and the key's usage conditions must also be satisfied. Conversely, obtaining the correct key handle does not establish that the recipient and quantity in this transfer have business authorization.

3. Why the signing API must not hash the digest again​

Some signing APIs accept a message and hash it internally. Others accept an already computed digest and sign it. Treating these as interchangeable can produce a signature over the wrong input.

BXB's EVM signing input is the 32-byte digest computed earlier. Its HSM signing path uses NONEwithECDSA. Here, NONE does not mean that no cryptographic operation takes place. It means this API stage does not hash the message again. SunPKCS11 maps this operation to the CKM_ECDSA mechanism.

For example, passing a Keccak-256 digest to a signing API that also applies SHA-256 would produce an ECDSA signature over an input different from the original transaction digest. Matching the key and the name of the signature algorithm is therefore insufficient. BXB's common EVM signing interface also checks that the input is exactly 32 bytes before calling the signing implementation.

The responsibilities in this path are divided as follows.

The HSM signs the digest in this path. The component constructing the transaction determines the business meaning of “10 tokens to B.” The content being hashed must therefore have passed input validation and business authorization.

4. An HSM signature is not yet an Ethereum transaction​

The core of an ECDSA signature is a pair of integers, r and s. The remaining work involves more than appending the bytes returned by the signing interface to a transaction.

First, the byte representation must be decoded. The PKCS#11 ECDSA signature format and the Java signature API's representation are distinct. The standard PKCS#11 format concatenates the bytes of r and s, whereas the BXB Java path examined here parses a DER-encoded result from the provider. DER encodes structured values, including the type and length of integers. This conversion matches the return format of the API in use; it does not mean that an HSM always returns DER.

Next comes low-s normalization. ECDSA can have s values on opposite sides of the range that express the same signing relationship, so Ethereum transactions restrict the permitted range of s. EIP-2 requires rejecting transaction signatures whose s value exceeds half the curve order. BXB adjusts the returned signature to this range.

Finally, it determines the information needed to recover the signer. What is recovered here is the public key, not the private key. The digest, r and s, and candidate recovery values yield public keys that can be compared with the public key associated with K-A. BXB finds a matching recovery value, then recovers the public key from the signature again to check the match. If it cannot find a matching value, it does not return the signature as a successful result.

The internal library passes this information as v, r, and s, but the final fields encoded into an EIP-1559 transaction are yParity, r, and s as required by that transaction format. The signing library's representation and the actual transaction fields must also be distinguished.

This check establishes whether the signature matches the selected HSM key. Selecting the right customer wallet and validating the quantity and recipient remain the responsibility of the earlier stages. BXB then constructs the signed transaction bytes and submits them to an RPC node. The transaction hash computed at this point also uses different input bytes from the digest sent for signing earlier.

5. The same HSM can receive different signing inputs for each chain​

The EVM explanation cannot be applied unchanged to other chains. The BXB implementation examined here has separate HSM paths for EVM, Cardano, and Solana. Both the signature algorithm and the input supplied to it vary.

PathAlgorithmInput supplied for signing
EVMsecp256k1 ECDSAKeccak-256 digest of the transaction
CardanoEd25519Blake2b-256 digest of the transaction body
SolanaEd25519Serialized transaction message

This table compares transaction signing paths. Cardano and Solana both use Ed25519, but that does not mean the Solana message should first be hashed as it is in the Cardano path. “Do not hash it first” here does not mean Ed25519 performs no hashing internally. It describes which bytes the caller supplies as the signing input.

BXB's Cardano and Solana paths use a separate integration that calls PKCS#11's CKM_EDDSA directly. Replacing the Java signature provider for EVM does not automatically align every chain's input and output formats. The HSM configuration also includes branches that reject unsupported key operations for XRPL and BIP122.

Assessing HSM support therefore requires checking the key type, operation mechanism, input bytes, and return format, as well as the device connection. This article describes the integration scope found in BXB's code. It does not report compatibility testing across every combination of HSM product and chain.

6. Where connection failures and signing retries belong​

What happens if HSM use is configured but the device cannot be opened? At startup, BXB's HSM manager checks whether it can open the provider and key store. A failure is treated as an initialization error. With HSM use configured, a connection failure does not silently switch this path to a software key.

This startup check does not establish that every key exists or that signing works for every chain. The separate sessions used by Cardano and Solana include paths initialized on actual use. Device connectivity, the selected key, and the required signing operation are separate conditions to check.

Even after a successful startup, a session can disconnect or a key lookup or signing call can fail. When a public key read or signing operation throws an exception, the EVM implementation examined here prepares the signing session again and retries that operation once. If the retry also fails, it returns an error. This handling does not precisely diagnose every cause of failure or provide unlimited recovery.

What it repeats is a public key read or a signature calculation. The transaction has not yet reached the chain submission stage, so this retry alone does not send the tokens twice. However, signing the same digest again should not be assumed to produce identical signature bytes every time. The signature result and whether a transaction was actually submitted must be tracked separately.

A lost response after the transaction has already been sent over RPC is a different problem. As described in the article on timeouts and retransmission, the first step in that case is to check whether the existing transaction was processed. Reconnecting an HSM session neither cancels an already submitted transaction nor establishes that it failed.

7. Generating a new key and importing an existing key have different histories​

How a key is prepared also matters. BXB has a path for generating a new key through the HSM provider and another for importing an existing private key into the device. Because this article's signing example starts after the key is prepared, either path can lead to the same label and signing interface.

Their histories differ, however. A key generated in the device and a key generated elsewhere and imported cannot both be described as having “never existed outside the device since creation.” For an imported key, the external original, any copies, and the import process are also part of what must be managed.

Whether a key can be exported is not determined simply by the fact that an HSM is used, either. The PKCS#11 specification distinguishes attributes concerning key sensitivity and extractability. The actual guarantees depend on how the key was created, its attributes, and device policy. A signing path that does not read the private key value and a guarantee that no external copy has existed during the key's entire lifetime are different claims.

8. Receiving a signature and completing a transfer​

Return to A and B from the opening example. BXB requests a signature over a 32-byte digest using K-A, converts the result into Ethereum's format, and checks it against the public key. The goal of A 90 / B 10 is reached when the signed transaction has been submitted and successful execution and the token movement have been confirmed. The network gas fee is paid separately from A's native coin balance; it is not deducted from the 10 tokens.

If this request ultimately fails during HSM signing and cannot be submitted, the balances remain A 100 / B 0, assuming no other transactions, and no on-chain transaction fee arises from this request. That case must be kept separate from an already submitted transaction whose outcome is still unknown.

The HSM protects keys and performs permitted cryptographic operations with them. The business system determines the correct transaction content before signing, then checks the signature format and execution result afterward. These responsibilities must fit together for a key inside the device to produce the blockchain transaction the customer intended.