Key Lifecycle Management
Builder Vault provides a number of methods to manage the life of a key.
Listing and Deleting Keys
You can get a list of the IDs of all keys for which a given MPC node holds shares:
ctx := context.Background()
keyIDs, err := client.KeyManagement().ListKeys(ctx)
Given a specific key ID, you can delete the corresponding key share on the MPC node like this:
err := client.KeyManagement().DeleteKeyShare(ctx, keyID)
Note that ListKeys
and DeleteKeyShare
operate on a single MPC node. So, the fact that a single MPC node returns a key ID does not necessarily mean that the key “exists” in the TSM. Likewise, deleting the key share may not delete the key itself from the TSM. Generally, a key “exists” in the TSM if a sufficient number of MPC nodes (usually t+1, where t is the security threshold of the key) hold shares of the key to generate MPC signatures using the key.
You can also count and delete the presignatures for a given key:
presigCount, err := client.KeyManagement().CountPresignatures(ctx, keyID)
err := client.KeyManagement().DeletePresignatures(ctx, keyID)
Key Resharing
Suppose you have a key with ID keyID
in the TSM. The secret sharing of the key can then be refreshed by running an MPC key resharing session.
First, choose the MPC session metadata, the session ID, and the set of nodes to participate. All nodes holding key shares of the key must participate in the resharing.
sessionID := tsm.GenerateSessionID()
players := []int{ 0, 1, 2 } // This assumes the key was generated among Node 0, 1, 2
sessionConfig := tsm.NewSessionConfig(sessionID, players, nil)
Then run the MPC session by calling this method on all SDKs:
ctx := context.Background()
err := client.ECDSA().Reshare(ctx, sessionConfig, keyID)
If the MPC session succeeds, the secret sharing of the key in the TSM will be replaced by a fresh random secret sharing (of the same key).
Note the following about resharing:
- Running a reshare operation deletes all existing presignatures for the given key.
- Care must to be taken if reshare is used together with our key import/export feature to create a key share backup. If one MPC node creates a backup of its own key share, and then the nodes run a reshare session, then the backup will be useless. A new backup of the updated share then needs to be created (pointed out in the online doc here).
- We’ve designed reshare such that the old key sharing is deleted only after the updated sharing is successfully created. But in rare cases (node crash or network malfunction) you may see that some nodes succeed while other nodes abort when running a reshare session. In such a case the system may end up in an “inconsistent” state between two epochs, and normal operations like signing may not work (they will give an “epoch inconsistency” error). We have designed reshare so that if this happens, it can always be fixed by running another reshare session on the key. So good practice would be to check that all node SDKs returned successfully from the session, and if not, then run another reshare operation.
- Only one reshare session can run at a time for a given key.
- During a reshare session we do allow other sessions, such as signing sessions for a key. If a reshare and a sign operation run concurrently, the signing may fail with the error message “inconsistent epochs”. To avoid this, you need to create a “lock” at the application level, such that no-one signs until the reshare session is complete.
Self-contained code examples showing how to reshare a key can be found in our demo repository (Go, Java, node.js). After resharing, the key will be the same, but it will be shared with a fresh, randomized secret sharing.
Key Copy
You can create a copy of a key that already exists in the Builder Vault. This is done as follows:
newKeyID, err = client.ECDSA().CopyKey(ctx, sessionConfig, keyID, curveName, newThreshold, desiredKeyID)
This call instructs the MPC node to participate in an MPC session that creates a copy of a key. The copy will represent the same key as the original key but with a new random and independent secret sharing. The copy will be saved under a new key ID, and the existing key will not be affected.
The MPC session may include MPC nodes that do not hold shares of the original key. For these MPC nodes, the key ID must be empty and curveName
must be the curve name for the original key, e.g., secp256k1
, or ED-25519
. MPC nodes that hold shares of the original key must provide keyID
and use an empty curveName
. The desiredKeyID
is optional, and if provided, it will be used as the key ID for the new copy.
The MPC session only succeeds if all MPC nodes agree on keyID
, newThreshold
, and desiredKeyID
. In addition, it will only succeed if threshold + 1 or more MPC nodes, who all hold key shares of the original key, participate in the session.
Use cases:
- If the number of MPC nodes in the key copy session is the same as the original number of MPC nodes that generated or imported the key, and the new threshold is also the same, this will just compute a fresh secret sharing of the same key. This will exist along with the old key, but with a different key ID. If the old key is then deleted, it works as a two-step resharing of the old key, which also changes the key ID.
- The new threshold can be different than the original threshold. This can be used to upgrade or downgrade the threshold security of the key. Note that this is not a security concern, since at least threshold + 1 MPC nodes are needed to complete the key copy. This number of MPC nodes would be able to sign anyway, and they could in principle also just recombine their key shares to gain full control of the key.
- The number of MPC nodes in the key copy session can be greater than or less than the number of MPC nodes that originally generated or imported the key. Given a (3,1) sharing, two of the original MPC nodes can run a key copy MPC session that creates a (2,1) copy of the key. It is also possible for five MPC nodes, two of which each hold a share of a (2,1) key, to run an MPC session that creates a new (5,2) copy of the key. Again, this is not a security concern since the MPC session requires acknowledgment of threshold+1 of the original key shareholders.
- If you want to copy a (3,2) key to a (2,1) key, you must make two calls to KeyCopy. The first copy must be a (3,1) key, and all three nodes must participate (recall that t+1=3 nodes must participate). Once the threshold is lowered, two of the nodes can then create a (2,1) copy from the (3,1) key. Once the (2,1) key is successfully created, you may want to clean up by deleting the (3,2) and (3,1) keys.
You can find a code example of how to use key copy in our demo repository (Go). In the example, we first generate a (2,1) key is among two MPC nodes. It is then copied to a (3,2) sharing among these two MPC nodes and a third node.
Updated 19 days ago