PHP WebShell
Текущая директория: /opt/BitGoJS/modules/bitgo/test/v2/unit
Просмотр файла: keychains.ts
//
// Test for Keychains
//
import { CoinFamily, CoinKind, coins, KeyCurve, UnderlyingAsset } from '@bitgo/statics';
import * as assert from 'assert';
import * as _ from 'lodash';
import * as nock from 'nock';
import * as should from 'should';
import * as sinon from 'sinon';
import { common, decodeOrElse, ECDSAUtils, EDDSAUtils, Keychains, OvcShare } from '@bitgo/sdk-core';
import { TestBitGo } from '@bitgo/sdk-test';
import { BitGo } from '../../../src/bitgo';
describe('V2 Keychains', function () {
let bitgo;
let basecoin;
let keychains;
let bgUrl;
before(function () {
bitgo = TestBitGo.decorate(BitGo, { env: 'mock' });
bitgo.initializeTestVars();
bitgo.setValidate(false);
basecoin = bitgo.coin('tltc');
keychains = basecoin.keychains();
bgUrl = common.Environments[bitgo.getEnv()].uri;
});
describe('Add Keychain', function () {
it('should add a keychain', async function () {
const scope = nock(bgUrl)
.post('/api/v2/tltc/key', function (body) {
body.pub.should.equal('pub');
body.derivedFromParentWithSeed.should.equal('derivedFromParentWithSeed');
return true;
})
.reply(200, {});
await keychains.add({ pub: 'pub', derivedFromParentWithSeed: 'derivedFromParentWithSeed' });
scope.done();
});
});
/**
* This section's intention is to provide some key generation sanity checking. generateKeyPair is a general surface
* for key generation but the keys are treated the same by BitGo down the line. Any SECP256K1 based coins key-pairs can
* be re-used so need to be the same.
**/
describe('Key generation enforcement for SECP256K1', function () {
// iterate over non-fiat crypto secp coins
const coinFamilyValues = Object.keys(CoinFamily).map((n) => n.toLowerCase());
const cryptoSecpCoins = coins.filter(
(n) =>
n.primaryKeyCurve === KeyCurve.Secp256k1 &&
n.kind === CoinKind.CRYPTO &&
n.asset !== UnderlyingAsset.USD &&
n.asset !== UnderlyingAsset.AVAXP &&
n.asset !== UnderlyingAsset.DOGE &&
n.asset !== UnderlyingAsset.ETHW &&
n.asset !== UnderlyingAsset.KAVA &&
n.asset !== UnderlyingAsset.COREUM &&
n.asset !== UnderlyingAsset.BERA &&
n.asset !== UnderlyingAsset.ISLM &&
n.asset !== UnderlyingAsset.ARBETH && // TODO(WIN-692): remove this once coin-specific module for arbeth is added
n.asset !== UnderlyingAsset.OPETH && // TODO(WIN-692): remove this once coin-specific module for opeth is added
n.asset !== UnderlyingAsset.ZKETH && // TODO(WIN-1427): remove this once coin-specific module for zketh is added
n.asset !== UnderlyingAsset.OAS && // TODO(WIN-3696): remove this once coin-specific module for oas is added
n.asset !== UnderlyingAsset.COREDAO && // TODO(WIN-3696): remove this once coin-specific module for coredao is added
n.asset !== UnderlyingAsset.FLR && // TODO(WIN-4215): remove this once coin-specific module for FLR is added
n.asset !== UnderlyingAsset.SGB && // TODO(WIN-4216): remove this once coin-specific module for SGB is added
n.asset !== UnderlyingAsset.WEMIX && // TODO(WIN-4177): remove this once coin-specific module for WEMIX is added
n.asset !== UnderlyingAsset.XDC && // TODO(WIN-4173): remove this once coin-specific module for XDC is added
n.asset !== UnderlyingAsset.RUNE &&
n.asset !== UnderlyingAsset.BABY &&
n.asset !== UnderlyingAsset.ICP &&
n.asset !== UnderlyingAsset.MANTRA &&
n.asset !== UnderlyingAsset.MON &&
n.asset !== UnderlyingAsset.WORLD &&
n.asset !== UnderlyingAsset.STT &&
n.asset !== UnderlyingAsset.SONEIUM &&
n.asset !== UnderlyingAsset.VET &&
n.asset !== UnderlyingAsset.CRONOS &&
n.asset !== UnderlyingAsset.FETCH &&
n.asset !== UnderlyingAsset.INIT &&
coinFamilyValues.includes(n.name)
);
const expectedXpub =
'xpub661MyMwAqRbcGpZf8mxNWhSPdWaLGvQzzage6vq2oQFzq8toVzmkjygYZ3HcZw6eCzAfn9ZdyGjKoKkcpKwackdgznVbiunpq7rkxDu7quS';
const expectedXprv =
'xprv9s21ZrQH143K4LVC2kRN9ZVf5UjqsTh9dMm3JYRRF4j1xLZexTTWCBN4hmdZUHeT3vCJPL181ErVaY489ArBKSWaB7Du7vyVS6XC43WtK7A';
const seed = Buffer.from('this is some random seed we will use', 'utf-8');
cryptoSecpCoins.forEach((coin) => {
it(`should create the same ${coin.name} key with the same seed`, function () {
const currentCoin = bitgo.coin(coin.name);
const keyPair = currentCoin.generateKeyPair(seed);
should.exist(keyPair.pub);
should.exist(keyPair.prv);
keyPair.pub.should.equal(expectedXpub);
keyPair.prv.should.equal(expectedXprv);
});
});
});
describe('Update Password', function () {
const oldPassword = 'oldPassword';
const newPassword = 'newPassword';
const otherPassword = 'otherPassword';
describe('should fail', function () {
let sandbox;
beforeEach(function () {
sandbox = sinon.createSandbox();
});
afterEach(function () {
sandbox.restore();
});
it('to update the password', async function () {
await keychains
.updatePassword({ newPassword: '5678' })
.should.be.rejectedWith('Missing parameter: oldPassword');
await keychains
.updatePassword({ oldPassword: 1234, newPassword: '5678' })
.should.be.rejectedWith('Expecting parameter string: oldPassword but found number');
await keychains
.updatePassword({ oldPassword: '1234' })
.should.be.rejectedWith('Missing parameter: newPassword');
await keychains
.updatePassword({ oldPassword: '1234', newPassword: 5678 })
.should.be.rejectedWith('Expecting parameter string: newPassword but found number');
});
it('to update the password for a single keychain', function () {
(() => keychains.updateSingleKeychainPassword({ newPassword: '5678' })).should.throw(
'expected old password to be a string'
);
(() => keychains.updateSingleKeychainPassword({ oldPassword: 1234, newPassword: '5678' })).should.throw(
'expected old password to be a string'
);
(() => keychains.updateSingleKeychainPassword({ oldPassword: '1234' })).should.throw(
'expected new password to be a string'
);
(() => keychains.updateSingleKeychainPassword({ oldPassword: '1234', newPassword: 5678 })).should.throw(
'expected new password to be a string'
);
(() => keychains.updateSingleKeychainPassword({ oldPassword: '1234', newPassword: '5678' })).should.throw(
'expected keychain to be an object with an encryptedPrv property'
);
(() =>
keychains.updateSingleKeychainPassword({
oldPassword: '1234',
newPassword: '5678',
keychain: {},
})).should.throw('expected keychain to be an object with an encryptedPrv property');
(() =>
keychains.updateSingleKeychainPassword({
oldPassword: '1234',
newPassword: '5678',
keychain: { encryptedPrv: 123 },
})).should.throw('expected keychain to be an object with an encryptedPrv property');
const keychain = { encryptedPrv: bitgo.encrypt({ input: 'xprv1', password: otherPassword }) };
(() => keychains.updateSingleKeychainPassword({ oldPassword, newPassword, keychain })).should.throw(
'password used to decrypt keychain private key is incorrect'
);
});
it('on any other error', async function () {
nock(bgUrl)
.get('/api/v2/tltc/key')
.query(true)
.reply(200, {
keys: [
{
pub: 'xpub1',
encryptedPrv: bitgo.encrypt({ input: 'xprv1', password: oldPassword }),
},
],
});
sandbox.stub(keychains, 'updateSingleKeychainPassword').throws('error', 'some random error');
await keychains.updatePassword({ oldPassword, newPassword }).should.be.rejectedWith('some random error');
});
});
describe('successful password update', function () {
const validateKeys = function (keys, newPassword, expectedLength) {
assert.ok(Object.keys(keys).length === expectedLength, 'should have the expected number of keys');
_.each(keys, function (value, key) {
assert.ok(key.includes('xpub') || key.includes('randomid'), 'key should be xpub or randomid');
const decryptedPrv = bitgo.decrypt({ input: value, password: newPassword });
decryptedPrv.should.startWith('xprv');
});
};
it('receive only one page when listing keychains', async function () {
nock(bgUrl)
.get('/api/v2/tltc/key')
.query(true)
.reply(200, {
keys: [
{
pub: 'xpub1',
encryptedPrv: bitgo.encrypt({ input: 'xprv1', password: oldPassword }),
},
{
pub: 'xpub2',
encryptedPrv: bitgo.encrypt({ input: 'xprv2', password: otherPassword }),
},
{
id: 'randomid1',
type: 'tss',
encryptedPrv: bitgo.encrypt({ input: 'xprv3', password: oldPassword }),
},
],
});
const keys = await keychains.updatePassword({ oldPassword: oldPassword, newPassword: newPassword });
validateKeys(keys, newPassword, 2);
});
it('receive multiple pages when listing keychains', async function () {
const prevId = 'prevId';
nock(bgUrl)
.get('/api/v2/tltc/key')
.query(true)
.reply(200, {
nextBatchPrevId: prevId,
keys: [
{
pub: 'xpub1',
encryptedPrv: bitgo.encrypt({ input: 'xprv1', password: oldPassword }),
},
{
pub: 'xpub2',
encryptedPrv: bitgo.encrypt({ input: 'xprv2', password: otherPassword }),
},
{
id: 'randomid1',
type: 'tss',
encryptedPrv: bitgo.encrypt({ input: 'xprv3', password: oldPassword }),
},
],
});
nock(bgUrl)
.get('/api/v2/tltc/key')
.query(function queryNextPageMatch(queryObject) {
return queryObject.prevId === prevId;
})
.reply(200, {
keys: [
{
pub: 'xpub3',
encryptedPrv: bitgo.encrypt({ input: 'xprv3', password: oldPassword }),
},
{
pub: 'xpub4',
encryptedPrv: bitgo.encrypt({ input: 'xprv4', password: otherPassword }),
},
],
});
const keys = await keychains.updatePassword({ oldPassword: oldPassword, newPassword: newPassword });
validateKeys(keys, newPassword, 3);
});
it('single keychain password update', () => {
const prv = 'xprvtest';
const keychain = {
xpub: 'xpub123',
encryptedPrv: bitgo.encrypt({ input: prv, password: oldPassword }),
};
const newKeychain = keychains.updateSingleKeychainPassword({ keychain, oldPassword, newPassword });
const decryptedPrv = bitgo.decrypt({ input: newKeychain.encryptedPrv, password: newPassword });
decryptedPrv.should.equal(prv);
});
it('should return the updated keys with ids', async function () {
nock(bgUrl)
.get('/api/v2/tltc/key')
.query(true)
.reply(200, {
keys: [
{
id: 'randomid1',
type: 'tss',
encryptedPrv: bitgo.encrypt({ input: 'xprv1', password: oldPassword }),
},
{
id: 'randomid2',
type: 'tss',
encryptedPrv: bitgo.encrypt({ input: 'xprv2', password: otherPassword }),
},
],
});
const keys = await keychains.updatePassword({ oldPassword: oldPassword, newPassword: newPassword });
validateKeys(keys, newPassword, 1);
});
});
describe('Create TSS Keychains', function () {
const stubbedKeychainsTriplet = {
userKeychain: {
id: '1',
pub: 'userPub',
},
backupKeychain: {
id: '2',
pub: 'userPub',
},
bitgoKeychain: {
id: '3',
pub: 'userPub',
},
};
let sandbox;
beforeEach(function () {
sandbox = sinon.createSandbox();
});
afterEach(function () {
sandbox.restore();
});
['tsol', 'tdot', 'tnear'].forEach((coin) => {
it('should create EDDSA TSS Keychains', async function () {
sandbox.stub(EDDSAUtils.default.prototype, 'createKeychains').resolves(stubbedKeychainsTriplet);
const keychains = await bitgo.coin(coin).keychains().createMpc({
multisigType: 'tss',
passphrase: 'password',
enterprise: 'enterprise',
originalPasscodeEncryptionCode: 'originalPasscodeEncryptionCode',
});
keychains.should.deepEqual(stubbedKeychainsTriplet);
});
});
['tbsc'].forEach((coin) => {
it('should create ECDSA TSS Keychains', async function () {
nock(bgUrl).get('/api/v2/tss/settings').reply(200, {
coinSettings: {},
});
sandbox.stub(ECDSAUtils.EcdsaUtils.prototype, 'createKeychains').resolves(stubbedKeychainsTriplet);
const keychains = await bitgo.coin(coin).keychains().createMpc({
multisigType: 'tss',
passphrase: 'password',
enterprise: 'enterprise',
originalPasscodeEncryptionCode: 'originalPasscodeEncryptionCode',
});
keychains.should.deepEqual(stubbedKeychainsTriplet);
});
});
});
describe('Recreate Keychains from MPCV1 to MPCV2', async function () {
const coin = 'hteth';
const walletId = 'walletId';
const otp = '000000';
const sandbox = sinon.createSandbox();
const decryptResult = JSON.stringify({ key: 'decrypted' });
beforeEach(function () {
nock(bgUrl)
.get('/api/v2/tss/settings')
.reply(200, {
coinSettings: {
eth: {
walletCreationSettings: {
multiSigTypeVersion: 'MPCv2',
},
},
},
});
sandbox.stub(BitGo.prototype, 'decrypt').returns(decryptResult);
});
afterEach(function () {
sandbox.restore();
nock.cleanAll();
});
it('should fail if empty strings are provided', async function () {
const params: Parameters<Keychains['recreateMpc']>[0] = {
coin,
walletId,
otp,
passphrase: 'password',
enterprise: 'enterprise',
encryptedMaterial: {
encryptedUserKey: 'encrypted',
encryptedBackupKey: 'encrypted',
encryptedWalletPassphrase: 'passphrase',
},
};
await keychains.recreateMpc({ ...params, coin: '' }).should.be.rejectedWith('missing required param coin');
await keychains
.recreateMpc({ ...params, walletId: '' })
.should.be.rejectedWith('missing required param walletId');
await keychains.recreateMpc({ ...params, otp: '' }).should.be.rejectedWith('missing required param otp');
await keychains
.recreateMpc({ ...params, passphrase: '' })
.should.be.rejectedWith('missing required param passphrase');
await keychains
.recreateMpc({
...params,
encryptedMaterial: {
...params.encryptedMaterial,
encryptedWalletPassphrase: '',
},
})
.should.be.rejectedWith('missing required param encryptedWalletPassphrase');
await keychains
.recreateMpc({
...params,
encryptedMaterial: {
...params.encryptedMaterial,
encryptedUserKey: '',
},
})
.should.be.rejectedWith('missing required param encryptedUserKey');
await keychains
.recreateMpc({
...params,
encryptedMaterial: {
...params.encryptedMaterial,
encryptedBackupKey: '',
},
})
.should.be.rejectedWith('missing required param encryptedBackupKey');
});
it('should fail if otp unlock fails', async function () {
nock(bgUrl).post('/api/v1/user/unlock').replyWithError('otp error');
const params = {
coin,
walletId,
otp,
passphrase: 'password',
encryptedMaterial: {
encryptedUserKey: 'encryptedUserKey',
encryptedBackupKey: 'encryptedBackupKey',
encryptedWalletPassphrase: 'encryptedWalletPassphrase',
},
};
await keychains.recreateMpc(params).should.be.rejectedWith('otp error');
});
it('should fail if passcode recovery api call fails', async function () {
nock(bgUrl).post('/api/v1/user/unlock').reply(200, { otp });
nock(bgUrl)
.post(`/api/v2/${coin}/wallet/${walletId}/passcoderecovery`)
.replyWithError('passcode recovery error');
const params = {
coin,
walletId,
otp,
passphrase: 'password',
encryptedMaterial: {
encryptedUserKey: 'encryptedUserKey',
encryptedBackupKey: 'encryptedBackupKey',
encryptedWalletPassphrase: 'encryptedWalletPassphrase',
},
};
await keychains.recreateMpc(params).should.be.rejectedWith('passcode recovery error');
});
it('should fail if passcode recovery api call returns invalid recovery info', async function () {
nock(bgUrl).post('/api/v1/user/unlock').reply(200, { otp });
nock(bgUrl).post(`/api/v2/${coin}/wallet/${walletId}/passcoderecovery`).reply(200, { recoveryInfo: {} });
const params = {
coin,
walletId,
otp,
passphrase: 'password',
encryptedMaterial: {
encryptedUserKey: 'encryptedUserKey',
encryptedBackupKey: 'encryptedBackupKey',
encryptedWalletPassphrase: 'encryptedWalletPassphrase',
},
};
await keychains.recreateMpc(params).should.be.rejectedWith('failed to get recovery info');
});
it('should call createMpc with the correct parameters', async function () {
nock(bgUrl).post('/api/v1/user/unlock').reply(200, { otp });
nock(bgUrl)
.post(`/api/v2/${coin}/wallet/${walletId}/passcoderecovery`)
.reply(200, { recoveryInfo: { passcodeEncryptionCode: '123' } });
const params = {
coin,
walletId: 'walletId',
otp,
passphrase: 'password',
enterprise: 'enterprise',
originalPasscodeEncryptionCode: 'originalPasscodeEncryptionCode',
encryptedMaterial: {
encryptedUserKey: 'encryptedUserKey',
encryptedBackupKey: 'encryptedBackupKey',
encryptedWalletPassphrase: 'encryptedWalletPassphrase',
},
};
const createMpcStub = sinon.stub(keychains, 'createMpc').resolves();
await keychains.recreateMpc(params);
assert.ok(
createMpcStub.calledOnceWith({
...params,
multisigType: 'tss',
retrofit: {
decryptedUserKey: decryptResult,
decryptedBackupKey: decryptResult,
walletId: params.walletId,
},
})
);
});
});
after(function afterUpdatePassword() {
nock.pendingMocks().should.be.empty();
});
});
describe('Create BitGo Key from OVC JSON', function () {
it('Parses the OVC JSON file properly and creates the next input for OVC', async function () {
const bitGoKeyResult = {
id: '6421eb755fea9e0006c2c040072f74bb',
commonKeychain: '123',
walletHSMGPGPublicKeySigs: '123',
verifiedVssProof: true,
keyShares: [
{
from: 'bitgo',
to: 'user',
publicShare: 'ccc',
privateShare: 'ccc private',
paillierPublicKey: 'ccc paillier',
vssProof: 'ccc vss proof',
},
{
from: 'bitgo',
to: 'backup',
publicShare: 'fff',
privateShare: 'fff private',
paillierPublicKey: 'fff paillier',
vssProof: 'fff vss proof',
},
],
};
nock(bgUrl)
.post('/api/v2/tsol/key', _.matches({ source: 'bitgo', keyType: 'tss' }))
.reply(200, bitGoKeyResult);
const ovcOutputJson = {
tssVersion: '0.0.1',
walletType: 'tss',
coin: 'sol',
state: 1,
ovc: {
1: {
gpgPubKey:
'-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nxk8EZBsq9RMFK4EEAAoCAwRgDpgm1bptRT5yLOMadcGAHuvkxISL8/3xPy/D\nYA+1NgBqIFK/3OOXxp73Tv86bt1dgH7OD1ACO0mVXAoX5EaVzWZvdmMtMS11\nc2VyLWRmMjQwOWY0NWNhMTZmNTU3OGNkMzAxMyA8b3ZjLTEtdXNlci1kZjI0\nMDlmNDVjYTE2ZjU1NzhjZDMwMTNAZGYyNDA5ZjQ1Y2ExNmY1NTc4Y2QzMDEz\nLmNvbT7CjAQQEwgAHQUCZBsq9QQLCQcIAxUICgQWAAIBAhkBAhsDAh4BACEJ\nEOUeC7QrGL+2FiEEjN6vPUFRweVtDKFZ5R4LtCsYv7Z7oAEAvNKaJrTIs3ky\nbxjkUicsuxOyA2oWGarJH6TGlWF6WD8A/3EIeZzPKSLaW+3enpbCPiU8RVDp\nC6yo6NMAqKp4XlyQzlMEZBsq9RIFK4EEAAoCAwQWlWPNMpk3afEzfgG0xFg4\nCEjY7fGO35n47nZ4qxjEXz2XN4I23xFMiwZbXbptDXlqm7W9ZAHKi892h+Yt\nU4B6AwEIB8J4BBgTCAAJBQJkGyr1AhsMACEJEOUeC7QrGL+2FiEEjN6vPUFR\nweVtDKFZ5R4LtCsYv7YqZwD8DLRuneB0HEzBCyrE4YL+UHaofoHQX1+nRh0j\n82qaDzAA/i3U1SoEIi32YMrorNG50vb4vaEPbbYmfglb+JQ1Yx7o\n=vjgl\n-----END PGP PUBLIC KEY BLOCK-----\n',
ovcToBitgoShare: {
publicShare:
'07bfbb052a1f4b106b315bd5a9d6a71604653289f861320d9801881e952f8550753c89511a360e3b599d9f239a8d36a4956437ed0b152180e22cb94fb08fdc81',
privateShare:
'-----BEGIN PGP MESSAGE-----\n\nwX4DUQ8XhGVGcTISAgMEd/wQ/AhwIRsSf/6iHwmHKvEYAwfaLtTQotS6BwZm\naX00T7LumGIrNZzBgcggBKMl+8Omom8mX5sP8FUE451iZjBmXlkpHlpAqskS\nEi5SfjlsT31utoLaBLA7NjNSmyYHIiyfh6YnwfV5U72k6hhfpuDSsQGy8Yxp\nM2dVlN4uoO31zgQPf+fgJkZvAPwvjYLBL4O8hs21HGf0VvG99brk4xlFVRhw\nQnuPpM51GOs4vUtbLNSYnAuhU4ReXwwDV9Xu0MXAjfQMk2E3wQLGQ+82uv2B\n1hPD9nDHTtAdWrXd6ZjXFrG4Mf2MQBxySFvVSnFi6yStjfZeiKcD5Vg38PjG\nWg1O5N3/paq98HfH0Q4qNKGZljwo3oEQZzlYm2kVnI0PULoMYg==\n=ovAx\n-----END PGP MESSAGE-----\n',
vssProof: 'be8198c2cef94cb381aa8aa9277a0a46ba5a54b0ac9930034b4af66b1b805234',
i: 3,
j: 1,
uSig: '-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nxk8EZBsq9RMFK4EEAAoCAwRgDpgm1bptRT5yLOMadcGAHuvkxISL8/3xPy/D\nYA+1NgBqIFK/3OOXxp73Tv86bt1dgH7OD1ACO0mVXAoX5EaVzWZvdmMtMS11\nc2VyLWRmMjQwOWY0NWNhMTZmNTU3OGNkMzAxMyA8b3ZjLTEtdXNlci1kZjI0\nMDlmNDVjYTE2ZjU1NzhjZDMwMTNAZGYyNDA5ZjQ1Y2ExNmY1NTc4Y2QzMDEz\nLmNvbT7CjAQQEwgAHQUCZBsq9QQLCQcIAxUICgQWAAIBAhkBAhsDAh4BACEJ\nEOUeC7QrGL+2FiEEjN6vPUFRweVtDKFZ5R4LtCsYv7Z7oAEAvNKaJrTIs3ky\nbxjkUicsuxOyA2oWGarJH6TGlWF6WD8A/3EIeZzPKSLaW+3enpbCPiU8RVDp\nC6yo6NMAqKp4XlyQzlMEZBsq9RIFK4EEAAoCAwQWlWPNMpk3afEzfgG0xFg4\nCEjY7fGO35n47nZ4qxjEXz2XN4I23xFMiwZbXbptDXlqm7W9ZAHKi892h+Yt\nU4B6AwEIB8J4BBgTCAAJBQJkGyr1AhsMACEJEOUeC7QrGL+2FiEEjN6vPUFR\nweVtDKFZ5R4LtCsYv7YqZwD8DLRuneB0HEzBCyrE4YL+UHaofoHQX1+nRh0j\n82qaDzAA/i3U1SoEIi32YMrorNG50vb4vaEPbbYmfglb+JQ1Yx7ozjMEZBsq\n9RYJKwYBBAHaRw8BAQdAS1534LdCC60ASpEgnEBC8pWPSOWWBLXyWaBhEOW2\n/ijCeAQYEwgACQUCZBsq9QIbIAAhCRDlHgu0Kxi/thYhBIzerz1BUcHlbQyh\nWeUeC7QrGL+2FUYA/AgMU4V7C7I/5HwK73mctaGXNdfVr/muRMNOGW/CAxVL\nAP9KaBr95o32oEN5eo7tWFByoOCCk9JMjs36Cq7o+sR31A==\n=eZ3B\n-----END PGP PUBLIC KEY BLOCK-----\n',
},
},
2: {
gpgPubKey:
'-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nxk8EZBsrNBMFK4EEAAoCAwT2xXv/mG/daPdKGD/fHIUEE2ZtcK+njtCZtMEr\nkIubmUwe3Dj8+hQxt3SKaTxQbuD+WaLSj986QYUr4Zw4T+W3zWpvdmMtMi1i\nYWNrdXAtNTQ3YmJkZjMwOGMxZTYxY2Q5ZGI4NmU4IDxvdmMtMi1iYWNrdXAt\nNTQ3YmJkZjMwOGMxZTYxY2Q5ZGI4NmU4QDU0N2JiZGYzMDhjMWU2MWNkOWRi\nODZlOC5jb20+wowEEBMIAB0FAmQbKzQECwkHCAMVCAoEFgACAQIZAQIbAwIe\nAQAhCRC2Ak5G2Sk7ZRYhBLTpSkFOe3ajbqouerYCTkbZKTtlxtYBALLIBnAa\n4AS77XvXmmznNCWO/HNuDPD2ugRqVhqU4SxmAQDma14APuMNSVyi17xomZjW\n0nimtaMIBjc0A4MXE6G4Xc5TBGQbKzQSBSuBBAAKAgMEUHoQDY98y8CAVouu\ny4y3Q2QnBpnUBK/0PELV7VANXd9lY7CShyogJScgPliUm97Au9FC17vqZa1B\n5bBMJAdXVwMBCAfCeAQYEwgACQUCZBsrNAIbDAAhCRC2Ak5G2Sk7ZRYhBLTp\nSkFOe3ajbqouerYCTkbZKTtlR5wA/3zOFTSeXXRRemXl3hY10spxabE4O2J8\nZD2VRfjbDpZjAQDWg1W+jPbM2Htikd1N01V+zweNDhJEH65r0Qr8BlXh2w==\n=Ettu\n-----END PGP PUBLIC KEY BLOCK-----\n',
ovcToBitgoShare: {
publicShare:
'ecf95e9ba6f02c0bc4c2ab254565d21a1562059c8a1ab70d286fa04ae2c511e0491410b6d6fa8ab22e691bed7938a7adaabfa8d9d59aab9cc2c078cd37dde01b',
privateShare:
'-----BEGIN PGP MESSAGE-----\n\nwX4DUQ8XhGVGcTISAgMEe1nYNv9DnHl8HX8jNs3reGs5nPT2bNzGMCFL0N3P\nKLwGd8DBkDJIMpoClaAS/HTUTPTRzj4U1GShV79I+bbfTDBV6uhyfZ7a88dV\nRDTXl6rchFl/fmwLoXnqH+BDPEXytpAvKwDrAg55T/H7aop5QbfSsQErEv7X\nTpTLHHHflEEQL62p1Rnnq2kKvwJK7TY1g5RtPgYXH6GEs33DLulPeUs8UkKq\nTPLf2+1KCLYyzMwmSi8KEC8HJb0vAkXZAlZ1+DoZ2PfiIJcVnz7a3omjiP77\nhmC8phTcJ718UxIB09f8uic0/fM7FNu0JHFgRDA69zzeFYnZc2XNQg5hs/dZ\nZ8AitP4rnaAfprsq4rAEE/c3Trm9tzQHZPCqr/2s4LluyUMVJw==\n=IJZH\n-----END PGP MESSAGE-----\n',
vssProof: '309d2fef2272ad31375954b99a862742f22d8023eef9855b8ae26ea84e08bf5e',
i: 3,
j: 2,
uSig: '-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nxk8EZBsrNBMFK4EEAAoCAwT2xXv/mG/daPdKGD/fHIUEE2ZtcK+njtCZtMEr\nkIubmUwe3Dj8+hQxt3SKaTxQbuD+WaLSj986QYUr4Zw4T+W3zWpvdmMtMi1i\nYWNrdXAtNTQ3YmJkZjMwOGMxZTYxY2Q5ZGI4NmU4IDxvdmMtMi1iYWNrdXAt\nNTQ3YmJkZjMwOGMxZTYxY2Q5ZGI4NmU4QDU0N2JiZGYzMDhjMWU2MWNkOWRi\nODZlOC5jb20+wowEEBMIAB0FAmQbKzQECwkHCAMVCAoEFgACAQIZAQIbAwIe\nAQAhCRC2Ak5G2Sk7ZRYhBLTpSkFOe3ajbqouerYCTkbZKTtlxtYBALLIBnAa\n4AS77XvXmmznNCWO/HNuDPD2ugRqVhqU4SxmAQDma14APuMNSVyi17xomZjW\n0nimtaMIBjc0A4MXE6G4Xc5TBGQbKzQSBSuBBAAKAgMEUHoQDY98y8CAVouu\ny4y3Q2QnBpnUBK/0PELV7VANXd9lY7CShyogJScgPliUm97Au9FC17vqZa1B\n5bBMJAdXVwMBCAfCeAQYEwgACQUCZBsrNAIbDAAhCRC2Ak5G2Sk7ZRYhBLTp\nSkFOe3ajbqouerYCTkbZKTtlR5wA/3zOFTSeXXRRemXl3hY10spxabE4O2J8\nZD2VRfjbDpZjAQDWg1W+jPbM2Htikd1N01V+zweNDhJEH65r0Qr8BlXh284z\nBGQbKzQWCSsGAQQB2kcPAQEHQIVTmlt8a/fjJCY9UyP8J51eTPX9PMRF3/Hr\nBYwtfOZYwngEGBMIAAkFAmQbKzQCGyAAIQkQtgJORtkpO2UWIQS06UpBTnt2\no26qLnq2Ak5G2Sk7ZcthAQD4ek3aqUDEbhfRHolm4jFhIPIbb9hUJwuBR0R4\n+gvaeAEAk8uk5cEACeqmpdEF52oGx7jmGCoX73AIILYVcf9iMkI=\n=92Hf\n-----END PGP PUBLIC KEY BLOCK-----\n',
},
ovcToOvcShare: {
publicShare:
'ecf95e9ba6f02c0bc4c2ab254565d21a1562059c8a1ab70d286fa04ae2c511e0491410b6d6fa8ab22e691bed7938a7adaabfa8d9d59aab9cc2c078cd37dde01b',
privateShare:
'-----BEGIN PGP MESSAGE-----\n\nwX4D+F3vI962zVMSAgMENy2X9xDIOm1gwOfMdL/1vZjeMW/ile/f2dRIP2GV\nv4w60K92+mHI9yooU1VT77jZrVOcNK41DFNCF/fuoUU+VzBON0I1hHyXm2QJ\nwL+nNdvAXwRv7nSFD3ABUmRYdG71AFIWjW2L+1C2hxpsNlmdxffSsQHHT9uP\nBNpFYgQN77OUxcgrweSVrPyer1rCQ8o+QnoK2/hIx9PlJZkcl3uwF6TpBtjs\nqvRxThomoHyo0hJHG0vmI42Gq5u0tcSeU902efpCDaeJhPVOiqISoJ96wn0r\nFB3lYLSflOpCLAE7nsZJRoXA6akU7xMCMNA++d4tv6p98FQ+MZ6e9x6kiSw1\nM+VWj+PvN1dtQ8fNYwpJf7KBfD1w6ISMFDmewkDE7iBOXF6FLw==\n=+3Yc\n-----END PGP MESSAGE-----\n',
vssProof: '309d2fef2272ad31375954b99a862742f22d8023eef9855b8ae26ea84e08bf5e',
i: 1,
j: 2,
uSig: '-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nxk8EZBsrNBMFK4EEAAoCAwT2xXv/mG/daPdKGD/fHIUEE2ZtcK+njtCZtMEr\nkIubmUwe3Dj8+hQxt3SKaTxQbuD+WaLSj986QYUr4Zw4T+W3zWpvdmMtMi1i\nYWNrdXAtNTQ3YmJkZjMwOGMxZTYxY2Q5ZGI4NmU4IDxvdmMtMi1iYWNrdXAt\nNTQ3YmJkZjMwOGMxZTYxY2Q5ZGI4NmU4QDU0N2JiZGYzMDhjMWU2MWNkOWRi\nODZlOC5jb20+wowEEBMIAB0FAmQbKzQECwkHCAMVCAoEFgACAQIZAQIbAwIe\nAQAhCRC2Ak5G2Sk7ZRYhBLTpSkFOe3ajbqouerYCTkbZKTtlxtYBALLIBnAa\n4AS77XvXmmznNCWO/HNuDPD2ugRqVhqU4SxmAQDma14APuMNSVyi17xomZjW\n0nimtaMIBjc0A4MXE6G4Xc5TBGQbKzQSBSuBBAAKAgMEUHoQDY98y8CAVouu\ny4y3Q2QnBpnUBK/0PELV7VANXd9lY7CShyogJScgPliUm97Au9FC17vqZa1B\n5bBMJAdXVwMBCAfCeAQYEwgACQUCZBsrNAIbDAAhCRC2Ak5G2Sk7ZRYhBLTp\nSkFOe3ajbqouerYCTkbZKTtlR5wA/3zOFTSeXXRRemXl3hY10spxabE4O2J8\nZD2VRfjbDpZjAQDWg1W+jPbM2Htikd1N01V+zweNDhJEH65r0Qr8BlXh284z\nBGQbKzQWCSsGAQQB2kcPAQEHQNVGg0vPsfK1yJjFuDYB8Tj7CQRHKGAVEDcj\nh/QIqr0KwngEGBMIAAkFAmQbKzQCGyAAIQkQtgJORtkpO2UWIQS06UpBTnt2\no26qLnq2Ak5G2Sk7ZS9oAQCe2zJD5ItW2GEgAitnY+NrLBjbXI6+LY29GjRa\nf6yFTQD/cP0E1DleqXMjgfR+ewt6quVFMZebhr3tBr/H0Zv/9EA=\n=8ai+\n-----END PGP PUBLIC KEY BLOCK-----\n',
},
},
},
};
const expectedBitGoOutput = {
wallet: {
...ovcOutputJson,
state: 2,
platform: {
commonKeychain: bitGoKeyResult.commonKeychain,
walletGpgPubKeySigs: bitGoKeyResult.walletHSMGPGPublicKeySigs,
ovc: {
1: {
bitgoToOvcShare: {
i: 1,
j: 3,
publicShare: bitGoKeyResult.keyShares[0].publicShare,
privateShare: bitGoKeyResult.keyShares[0].privateShare,
paillierPublicKey: bitGoKeyResult.keyShares[0].paillierPublicKey,
vssProof: bitGoKeyResult.keyShares[0].vssProof,
},
},
2: {
bitgoToOvcShare: {
i: 2,
j: 3,
publicShare: bitGoKeyResult.keyShares[1].publicShare,
privateShare: bitGoKeyResult.keyShares[1].privateShare,
paillierPublicKey: bitGoKeyResult.keyShares[1].paillierPublicKey,
vssProof: bitGoKeyResult.keyShares[1].vssProof,
},
},
},
},
},
};
const platformOutput = await bitgo.coin('tsol').keychains().createTssBitGoKeyFromOvcShares(ovcOutputJson);
should.equal(platformOutput.bitGoKeyId, bitGoKeyResult.id);
should.deepEqual(platformOutput.bitGoOutputJsonForOvc, expectedBitGoOutput);
});
it('Should fail if the state is not 1', async function () {
const ovcOutputJson = {
tssVersion: '0.0.1',
walletType: 'tss',
coin: 'sol',
state: 0,
ovc: {
1: {
gpgPubKey:
'-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nxk8EZBsq9RMFK4EEAAoCAwRgDpgm1bptRT5yLOMadcGAHuvkxISL8/3xPy/D\nYA+1NgBqIFK/3OOXxp73Tv86bt1dgH7OD1ACO0mVXAoX5EaVzWZvdmMtMS11\nc2VyLWRmMjQwOWY0NWNhMTZmNTU3OGNkMzAxMyA8b3ZjLTEtdXNlci1kZjI0\nMDlmNDVjYTE2ZjU1NzhjZDMwMTNAZGYyNDA5ZjQ1Y2ExNmY1NTc4Y2QzMDEz\nLmNvbT7CjAQQEwgAHQUCZBsq9QQLCQcIAxUICgQWAAIBAhkBAhsDAh4BACEJ\nEOUeC7QrGL+2FiEEjN6vPUFRweVtDKFZ5R4LtCsYv7Z7oAEAvNKaJrTIs3ky\nbxjkUicsuxOyA2oWGarJH6TGlWF6WD8A/3EIeZzPKSLaW+3enpbCPiU8RVDp\nC6yo6NMAqKp4XlyQzlMEZBsq9RIFK4EEAAoCAwQWlWPNMpk3afEzfgG0xFg4\nCEjY7fGO35n47nZ4qxjEXz2XN4I23xFMiwZbXbptDXlqm7W9ZAHKi892h+Yt\nU4B6AwEIB8J4BBgTCAAJBQJkGyr1AhsMACEJEOUeC7QrGL+2FiEEjN6vPUFR\nweVtDKFZ5R4LtCsYv7YqZwD8DLRuneB0HEzBCyrE4YL+UHaofoHQX1+nRh0j\n82qaDzAA/i3U1SoEIi32YMrorNG50vb4vaEPbbYmfglb+JQ1Yx7o\n=vjgl\n-----END PGP PUBLIC KEY BLOCK-----\n',
ovcToBitgoShare: {
publicShare:
'07bfbb052a1f4b106b315bd5a9d6a71604653289f861320d9801881e952f8550753c89511a360e3b599d9f239a8d36a4956437ed0b152180e22cb94fb08fdc81',
privateShare:
'-----BEGIN PGP MESSAGE-----\n\nwX4DUQ8XhGVGcTISAgMEd/wQ/AhwIRsSf/6iHwmHKvEYAwfaLtTQotS6BwZm\naX00T7LumGIrNZzBgcggBKMl+8Omom8mX5sP8FUE451iZjBmXlkpHlpAqskS\nEi5SfjlsT31utoLaBLA7NjNSmyYHIiyfh6YnwfV5U72k6hhfpuDSsQGy8Yxp\nM2dVlN4uoO31zgQPf+fgJkZvAPwvjYLBL4O8hs21HGf0VvG99brk4xlFVRhw\nQnuPpM51GOs4vUtbLNSYnAuhU4ReXwwDV9Xu0MXAjfQMk2E3wQLGQ+82uv2B\n1hPD9nDHTtAdWrXd6ZjXFrG4Mf2MQBxySFvVSnFi6yStjfZeiKcD5Vg38PjG\nWg1O5N3/paq98HfH0Q4qNKGZljwo3oEQZzlYm2kVnI0PULoMYg==\n=ovAx\n-----END PGP MESSAGE-----\n',
vssProof: 'be8198c2cef94cb381aa8aa9277a0a46ba5a54b0ac9930034b4af66b1b805234',
i: 3,
j: 1,
uSig: '-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nxk8EZBsq9RMFK4EEAAoCAwRgDpgm1bptRT5yLOMadcGAHuvkxISL8/3xPy/D\nYA+1NgBqIFK/3OOXxp73Tv86bt1dgH7OD1ACO0mVXAoX5EaVzWZvdmMtMS11\nc2VyLWRmMjQwOWY0NWNhMTZmNTU3OGNkMzAxMyA8b3ZjLTEtdXNlci1kZjI0\nMDlmNDVjYTE2ZjU1NzhjZDMwMTNAZGYyNDA5ZjQ1Y2ExNmY1NTc4Y2QzMDEz\nLmNvbT7CjAQQEwgAHQUCZBsq9QQLCQcIAxUICgQWAAIBAhkBAhsDAh4BACEJ\nEOUeC7QrGL+2FiEEjN6vPUFRweVtDKFZ5R4LtCsYv7Z7oAEAvNKaJrTIs3ky\nbxjkUicsuxOyA2oWGarJH6TGlWF6WD8A/3EIeZzPKSLaW+3enpbCPiU8RVDp\nC6yo6NMAqKp4XlyQzlMEZBsq9RIFK4EEAAoCAwQWlWPNMpk3afEzfgG0xFg4\nCEjY7fGO35n47nZ4qxjEXz2XN4I23xFMiwZbXbptDXlqm7W9ZAHKi892h+Yt\nU4B6AwEIB8J4BBgTCAAJBQJkGyr1AhsMACEJEOUeC7QrGL+2FiEEjN6vPUFR\nweVtDKFZ5R4LtCsYv7YqZwD8DLRuneB0HEzBCyrE4YL+UHaofoHQX1+nRh0j\n82qaDzAA/i3U1SoEIi32YMrorNG50vb4vaEPbbYmfglb+JQ1Yx7ozjMEZBsq\n9RYJKwYBBAHaRw8BAQdAS1534LdCC60ASpEgnEBC8pWPSOWWBLXyWaBhEOW2\n/ijCeAQYEwgACQUCZBsq9QIbIAAhCRDlHgu0Kxi/thYhBIzerz1BUcHlbQyh\nWeUeC7QrGL+2FUYA/AgMU4V7C7I/5HwK73mctaGXNdfVr/muRMNOGW/CAxVL\nAP9KaBr95o32oEN5eo7tWFByoOCCk9JMjs36Cq7o+sR31A==\n=eZ3B\n-----END PGP PUBLIC KEY BLOCK-----\n',
},
},
2: {
gpgPubKey:
'-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nxk8EZBsrNBMFK4EEAAoCAwT2xXv/mG/daPdKGD/fHIUEE2ZtcK+njtCZtMEr\nkIubmUwe3Dj8+hQxt3SKaTxQbuD+WaLSj986QYUr4Zw4T+W3zWpvdmMtMi1i\nYWNrdXAtNTQ3YmJkZjMwOGMxZTYxY2Q5ZGI4NmU4IDxvdmMtMi1iYWNrdXAt\nNTQ3YmJkZjMwOGMxZTYxY2Q5ZGI4NmU4QDU0N2JiZGYzMDhjMWU2MWNkOWRi\nODZlOC5jb20+wowEEBMIAB0FAmQbKzQECwkHCAMVCAoEFgACAQIZAQIbAwIe\nAQAhCRC2Ak5G2Sk7ZRYhBLTpSkFOe3ajbqouerYCTkbZKTtlxtYBALLIBnAa\n4AS77XvXmmznNCWO/HNuDPD2ugRqVhqU4SxmAQDma14APuMNSVyi17xomZjW\n0nimtaMIBjc0A4MXE6G4Xc5TBGQbKzQSBSuBBAAKAgMEUHoQDY98y8CAVouu\ny4y3Q2QnBpnUBK/0PELV7VANXd9lY7CShyogJScgPliUm97Au9FC17vqZa1B\n5bBMJAdXVwMBCAfCeAQYEwgACQUCZBsrNAIbDAAhCRC2Ak5G2Sk7ZRYhBLTp\nSkFOe3ajbqouerYCTkbZKTtlR5wA/3zOFTSeXXRRemXl3hY10spxabE4O2J8\nZD2VRfjbDpZjAQDWg1W+jPbM2Htikd1N01V+zweNDhJEH65r0Qr8BlXh2w==\n=Ettu\n-----END PGP PUBLIC KEY BLOCK-----\n',
ovcToBitgoShare: {
publicShare:
'ecf95e9ba6f02c0bc4c2ab254565d21a1562059c8a1ab70d286fa04ae2c511e0491410b6d6fa8ab22e691bed7938a7adaabfa8d9d59aab9cc2c078cd37dde01b',
privateShare:
'-----BEGIN PGP MESSAGE-----\n\nwX4DUQ8XhGVGcTISAgMEe1nYNv9DnHl8HX8jNs3reGs5nPT2bNzGMCFL0N3P\nKLwGd8DBkDJIMpoClaAS/HTUTPTRzj4U1GShV79I+bbfTDBV6uhyfZ7a88dV\nRDTXl6rchFl/fmwLoXnqH+BDPEXytpAvKwDrAg55T/H7aop5QbfSsQErEv7X\nTpTLHHHflEEQL62p1Rnnq2kKvwJK7TY1g5RtPgYXH6GEs33DLulPeUs8UkKq\nTPLf2+1KCLYyzMwmSi8KEC8HJb0vAkXZAlZ1+DoZ2PfiIJcVnz7a3omjiP77\nhmC8phTcJ718UxIB09f8uic0/fM7FNu0JHFgRDA69zzeFYnZc2XNQg5hs/dZ\nZ8AitP4rnaAfprsq4rAEE/c3Trm9tzQHZPCqr/2s4LluyUMVJw==\n=IJZH\n-----END PGP MESSAGE-----\n',
vssProof: '309d2fef2272ad31375954b99a862742f22d8023eef9855b8ae26ea84e08bf5e',
i: 3,
j: 2,
uSig: '-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nxk8EZBsrNBMFK4EEAAoCAwT2xXv/mG/daPdKGD/fHIUEE2ZtcK+njtCZtMEr\nkIubmUwe3Dj8+hQxt3SKaTxQbuD+WaLSj986QYUr4Zw4T+W3zWpvdmMtMi1i\nYWNrdXAtNTQ3YmJkZjMwOGMxZTYxY2Q5ZGI4NmU4IDxvdmMtMi1iYWNrdXAt\nNTQ3YmJkZjMwOGMxZTYxY2Q5ZGI4NmU4QDU0N2JiZGYzMDhjMWU2MWNkOWRi\nODZlOC5jb20+wowEEBMIAB0FAmQbKzQECwkHCAMVCAoEFgACAQIZAQIbAwIe\nAQAhCRC2Ak5G2Sk7ZRYhBLTpSkFOe3ajbqouerYCTkbZKTtlxtYBALLIBnAa\n4AS77XvXmmznNCWO/HNuDPD2ugRqVhqU4SxmAQDma14APuMNSVyi17xomZjW\n0nimtaMIBjc0A4MXE6G4Xc5TBGQbKzQSBSuBBAAKAgMEUHoQDY98y8CAVouu\ny4y3Q2QnBpnUBK/0PELV7VANXd9lY7CShyogJScgPliUm97Au9FC17vqZa1B\n5bBMJAdXVwMBCAfCeAQYEwgACQUCZBsrNAIbDAAhCRC2Ak5G2Sk7ZRYhBLTp\nSkFOe3ajbqouerYCTkbZKTtlR5wA/3zOFTSeXXRRemXl3hY10spxabE4O2J8\nZD2VRfjbDpZjAQDWg1W+jPbM2Htikd1N01V+zweNDhJEH65r0Qr8BlXh284z\nBGQbKzQWCSsGAQQB2kcPAQEHQIVTmlt8a/fjJCY9UyP8J51eTPX9PMRF3/Hr\nBYwtfOZYwngEGBMIAAkFAmQbKzQCGyAAIQkQtgJORtkpO2UWIQS06UpBTnt2\no26qLnq2Ak5G2Sk7ZcthAQD4ek3aqUDEbhfRHolm4jFhIPIbb9hUJwuBR0R4\n+gvaeAEAk8uk5cEACeqmpdEF52oGx7jmGCoX73AIILYVcf9iMkI=\n=92Hf\n-----END PGP PUBLIC KEY BLOCK-----\n',
},
ovcToOvcShare: {
publicShare:
'ecf95e9ba6f02c0bc4c2ab254565d21a1562059c8a1ab70d286fa04ae2c511e0491410b6d6fa8ab22e691bed7938a7adaabfa8d9d59aab9cc2c078cd37dde01b',
privateShare:
'-----BEGIN PGP MESSAGE-----\n\nwX4D+F3vI962zVMSAgMENy2X9xDIOm1gwOfMdL/1vZjeMW/ile/f2dRIP2GV\nv4w60K92+mHI9yooU1VT77jZrVOcNK41DFNCF/fuoUU+VzBON0I1hHyXm2QJ\nwL+nNdvAXwRv7nSFD3ABUmRYdG71AFIWjW2L+1C2hxpsNlmdxffSsQHHT9uP\nBNpFYgQN77OUxcgrweSVrPyer1rCQ8o+QnoK2/hIx9PlJZkcl3uwF6TpBtjs\nqvRxThomoHyo0hJHG0vmI42Gq5u0tcSeU902efpCDaeJhPVOiqISoJ96wn0r\nFB3lYLSflOpCLAE7nsZJRoXA6akU7xMCMNA++d4tv6p98FQ+MZ6e9x6kiSw1\nM+VWj+PvN1dtQ8fNYwpJf7KBfD1w6ISMFDmewkDE7iBOXF6FLw==\n=+3Yc\n-----END PGP MESSAGE-----\n',
vssProof: '309d2fef2272ad31375954b99a862742f22d8023eef9855b8ae26ea84e08bf5e',
i: 1,
j: 2,
uSig: '-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nxk8EZBsrNBMFK4EEAAoCAwT2xXv/mG/daPdKGD/fHIUEE2ZtcK+njtCZtMEr\nkIubmUwe3Dj8+hQxt3SKaTxQbuD+WaLSj986QYUr4Zw4T+W3zWpvdmMtMi1i\nYWNrdXAtNTQ3YmJkZjMwOGMxZTYxY2Q5ZGI4NmU4IDxvdmMtMi1iYWNrdXAt\nNTQ3YmJkZjMwOGMxZTYxY2Q5ZGI4NmU4QDU0N2JiZGYzMDhjMWU2MWNkOWRi\nODZlOC5jb20+wowEEBMIAB0FAmQbKzQECwkHCAMVCAoEFgACAQIZAQIbAwIe\nAQAhCRC2Ak5G2Sk7ZRYhBLTpSkFOe3ajbqouerYCTkbZKTtlxtYBALLIBnAa\n4AS77XvXmmznNCWO/HNuDPD2ugRqVhqU4SxmAQDma14APuMNSVyi17xomZjW\n0nimtaMIBjc0A4MXE6G4Xc5TBGQbKzQSBSuBBAAKAgMEUHoQDY98y8CAVouu\ny4y3Q2QnBpnUBK/0PELV7VANXd9lY7CShyogJScgPliUm97Au9FC17vqZa1B\n5bBMJAdXVwMBCAfCeAQYEwgACQUCZBsrNAIbDAAhCRC2Ak5G2Sk7ZRYhBLTp\nSkFOe3ajbqouerYCTkbZKTtlR5wA/3zOFTSeXXRRemXl3hY10spxabE4O2J8\nZD2VRfjbDpZjAQDWg1W+jPbM2Htikd1N01V+zweNDhJEH65r0Qr8BlXh284z\nBGQbKzQWCSsGAQQB2kcPAQEHQNVGg0vPsfK1yJjFuDYB8Tj7CQRHKGAVEDcj\nh/QIqr0KwngEGBMIAAkFAmQbKzQCGyAAIQkQtgJORtkpO2UWIQS06UpBTnt2\no26qLnq2Ak5G2Sk7ZS9oAQCe2zJD5ItW2GEgAitnY+NrLBjbXI6+LY29GjRa\nf6yFTQD/cP0E1DleqXMjgfR+ewt6quVFMZebhr3tBr/H0Zv/9EA=\n=8ai+\n-----END PGP PUBLIC KEY BLOCK-----\n',
},
},
},
};
await bitgo
.coin('tsol')
.keychains()
.createTssBitGoKeyFromOvcShares(ovcOutputJson)
.should.be.rejectedWith('State expected to be "1". Please complete the first two OVC operations');
});
it('Fails to decode if the OVC json is missing fields', async function () {
const ovcOutputJson = {
tssVersion: '0.0.1',
state: 1,
coin: 'tsol',
ovc: {
1: {
gpgPubKey:
'-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nxk8EZBsq9RMFK4EEAAoCAwRgDpgm1bptRT5yLOMadcGAHuvkxISL8/3xPy/D\nYA+1NgBqIFK/3OOXxp73Tv86bt1dgH7OD1ACO0mVXAoX5EaVzWZvdmMtMS11\nc2VyLWRmMjQwOWY0NWNhMTZmNTU3OGNkMzAxMyA8b3ZjLTEtdXNlci1kZjI0\nMDlmNDVjYTE2ZjU1NzhjZDMwMTNAZGYyNDA5ZjQ1Y2ExNmY1NTc4Y2QzMDEz\nLmNvbT7CjAQQEwgAHQUCZBsq9QQLCQcIAxUICgQWAAIBAhkBAhsDAh4BACEJ\nEOUeC7QrGL+2FiEEjN6vPUFRweVtDKFZ5R4LtCsYv7Z7oAEAvNKaJrTIs3ky\nbxjkUicsuxOyA2oWGarJH6TGlWF6WD8A/3EIeZzPKSLaW+3enpbCPiU8RVDp\nC6yo6NMAqKp4XlyQzlMEZBsq9RIFK4EEAAoCAwQWlWPNMpk3afEzfgG0xFg4\nCEjY7fGO35n47nZ4qxjEXz2XN4I23xFMiwZbXbptDXlqm7W9ZAHKi892h+Yt\nU4B6AwEIB8J4BBgTCAAJBQJkGyr1AhsMACEJEOUeC7QrGL+2FiEEjN6vPUFR\nweVtDKFZ5R4LtCsYv7YqZwD8DLRuneB0HEzBCyrE4YL+UHaofoHQX1+nRh0j\n82qaDzAA/i3U1SoEIi32YMrorNG50vb4vaEPbbYmfglb+JQ1Yx7o\n=vjgl\n-----END PGP PUBLIC KEY BLOCK-----\n',
ovcToBitgoShare: {
publicShare:
'07bfbb052a1f4b106b315bd5a9d6a71604653289f861320d9801881e952f8550753c89511a360e3b599d9f239a8d36a4956437ed0b152180e22cb94fb08fdc81',
privateShare:
'-----BEGIN PGP MESSAGE-----\n\nwX4DUQ8XhGVGcTISAgMEd/wQ/AhwIRsSf/6iHwmHKvEYAwfaLtTQotS6BwZm\naX00T7LumGIrNZzBgcggBKMl+8Omom8mX5sP8FUE451iZjBmXlkpHlpAqskS\nEi5SfjlsT31utoLaBLA7NjNSmyYHIiyfh6YnwfV5U72k6hhfpuDSsQGy8Yxp\nM2dVlN4uoO31zgQPf+fgJkZvAPwvjYLBL4O8hs21HGf0VvG99brk4xlFVRhw\nQnuPpM51GOs4vUtbLNSYnAuhU4ReXwwDV9Xu0MXAjfQMk2E3wQLGQ+82uv2B\n1hPD9nDHTtAdWrXd6ZjXFrG4Mf2MQBxySFvVSnFi6yStjfZeiKcD5Vg38PjG\nWg1O5N3/paq98HfH0Q4qNKGZljwo3oEQZzlYm2kVnI0PULoMYg==\n=ovAx\n-----END PGP MESSAGE-----\n',
vssProof: 'be8198c2cef94cb381aa8aa9277a0a46ba5a54b0ac9930034b4af66b1b805234',
i: 3,
j: 1,
uSig: '-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nxk8EZBsq9RMFK4EEAAoCAwRgDpgm1bptRT5yLOMadcGAHuvkxISL8/3xPy/D\nYA+1NgBqIFK/3OOXxp73Tv86bt1dgH7OD1ACO0mVXAoX5EaVzWZvdmMtMS11\nc2VyLWRmMjQwOWY0NWNhMTZmNTU3OGNkMzAxMyA8b3ZjLTEtdXNlci1kZjI0\nMDlmNDVjYTE2ZjU1NzhjZDMwMTNAZGYyNDA5ZjQ1Y2ExNmY1NTc4Y2QzMDEz\nLmNvbT7CjAQQEwgAHQUCZBsq9QQLCQcIAxUICgQWAAIBAhkBAhsDAh4BACEJ\nEOUeC7QrGL+2FiEEjN6vPUFRweVtDKFZ5R4LtCsYv7Z7oAEAvNKaJrTIs3ky\nbxjkUicsuxOyA2oWGarJH6TGlWF6WD8A/3EIeZzPKSLaW+3enpbCPiU8RVDp\nC6yo6NMAqKp4XlyQzlMEZBsq9RIFK4EEAAoCAwQWlWPNMpk3afEzfgG0xFg4\nCEjY7fGO35n47nZ4qxjEXz2XN4I23xFMiwZbXbptDXlqm7W9ZAHKi892h+Yt\nU4B6AwEIB8J4BBgTCAAJBQJkGyr1AhsMACEJEOUeC7QrGL+2FiEEjN6vPUFR\nweVtDKFZ5R4LtCsYv7YqZwD8DLRuneB0HEzBCyrE4YL+UHaofoHQX1+nRh0j\n82qaDzAA/i3U1SoEIi32YMrorNG50vb4vaEPbbYmfglb+JQ1Yx7ozjMEZBsq\n9RYJKwYBBAHaRw8BAQdAS1534LdCC60ASpEgnEBC8pWPSOWWBLXyWaBhEOW2\n/ijCeAQYEwgACQUCZBsq9QIbIAAhCRDlHgu0Kxi/thYhBIzerz1BUcHlbQyh\nWeUeC7QrGL+2FUYA/AgMU4V7C7I/5HwK73mctaGXNdfVr/muRMNOGW/CAxVL\nAP9KaBr95o32oEN5eo7tWFByoOCCk9JMjs36Cq7o+sR31A==\n=eZ3B\n-----END PGP PUBLIC KEY BLOCK-----\n',
},
},
},
};
await bitgo.coin('tsol').keychains().createTssBitGoKeyFromOvcShares(ovcOutputJson).should.be.rejected();
});
it('OvcShare codec decodes correctly', async function () {
const test = {
publicShare:
'07bfbb052a1f4b106b315bd5a9d6a71604653289f861320d9801881e952f8550753c89511a360e3b599d9f239a8d36a4956437ed0b152180e22cb94fb08fdc81',
privateShare:
'-----BEGIN PGP MESSAGE-----\n\nwX4DUQ8XhGVGcTISAgMEd/wQ/AhwIRsSf/6iHwmHKvEYAwfaLtTQotS6BwZm\naX00T7LumGIrNZzBgcggBKMl+8Omom8mX5sP8FUE451iZjBmXlkpHlpAqskS\nEi5SfjlsT31utoLaBLA7NjNSmyYHIiyfh6YnwfV5U72k6hhfpuDSsQGy8Yxp\nM2dVlN4uoO31zgQPf+fgJkZvAPwvjYLBL4O8hs21HGf0VvG99brk4xlFVRhw\nQnuPpM51GOs4vUtbLNSYnAuhU4ReXwwDV9Xu0MXAjfQMk2E3wQLGQ+82uv2B\n1hPD9nDHTtAdWrXd6ZjXFrG4Mf2MQBxySFvVSnFi6yStjfZeiKcD5Vg38PjG\nWg1O5N3/paq98HfH0Q4qNKGZljwo3oEQZzlYm2kVnI0PULoMYg==\n=ovAx\n-----END PGP MESSAGE-----\n',
vssProof: 'be8198c2cef94cb381aa8aa9277a0a46ba5a54b0ac9930034b4af66b1b805234',
i: 3,
j: 1,
};
const decodedRes = decodeOrElse(OvcShare.name, OvcShare, test, (errors) => {
throw new Error(`error(s) parsing parsing json: ${errors}`);
});
assert(decodedRes);
});
});
it('should generate backup without encryptedPrv when passphrase not provided', async () => {
const scope = nock(bgUrl)
.post('/api/v2/tltc/key', (body) => {
return body.encryptedPrv === undefined && body.prv === undefined;
})
.reply(200);
const backup = await keychains.createBackup({});
scope.isDone().should.be.true();
backup.should.not.have.property('encryptedPrv');
backup.should.have.property('prv');
});
it('should generate backup and call endpoint with encryptedPrv when passphrase is provided', async () => {
const scope = nock(bgUrl)
.post('/api/v2/tltc/key', (body) => {
return body.encryptedPrv !== undefined && body.prv === undefined;
})
.reply(200);
const backup = await keychains.createBackup({ passphrase: 't3stSicretly!' });
scope.isDone().should.be.true();
backup.should.have.property('encryptedPrv');
const decryptedPrv = bitgo.decrypt({ input: backup.encryptedPrv, password: 't3stSicretly!' });
decryptedPrv.should.startWith('xprv');
});
});
Выполнить команду
Для локальной разработки. Не используйте в интернете!