Create Keys

Overview

You can create your own user and backup keys for self-managed wallets. Key creation occurs entirely client side. At no point does BitGo have access to your private user or backup keys for self-managed wallets.

Note: BitGo always creates and stores the BitGo key.

  • Cold Wallets
  • Hot Wallets

Enhance your security by creating keys on an air-gapped machine, either programmatically (using the steps below) or through the Offline Vault Console (OVC). When you create a cold wallet, you send to BitGo only your public keys.

Prerequisites

Get Started

Steps: Multisig

1. Create Public and Private Keys

  • SDK
  • Express
1 2 3 4 5 6 7 8 9 10 11 const BitGoJS = require('../../../src/index.js'); const bitgo = new BitGoJS.BitGo({ env: 'test' }); // Set your access token here const accessToken = 'v2xcbe8617bd58947a9ec41cc7a92e0a9a9d81dc2780669faa59eab3016ad5792ae'; // Set your coin of choice here const coin = 'tbtc'; bitgo.authenticateWithAccessToken({ accessToken }); let key = bitgo.coin(coin).keychains().create(); console.dir(key);
Step Result
1 2 3 4 { "pub": "xpub661MyMwAqRbcEq5qQLciVPfCyCvx9KstKVp71TxujjY9Kbapv6o2YjtRAV1tfYgQZxBaN6FfFfE3CD21ZRSsd4WkqkFWSZDTiDqf49qtkh7", "prv": "xprv9s21ZrQH143K2M1NJK5i8FiURB6TjsA2xGtWD5ZJBQ1ASoFgNZUmzwZwKC9WnyRaN2f4uAdHPdMmLbw2SsUKa6J2bWUEWihbMKcrhJSZueH" }

To create your backup key and BitGo key, repeat this step 2 more times.

Note: This step may appear to create the actual BitGo key. However, the pub and priv that you get for the BitGo key are only temporary. BitGo creates the actual public and private key pair for the BitGo key in the next step.

2. Upload Public Keys to BitGo

Upload an encrypted version of your private keys to BitGo.

Note: If you want to store your own keys for your self-managed hot wallets, follow the steps in Set Up External-Signing Mode.

  • SDK
  • API
1 2 3 4 5 6 7 8 9 10 11 // Creates user key let userKey = bitgo.coin("tbtc").keychains().create(); // Creates BitGo key let bitGoKey = bitgo.coin("tbtc").keychains().createBitGo(); // Creates backup key let backupKey = bitgo .coin("tbtc") .keychains() .createBackup({ provider: "coincover" });

Step Result

1 2 3 4 5 6 7 { "id": "62e18649381037000872496848a7939f", "pub": "xpub661MyMwAqRbcEq5qQLciVPfCyCvx9KstKVp71TxujjY9Kbapv6o2YjtRAV1tfYgQZxBaN6FfFfE3CD21ZRSsd4WkqkFWSZDTiDqf49qtkh7", "ethAddress": "0x9414569b0f0678b4eb6bacf99689fe596482473b", "source": "user", "type": "independent" }

You receive an id for each key that you will use when you create your wallets.

This call also triggers BitGo to create the actual public and private key pair for the BitGo key. This is stored by BitGo and isn't shared with you. Although you do use the id for the BitGo key to create a wallet, you can't use the BitGo key you created in step 1 to co-sign transactions.

Steps: TSS

For TSS wallets, you create a key share by exchanging a public share and an encrypted-private share of the key between all parties (user, backup, and BitGo). The backup can be you or a key recovery service (KRS). 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.

1. Set Up

  • SDK
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 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

  • SDK
1 2 3 4 5 6 7 8 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.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 { "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

  • SDK
1 2 3 4 5 6 7 8 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.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 { "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

  • SDK
  • API
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 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: "tss", 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 { "id": "62fd86fcf9ce8e00083e1f6ea215960f", "source": "bitgo", "type": "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.

  • SDK
  • API
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 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: "tss", 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.

1 2 3 4 5 6 7 { "id": "62fd86fc61fd1f00085664fa62f19d64", "source": "user", "type": "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.

  • SDK
  • API
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 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: "tss", 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.

1 2 3 4 5 6 { "id": "62fd86fc33275f000855f457021b5976", "source": "backup", "type": "tss", "commonKeychain": "2b4a206676f076cdd3586716ee6f39c15218f3c4f4b6fdfa97f1e088891903c89c4b412a8a9eaec9461b64e25c4c024eb043aca4d3d41c4bd043981e7da019f8" }

Next

Use the id for each key when you Create Wallets.

See Also