Create
Create MPC Keys
Overview
For self-custody MPC wallets, you can create a key share by exchanging a public share and an encrypted-private share of a key between all parties (user, backup, and BitGo). Unlike multisignature wallets, the backup can't be managed by a key recovery service (KRS) - you must manage it yourself. For example:
- User exchanges shares with the backup and BitGo.
- Backup exchanges shares with the user and BitGo.
- BitGo exchanges shares with the user and backup.
Key-share creation completes once each party exchanges its shares with a different party member and each member verifies they can derive the same common key.
Note
If you want to store your own keys for your self-custody wallets, follow the steps in Set Up External-Signing Mode.
ECDSA or EdDSA
Cookbooks
Need just the steps? Expand a cookbook below to get started:
Create MPC Keys (ECDSA)Open Cookbook Create MPC Keys (EdDSA)Open CookbookThe elliptic curve of the asset determines which algorithm BitGo uses to generate the keys. Select the elliptic curve for the asset you want to create keys for:
Prerequisites
Create Keys
import * as dotenv from "dotenv";
dotenv.config();
import { EnvironmentName } from "bitgo";
import { BitGoAPI } from "@bitgo/sdk-api";
import { Hteth } from "@bitgo/sdk-coin-eth";
const config = {
USERNAME: process.env.USERNAME as string,
PASSWORD: process.env.PASSWORD as string,
ENV: process.env.ENV as EnvironmentName,
OTP: process.env.OTP as string,
ENTERPRISE_ID: process.env.ENTERPRISE_ID as string,
};
const bitgo = new BitGoAPI({ env: config.ENV });
bitgo.register("hteth", Hteth.createInstance);
const coin = bitgo.coin("hteth");
async function auth() {
await bitgo.authenticate({
username: config.USERNAME,
password: config.PASSWORD,
otp: config.OTP,
});
}
async function main() {
await auth();
const keychains = await coin.keychains().createMpc({
multisigType: "tss",
passphrase: config.PASSWORD,
enterprise: config.ENTERPRISE_ID,
});
console.log(keychains);
/**
* Note: the userKeychain and backupKeychain fields have a very large encryptedPrv
* Note: the reducedEncryptedPrv field is the same as what exists on KeyCards generated in the web UI
* Or if the result of this is passed into the @bitgo/key-card package
*/
}
main().catch((err) => console.error(err));
Step Result
Note
This is critical key information. Save it in a secure place. This is the only time you're given the full encryptedPrv that you use to decrypt the user key.
{
"userKeychain": {
"id": "6674a960bb9d6a5d41228bfcf8d15724",
"source": "user",
"type": "tss",
"commonKeychain": "032ba30f224e85a300fdc94eb28b37c83d0435e706389db33e0b977ad15b94edbc63b15dee6045330287bc9ccd33522a6e50c90a5f7e845e6dbc6299556e3619c6",
"encryptedPrv": "string",
"reducedEncryptedPrv": "string"
},
"backupKeychain": {
"id": "6674a96064bda5f82a6f95efc7ad656e",
"source": "backup",
"type": "tss",
"commonKeychain": "032ba30f224e85a300fdc94eb28b37c83d0435e706389db33e0b977ad15b94edbc63b15dee6045330287bc9ccd33522a6e50c90a5f7e845e6dbc6299556e3619c6",
"encryptedPrv": "string",
"reducedEncryptedPrv": "string"
},
"bitgoKeychain": {
"id": "6674a95f38be1dec30ce8f2ae40489c4",
"source": "bitgo",
"type": "tss",
"commonKeychain": "032ba30f224e85a300fdc94eb28b37c83d0435e706389db33e0b977ad15b94edbc63b15dee6045330287bc9ccd33522a6e50c90a5f7e845e6dbc6299556e3619c6",
"isBitGo": true
}
}
Prerequisites
1. Set Up SDK
Set up the SDK to generate key shares.
const bitgo = new BitGo({
accessToken:
"my access token",
env: "test",
});
const enterprise = "my enterprise id";
const passphrase = "my very secure wallet passphrase";
const originalPasscodeEncryptionCode = "1234";
const coin = "tsol";
const m = 2;
const n = 3;
// Allow generating secp256k1 key pairs
openpgp.config.rejectCurves = new Set();
async function main() {
// setup
const uploadKeyUrl = bitgo.microservicesUrl(`/api/v2/${coin}/key`);
const MPC = await Eddsa.initialize();
const randomHexString = crypto.randomBytes(12).toString("hex");
const userGpgKey = await openpgp.generateKey({
userIDs: [
{
name: randomHexString,
email: `user-${randomHexString}@${randomHexString}.com`,
},
],
curve: "secp256k1",
});
const bitgoPublicKeyStr = (await bitgo.fetchConstants()).mpc
.bitgoPublicKey as string;
const bitgoKey = await openpgp.readKey({ armoredKey: bitgoPublicKeyStr });
console.log("\n\nbitgo public key");
console.log(bitgoPublicKeyStr);
// ....
}
2. Create User Key Shares
Generate the user key shares.
async function main() {
// ... setup
// create user key share
const userKeyShare = MPC.keyShare(1, m, n);
console.log("\n\ncreated user key share");
console.log(JSON.stringify(userKeyShare, undefined, 2));
// ...
}
Step Result
Returns the user key shares.
{
"uShare": {
"i": 1,
"t": 2,
"n": 3,
"y": "9a9c57f85a74eae15a57401b6467a3198743d56768d1273bf1d6cf5db147bea9",
"seed": "0350cb2e4d7409745d84b79ca5fa7f5ca6a18a743ad61ea1e5b405828e66882f",
"chaincode": "03c10c0e45befd366720ea8ac8fb0f4c313f99ef9b08a1e18e474d05a8e8c522"
},
"yShares": {
"2": {
"i": 2,
"j": 1,
"y": "9a9c57f85a74eae15a57401b6467a3198743d56768d1273bf1d6cf5db147bea9",
"u": "1b9932507b5d4b522dfd37f6341f58afe85dacb8e5208df18a59e6420e269b03",
"chaincode": "03c10c0e45befd366720ea8ac8fb0f4c313f99ef9b08a1e18e474d05a8e8c522"
},
"3": {
"i": 3,
"j": 1,
"y": "9a9c57f85a74eae15a57401b6467a3198743d56768d1273bf1d6cf5db147bea9",
"u": "da1db2fb700e1d17511176da6d3c42089c5da339bc4a1018a1547f5972afc201",
"chaincode": "03c10c0e45befd366720ea8ac8fb0f4c313f99ef9b08a1e18e474d05a8e8c522"
}
}
}
3. Create Backup Key Shares
Generate the backup key shares.
async function main() {
// ... setup, user keyshare
// create backup key share
const backupKeyShare = MPC.keyShare(2, m, n);
console.log("\n\ncreated backup key share");
console.log(JSON.stringify(backupKeyShare, undefined, 2));
// ...
}
Step Result
Returns backup key shares.
{
"uShare": {
"i": 2,
"t": 2,
"n": 3,
"y": "c882eaf251d330d9871de9abc12723067951febb0f6c3c2aa4413460d1ecec82",
"seed": "90251953dd94f6d79136b5b85691e909592f8f01711607b80054e2b3c3399db6",
"chaincode": "280b166e7e9b8ebff854721906f438d3f54bd7f68838be4059008687c9a2948b"
},
"yShares": {
"1": {
"i": 1,
"j": 2,
"y": "c882eaf251d330d9871de9abc12723067951febb0f6c3c2aa4413460d1ecec82",
"u": "1f06d6d087a5b9e9d9dd681daf4d54a2c26ead32c4c5af1a6ed3087a394e330f",
"chaincode": "280b166e7e9b8ebff854721906f438d3f54bd7f68838be4059008687c9a2948b"
},
"3": {
"i": 3,
"j": 2,
"y": "c882eaf251d330d9871de9abc12723067951febb0f6c3c2aa4413460d1ecec82",
"u": "461c7ab528d4fe0048a351733fae0fd728ada5fd2d87a0dbc2f42f494f9cb801",
"chaincode": "280b166e7e9b8ebff854721906f438d3f54bd7f68838be4059008687c9a2948b"
}
}
}
4. Create BitGo Keychain
Generate the BitGo key shares.
export COIN="<ASSET_ID>"
export ACCESS_TOKEN="<YOUR_ACCESS_TOKEN>"
export ENTERPRISE="<ENTERPRISE_ID>"
curl -X POST \
https://app.bitgo-test.com/api/v2/$COIN/key \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d '{
"keyType":"tss",
"source": "bitgo",
"enterprise": "'"$ENTERPRISE"'",
"keyShares": [
{
"from": "user",
"to": "bitgo",
"publicShare": "07e06410e065c8cf38bf885de903a005f50c4ca37fdfde2f553d98ac59ddb5eb46ac8fcc05ad3bce5446772559aacf62c0ac92bea6097a88183542fa3a3bb531",
"privateShare": "-----BEGIN PGP MESSAGE-----\n\nwX4DUQ8XhGVGcTISAgME/TUtCKkLyqAxkCNeob7iF9jo4na651HpQaysMJ4o\npowC428eO4jTlifFcPcrkbgsHSJSdlFxkzhOq5WD3xXWWjD7MEu1kRgquA0v\nKKpS1c8YIwNmE21B/pVuHBM8GaX5+QcHgVpQYV3xBG8q1tti3O3SsQEn8cp5\nLYsUZMARDCxwRWp5nsIMxq+YAr0a2J00qTiSIL5AMzUAERix/DCErHMEjq1u\nyUnqi/O7M8gNTKItUQ0b5A660Z4Hp4u+95Ij/HCtbQC9eOuQRZ64N0OgT0bH\nvRtgwa0NRV4senyeBneTDJIXbvA5x779O5JCJCa/1/UJTBv8FPeDXQ0UNyX9\nLhykR7fp9dOGCqcAFYvNf7j2bTLhi3o+4IM5nkyWhgjd+xIp5w==\n=Jq0c\n-----END PGP MESSAGE-----\n",
"privateShareProof": "-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nxk8EYv2JxxMFK4EEAAoCAwQTxTec5csKSgVmwr+BQelQy0LJCeMjzYZZHzYe\nsGjPLWh43Y5TU/ZefmT+Rfr1Ew0QgiI7gqYG51HXVDoO60TIzVUyZTQ4YTAy\nNTdlODZjOGMzNjdjNzMwMmQgPHVzZXItMmU0OGEwMjU3ZTg2YzhjMzY3Yzcz\nMDJkQDJlNDhhMDI1N2U4NmM4YzM2N2M3MzAyZC5jb20+wowEEBMIAB0FAmL9\niccECwkHCAMVCAoEFgACAQIZAQIbAwIeAQAhCRBBJBbTRtjtgBYhBJM0QF28\nEWsoCBL1N0EkFtNG2O2ACW0BAIWngWQibooh+8LoNkaEhh8LxRC3lIC1F6/W\nb5/cfosfAP0cEc3ZUK4GHziD8dOBAqqCfpigkuuzK3uGIPYkE1vZzM5TBGL9\niccSBSuBBAAKAgMEeJYP7IL9+75lMli/easFEeTo95uYD9WnkJFju9O8BUay\ng1zo5sm/1JzXmA/Mep/eVhlBDBGjmY/EMaxbVXNIMwMBCAfCeAQYEwgACQUC\nYv2JxwIbDAAhCRBBJBbTRtjtgBYhBJM0QF28EWsoCBL1N0EkFtNG2O2AaucB\nAJRUS3jlMcmO232C/TFkYqLijp9MWvweL6p3FkzlgYRcAPwLCQ77r8rwUeeq\nRbCR+hJVrFYONjilWDEUNu+pBmGteM4zBGL9iccWCSsGAQQB2kcPAQEHQGTj\n63Ot8Kb2dDPCwjPtPAtyycPbWHP+v1LG8KEWfW21wngEGBMIAAkFAmL9iccC\nGyAAIQkQQSQW00bY7YAWIQSTNEBdvBFrKAgS9TdBJBbTRtjtgI2TAQCo/iym\nsC9/GhSykea51lTlGonxXEun52po59lMMyoH8gEAsSi1bLgrNs+DHg1L0ZZ/\nvy+c3IR2tJHatiuW+mEa784=\n=mGjv\n-----END PGP PUBLIC KEY BLOCK-----\n"
},
{
"from": "backup",
"to": "bitgo",
"publicShare": "2f10b3bac365ae75a171cfff6c189a510639a7da9e930d3bf6d012a17bbde213dea25d7438e3c3549a86fb2a89e6f22d548d0505af5ddc00717867f74c358bd3",
"privateShare":"-----BEGIN PGP MESSAGE-----\n\nwX4DUQ8XhGVGcTISAgME36VD2F5UM76Wj78niOU2YgAbbsshT/UZAWcBjOSL\nLDfB0s1Btv3TN96nzNBlFjjVExN7/gVbzEjpoJgYh/j1KzCoiazk7aLRzQiq\n9vndZT4eqDj7ndzeNrG6AExpYnrcPj5LHpmUmSvUD8qNgOTU9JzSsQEvFap+\nib4D1U0trFwZnAzB5l04uFls92UZm2SYSaCnPvc2gi/bGyit45xatOtSBrGn\nRg5+lUbZan/Re1aD1DtmX6tEpThOIQR2nqfKQB3RX8Iyk4a7nAeDZCsuMoN9\niCsB6HKnUm0QBsVa7+0iGtWq0NczTmE33DR9k52fAnE0m6kjUhC6GhEY6X3y\nz0wq95GfHLlZCdOd0jzU7PkdqHzPWCa1tx91DJbdum8oo3TetQ==\n=Zl6I\n-----END PGP MESSAGE-----\n",
"privateShare": "-----BEGIN PGP MESSAGE-----\n\nwX4DUQ8XhGVGcTISAgME36VD2F5UM76Wj78niOU2YgAbbsshT/UZAWcBjOSL\nLDfB0s1Btv3TN96nzNBlFjjVExN7/gVbzEjpoJgYh/j1KzCoiazk7aLRzQiq\n9vndZT4eqDj7ndzeNrG6AExpYnrcPj5LHpmUmSvUD8qNgOTU9JzSsQEvFap+\nib4D1U0trFwZnAzB5l04uFls92UZm2SYSaCnPvc2gi/bGyit45xatOtSBrGn\nRg5+lUbZan/Re1aD1DtmX6tEpThOIQR2nqfKQB3RX8Iyk4a7nAeDZCsuMoN9\niCsB6HKnUm0QBsVa7+0iGtWq0NczTmE33DR9k52fAnE0m6kjUhC6GhEY6X3y\nz0wq95GfHLlZCdOd0jzU7PkdqHzPWCa1tx91DJbdum8oo3TetQ==\n=Zl6I\n-----END PGP MESSAGE-----\n",
"privateShareProof": "-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nxk8EYv2JxxMFK4EEAAoCAwQTxTec5csKSgVmwr+BQelQy0LJCeMjzYZZHzYe\nsGjPLWh43Y5TU/ZefmT+Rfr1Ew0QgiI7gqYG51HXVDoO60TIzVUyZTQ4YTAy\nNTdlODZjOGMzNjdjNzMwMmQgPHVzZXItMmU0OGEwMjU3ZTg2YzhjMzY3Yzcz\nMDJkQDJlNDhhMDI1N2U4NmM4YzM2N2M3MzAyZC5jb20+wowEEBMIAB0FAmL9\niccECwkHCAMVCAoEFgACAQIZAQIbAwIeAQAhCRBBJBbTRtjtgBYhBJM0QF28\nEWsoCBL1N0EkFtNG2O2ACW0BAIWngWQibooh+8LoNkaEhh8LxRC3lIC1F6/W\nb5/cfosfAP0cEc3ZUK4GHziD8dOBAqqCfpigkuuzK3uGIPYkE1vZzM5TBGL9\niccSBSuBBAAKAgMEeJYP7IL9+75lMli/easFEeTo95uYD9WnkJFju9O8BUay\ng1zo5sm/1JzXmA/Mep/eVhlBDBGjmY/EMaxbVXNIMwMBCAfCeAQYEwgACQUC\nYv2JxwIbDAAhCRBBJBbTRtjtgBYhBJM0QF28EWsoCBL1N0EkFtNG2O2AaucB\nAJRUS3jlMcmO232C/TFkYqLijp9MWvweL6p3FkzlgYRcAPwLCQ77r8rwUeeq\nRbCR+hJVrFYONjilWDEUNu+pBmGteM4zBGL9iccWCSsGAQQB2kcPAQEHQH5M\nnFUeGE3EvOQ29sQ8QUopQ7tBF14j4uyy7jDLqo2swngEGBMIAAkFAmL9iccC\nGyAAIQkQQSQW00bY7YAWIQSTNEBdvBFrKAgS9TdBJBbTRtjtgI2TAQCo/iym\nsC9/GhSykea51lTlGonxXEun52po59lMMyoH8gEAsSi1bLgrNs+DHg1L0ZZ/\nvy+c3IR2tJHatiuW+mEa784=\n=Xx1W\n-----END PGP PUBLIC KEY BLOCK-----\n"
}
],
"userGPGPublicKey": "-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nxk8EYv2JxxMFK4EEAAoCAwQTxTec5csKSgVmwr+BQelQy0LJCeMjzYZZHzYe\nsGjPLWh43Y5TU/ZefmT+Rfr1Ew0QgiI7gqYG51HXVDoO60TIzVUyZTQ4YTAy\nNTdlODZjOGMzNjdjNzMwMmQgPHVzZXItMmU0OGEwMjU3ZTg2YzhjMzY3Yzcz\nMDJkQDJlNDhhMDI1N2U4NmM4YzM2N2M3MzAyZC5jb20+wowEEBMIAB0FAmL9\niccECwkHCAMVCAoEFgACAQIZAQIbAwIeAQAhCRBBJBbTRtjtgBYhBJM0QF28\nEWsoCBL1N0EkFtNG2O2ACW0BAIWngWQibooh+8LoNkaEhh8LxRC3lIC1F6/W\nb5/cfosfAP0cEc3ZUK4GHziD8dOBAqqCfpigkuuzK3uGIPYkE1vZzM5TBGL9\niccSBSuBBAAKAgMEeJYP7IL9+75lMli/easFEeTo95uYD9WnkJFju9O8BUay\ng1zo5sm/1JzXmA/Mep/eVhlBDBGjmY/EMaxbVXNIMwMBCAfCeAQYEwgACQUC\nYv2JxwIbDAAhCRBBJBbTRtjtgBYhBJM0QF28EWsoCBL1N0EkFtNG2O2AaucB\nAJRUS3jlMcmO232C/TFkYqLijp9MWvweL6p3FkzlgYRcAPwLCQ77r8rwUeeq\nRbCR+hJVrFYONjilWDEUNu+pBmGteA==\n=43NM\n-----END PGP PUBLIC KEY BLOCK-----\n",
"backupGPGPublicKey": "-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nxk8EYv2JxxMFK4EEAAoCAwQTxTec5csKSgVmwr+BQelQy0LJCeMjzYZZHzYe\nsGjPLWh43Y5TU/ZefmT+Rfr1Ew0QgiI7gqYG51HXVDoO60TIzVUyZTQ4YTAy\nNTdlODZjOGMzNjdjNzMwMmQgPHVzZXItMmU0OGEwMjU3ZTg2YzhjMzY3Yzcz\nMDJkQDJlNDhhMDI1N2U4NmM4YzM2N2M3MzAyZC5jb20+wowEEBMIAB0FAmL9\niccECwkHCAMVCAoEFgACAQIZAQIbAwIeAQAhCRBBJBbTRtjtgBYhBJM0QF28\nEWsoCBL1N0EkFtNG2O2ACW0BAIWngWQibooh+8LoNkaEhh8LxRC3lIC1F6/W\nb5/cfosfAP0cEc3ZUK4GHziD8dOBAqqCfpigkuuzK3uGIPYkE1vZzM5TBGL9\niccSBSuBBAAKAgMEeJYP7IL9+75lMli/easFEeTo95uYD9WnkJFju9O8BUay\ng1zo5sm/1JzXmA/Mep/eVhlBDBGjmY/EMaxbVXNIMwMBCAfCeAQYEwgACQUC\nYv2JxwIbDAAhCRBBJBbTRtjtgBYhBJM0QF28EWsoCBL1N0EkFtNG2O2AaucB\nAJRUS3jlMcmO232C/TFkYqLijp9MWvweL6p3FkzlgYRcAPwLCQ77r8rwUeeq\nRbCR+hJVrFYONjilWDEUNu+pBmGteA==\n=43NM\n-----END PGP PUBLIC KEY BLOCK-----\n"
}'
async function main() {
// ... setup, user keyshare, backup keyshare
// create bitgo keychain
const userToBitgoPublicShare = Buffer.concat([
Buffer.from(userKeyShare.uShare.y, "hex"),
Buffer.from(userKeyShare.uShare.chaincode, "hex"),
]).toString("hex");
const userToBitgoPrivateShare = Buffer.concat([
Buffer.from(userKeyShare.yShares[3].u, "hex"),
Buffer.from(userKeyShare.yShares[3].chaincode, "hex"),
]).toString("hex");
const userToBitgoKeyShare = {
publicShare: userToBitgoPublicShare,
privateShare: userToBitgoPrivateShare,
privateShareProof: await createShareProof(
userGpgKey.privateKey,
userToBitgoPrivateShare.slice(0, 64)
),
};
const backupToBitgoPublicShare = Buffer.concat([
Buffer.from(backupKeyShare.uShare.y, "hex"),
Buffer.from(backupKeyShare.uShare.chaincode, "hex"),
]).toString("hex");
const backupToBitgoPrivateShare = Buffer.concat([
Buffer.from(backupKeyShare.yShares[3].u, "hex"),
Buffer.from(backupKeyShare.yShares[3].chaincode, "hex"),
]).toString("hex");
const backupToBitgoKeyShare = {
publicShare: backupToBitgoPublicShare,
privateShare: backupToBitgoPrivateShare,
privateShareProof: await createShareProof(
userGpgKey.privateKey,
backupToBitgoPrivateShare.slice(0, 64)
),
};
// Prepare data for API
const encUserToBitGoMessage = await encryptText(
userToBitgoKeyShare.privateShare,
bitgoKey
);
const encBackupToBitGoMessage = await encryptText(
userToBitgoKeyShare.privateShare,
bitgoKey
);
const createBitGoMPCParams = {
keyType: "MPC",
source: "bitgo",
keyShares: [
{
from: "user",
to: "bitgo",
publicShare: userToBitgoKeyShare.publicShare,
privateShare: encUserToBitGoMessage,
privateShareProof: userToBitgoKeyShare.privateShareProof,
},
{
from: "backup",
to: "bitgo",
publicShare: backupToBitgoKeyShare.publicShare,
privateShare: encBackupToBitGoMessage,
privateShareProof: backupToBitgoKeyShare.privateShareProof,
},
],
userGPGPublicKey: userGpgKey.publicKey,
backupGPGPublicKey: userGpgKey.publicKey,
enterprise: enterprise,
};
const bitgoKeychain = (await bitgo
.post(uploadKeyUrl)
.send(createBitGoMPCParams)
.result()) as any as Keychain;
console.log("\n\ncreated bitgo keychain");
console.log(JSON.stringify(bitgoKeychain, undefined, 2));
}
Step Result
BitGo creates the BitGo keychain and returns the following:
- BitGo-to-backup shares
- BitGo-to-user shares
commonKeychain- Key
id
Note
This response contains critical key material. Save it in a secure place. This is the only time you're given the full private key share material.
{
"id": "62fd86fcf9ce8e00083e1f6ea215960f",
"source": "bitgo",
"keyType":"tss",
"commonKeychain": "2b4a206676f076cdd3586716ee6f39c15218f3c4f4b6fdfa97f1e088891903c89c4b412a8a9eaec9461b64e25c4c024eb043aca4d3d41c4bd043981e7da019f8",
"isBitGo": true,
"keyShares": [
{
"from": "user",
"to": "bitgo",
"publicShare": "9a9c57f85a74eae15a57401b6467a3198743d56768d1273bf1d6cf5db147bea903c10c0e45befd366720ea8ac8fb0f4c313f99ef9b08a1e18e474d05a8e8c522",
"privateShare": "-----BEGIN PGP MESSAGE-----\n\nwX4DUQ8XhGVGcTISAgMEd+DSpPq0yS44o8MvhHwbf2ubaW6A9060T/+X5R0i\ngc9V9LDPaCjxImBFMwh/aZmcLg1ctNHQpPQTmEEk+TNDDTDA0H9eWrA6Ug91\n9+Dq+HDTqo+SFIVXbnshvr1tIwvmgwzwZlYXbhkwbf6lTbi50uHSsQGDrOmB\nK4bdMGdBY8CKWMTE2oXG+EX9ufCxoKOg2dp6Q4cGhRx3y8JMCFFaSfnVzytK\n8TyqqVaDUpJPvrBq4aeYlFNmkEbp83T2Ov1ywK1itfDsbi4H+nkUsZCOvI/R\nLxg9/sQVmKSop5TARWRNDmqHnICP1JiWVuhPIE0+02cGnOjYUyVOWrRrl5ER\n0b4R4lfYF36BqovcNksHO4KUfLqDeQbHneBzOpjZ98+HBq0PfQ==\n=FjpX\n-----END PGP MESSAGE-----\n",
"privateShareProof": "-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nxk8EYv2G6hMFK4EEAAoCAwTjymX/hj8Q3pja+5pC+faIzpf5JkNFmTxaDuTf\nMAaG9UDqCZ5Q0+pgDXtknYqwMYQ4fWA304O9GL/Q7ejupucnzVVhZjEwNTY2\nZTFjMDQ0NjMzMGJmYzBmNjMgPHVzZXItYWYxMDU2NmUxYzA0NDYzMzBiZmMw\nZjYzQGFmMTA1NjZlMWMwNDQ2MzMwYmZjMGY2My5jb20+wowEEBMIAB0FAmL9\nhuoECwkHCAMVCAoEFgACAQIZAQIbAwIeAQAhCRAoDzj78xv7lhYhBP1EGUlN\nt8yjAJyMzSgPOPvzG/uWvE4A/inM8FbN0MwbjiBvEnjdiUAl33u4/oT97F3T\nCOuL/fvOAQDAALsCXeTTY2lzKDkcn3o2rZHpTShKa6UOX9cRyqDvds5TBGL9\nhuoSBSuBBAAKAgMEeb4RLR4x+QHwzThdIFxb5Z7r0XyGvIJ5w2pUmWfbKaIV\nql5I/qRoQhsl9MMP72LEEEVuZH/91mVYnXj5t4c9xwMBCAfCeAQYEwgACQUC\nYv2G6gIbDAAhCRAoDzj78xv7lhYhBP1EGUlNt8yjAJyMzSgPOPvzG/uWJ+sA\n/jfHf+gWKxRQ4yjnj5lX/TVMBKs3Mhy1UnfaHuJCvpQRAQC3FTAATDbgwNgW\nF6lnI3v0DIVTixpXdzl1JziLSrRv1M4zBGL9husWCSsGAQQB2kcPAQEHQESR\nV4u+bIO/aW/fiQCgAFe5jvyll5P0vtercMwNrZPjwngEGBMIAAkFAmL9husC\nGyAAIQkQKA84+/Mb+5YWIQT9RBlJTbfMowCcjM0oDzj78xv7ljjmAP9N7mBi\nbqEuxweQDBZiS9nyr2hdKH1NEArbl/AYw8z8TQEAtGIBZ1OUoNe5dgHMANhA\nYy3fsF0loeRkoj3IzbNmPWo=\n=dEfn\n-----END PGP PUBLIC KEY BLOCK-----\n"
},
{
"from": "backup",
"to": "bitgo",
"publicShare": "c882eaf251d330d9871de9abc12723067951febb0f6c3c2aa4413460d1ecec82280b166e7e9b8ebff854721906f438d3f54bd7f68838be4059008687c9a2948b",
"privateShare": "-----BEGIN PGP MESSAGE-----\n\nwX4DUQ8XhGVGcTISAgMEGRDHD0Wn8UzkWVfEYtMg6F9/URUBlKfBAo+PnV26\nhPU7ZYMix/N3aKbobY+9olPeokqdQ7DudHy4TgZhUoptKDAZmuu03umQ3OTd\n1XJxDEaf5OhwPxdFKviHBrE04eqCjHkbkt8sHcNLoOUoN8yZs1nSsQHb66Yz\nwNT9INvyYi694VVu4vXpg7VbbAu+3nNdJh+2OYeI837xDaKZMQSMmpDno/4D\niFUDKQhzj1sRDp7uK27qTI0+ndTk0DDQETHLnYlwSuiVG8SUzKoKKAQa0MFa\nBqmOHi6McR5V3JUTesH2yVXAEr3Afs6T1vEiWeDkPU2jcL60l90DdcSVA45C\n4Vj1Esko9JvOSND0RLByufFZTjY/rt6sqm8XXiodQBPVoVFGEg==\n=yX9u\n-----END PGP MESSAGE-----\n",
"privateShareProof": "-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nxk8EYv2G6hMFK4EEAAoCAwTjymX/hj8Q3pja+5pC+faIzpf5JkNFmTxaDuTf\nMAaG9UDqCZ5Q0+pgDXtknYqwMYQ4fWA304O9GL/Q7ejupucnzVVhZjEwNTY2\nZTFjMDQ0NjMzMGJmYzBmNjMgPHVzZXItYWYxMDU2NmUxYzA0NDYzMzBiZmMw\nZjYzQGFmMTA1NjZlMWMwNDQ2MzMwYmZjMGY2My5jb20+wowEEBMIAB0FAmL9\nhuoECwkHCAMVCAoEFgACAQIZAQIbAwIeAQAhCRAoDzj78xv7lhYhBP1EGUlN\nt8yjAJyMzSgPOPvzG/uWvE4A/inM8FbN0MwbjiBvEnjdiUAl33u4/oT97F3T\nCOuL/fvOAQDAALsCXeTTY2lzKDkcn3o2rZHpTShKa6UOX9cRyqDvds5TBGL9\nhuoSBSuBBAAKAgMEeb4RLR4x+QHwzThdIFxb5Z7r0XyGvIJ5w2pUmWfbKaIV\nql5I/qRoQhsl9MMP72LEEEVuZH/91mVYnXj5t4c9xwMBCAfCeAQYEwgACQUC\nYv2G6gIbDAAhCRAoDzj78xv7lhYhBP1EGUlNt8yjAJyMzSgPOPvzG/uWJ+sA\n/jfHf+gWKxRQ4yjnj5lX/TVMBKs3Mhy1UnfaHuJCvpQRAQC3FTAATDbgwNgW\nF6lnI3v0DIVTixpXdzl1JziLSrRv1M4zBGL9husWCSsGAQQB2kcPAQEHQFw1\nvExxuu7fzls42q6bYKWhH9Z9/7oHoO11mIX2mdV6wngEGBMIAAkFAmL9husC\nGyAAIQkQKA84+/Mb+5YWIQT9RBlJTbfMowCcjM0oDzj78xv7ljjmAP9CgMJr\n8neb8k9nJ4ZJAxRysF0fAlIFFKnhP9Z0EoQcWAD9FeB+A4ubLRLDDZMc4ryt\nLGTnwU8InXWKsJdVfkgsBCQ=\n=UsYr\n-----END PGP PUBLIC KEY BLOCK-----\n"
},
{
"from": "bitgo",
"to": "user",
"publicShare": "6d9d45b9a9a5d992c5cdb53aaea81fd76ed99a2ca0fde9da26fb399059fb02d7707f1eadc64422d2e6a6083e8c5cba2e89b83abeb092bc29e8fbc4910b14c04b",
"privateShare": "-----BEGIN PGP MESSAGE-----\n\nwX4D7OCwmxeFTc0SAgMEU+OdYCwkW1s2hh+2zED5bV76M/oDwClbL6LT8hiZ\nZBjo0ycxzWrQ0wflDVaqqGTrYAK5QO19R9JYRkAn8QQCITAJoZOOsOh+Oc7J\nJWvr9J9tSFG9zBigeYSe5xSnmTS0jnW0BFa1F79HqFuu9ZdTAFbSsQF3YWZc\nM9Bk2vm+YJZpNEdDrv20KQaoFtrDQVKGxteiOLEtbtkum02pzTrSmXLiBV3R\nYrwfEX6XF/8xM2NSkjm8iBJW6ZL9SO/2/EIh9I2IxHiOIjJUHgS0i4IvS1A9\n3OQysa5g2AYJX+EsqB1wcEHZrkHA3BcJZp/JzUWIuzHsTtPI0BCmrkbWB3Z9\nem/3TpAD0KMURfj3KCnPgskIxI2BF6iZj4xqqWcv+LBNyDTqZA==\n=c3Sd\n-----END PGP MESSAGE-----\n",
"hsmSig": "-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nxk8EYqEU5hMFK4EEAAoCAwQDdbAIZrsblEXIavyg2go6p9oG0SqWTgFsdHTc\nBhqdIS/WjQ8pj75q+vLqFtV9hlImYGInsIWh97fsigzB2owyzRhoc20gPGhz\nbUB0ZXN0LmJpdGdvLmNvbT7ChAQTEwgAFQUCYqEU5wILCQIVCAIWAAIbAwIe\nAQAhCRCJNRsIDGunexYhBHRL5D/8nRM3opQnXok1GwgMa6d7tg8A/24A9awq\nSCJx7RddiUzFHcKhVvvo3R5N7bHaOGP3TP79AP0TavF2WzhUXmZSjt3IK23O\n7/aknbijVeq52ghbWb1Sws43BGL9hvUSCSsGAQQB2kcPAQEHQGGlLDhEqpZd\n7L2zLw1ujn29SRH3rUejCKFU3nLsoqYBAwEIB8LAzgQYEwgBHwUCYv2G9pcU\ngAAAAAAOAIBjb21tb25LZXlDaGFpbjJiNGEyMDY2NzZmMDc2Y2RkMzU4Njcx\nNmVlNmYzOWMxNTIxOGYzYzRmNGI2ZmRmYTk3ZjFlMDg4ODkxOTAzYzg5YzRi\nNDEyYThhOWVhZWM5NDYxYjY0ZTI1YzRjMDI0ZWIwNDNhY2E0ZDNkNDFjNGJk\nMDQzOTgxZTdkYTAxOWY4PRSAAAAAAAwAKHVzZXJHcGdLZXlJZGZkNDQxOTQ5\nNGRiN2NjYTMwMDljOGNjZDI4MGYzOGZiZjMxYmZiOTY/FIAAAAAADgAoYmFj\na3VwR3BnS2V5SWRmZDQ0MTk0OTRkYjdjY2EzMDA5YzhjY2QyODBmMzhmYmYz\nMWJmYjk2AhsMACEJEIk1GwgMa6d7FiEEdEvkP/ydEzeilCdeiTUbCAxrp3v/\nVAD/VmZNpGDaZRkvIj8ehCWmsDS7IgxQinpck9AMZ52y6UwA+gJ5QbW6/XTW\n+FFf7K8WcF0WzNxQwoD+2FyGR6Anwmfl\n=cQgT\n-----END PGP PUBLIC KEY BLOCK-----\n"
},
{
"from": "bitgo",
"to": "backup",
"publicShare": "6d9d45b9a9a5d992c5cdb53aaea81fd76ed99a2ca0fde9da26fb399059fb02d7707f1eadc64422d2e6a6083e8c5cba2e89b83abeb092bc29e8fbc4910b14c04b",
"privateShare": "-----BEGIN PGP MESSAGE-----\n\nwX4D7OCwmxeFTc0SAgMEvcMNV3JEL1hSp0JvAGUZ7PAMl6gAb7jSZkTqPgWu\nhLgeq7H2Zb1bFvk2MKY8JPcbtIRudaUwIkWYGI4TucNb7jAZavG3M/ay4Wnr\nSAZo/5VWtkyg/V2WyGl8Uw86UI8Tq5KSAaj/xQwk7hFD0/HSUyDSsQEQCi7p\nSM3ljK6N8aXMvwNzm7ceyLYRhYr2ljPUdVUNZmdQ0aocjILaSQ6smWZhFdjK\nFgYpiTjvrSZdqnt0FCUjJCPZyAbg8QVVhwSQOW9vcuDuH0fS8mIXueLr7gYw\non0TviBzw3XYdg5qgERkI2rsXilA9lqds9GKCLvBYVJbxCzR5GkdFadyRQrm\nZilHheMjc+wACUF8m+SZQDNeLlZC1lfCULqNbf6vv8Qc89BzFw==\n=TZKY\n-----END PGP MESSAGE-----\n",
"hsmSig": "-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nxk8EYqEU5hMFK4EEAAoCAwQDdbAIZrsblEXIavyg2go6p9oG0SqWTgFsdHTc\nBhqdIS/WjQ8pj75q+vLqFtV9hlImYGInsIWh97fsigzB2owyzRhoc20gPGhz\nbUB0ZXN0LmJpdGdvLmNvbT7ChAQTEwgAFQUCYqEU5wILCQIVCAIWAAIbAwIe\nAQAhCRCJNRsIDGunexYhBHRL5D/8nRM3opQnXok1GwgMa6d7tg8A/24A9awq\nSCJx7RddiUzFHcKhVvvo3R5N7bHaOGP3TP79AP0TavF2WzhUXmZSjt3IK23O\n7/aknbijVeq52ghbWb1Sws43BGL9hvcSCSsGAQQB2kcPAQEHQCOhrt0dekhL\nkdlXxW6c2Fw+biM46OEerUatalkOnXEFAwEIB8LAzgQYEwgBHwUCYv2G+JcU\ngAAAAAAOAIBjb21tb25LZXlDaGFpbjJiNGEyMDY2NzZmMDc2Y2RkMzU4Njcx\nNmVlNmYzOWMxNTIxOGYzYzRmNGI2ZmRmYTk3ZjFlMDg4ODkxOTAzYzg5YzRi\nNDEyYThhOWVhZWM5NDYxYjY0ZTI1YzRjMDI0ZWIwNDNhY2E0ZDNkNDFjNGJk\nMDQzOTgxZTdkYTAxOWY4PRSAAAAAAAwAKHVzZXJHcGdLZXlJZGZkNDQxOTQ5\nNGRiN2NjYTMwMDljOGNjZDI4MGYzOGZiZjMxYmZiOTY/FIAAAAAADgAoYmFj\na3VwR3BnS2V5SWRmZDQ0MTk0OTRkYjdjY2EzMDA5YzhjY2QyODBmMzhmYmYz\nMWJmYjk2AhsMACEJEIk1GwgMa6d7FiEEdEvkP/ydEzeilCdeiTUbCAxrp3tK\ntAD+Ocx42Y99pJVz7td0nSlz7rUkGTHF/lGwCvobLJaPzcgA/jG3fxS7ni65\n0YIe1ZqpxbsGg07PNjDBwikwHYr1+Yvc\n=641H\n-----END PGP PUBLIC KEY BLOCK-----\n"
}
],
"commonKeychainSig": "-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nxk8EYqEU5hMFK4EEAAoCAwQDdbAIZrsblEXIavyg2go6p9oG0SqWTgFsdHTc\nBhqdIS/WjQ8pj75q+vLqFtV9hlImYGInsIWh97fsigzB2owyzRhoc20gPGhz\nbUB0ZXN0LmJpdGdvLmNvbT7ChAQTEwgAFQUCYqEU5wILCQIVCAIWAAIbAwIe\nAQAhCRCJNRsIDGunexYhBHRL5D/8nRM3opQnXok1GwgMa6d7tg8A/24A9awq\nSCJx7RddiUzFHcKhVvvo3R5N7bHaOGP3TP79AP0TavF2WzhUXmZSjt3IK23O\n7/aknbijVeq52ghbWb1Sws43BGL9hvoSCSsGAQQB2kcPAQEHQCtKIGZ28HbN\n01hnFu5vOcFSGPPE9Lb9+pfx4IiJGQPIAwEIB8LAzgQYEwgBHwUCYv2G+pcU\ngAAAAAAOAIBjb21tb25LZXlDaGFpbjJiNGEyMDY2NzZmMDc2Y2RkMzU4Njcx\nNmVlNmYzOWMxNTIxOGYzYzRmNGI2ZmRmYTk3ZjFlMDg4ODkxOTAzYzg5YzRi\nNDEyYThhOWVhZWM5NDYxYjY0ZTI1YzRjMDI0ZWIwNDNhY2E0ZDNkNDFjNGJk\nMDQzOTgxZTdkYTAxOWY4PRSAAAAAAAwAKHVzZXJHcGdLZXlJZGZkNDQxOTQ5\nNGRiN2NjYTMwMDljOGNjZDI4MGYzOGZiZjMxYmZiOTY/FIAAAAAADgAoYmFj\na3VwR3BnS2V5SWRmZDQ0MTk0OTRkYjdjY2EzMDA5YzhjY2QyODBmMzhmYmYz\nMWJmYjk2AhsMACEJEIk1GwgMa6d7FiEEdEvkP/ydEzeilCdeiTUbCAxrp3vb\nOgD+Km7XHGKnWY5/IECSeKsU0DJAo5XTJaHy3MOZWI484loA/2Fr+KHXRqMs\nioKT5vlWoYczg5TA5l1WykZk5+w4l1u9\n=Hu2L\n-----END PGP PUBLIC KEY BLOCK-----\n",
"walletHSMGPGPublicKeySigs": "-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nxk8EYv2G6hMFK4EEAAoCAwTjymX/hj8Q3pja+5pC+faIzpf5JkNFmTxaDuTf\nMAaG9UDqCZ5Q0+pgDXtknYqwMYQ4fWA304O9GL/Q7ejupucnzVVhZjEwNTY2\nZTFjMDQ0NjMzMGJmYzBmNjMgPHVzZXItYWYxMDU2NmUxYzA0NDYzMzBiZmMw\nZjYzQGFmMTA1NjZlMWMwNDQ2MzMwYmZjMGY2My5jb20+wowEEBMIAB0FAmL9\nhuoECwkHCAMVCAoEFgACAQIZAQIbAwIeAQAhCRAoDzj78xv7lhYhBP1EGUlN\nt8yjAJyMzSgPOPvzG/uWvE4A/inM8FbN0MwbjiBvEnjdiUAl33u4/oT97F3T\nCOuL/fvOAQDAALsCXeTTY2lzKDkcn3o2rZHpTShKa6UOX9cRyqDvdsLA2gQT\nEwgBKwUCYv2G8gILCZcUgAAAAAAOAIBjb21tb25LZXlDaGFpbjJiNGEyMDY2\nNzZmMDc2Y2RkMzU4NjcxNmVlNmYzOWMxNTIxOGYzYzRmNGI2ZmRmYTk3ZjFl\nMDg4ODkxOTAzYzg5YzRiNDEyYThhOWVhZWM5NDYxYjY0ZTI1YzRjMDI0ZWIw\nNDNhY2E0ZDNkNDFjNGJkMDQzOTgxZTdkYTAxOWY4PRSAAAAAAAwAKHVzZXJH\ncGdLZXlJZGZkNDQxOTQ5NGRiN2NjYTMwMDljOGNjZDI4MGYzOGZiZjMxYmZi\nOTY/FIAAAAAADgAoYmFja3VwR3BnS2V5SWRmZDQ0MTk0OTRkYjdjY2EzMDA5\nYzhjY2QyODBmMzhmYmYzMWJmYjk2AhUIAhYAAhsDAh4BACEJEIk1GwgMa6d7\nFiEEdEvkP/ydEzeilCdeiTUbCAxrp3tVtAD/XFA1qhmMDUCSFIN8nq1sEBhj\nA//+cllpIZh6bi1XpK4A/05ik2s7e85qCHdB9UJ+0HTGiwhzzW9yHA405uos\nAyPUzlMEYv2G6hIFK4EEAAoCAwR5vhEtHjH5AfDNOF0gXFvlnuvRfIa8gnnD\nalSZZ9spohWqXkj+pGhCGyX0ww/vYsQQRW5kf/3WZVidePm3hz3HAwEIB8J4\nBBgTCAAJBQJi/YbqAhsMACEJECgPOPvzG/uWFiEE/UQZSU23zKMAnIzNKA84\n+/Mb+5Yn6wD+N8d/6BYrFFDjKOePmVf9NUwEqzcyHLVSd9oe4kK+lBEBALcV\nMABMNuDA2BYXqWcje/QMhVOLGld3OXUnOItKtG/Uxk8EYv2G6hMFK4EEAAoC\nAwTjymX/hj8Q3pja+5pC+faIzpf5JkNFmTxaDuTfMAaG9UDqCZ5Q0+pgDXtk\nnYqwMYQ4fWA304O9GL/Q7ejupucnzVVhZjEwNTY2ZTFjMDQ0NjMzMGJmYzBm\nNjMgPHVzZXItYWYxMDU2NmUxYzA0NDYzMzBiZmMwZjYzQGFmMTA1NjZlMWMw\nNDQ2MzMwYmZjMGY2My5jb20+wowEEBMIAB0FAmL9huoECwkHCAMVCAoEFgAC\nAQIZAQIbAwIeAQAhCRAoDzj78xv7lhYhBP1EGUlNt8yjAJyMzSgPOPvzG/uW\nvE4A/inM8FbN0MwbjiBvEnjdiUAl33u4/oT97F3TCOuL/fvOAQDAALsCXeTT\nY2lzKDkcn3o2rZHpTShKa6UOX9cRyqDvdsLA2gQTEwgBKwUCYv2G9AILCZcU\ngAAAAAAOAIBjb21tb25LZXlDaGFpbjJiNGEyMDY2NzZmMDc2Y2RkMzU4Njcx\nNmVlNmYzOWMxNTIxOGYzYzRmNGI2ZmRmYTk3ZjFlMDg4ODkxOTAzYzg5YzRi\nNDEyYThhOWVhZWM5NDYxYjY0ZTI1YzRjMDI0ZWIwNDNhY2E0ZDNkNDFjNGJk\nMDQzOTgxZTdkYTAxOWY4PRSAAAAAAAwAKHVzZXJHcGdLZXlJZGZkNDQxOTQ5\nNGRiN2NjYTMwMDljOGNjZDI4MGYzOGZiZjMxYmZiOTY/FIAAAAAADgAoYmFj\na3VwR3BnS2V5SWRmZDQ0MTk0OTRkYjdjY2EzMDA5YzhjY2QyODBmMzhmYmYz\nMWJmYjk2AhUIAhYAAhsDAh4BACEJEIk1GwgMa6d7FiEEdEvkP/ydEzeilCde\niTUbCAxrp3tZVAD6A4oxsMlIqIDBpKgfmTzyup8k7JXIV06O41C8XqCDtecA\n/0oGy1rZM4VlvRD1nJUdJY6aKszfOymffPCgiTd2x9VfzlMEYv2G6hIFK4EE\nAAoCAwR5vhEtHjH5AfDNOF0gXFvlnuvRfIa8gnnDalSZZ9spohWqXkj+pGhC\nGyX0ww/vYsQQRW5kf/3WZVidePm3hz3HAwEIB8J4BBgTCAAJBQJi/YbqAhsM\nACEJECgPOPvzG/uWFiEE/UQZSU23zKMAnIzNKA84+/Mb+5Yn6wD+N8d/6BYr\nFFDjKOePmVf9NUwEqzcyHLVSd9oe4kK+lBEBALcVMABMNuDA2BYXqWcje/QM\nhVOLGld3OXUnOItKtG/U\n=Ehed\n-----END PGP PUBLIC KEY BLOCK-----\n"
}
5. Create User Keychain
Submit the completed key share for the user key.
export COIN="<ASSET_ID>"
export ACCESS_TOKEN="<YOUR_ACCESS_TOKEN>"
export ENTERPRISE="<ENTERPRISE_ID>"
curl -X POST \
https://app.bitgo-test.com/api/v2/$COIN/key \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d '{
"commonKeychain": "d8f118329ca1ee311e1b76480db69bf40a7b943fcc0c8a0a88c89046c41d1531c22809a059c56a4772302d3b11ee5d4ec90fc45b1fbd11824642e3f4b7491ecf",
"encryptedPrv": "{\"iv\":\"lp2GTR9KiSTYbG7qBtiViA==\",\"v\":1,\"iter\":10000,\"ks\":256,\"ts\":64,\"mode\":\"ccm\",\"adata\":\"\",\"cipher\":\"aes\",\"salt\":\"Eo79EY3uUZ8=\",\"ct\":\"C39MDrBf8Amn62bL2ncVkGT59wQ10EBDPGPj/kVxl8YEDcHEJAmYGO7SNBH7rPNBCRCkAUBgQ5Rdq0Fu5X7/tciTsggFuPKL0HR0twPALWn2cgXPH8oVdHSpx1pRJuxiI3WQRoWOtb4+qW0yhWqud4VLi8Db0FnWaHaKmbAbWakny3hZeoxrhjb5ifSDwKOfyxB1EcVjX2RRDuuyxTBL3MLJFQh4mdnFUFmcG9pcUKfZKZBYc/bTIWgNULsDBP7y3tiXPMuh5u/gdk9rupEXZCGyc7XzR8qEPqLe9K6dnH+Bc6GkV+YEFAAfCdKbVdJ9EHkizp7NhG8zqkFRjpJzEaphFYOsp1yxX4DwFRdCvcrBOG8+D/MX5CdRiGfLondZ3xATnkb7Wm68/AzCuXZ1rwdZULmYHaQlqF9NRQUfUfO3Bn3PqGLzmMZps2oX893zghM59hGWe+TUz5OGdkckNaRZMU7qHBHXL+vaNsVV4dcdrrGy7YW74K9YgWepnf5j56lMkL12PVHq8fT0UOhaS04VqTAJty9NAF+0lg/YnVfn9yvLr6PCNOHrD5mO8T6m+rqvkYZqYk2uKxwRaOiTtSfbbedyOGXi1e71TDClE9MXWTKpelY/lq5iEONXyQVElqdSvvPY5XcclGkFNRNTDxwBiUvFmsO8xV5TBcPXPnm8rUO5T3XGjtc1EdVGhv6M4xL3jB8vpoheTTUAlbSyclATKu5Prd+yeGTXp0hzJOK+r4r8hsKtuAKsMgPhpNCBNR3vnw6OojFe7efiBrvCLdirThdYFZoiTKcSvB/H+tjwIleKsm7ApwzzzBPy7oN/ibmbRiGaz8voOzdMLvyMWfgNCH2MXgONi4rg8Tlli4WXjNjSAnIoNJVg4/ocG+aqs9v4HBdrfrb8uw6ERH9HamICdLXwixSMI4EDTNgK+iBgeFqASwLjnnCMq5tXQHsM/lF0MyCHjT5g4mXQdKbLChOY1koiOggntJrVcEZTcaUogZnQTtwcIX4=\"}",
"keyType":"tss",
"source": "user",
"originalPasscodeEncryptionCode": "4K9TD9KA1DUmNLugcvxZqpnAY42P"
}'
async function main() {
// ... setup, user keyshare, backup keyshare, bitgo keychain
// create user keychain
const bitgoKeyShares = bitgoKeychain.keyShares;
const bitGoToUserShare = bitgoKeyShares!.find(
(keyShare) => keyShare.from === "bitgo" && keyShare.to === "user"
);
const bitGoToUserPrivateShare = await decryptPrivateShare(
bitGoToUserShare!.privateShare,
userGpgKey
);
const bitgoToUser = {
i: 1,
j: 3,
y: bitGoToUserShare!.publicShare.slice(0, 64),
u: bitGoToUserPrivateShare.slice(0, 64).toString(),
chaincode: bitGoToUserPrivateShare.slice(64).toString(),
};
const userCombined = MPC.keyCombine(userKeyShare.uShare, [
backupKeyShare.yShares[1],
bitgoToUser,
]);
const commonKeychain =
userCombined.pShare.y + userCombined.pShare.chaincode;
// IMPORTANT: Verify the common keychain bitgo returns is the same one we derive
if (commonKeychain !== bitgoKeychain.commonKeychain) {
throw new Error(
"Failed to create user keychain - commonKeychains do not match."
);
}
// IMPORTANT: This is your private material
const userSigningMaterial = {
uShare: userKeyShare.uShare,
bitgoYShare: bitgoToUser,
backupYShare: backupKeyShare.yShares[1],
};
const userKeychainParams: AddKeychainOptions = {
source: "user",
keyType: "MPC",
commonKeychain: bitgoKeychain.commonKeychain,
encryptedPrv: bitgo.encrypt({
input: JSON.stringify(userSigningMaterial),
password: passphrase,
}),
originalPasscodeEncryptionCode,
};
const userKeychain = (await bitgo
.post(uploadKeyUrl)
.send(userKeychainParams)
.result()) as any as Keychain;
console.log("\n\ncreated user keychain");
console.log(JSON.stringify(userKeychain, undefined, 2));
// ...
}
Step Result
You create the user keychain and receive an id for it.
Note
This response contains critical key material. Save it in a secure place.
{
"id": "62fd86fc61fd1f00085664fa62f19d64",
"source": "user",
"keyType":"tss",
"commonKeychain": "2b4a206676f076cdd3586716ee6f39c15218f3c4f4b6fdfa97f1e088891903c89c4b412a8a9eaec9461b64e25c4c024eb043aca4d3d41c4bd043981e7da019f8",
"encryptedPrv": "{\"iv\":\"K6Zg4ea++IEy7Ate56RchQ==\",\"v\":1,\"iter\":10000,\"ks\":256,\"ts\":64,\"mode\":\"ccm\",\"adata\":\"\",\"cipher\":\"aes\",\"salt\":\"LhtFvVgAeMg=\",\"ct\":\"8fSPwEcuYNM7OL/rJZSGHhToKoiL1o9VOFhx+KO1WIIwAHA6MUIN2/GUJj3fqMhtSk2NSHOkWOBLpqU90F2UjeTMY8MnVeQSsuq4G+i4DQtxviXxq4+V3ErQ5EBbMNH6BmfKNqzuncyKbF8hAH5AoDyDcI8JNgfy4MNPyx0xSyiZAG9XMGsWXHKCu6x3CSq9s0jDN1In0pFHYQsg1KvnDThiyv5/qMTrAAZV6Eu20ZSgkALc1FDM5JSTFC95o04UZQyDOXrDvzyoOxRv8j7UXw0h/UhcWz3QqTgpYLkBhPcdtdkQy8OpdnmVcfHQ92L6rCMicMMYKF8vnCJtBf+9dKFRznY+QiuL+9G5AMINbYczb85HvxMXhUAoA8C7hink8QMy+eljnFTlxbMLIyeP3FdEH8UOf8QYFuEOntLNWSmBD4lXmCZunuvzWzYwbk8isUduczZGn5RDxgezk5kvkKifOBW7r8g1u1WPmjmsiZ3WIzoaIoAavQ6uARtNU1fjocP5a6KAzQy/G/cCDT47OKS1gegCrWxoT8P9wPhSMc/XXsPVJD9brZFbhqJyp838ArE+ydbqB+VHsP/mTSvGYd5jhwzLEZ+Szyd0iP4QvzMgJKLgdh4FgZpmvk6SdjJ+aQ02VX+M/Fh2rd7WQyeOBRxl6mQiiNJCuzqw2yENh6JcSAaUZezlwQ88mp0Kj+N3zV3RLgwKgCd4FOGOn3vSnM4zvaVRzdY0JRupcVCxaQDP27zmm9WxDGIPOK0sY1sEoFzhURpw9jXl/SFhdQQJIXXN9IUBcinBXi7K4QCIIcb6nVkdTbjTPJYYhQX1mv6LvEZwdo3Q9ED5FA/4ZxcCk1BbsU9WwARpIE2UZBavfT0eTFDzHBNN3IAEMasF2PdzLD4VPHe+WzEKBipfyJ7xciM8ucxUMeUtYg87bmN7pqdwGI+6ybEhUjrYLP0UAjwoy6VbVjSg+XkQNRRcQOT1Bx5wsx2PfeRBu76S1UlVYKAHCEeZ2o1xWUA=\"}"
}
6. Create Backup Keychain
Submit the completed key share for the backup key.
export COIN="<ASSET_ID>"
export ACCESS_TOKEN="<YOUR_ACCESS_TOKEN>"
export ENTERPRISE="<ENTERPRISE_ID>"
curl -X POST \
https://app.bitgo-test.com/api/v2/$COIN/key \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d '{
"commonKeychain": "d8f118329ca1ee311e1b76480db69bf40a7b943fcc0c8a0a88c89046c41d1531c22809a059c56a4772302d3b11ee5d4ec90fc45b1fbd11824642e3f4b7491ecf",
"encryptedPrv": "{\"iv\":\"BgarW8LYYqFv6lApD4416g==\",\"v\":1,\"iter\":10000,\"ks\":256,\"ts\":64,\"mode\":\"ccm\",\"adata\":\"\",\"cipher\":\"aes\",\"salt\":\"y0DdxUmZDrI=\",\"ct\":\"Khr6tmQms8bizAWbnDo6eLOhgLPrldM2swAWmP4HB5Hnw/ddA7t1uQoE7YEMGc0u2ELM5fQkceAOTG1oicEPEkjfONo1/Jifr51c04aN0XT+FfcNmKNvbn+wQgg/X2PBoZnvce+9R0n5Ssx06HRzkJsFLob0BJkUMUiuAhMvJjxCAfyv89RiU2sjYlq7fO8i30Yzv5mcTIgZl3bfy3Z/Rj8htKGoCDM/6kh1V8KYBNseAmXSMdywYlUWasFoSvcG3xG9pygfooZ8RHFJ4CO97Rd8OkLdhvdy30hZ3IDwqG17nqraipoKr0kYvyQ0KgTY9xv1oJ/uP95SUyCHUUur9uVlNRUcdaUS0A2/W35rRHp5iyfqmrJj9bl0GtVlw4Eio3OFPmLnmF7S9+t72gPIO15RNubDebWM7b0U4ppZ4whuFMQl00WOXZlM/7DkHQvlltp+JiW42/3vVZj2arq1fI61BtirA58uhgvT1W9TK/n23LIGHd9Erns1+jBAteBTIgIr0lVeL3w1Jw1bCSsv3t3GSG4J74pbYRRraz6W59sPD2d4beJLm3VgkQwQDvZ+ilatqmu/6tW5+u8iMVMIffpLD2vwZgsiTf4+3oR6yRd86ff8r/MaDM/nHKXUf52uVq+MIBAigAzonFJk3Eu6b6lXtr9pRUnhD9Ywazj4uKrK5dBGB4KzzKsHkeQIiq9Py59yyJOKZB0lS1KAbIxY+ZDtC4WfTGE/cDfXcL/frpxaucnCM0oXUNgk+YMDK03pccHQVwNU9d8CGtOC/6pKVAlh7QCPhCU38OgMF1RglCg3n1CaJY4WnIpu8mse0W9ZMeQCqy2LPIUj5ptgTJxTMRb5jDOEUdmR6M+D3PSzM7ll5VJZrIvQCZmTGirHB94wb9xZkSWAGw7D8K2Sgo/E3VXn7880HyGbjk94698qHlJ6QXdbEq08JYcuYmUdThYqIQPwYuZT2FDS/diR/8ZbG2MLr4APqIxOirNBjm65xU6kepW5VhIQ\"}",
"keyType":"tss",
"source": "backup",
}'
async function main() {
// ... setup, user keyshare, backup keyshare, bitgo keychain
// create user keychain
const bitgoKeyShares = bitgoKeychain.keyShares;
const bitGoToBackupShare = bitgoKeyShares!.find(
(keyShare) => keyShare.from === "bitgo" && keyShare.to === "backup"
);
const bitGoToBackupPrivateShare = await decryptPrivateShare(
bitGoToBackupShare!.privateShare,
userGpgKey
);
const bitgoToBackup = {
i: 2,
j: 3,
y: bitGoToBackupShare!.publicShare.slice(0, 64),
u: bitGoToBackupPrivateShare.slice(0, 64).toString(),
chaincode: bitGoToBackupPrivateShare.slice(64).toString(),
};
const backupCombined = MPC.keyCombine(backupKeyShare.uShare, [
userKeyShare.yShares[2],
bitgoToBackup,
]);
const commonKeychain =
backupCombined.pShare.y + backupCombined.pShare.chaincode;
// IMPORTANT: Verify the common keychain bitgo returns is the same one we derive
if (commonKeychain !== bitgoKeychain.commonKeychain) {
throw new Error(
"Failed to create backup keychain - commonKeychains do not match."
);
}
const backupSigningMaterial = {
uShare: backupKeyShare.uShare,
bitgoYShare: bitgoToBackup,
userYShare: userKeyShare.yShares[2],
};
console.log(
"\n\ncreated backup keychain (not uploaded to bitgo, must be stored locally)"
);
console.log(JSON.stringify(backupSigningMaterial, undefined, 2));
const backupKeychainParams: AddKeychainOptions = {
source: "backup",
keyType: "MPC",
commonKeychain,
};
const backupKeychain = (await bitgo
.post(uploadKeyUrl)
.send(backupKeychainParams)
.result()) as any as Keychain;
console.log("\n\ncreated backup keychain");
console.log(JSON.stringify(backupKeychain, undefined, 2));
// ...
}
Step Result
You create the backup keychain receive an id for it.
Note
This response contains critical key material. Save it in a secure place.
{
"id": "62fd86fc33275f000855f457021b5976",
"source": "backup",
"keyType":"tss",
"commonKeychain": "2b4a206676f076cdd3586716ee6f39c15218f3c4f4b6fdfa97f1e088891903c89c4b412a8a9eaec9461b64e25c4c024eb043aca4d3d41c4bd043981e7da019f8"
}
Next
Use the id for each key when you Create Wallets.