Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(root): multisig eddsa root keys test #4268

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .iyarc
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# false positive

GHSA-8x6c-cv3v-vp6g
GHSA-78xj-cgh5-2h22

## https://github.com/github/advisory-database/pull/1693
2 changes: 1 addition & 1 deletion examples/js/backup-key-creation.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const coin = 'btc';
// Create the wallet
Promise.coroutine(function* () {
// this function takes one parameter - seed - if you want to create from your own entropy (recommended)
const backupKey = bitgo.coin(coin).keychains().create();
const backupKey = yield bitgo.coin(coin).keychains().create();

console.log('BACK THIS UP: ');
console.log(`Pub - this is what you add in the browser under the I have a backup key option: ${backupKey.pub}`);
Expand Down
2 changes: 1 addition & 1 deletion examples/ts/backup-key-creation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ bitgo.register(coin, Tbtc.createInstance);
// Create the wallet
async function main() {
// this function takes one parameter - seed - if you want to create from your own entropy (recommended)
const backupKey = bitgo.coin(coin).keychains().create();
const backupKey = await bitgo.coin(coin).keychains().create();

console.log('BACK THIS UP: ');
console.log(`Pub - this is what you add in the browser under the I have a backup key option: ${backupKey.pub}`);
Expand Down
2 changes: 1 addition & 1 deletion modules/abstract-cosmos/src/cosmosCoin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -583,7 +583,7 @@ export class CosmosCoin extends BaseCoin {
}

/** @inheritDoc **/
generateKeyPair(seed?: Buffer): KeyPair {
async generateKeyPair(seed?: Buffer): Promise<KeyPair> {
if (!seed) {
// An extended private key has both a normal 256 bit private key and a 256
// bit chain code, both of which must be random. 512 bits is therefore the
Expand Down
2 changes: 1 addition & 1 deletion modules/abstract-eth/src/abstractEthLikeCoin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ export abstract class AbstractEthLikeCoin extends BaseCoin {
return isValidEthAddress(address);
}

generateKeyPair(seed?: Buffer): KeyPair {
async generateKeyPair(seed?: Buffer): Promise<KeyPair> {
const extendedKey = bip32.fromSeed(seed || randomBytes(32));
const xpub = extendedKey.neutered().toBase58();

Expand Down
4 changes: 2 additions & 2 deletions modules/abstract-eth/src/abstractEthLikeNewCoins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2011,7 +2011,7 @@ export abstract class AbstractEthLikeNewCoins extends AbstractEthLikeCoin {
const walletPassphrase = buildParams.walletPassphrase;

const userKeychain = await this.keychains().get({ id: wallet.keyIds()[0] });
const userPrv = wallet.getUserPrv({ keychain: userKeychain, walletPassphrase });
const userPrv = await wallet.getUserPrv({ keychain: userKeychain, walletPassphrase });
const userPrvBuffer = bip32.fromBase58(userPrv).privateKey;
if (!userPrvBuffer) {
throw new Error('invalid userPrv');
Expand Down Expand Up @@ -2222,7 +2222,7 @@ export abstract class AbstractEthLikeNewCoins extends AbstractEthLikeCoin {
* @param {Buffer} seed
* @returns {KeyPair} object with generated pub and prv
*/
generateKeyPair(seed: Buffer): KeyPair {
async generateKeyPair(seed?: Buffer): Promise<KeyPair> {
if (!seed) {
// An extended private key has both a normal 256 bit private key and a 256
// bit chain code, both of which must be random. 512 bits is therefore the
Expand Down
2 changes: 1 addition & 1 deletion modules/abstract-utxo/src/abstractUtxoCoin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1450,7 +1450,7 @@ export abstract class AbstractUtxoCoin extends BaseCoin {
* @param seed
* @returns {Object} object with generated pub and prv
*/
generateKeyPair(seed: Buffer): { pub: string; prv: string } {
async generateKeyPair(seed?: Buffer): Promise<{ pub: string; prv: string }> {
if (!seed) {
// An extended private key has both a normal 256 bit private key and a 256
// bit chain code, both of which must be random. 512 bits is therefore the
Expand Down
17 changes: 17 additions & 0 deletions modules/account-lib/test/resources/eddsaKeyDeriver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
export const data = {
seed: {
validSeed:
'e3e670f488500f300790bee3fc2fb075d82d279459fa53024168664aec73054f2f5a0abfcd5889100604b0c22a430c4f9e1ac92b43675ca7cef0f9550acd2afa',
expectedRootKeys: {
prv: 'rprvb047f0d8b29083e1933102983d3c611cbf3364039cf3c985730e242488936070:2f5a0abfcd5889100604b0c22a430c4f9e1ac92b43675ca7cef0f9550acd2afa:049aa12f8beaf88eb1a404e4fc5a7ad290accd5b6bb37fa497f2e3bd56fa5990',
pub: 'rpubf008e38df59581e2851939f035bebbb18755fcb9d3864eb2aaa22be060ede6:2f5a0abfcd5889100604b0c22a430c4f9e1ac92b43675ca7cef0f9550acd2afa',
},
},
rootKeys1: {
prv: 'rprvb00584090478b47d1d1bf45ee8bbd012ec3634ec5eb40fb944c22602daac8979:427b2e97eeab94519d08e651b48d3df9326e9b22615f7655ad8c256659ec45af:838b4de99dcaf2392cec3222b29146816b1d3dfc1a7cad0695959a53ec23fa77',
pub: 'rpub6b0de9d546d71d95a04a9cfe0b6b8cd2f5da4961c6170ff5e8b7d27098e3a909:427b2e97eeab94519d08e651b48d3df9326e9b22615f7655ad8c256659ec45af',
derivedPub: '8beba02ca52fcb799134bc5698ee7f2b9e4e254749ea6baa65d7ddfbab82e330',
derivedPrv:
'dd6122533efd21fece9248f54e82b812d16996b47726f8cadc2a20f1ddac89098beba02ca52fcb799134bc5698ee7f2b9e4e254749ea6baa65d7ddfbab82e330',
},
};
74 changes: 74 additions & 0 deletions modules/account-lib/test/unit/utils/eddsaKeyDeriver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import assert from 'assert';
import { EddsaKeyDeriver } from '@bitgo/sdk-core';
import { data } from '../../resources/eddsaKeyDeriver';

describe('EddsaKeyDeriver', () => {
describe('createRootKeys', () => {
it('should create root keys without seed', async () => {
const rootKeys = await EddsaKeyDeriver.createRootKeys();

assert.ok(rootKeys.prv);
assert.equal(rootKeys.prv.length, data.rootKeys1.prv.length);
assert.ok(rootKeys.prv.startsWith(EddsaKeyDeriver.ROOT_PRV_KEY_PREFIX));
assert.ok(rootKeys.pub);
assert.equal(rootKeys.pub.length, data.rootKeys1.pub.length);
assert.ok(rootKeys.pub.startsWith(EddsaKeyDeriver.ROOT_PUB_KEY_PREFIX));
});

it('should create root keys with seed', async () => {
const seed = Buffer.from(data.seed.validSeed, 'hex');
const rootKeys = await EddsaKeyDeriver.createRootKeys(seed);

assert.ok(rootKeys.prv);
assert.equal(rootKeys.prv, data.seed.expectedRootKeys.prv);
assert.ok(rootKeys.pub);
assert.equal(rootKeys.pub, data.seed.expectedRootKeys.pub);
});

it('should throw for invalid seed', async () => {
const seed = Buffer.from('asdf12f1', 'hex');

assert.rejects(
async () => {
await EddsaKeyDeriver.createRootKeys(seed);
},
{ message: 'Invalid seed' },
);
});
});

describe('deriveKeyWithSeed', () => {
const seed = 'seed123';
const expectedPath = 'm/999999/240510315/85914100';
it('should derive a pub key and path from for root public key with seed', async () => {
const rootPubKey = data.rootKeys1.pub;

const derivedKey = await EddsaKeyDeriver.deriveKeyWithSeed(rootPubKey, seed);

assert.equal(derivedKey.key.length, 64);
assert.equal(derivedKey.key, data.rootKeys1.derivedPub);
assert.equal(derivedKey.derivationPath, expectedPath);
});

it('should derive a private key and path from for root private key with seed', async () => {
const rootPrvKey = data.rootKeys1.prv;

const derivedKey = await EddsaKeyDeriver.deriveKeyWithSeed(rootPrvKey, seed);

assert.equal(derivedKey.key.length, 128);
assert.equal(derivedKey.key, data.rootKeys1.derivedPrv);
assert.equal(derivedKey.derivationPath, expectedPath);
});

it('should throw an error for invalid key format', async () => {
const invalidKey = 'invalid:key:format';

await assert.rejects(
async () => {
await EddsaKeyDeriver.deriveKeyWithSeed(invalidKey, seed);
},
{ message: 'Invalid key format' },
);
});
});
});
8 changes: 4 additions & 4 deletions modules/bitgo/test/v2/unit/coins/abstractEthCoin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,16 +197,16 @@ describe('ETH-like coins', () => {
});

describe('Generate keypair', () => {
it('Should generate valid keypair without seed', () => {
const { pub, prv } = basecoin.generateKeyPair();
it('Should generate valid keypair without seed', async () => {
const { pub, prv } = await basecoin.generateKeyPair();
basecoin.isValidPub(pub).should.equal(true);
const bitgoKey = bip32.fromBase58(prv);
basecoin.isValidPub(bitgoKey.neutered().toBase58()).should.equal(true);
});

it('Should generate valid keypair with seed', () => {
it('Should generate valid keypair with seed', async () => {
const seed = Buffer.from('c3b09c24731be2851b641d9d5b3f60fa129695c24071768d15654bea207b7bb6', 'hex');
const { pub, prv } = basecoin.generateKeyPair(seed);
const { pub, prv } = await basecoin.generateKeyPair(seed);
basecoin.isValidPub(pub).should.equal(true);
const bitgoKey = bip32.fromBase58(prv);
basecoin.isValidPub(bitgoKey.neutered().toBase58()).should.equal(true);
Expand Down
26 changes: 13 additions & 13 deletions modules/bitgo/test/v2/unit/coins/abstractUtxoCoin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,20 +117,20 @@ describe('Abstract UTXO Coin:', () => {
});
});

describe('Custom Change Wallets', () => {
describe('Custom Change Wallets', async () => {
const bitgo: BitGo = TestBitGo.decorate(BitGo, { env: 'mock' });
const coin = bitgo.coin('tbtc') as AbstractUtxoCoin;

const keys = {
send: {
user: { id: '0', key: coin.keychains().create() },
backup: { id: '1', key: coin.keychains().create() },
bitgo: { id: '2', key: coin.keychains().create() },
user: { id: '0', key: await coin.keychains().create() },
backup: { id: '1', key: await coin.keychains().create() },
bitgo: { id: '2', key: await coin.keychains().create() },
},
change: {
user: { id: '3', key: coin.keychains().create() },
backup: { id: '4', key: coin.keychains().create() },
bitgo: { id: '5', key: coin.keychains().create() },
user: { id: '3', key: await coin.keychains().create() },
backup: { id: '4', key: await coin.keychains().create() },
bitgo: { id: '5', key: await coin.keychains().create() },
},
};

Expand Down Expand Up @@ -247,17 +247,17 @@ describe('Abstract UTXO Coin:', () => {
});
});

describe('Verify Transaction', () => {
describe('Verify Transaction', async () => {
const bitgo: BitGo = TestBitGo.decorate(BitGo, { env: 'mock' });
const coin = bitgo.coin('tbtc') as AbstractUtxoCoin;

const userKeychain = coin.keychains().create();
const otherKeychain = coin.keychains().create();
const userKeychain = await coin.keychains().create();
const otherKeychain = await coin.keychains().create();

const changeKeys = {
user: coin.keychains().create(),
backup: coin.keychains().create(),
bitgo: coin.keychains().create(),
user: await coin.keychains().create(),
backup: await coin.keychains().create(),
bitgo: await coin.keychains().create(),
};

// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
Expand Down
4 changes: 2 additions & 2 deletions modules/bitgo/test/v2/unit/coins/ofc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ describe('OFC:', function () {
ofcCoin.isValidMofNSetup({ m: 1, n: 1 }).should.be.true();
});

it('should validate pub key', () => {
const { pub } = ofcCoin.keychains().create();
it('should validate pub key', async () => {
const { pub } = await ofcCoin.keychains().create();
ofcCoin.isValidPub(pub).should.equal(true);
});
});
4 changes: 2 additions & 2 deletions modules/bitgo/test/v2/unit/coins/utxo/keychains.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import { utxoCoins } from './util';

function run(coin: AbstractUtxoCoin) {
describe(`UTXO Keychains ${coin.getChain()}`, function () {
it('validates pub', function () {
const { pub } = coin.keychains().create();
it('validates pub', async function () {
const { pub } = await coin.keychains().create();
assert(pub);
coin.isValidPub(pub).should.equal(true);
});
Expand Down
22 changes: 11 additions & 11 deletions modules/bitgo/test/v2/unit/internal/blsUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ describe('BLS Utils:', async function () {
const coinName = 'eth2';

before(async function () {
bitgoKeyShare = eth2.generateKeyPair();
bitgoKeyShare = await eth2.generateKeyPair();

const bitGoGPGKey = await openpgp.generateKey({
userIDs: [
Expand All @@ -45,11 +45,11 @@ describe('BLS Utils:', async function () {

it('should generate BLS-DKG key chains', async function () {
const userKeyShare: IBlsKeyPair = {
...eth2.generateKeyPair(),
...(await eth2.generateKeyPair()),
chaincode: '0',
};
const backupKeyShare: IBlsKeyPair = {
...eth2.generateKeyPair(),
...(await eth2.generateKeyPair()),
chaincode: '0',
};
const userGpgKey = await openpgp.generateKey({
Expand Down Expand Up @@ -126,8 +126,8 @@ describe('BLS Utils:', async function () {
const enterprise = 'enterprise';
const originalPasscodeEncryptionCode = 'originalPasscodeEncryptionCode';

const userKeyShare: IBlsKeyPair = { ...eth2.generateKeyPair(), chaincode: '0' };
const backupKeyShare: IBlsKeyPair = { ...eth2.generateKeyPair(), chaincode: '0' };
const userKeyShare: IBlsKeyPair = { ...(await eth2.generateKeyPair()), chaincode: '0' };
const backupKeyShare: IBlsKeyPair = { ...(await eth2.generateKeyPair()), chaincode: '0' };
const userGpgKey = await openpgp.generateKey({
userIDs: [
{
Expand Down Expand Up @@ -206,8 +206,8 @@ describe('BLS Utils:', async function () {
});

it('should fail to generate BLS-DKG key chains', async function () {
const userKeyShare: IBlsKeyPair = { ...eth2.generateKeyPair(), chaincode: '0' };
const backupKeyShare: IBlsKeyPair = { ...eth2.generateKeyPair(), chaincode: '0' };
const userKeyShare: IBlsKeyPair = { ...(await eth2.generateKeyPair()), chaincode: '0' };
const backupKeyShare: IBlsKeyPair = { ...(await eth2.generateKeyPair()), chaincode: '0' };
const userGpgKey = await openpgp.generateKey({
userIDs: [
{
Expand Down Expand Up @@ -239,15 +239,15 @@ describe('BLS Utils:', async function () {
.createUserKeychain(
userGpgKey,
userKeyShare,
{ ...eth2.generateKeyPair(), chaincode: '0' },
{ ...(await eth2.generateKeyPair()), chaincode: '0' },
bitgoKeychain,
'passphrase'
)
.should.be.rejectedWith('Failed to create user keychain - commonKeychains do not match.');
await blsUtils
.createUserKeychain(
userGpgKey,
{ ...eth2.generateKeyPair(), chaincode: '0' },
{ ...(await eth2.generateKeyPair()), chaincode: '0' },
backupKeyShare,
bitgoKeychain,
'passphrase'
Expand All @@ -257,7 +257,7 @@ describe('BLS Utils:', async function () {
await blsUtils
.createBackupKeychain(
backupGpgKey,
{ ...eth2.generateKeyPair(), chaincode: '0' },
{ ...(await eth2.generateKeyPair()), chaincode: '0' },
backupKeyShare,
bitgoKeychain,
'passphrase'
Expand All @@ -267,7 +267,7 @@ describe('BLS Utils:', async function () {
.createBackupKeychain(
backupGpgKey,
userKeyShare,
{ ...eth2.generateKeyPair(), chaincode: '0' },
{ ...(await eth2.generateKeyPair()), chaincode: '0' },
bitgoKeychain,
'passphrase'
)
Expand Down
2 changes: 1 addition & 1 deletion modules/bitgo/test/v2/unit/internal/tssUtils/ecdsa.ts
Original file line number Diff line number Diff line change
Expand Up @@ -994,7 +994,7 @@ describe('TSS Ecdsa Utils:', async function () {
});

// Seems to be flaky on CI, failed here: https://github.com/BitGo/BitGoJS/actions/runs/5902489990/job/16010623888?pr=3822
it.skip('createOfflineMuDeltaShare should succeed', async function () {
xit('createOfflineMuDeltaShare should succeed', async function () {
const mockPassword = 'password';
const alphaLength = 1536;
const deltaLength = 64;
Expand Down
4 changes: 2 additions & 2 deletions modules/bitgo/test/v2/unit/keychains.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,9 @@ describe('V2 Keychains', function () {
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 () {
it(`should create the same ${coin.name} key with the same seed`, async function () {
const currentCoin = bitgo.coin(coin.name);
const keyPair = currentCoin.generateKeyPair(seed);
const keyPair = await currentCoin.generateKeyPair(seed);

should.exist(keyPair.pub);
should.exist(keyPair.prv);
Expand Down
8 changes: 4 additions & 4 deletions modules/bitgo/test/v2/unit/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ describe('V2 Wallet:', function () {
prv,
coldDerivationSeed: '123',
};
wallet.getUserPrv(userPrvOptions).should.eql(derivedPrv);
(await wallet.getUserPrv(userPrvOptions)).should.eql(derivedPrv);
});

it('should use the user keychain derivedFromParentWithSeed as the cold derivation seed if none is provided', async () => {
Expand All @@ -337,7 +337,7 @@ describe('V2 Wallet:', function () {
type: 'independent',
},
};
wallet.getUserPrv(userPrvOptions).should.eql(derivedPrv);
(await wallet.getUserPrv(userPrvOptions)).should.eql(derivedPrv);
});

it('should prefer the explicit cold derivation seed to the user keychain derivedFromParentWithSeed', async () => {
Expand All @@ -351,7 +351,7 @@ describe('V2 Wallet:', function () {
type: 'independent',
},
};
wallet.getUserPrv(userPrvOptions).should.eql(derivedPrv);
(await wallet.getUserPrv(userPrvOptions)).should.eql(derivedPrv);
});

it('should return the prv provided for TSS SMC', async () => {
Expand Down Expand Up @@ -379,7 +379,7 @@ describe('V2 Wallet:', function () {
prv,
keychain,
};
wallet.getUserPrv(userPrvOptions).should.eql(prv);
(await wallet.getUserPrv(userPrvOptions)).should.eql(prv);
});
});

Expand Down
Loading
Loading