Key Export
The Builder Vault supports export of keys. This can be done by running an MPC session, where each SDK calls the following method:
wrappedKeyShare, err := client.ECDSA().ExportKey(ctx, sessionConfig, keyID, derivationPath, wrappingKey)
This returns to each SDK a share of the key, encrypted under the provided wrapping key. The wrapping key must be the SubjectPublicKeyInfo
in an ASN.1 DER encoding.
The key export MPC session will only work if all MPC nodes are configured to allow key share export, and if the provided wrapping keys are whitelisted in the MPC nodes' configuration.
While the original key shares remain unchanged in the Builder Vault, the exported key shares are actually shares of a new, independent, re-sharing of the key. This ensures that the security of the original key sharing remains unaffected if a few of the exported key shares should leak to an attacker (as long as the attacker sees t or less shares, where t is the security threshold of the key).
If derivationPath
is provided, the exported key shares will be shares of a key derived from the original key defined by keyID
, using the provided derivation path.
The idea of exporting the key shares individually, and encrypted under wrapping keys, is to make it easier to transport the key securely to a destination, such as another Builder Vault instance or an HSM, without having to reconstruct the key in the clear while it in transit. To accomplish this, unwrapping and recombination of the secret shares should only happen in the destination. An example of this, where the destination is another Builder Vault instance, see this tutorial.
Exporting Keys with No Single Point of TrustIn the following, we show how to unwrap the shares and recombine them into the secret key. This can be useful, if you just want to recover the key in the clear. This does, however, introduce a single point of trust, which is what the Builder Vault otherwise avoids.
To achieve the highest level of security, you should consider not to introduce a single point of trust while the key is in transit, by moving the wrapped key shares to the destination (e.g., another wallet, a HSM, or another Builder Vault instance) and only unwrap and recombine the key inside this destination. An example of moving the key to another Builder Vault instance without introducing any single point of trust is given here.
To unwrap a key share, you can do the following:
keyShare, err = tsmutils.Unwrap(unwrappingKey, wrappedKeyShare.WrappedKeyShare)
Finally, if you have enough unwrapped key shares, you can recombine them into the secret key as follows:
exportedKey, err := tsmutils.ShamirRecombine(threshold, exportedKeyShares, curveName)
It is not only the key share, but also the corresponding public key and the chain code that is exported. The chain code is also encrypted with the wrapping key. You can access the public key and chain code as follows:
exportedPublicKey := wrappedKeyShare.PKIXPublicKey
exportedChainCode, err = tsmutils.Unwrap(unwrappingKey, wrappedKeyShare.WrappedChainCode)
Comparing Key Export and Emergency Recovery
The key export feature in this section has some similarity with the emergency recovery feature. Both lets you export a secret from the Builder Vault. The difference is that key export only exports one share to each SDK, whereas the RecoveryData
method which is part of the the emergency recovery procedure, outputs all key shares to one SDK, encrypted under an external RSA key, and accompanied by a zero-knowledge proof. So the regular key export feature is better suited, if you want to migrate the key sharing to another Builder Vault instance, without reducing the threshold security.
Code Example
You can find a complete example showing how a private key can be exported from a Builder Vault instance in our demo repository (Go).
Updated 19 days ago