From 7ea8c5b9ba714af3cc9d56c4c32abbccd644b202 Mon Sep 17 00:00:00 2001 From: Alejandro Busse Date: Wed, 7 Feb 2024 18:51:30 -0300 Subject: [PATCH] feat(root): multisig eddsa root keys test test WP-0000 --- examples/js/backup-key-creation.js | 2 +- examples/ts/backup-key-creation.ts | 2 +- modules/abstract-cosmos/src/cosmosCoin.ts | 2 +- .../abstract-eth/src/abstractEthLikeCoin.ts | 2 +- .../src/abstractEthLikeNewCoins.ts | 4 +- modules/abstract-utxo/src/abstractUtxoCoin.ts | 2 +- .../test/resources/eddsaKeyDeriver.ts | 17 +++ .../test/unit/utils/eddsaKeyDeriver.ts | 74 ++++++++++++ modules/bitgo/test/ecdh.ts | 8 +- modules/bitgo/test/integration/keychains.ts | 26 ++-- modules/bitgo/test/integration/wallet.ts | 6 +- modules/bitgo/test/integration/wallets.ts | 76 ++++++------ .../bitgo/test/v2/integration/coins/xlm.ts | 2 +- modules/bitgo/test/v2/integration/wallets.ts | 24 ++-- .../test/v2/unit/coins/abstractEthCoin.ts | 8 +- .../test/v2/unit/coins/abstractUtxoCoin.ts | 26 ++-- modules/bitgo/test/v2/unit/coins/ofc.ts | 4 +- .../test/v2/unit/coins/utxo/keychains.ts | 4 +- modules/bitgo/test/v2/unit/enterprise.ts | 6 +- .../bitgo/test/v2/unit/internal/blsUtils.ts | 22 ++-- .../test/v2/unit/internal/tssUtils/ecdsa.ts | 14 +-- modules/bitgo/test/v2/unit/keychains.ts | 4 +- modules/bitgo/test/v2/unit/wallet.ts | 8 +- modules/express/src/clientRoutes.ts | 2 +- modules/sdk-api/src/bitgoAPI.ts | 2 +- modules/sdk-api/src/v1/wallets.ts | 8 +- modules/sdk-coin-ada/src/ada.ts | 2 +- modules/sdk-coin-ada/test/unit/ada.ts | 8 +- modules/sdk-coin-algo/src/algo.ts | 25 ++-- modules/sdk-coin-algo/test/unit/algo.ts | 22 +--- modules/sdk-coin-avaxc/src/avaxc.ts | 2 +- modules/sdk-coin-avaxc/test/unit/avaxc.ts | 14 +-- modules/sdk-coin-avaxp/src/avaxp.ts | 2 +- modules/sdk-coin-avaxp/test/unit/avaxp.ts | 16 +-- .../sdk-coin-btc/src/inscriptionBuilder.ts | 6 +- modules/sdk-coin-cspr/src/cspr.ts | 2 +- modules/sdk-coin-cspr/test/unit/cspr.ts | 12 +- modules/sdk-coin-dot/src/dot.ts | 2 +- modules/sdk-coin-dot/test/unit/dot.ts | 8 +- modules/sdk-coin-dot/test/unit/keypair.ts | 17 --- modules/sdk-coin-eos/src/eos.ts | 2 +- modules/sdk-coin-eos/test/unit/eos.ts | 16 +-- modules/sdk-coin-eos/test/unit/eosToken.ts | 4 +- modules/sdk-coin-eth2/src/eth2.ts | 2 +- modules/sdk-coin-eth2/test/unit/eth2.ts | 28 ++--- modules/sdk-coin-ethw/src/ethw.ts | 2 +- modules/sdk-coin-hbar/src/hbar.ts | 12 +- modules/sdk-coin-hbar/test/unit/hbar.ts | 34 +++++- modules/sdk-coin-near/src/near.ts | 2 +- modules/sdk-coin-near/test/unit/near.ts | 8 +- modules/sdk-coin-sol/src/sol.ts | 2 +- modules/sdk-coin-sol/test/unit/keyPair.ts | 32 +---- modules/sdk-coin-sol/test/unit/sol.ts | 22 ++-- modules/sdk-coin-stx/src/stx.ts | 2 +- modules/sdk-coin-stx/test/unit/stx.ts | 8 +- modules/sdk-coin-sui/src/sui.ts | 2 +- modules/sdk-coin-ton/src/ton.ts | 2 +- modules/sdk-coin-trx/src/trx.ts | 2 +- modules/sdk-coin-trx/test/unit/trx.ts | 8 +- modules/sdk-coin-xlm/src/xlm.ts | 36 ++---- modules/sdk-coin-xlm/test/unit/xlm.ts | 34 ++---- modules/sdk-coin-xrp/src/xrp.ts | 2 +- modules/sdk-coin-xrp/test/unit/xrp.ts | 4 +- modules/sdk-coin-xtz/src/xtz.ts | 2 +- modules/sdk-coin-xtz/test/unit/xtz.ts | 12 +- .../account-lib/baseCoin/ed25519KeyPair.ts | 18 --- modules/sdk-core/src/account-lib/index.ts | 2 + modules/sdk-core/src/account-lib/mpc/util.ts | 2 + .../src/account-lib/util/ed25519KeyDeriver.ts | 2 + .../src/account-lib/util/eddsaKeyDeriver.ts | 112 ++++++++++++++++++ .../sdk-core/src/bitgo/baseCoin/baseCoin.ts | 10 +- .../sdk-core/src/bitgo/baseCoin/iBaseCoin.ts | 4 +- .../sdk-core/src/bitgo/keychain/iKeychains.ts | 2 +- .../sdk-core/src/bitgo/keychain/keychains.ts | 2 +- modules/sdk-core/src/bitgo/utils/blsUtils.ts | 4 +- modules/sdk-core/src/bitgo/wallet/iWallet.ts | 2 +- modules/sdk-core/src/bitgo/wallet/wallet.ts | 16 ++- modules/sdk-core/src/bitgo/wallet/wallets.ts | 4 +- modules/sdk-core/src/coins/fiateur.ts | 2 +- modules/sdk-core/src/coins/fiatgbp.ts | 2 +- modules/sdk-core/src/coins/fiatusd.ts | 2 +- modules/sdk-core/src/coins/ofc.ts | 2 +- modules/sdk-core/src/coins/susd.ts | 2 +- .../template/boilerplates/simple/.mainnet.ts | 2 +- 84 files changed, 555 insertions(+), 410 deletions(-) create mode 100644 modules/account-lib/test/resources/eddsaKeyDeriver.ts create mode 100644 modules/account-lib/test/unit/utils/eddsaKeyDeriver.ts create mode 100644 modules/sdk-core/src/account-lib/util/eddsaKeyDeriver.ts diff --git a/examples/js/backup-key-creation.js b/examples/js/backup-key-creation.js index 92030512ec..bd7b6d8742 100644 --- a/examples/js/backup-key-creation.js +++ b/examples/js/backup-key-creation.js @@ -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}`); diff --git a/examples/ts/backup-key-creation.ts b/examples/ts/backup-key-creation.ts index a53e45cdc8..6e9ea348e5 100644 --- a/examples/ts/backup-key-creation.ts +++ b/examples/ts/backup-key-creation.ts @@ -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}`); diff --git a/modules/abstract-cosmos/src/cosmosCoin.ts b/modules/abstract-cosmos/src/cosmosCoin.ts index 23396cac84..921a79efd8 100644 --- a/modules/abstract-cosmos/src/cosmosCoin.ts +++ b/modules/abstract-cosmos/src/cosmosCoin.ts @@ -583,7 +583,7 @@ export class CosmosCoin extends BaseCoin { } /** @inheritDoc **/ - generateKeyPair(seed?: Buffer): KeyPair { + async generateKeyPair(seed?: Buffer): Promise { 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 diff --git a/modules/abstract-eth/src/abstractEthLikeCoin.ts b/modules/abstract-eth/src/abstractEthLikeCoin.ts index b1e60da46b..56a8dea026 100644 --- a/modules/abstract-eth/src/abstractEthLikeCoin.ts +++ b/modules/abstract-eth/src/abstractEthLikeCoin.ts @@ -121,7 +121,7 @@ export abstract class AbstractEthLikeCoin extends BaseCoin { return isValidEthAddress(address); } - generateKeyPair(seed?: Buffer): KeyPair { + async generateKeyPair(seed?: Buffer): Promise { const extendedKey = bip32.fromSeed(seed || randomBytes(32)); const xpub = extendedKey.neutered().toBase58(); diff --git a/modules/abstract-eth/src/abstractEthLikeNewCoins.ts b/modules/abstract-eth/src/abstractEthLikeNewCoins.ts index 06ff2cc540..03c8681184 100644 --- a/modules/abstract-eth/src/abstractEthLikeNewCoins.ts +++ b/modules/abstract-eth/src/abstractEthLikeNewCoins.ts @@ -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'); @@ -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 { 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 diff --git a/modules/abstract-utxo/src/abstractUtxoCoin.ts b/modules/abstract-utxo/src/abstractUtxoCoin.ts index 0b5f04f776..16d7146970 100644 --- a/modules/abstract-utxo/src/abstractUtxoCoin.ts +++ b/modules/abstract-utxo/src/abstractUtxoCoin.ts @@ -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 diff --git a/modules/account-lib/test/resources/eddsaKeyDeriver.ts b/modules/account-lib/test/resources/eddsaKeyDeriver.ts new file mode 100644 index 0000000000..281b582685 --- /dev/null +++ b/modules/account-lib/test/resources/eddsaKeyDeriver.ts @@ -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', + }, +}; diff --git a/modules/account-lib/test/unit/utils/eddsaKeyDeriver.ts b/modules/account-lib/test/unit/utils/eddsaKeyDeriver.ts new file mode 100644 index 0000000000..630de74460 --- /dev/null +++ b/modules/account-lib/test/unit/utils/eddsaKeyDeriver.ts @@ -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' }, + ); + }); + }); +}); diff --git a/modules/bitgo/test/ecdh.ts b/modules/bitgo/test/ecdh.ts index 295dd6be15..2cf2a11960 100644 --- a/modules/bitgo/test/ecdh.ts +++ b/modules/bitgo/test/ecdh.ts @@ -40,9 +40,9 @@ describe('ECDH utils', () => { }); describe('signMessageWithDerivedEcdhKey and verifyEcdhSignature', function () { - it('signMessageWithDerivedEcdhKey and verifyEcdhSignature are able to sign/verify the same message', function () { + it('signMessageWithDerivedEcdhKey and verifyEcdhSignature are able to sign/verify the same message', async function () { const bitgo = TestBitGo.decorate(BitGo, { env: 'mock' }); - const myEcdhKeychain = bitgo.keychains().create(); + const myEcdhKeychain = await bitgo.keychains().create(); const message = { ntilde: 'bla', h1: 'bla', @@ -56,9 +56,9 @@ describe('ECDH utils', () => { }); }); - it('verifyEcdhSignature fails if the message/signature or pub key is diff than the one used for signing', function () { + it('verifyEcdhSignature fails if the message/signature or pub key is diff than the one used for signing', async function () { const bitgo = TestBitGo.decorate(BitGo, { env: 'mock' }); - const myEcdhKeychain = bitgo.keychains().create(); + const myEcdhKeychain = await bitgo.keychains().create(); const message = { ntilde: 'bla', h1: 'bla', diff --git a/modules/bitgo/test/integration/keychains.ts b/modules/bitgo/test/integration/keychains.ts index 4c5444eebe..d250f03b01 100644 --- a/modules/bitgo/test/integration/keychains.ts +++ b/modules/bitgo/test/integration/keychains.ts @@ -54,18 +54,18 @@ describe('Keychains', function () { ); }); - it('create', function () { + it('create', async function () { // must use seed of at least 128 bits // standard test vector taken from bip32 spec const seed = Buffer.from('000102030405060708090a0b0c0d0e0f', 'hex'); assert.equal( - keychains.create({ seed: seed }).xprv, + await keychains.create({ seed: seed }).xprv, 'xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi' ); // two keys created one after the other with no seed should have // non-equivalent xprivs, i.e. check that the RNG is actually working. - assert.notEqual(keychains.create().xprv, keychains.create().xprv); + assert.notEqual(await keychains.create().xprv, await keychains.create().xprv); }); it('deriveLocal', function () { @@ -180,8 +180,8 @@ describe('Keychains', function () { }); }); - it('non existent keychain', function (done) { - const newKey = keychains.create(); + it('non existent keychain', async function (done) { + const newKey = await keychains.create(); const options = { xpub: newKey.xpub, }; @@ -194,8 +194,8 @@ describe('Keychains', function () { describe('Add', function () { it('arguments', function () { - assert.throws(function () { - keychains.create('invalid'); + assert.rejects(async function () { + await keychains.create('invalid'); }); assert.throws(function () { keychains.add(); @@ -211,9 +211,9 @@ describe('Keychains', function () { describe('public', function () { let extendedKey; - before(function (done) { + before(async function (done) { // Generate a new keychain - extendedKey = keychains.create(); + extendedKey = await keychains.create(); bitgo.unlock({ otp: bitgo.testUserOTP() }, function (err) { assert.equal(err, null); @@ -249,9 +249,9 @@ describe('Keychains', function () { describe('private', function () { let extendedKey; - before(function () { + before(async function () { // Generate a new keychain - extendedKey = keychains.create(); + extendedKey = await keychains.create(); }); it('add', function (done) { @@ -325,8 +325,8 @@ describe('Keychains', function () { describe('Update', function () { let newKey; - before(function () { - newKey = keychains.create(); + before(async function () { + newKey = await keychains.create(); }); it('arguments', function () { diff --git a/modules/bitgo/test/integration/wallet.ts b/modules/bitgo/test/integration/wallet.ts index 1cea20b960..ecf05f7f49 100644 --- a/modules/bitgo/test/integration/wallet.ts +++ b/modules/bitgo/test/integration/wallet.ts @@ -273,9 +273,9 @@ describe('Wallet API', function () { }); }); - it('get sharing key for a user', function (done) { + it('get sharing key for a user', async function (done) { const keychains = bitgo.keychains(); - keychains.create(); + await keychains.create(); bitgo.getSharingKey({ email: TestBitGo.TEST_SHARED_KEY_USER }).done(function (result) { result.should.have.property('userId'); @@ -1370,7 +1370,7 @@ describe('Wallet API', function () { }); }); - it('spend from wallet with no unspents', function () { + it('spend from wallet with no unspents', async function () { let wallet; return bitgo diff --git a/modules/bitgo/test/integration/wallets.ts b/modules/bitgo/test/integration/wallets.ts index a0ad95aca4..8e9f6d7b30 100644 --- a/modules/bitgo/test/integration/wallets.ts +++ b/modules/bitgo/test/integration/wallets.ts @@ -136,9 +136,9 @@ describe('Wallets', function () { }); describe('Add', function () { - before(function () { - keychains.push(bitgo.keychains().create()); - keychains.push(bitgo.keychains().create()); + before(async function () { + keychains.push(await bitgo.keychains().create()); + keychains.push(await bitgo.keychains().create()); }); it('arguments', function () { @@ -203,44 +203,46 @@ describe('Wallets', function () { }); }); - describe('Create wallet with createWalletWithKeychains', function () { + describe('Create wallet with createWalletWithKeychains', async function () { it('arguments', function () { const backupXpub = 1234567890; - assert.throws(function () { - wallets.createWalletWithKeychains({ passphrase: TestBitGo.TEST_WALLET1_PASSCODE, backupXpub: backupXpub }); - }); - assert.throws(function () { - wallets.createWalletWithKeychains({ - passphrase: TestBitGo.TEST_WALLET1_PASSCODE, - label: TEST_WALLET_LABEL, - backupXpub: backupXpub, - }); - }); - assert.throws(function () { - wallets.createWalletWithKeychains({ - passphrase: TestBitGo.TEST_WALLET1_PASSCODE, - label: TEST_WALLET_LABEL, - backupXpub: 123, - }); - }); - assert.throws(function () { - wallets.createWalletWithKeychains({ label: TEST_WALLET_LABEL, backupXpub: backupXpub }); - }); - assert.throws(function () { - wallets.createWalletWithKeychains('invalid'); - }); - assert.throws(function () { - wallets.createWalletWithKeychains(); - }); + assert.rejects( + async () => + await wallets.createWalletWithKeychains({ + passphrase: TestBitGo.TEST_WALLET1_PASSCODE, + backupXpub: backupXpub, + }) + ); + assert.rejects( + async () => + await wallets.createWalletWithKeychains({ + passphrase: TestBitGo.TEST_WALLET1_PASSCODE, + label: TEST_WALLET_LABEL, + backupXpub: backupXpub, + }) + ); + assert.rejects( + async () => + await wallets.createWalletWithKeychains({ + passphrase: TestBitGo.TEST_WALLET1_PASSCODE, + label: TEST_WALLET_LABEL, + backupXpub: 123, + }) + ); + assert.rejects( + async () => await wallets.createWalletWithKeychains({ label: TEST_WALLET_LABEL, backupXpub: backupXpub }) + ); + assert.rejects(async () => await wallets.createWalletWithKeychains('invalid')); + assert.rejects(async () => await wallets.createWalletWithKeychains()); }); - it('default create', function (done) { + it('default create', async function (done) { const options = { passphrase: TestBitGo.TEST_WALLET1_PASSCODE, label: TEST_WALLET_LABEL, }; - bitgo.wallets().createWalletWithKeychains(options, function (err, result) { + await bitgo.wallets().createWalletWithKeychains(options, function (err, result) { assert.equal(err, null); assert.notEqual(result, null); @@ -268,16 +270,16 @@ describe('Wallets', function () { }); }); - it('create with cold backup xpub', function (done) { + it('create with cold backup xpub', async function (done) { // Simulate a cold backup key - const coldBackupKey = bitgo.keychains().create(); + const coldBackupKey = await bitgo.keychains().create(); const options = { passphrase: TestBitGo.TEST_WALLET1_PASSCODE, label: TEST_WALLET_LABEL, backupXpub: coldBackupKey.xpub, }; - bitgo.wallets().createWalletWithKeychains(options, function (err, result) { + await bitgo.wallets().createWalletWithKeychains(options, function (err, result) { assert.equal(err, null); assert.notEqual(result, null); @@ -306,14 +308,14 @@ describe('Wallets', function () { }); }); - it('create with backup xpub provider (KRS wallet)', function (done) { + it('create with backup xpub provider (KRS wallet)', async function (done) { const options = { passphrase: TestBitGo.TEST_WALLET1_PASSCODE, label: TEST_WALLET_LABEL, backupXpubProvider: 'keyvault-io', }; - bitgo.wallets().createWalletWithKeychains(options, function (err, result) { + await bitgo.wallets().createWalletWithKeychains(options, function (err, result) { assert.equal(err, null); assert.notEqual(result, null); diff --git a/modules/bitgo/test/v2/integration/coins/xlm.ts b/modules/bitgo/test/v2/integration/coins/xlm.ts index 510156e95a..3fb41e094c 100644 --- a/modules/bitgo/test/v2/integration/coins/xlm.ts +++ b/modules/bitgo/test/v2/integration/coins/xlm.ts @@ -59,7 +59,7 @@ describe('XLM:', function () { it( 'Should generate wallet with custom root address', co(function* () { - const keyPair = basecoin.generateKeyPair(); + const keyPair = yield basecoin.generateKeyPair(); const params = { passphrase: TestBitGo.V2.TEST_WALLET1_PASSCODE, label: 'Stellar Wallet Test', diff --git a/modules/bitgo/test/v2/integration/wallets.ts b/modules/bitgo/test/v2/integration/wallets.ts index 920e4ad38f..327de19fdb 100644 --- a/modules/bitgo/test/v2/integration/wallets.ts +++ b/modules/bitgo/test/v2/integration/wallets.ts @@ -158,8 +158,8 @@ describe('V2 Wallets:', function () { }); }); - it('should make wallet with client-generated user and krs backupkey', function () { - const xpub = keychains.create().pub; // random xpub + it('should make wallet with client-generated user and krs backupkey', async function () { + const xpub = await keychains.create().pub; // random xpub const params = { passphrase: passphrase, label: label, @@ -182,9 +182,9 @@ describe('V2 Wallets:', function () { }); }); - it('should make wallet with provided user key and backup key', function () { - const backupXpub = keychains.create().pub; // random xpub - const userXpub = keychains.create().pub; // random xpub + it('should make wallet with provided user key and backup key', async function () { + const backupXpub = await keychains.create().pub; // random xpub + const userXpub = await keychains.create().pub; // random xpub const params = { label: label, backupXpub: backupXpub, @@ -209,8 +209,8 @@ describe('V2 Wallets:', function () { }); }); - it('should make wallet with provided user key and custom derivation path', function () { - const userXpub = keychains.create().pub; // random xpub + it('should make wallet with provided user key and custom derivation path', async function () { + const userXpub = await keychains.create().pub; // random xpub const params = { label: label, userKey: userXpub, @@ -238,9 +238,9 @@ describe('V2 Wallets:', function () { }); }); - it('should generate wallet and freeze it', function () { - const backupXpub = keychains.create().pub; // random xpub - const userXpub = keychains.create().pub; // random xpub + it('should generate wallet and freeze it', async function () { + const backupXpub = await keychains.create().pub; // random xpub + const userXpub = await keychains.create().pub; // random xpub const params = { label: label, backupXpub: backupXpub, @@ -326,8 +326,8 @@ describe('V2 Wallets:', function () { let userKeychain; // Add the user keychain - const userKeychainPromise = Q.fcall(function () { - userKeychain = keychains.create(); + const userKeychainPromise = Q.fcall(async function () { + userKeychain = await keychains.create(); return keychains.add(userKeychain); }).then(function (keychain) { userKeychainId = keychain.id; diff --git a/modules/bitgo/test/v2/unit/coins/abstractEthCoin.ts b/modules/bitgo/test/v2/unit/coins/abstractEthCoin.ts index d29f6e0420..aa5085e6b7 100644 --- a/modules/bitgo/test/v2/unit/coins/abstractEthCoin.ts +++ b/modules/bitgo/test/v2/unit/coins/abstractEthCoin.ts @@ -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); diff --git a/modules/bitgo/test/v2/unit/coins/abstractUtxoCoin.ts b/modules/bitgo/test/v2/unit/coins/abstractUtxoCoin.ts index edbdfc6949..0141e910c9 100644 --- a/modules/bitgo/test/v2/unit/coins/abstractUtxoCoin.ts +++ b/modules/bitgo/test/v2/unit/coins/abstractUtxoCoin.ts @@ -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() }, }, }; @@ -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 diff --git a/modules/bitgo/test/v2/unit/coins/ofc.ts b/modules/bitgo/test/v2/unit/coins/ofc.ts index 36c03c3b4b..4a9bf869ea 100644 --- a/modules/bitgo/test/v2/unit/coins/ofc.ts +++ b/modules/bitgo/test/v2/unit/coins/ofc.ts @@ -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); }); }); diff --git a/modules/bitgo/test/v2/unit/coins/utxo/keychains.ts b/modules/bitgo/test/v2/unit/coins/utxo/keychains.ts index 8908534c0b..21004e65c6 100644 --- a/modules/bitgo/test/v2/unit/coins/utxo/keychains.ts +++ b/modules/bitgo/test/v2/unit/coins/utxo/keychains.ts @@ -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); }); diff --git a/modules/bitgo/test/v2/unit/enterprise.ts b/modules/bitgo/test/v2/unit/enterprise.ts index 9a54851bb3..8ef46dac6f 100644 --- a/modules/bitgo/test/v2/unit/enterprise.ts +++ b/modules/bitgo/test/v2/unit/enterprise.ts @@ -53,14 +53,14 @@ describe('Enterprise:', function () { scope.isDone().should.be.True(); }); - describe('Resign enterprise challenge', function () { + describe('Resign enterprise challenge', async function () { const bitgo = TestBitGo.decorate(BitGo, { env: 'mock' }); const enterprise = new Enterprise(bitgo, bitgo.coin('tbtc'), { id: '123', name: 'Test Enterprise' }); - const oldAdminEcdhKey = bitgo.keychains().create(); + const oldAdminEcdhKey = await bitgo.keychains().create(); const oldAdminDerivationPath = 'm/0/0'; - const newAdminEcdhKey = bitgo.keychains().create(); + const newAdminEcdhKey = await bitgo.keychains().create(); const newAdminDerivationPath = 'm/0/1'; const entChallenge = { diff --git a/modules/bitgo/test/v2/unit/internal/blsUtils.ts b/modules/bitgo/test/v2/unit/internal/blsUtils.ts index c605d07fad..05736bbd65 100644 --- a/modules/bitgo/test/v2/unit/internal/blsUtils.ts +++ b/modules/bitgo/test/v2/unit/internal/blsUtils.ts @@ -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: [ @@ -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({ @@ -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: [ { @@ -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: [ { @@ -239,7 +239,7 @@ describe('BLS Utils:', async function () { .createUserKeychain( userGpgKey, userKeyShare, - { ...eth2.generateKeyPair(), chaincode: '0' }, + { ...(await eth2.generateKeyPair()), chaincode: '0' }, bitgoKeychain, 'passphrase' ) @@ -247,7 +247,7 @@ describe('BLS Utils:', async function () { await blsUtils .createUserKeychain( userGpgKey, - { ...eth2.generateKeyPair(), chaincode: '0' }, + { ...(await eth2.generateKeyPair()), chaincode: '0' }, backupKeyShare, bitgoKeychain, 'passphrase' @@ -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' @@ -267,7 +267,7 @@ describe('BLS Utils:', async function () { .createBackupKeychain( backupGpgKey, userKeyShare, - { ...eth2.generateKeyPair(), chaincode: '0' }, + { ...(await eth2.generateKeyPair()), chaincode: '0' }, bitgoKeychain, 'passphrase' ) diff --git a/modules/bitgo/test/v2/unit/internal/tssUtils/ecdsa.ts b/modules/bitgo/test/v2/unit/internal/tssUtils/ecdsa.ts index 42cfc5b726..488ce82d6c 100644 --- a/modules/bitgo/test/v2/unit/internal/tssUtils/ecdsa.ts +++ b/modules/bitgo/test/v2/unit/internal/tssUtils/ecdsa.ts @@ -1171,7 +1171,7 @@ describe('TSS Ecdsa Utils:', async function () { } }); - describe('getEcdsaSigningChallenges', function () { + describe('getEcdsaSigningChallenges', async function () { const mockWalletPaillierKey = { n: 'f47be4c2d8bc1e28f88c6c4da634da97d92a1c279a7b0fe7b87c337c36a27b32ce0ff0c45f16e4e15bbd20e4e640de12047eff9b1a2b98144f9a268d406bd000d192a35b6847a17e40fb85f55b314d001ff87393481cafe391807d0eb83eff9e38614b38e5f25fc4449cb01caed805584d026b5d866c723f3d4d4f1e462662f2113b1561eb2bf755b4b91d0308d8eacc439167da8b7d6e108524f226960360af00215d9614457414ebdbe8834999689e2e903208c8713ff5d9901f9eaba3aa81d705323cbbba61ba7fa9f3228f30853fb55da1b3d3ed7db1dfc6545bc96aa8d2eb848931c1b807fdfe8f65af72f68638a82fe9e22ac1f0f032e621066806a1f144b5719a5f091986867b384be6c34146c8241cbfbd781966ebbcd19e6caa27fab040e62e5a162888aa8624d046c8fe3b72244f04a7264c4a36b6366dbe7da98afb201d34be2c0d6dd11982af35bf7535582b263914725aaec280d52290527382d3ab297d746c41aacd8de98c09fcfb85a95e02de1b34d4933e51045e2f1ce8af', lambda: @@ -1186,8 +1186,8 @@ describe('TSS Ecdsa Utils:', async function () { const txRequestId = 'fakeTxRequestId'; const rawEntChallengeWithProofs: EcdsaTypes.SerializedNtildeWithProofs = mockSerializedChallengeWithProofs; let rawBitgoChallenge: EcdsaTypes.SerializedEcdsaChallenges & { n: string }; - const adminEcdhKey = bitgo.keychains().create(); - const fakeAdminEcdhKey = bitgo.keychains().create(); + const adminEcdhKey = await bitgo.keychains().create(); + const fakeAdminEcdhKey = await bitgo.keychains().create(); const derivationPath = 'm/0/0'; const mockedSigningKey = { userId: 'id', @@ -1352,9 +1352,9 @@ describe('TSS Ecdsa Utils:', async function () { }); }); - describe('getVerifyAndSignBitGoChallenges', function () { + describe('getVerifyAndSignBitGoChallenges', async function () { const bitgo = TestBitGo.decorate(BitGo, { env: 'mock' }); - const adminEcdhKey = bitgo.keychains().create(); + const adminEcdhKey = await bitgo.keychains().create(); const derivationPath = 'm/0/0'; const bitgoInstChallenge = mockChallengeA; const bitgoNitroChallenge = mockChallengeB; @@ -1537,9 +1537,9 @@ describe('TSS Ecdsa Utils:', async function () { }); }); - describe('initiateChallengesForEnterprise', function () { + describe('initiateChallengesForEnterprise', async function () { const bitgo = TestBitGo.decorate(BitGo, { env: 'mock' }); - const adminEcdhKey = bitgo.keychains().create(); + const adminEcdhKey = await bitgo.keychains().create(); const derivationPath = 'm/0/0'; const bitgoInstChallenge = mockChallengeA; const bitgoNitroChallenge = mockChallengeB; diff --git a/modules/bitgo/test/v2/unit/keychains.ts b/modules/bitgo/test/v2/unit/keychains.ts index f261e4c7de..d9391e073d 100644 --- a/modules/bitgo/test/v2/unit/keychains.ts +++ b/modules/bitgo/test/v2/unit/keychains.ts @@ -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); diff --git a/modules/bitgo/test/v2/unit/wallet.ts b/modules/bitgo/test/v2/unit/wallet.ts index 528e36fa62..6dfe5758f9 100644 --- a/modules/bitgo/test/v2/unit/wallet.ts +++ b/modules/bitgo/test/v2/unit/wallet.ts @@ -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 () => { @@ -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 () => { @@ -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 () => { @@ -379,7 +379,7 @@ describe('V2 Wallet:', function () { prv, keychain, }; - wallet.getUserPrv(userPrvOptions).should.eql(prv); + await wallet.getUserPrv(userPrvOptions).should.eql(prv); }); }); diff --git a/modules/express/src/clientRoutes.ts b/modules/express/src/clientRoutes.ts index 62e96d9ef9..0054d8bfc8 100755 --- a/modules/express/src/clientRoutes.ts +++ b/modules/express/src/clientRoutes.ts @@ -495,7 +495,7 @@ export async function handleV2Sign(req: express.Request) { let privKey = decryptPrivKey(bitgo, encryptedPrivKey, walletPw); const coin = bitgo.coin(req.params.coin); if (req.body.derivationSeed) { - privKey = coin.deriveKeyWithSeed({ key: privKey, seed: req.body.derivationSeed }).key; + privKey = (await coin.deriveKeyWithSeed({ key: privKey, seed: req.body.derivationSeed })).key; } try { return await coin.signTransaction({ ...req.body, prv: privKey }); diff --git a/modules/sdk-api/src/bitgoAPI.ts b/modules/sdk-api/src/bitgoAPI.ts index dc274fdbe7..7ba9de7f74 100644 --- a/modules/sdk-api/src/bitgoAPI.ts +++ b/modules/sdk-api/src/bitgoAPI.ts @@ -769,7 +769,7 @@ export class BitGoAPI implements BitGoBase { * @throws {Error} - Throws an error if there is an issue creating the keychain. */ public async createUserEcdhKeychain(loginPassword: string): Promise { - const keyData = this.keychains().create(); + const keyData = await this.keychains().create(); const hdNode = bitcoin.HDNode.fromBase58(keyData.xprv); /** diff --git a/modules/sdk-api/src/v1/wallets.ts b/modules/sdk-api/src/v1/wallets.ts index ca8f113a85..64d6ece286 100644 --- a/modules/sdk-api/src/v1/wallets.ts +++ b/modules/sdk-api/src/v1/wallets.ts @@ -327,7 +327,7 @@ Wallets.prototype.createKey = function (params) { // ** BE SURE TO BACK UP THE ENCRYPTED USER AND BACKUP KEYCHAINS!** // // } -Wallets.prototype.createWalletWithKeychains = function (params, callback) { +Wallets.prototype.createWalletWithKeychains = async function (params, callback) { params = params || {}; common.validateParams( params, @@ -339,7 +339,7 @@ Wallets.prototype.createWalletWithKeychains = function (params, callback) { const label = params.label; // Create the user and backup key. - const userKeychain = this.bitgo.keychains().create(); + const userKeychain = await this.bitgo.keychains().create(); userKeychain.encryptedXprv = this.bitgo.encrypt({ password: params.passphrase, input: userKeychain.xprv }); const keychainData: any = { @@ -368,7 +368,7 @@ Wallets.prototype.createWalletWithKeychains = function (params, callback) { return self.bitgo .keychains() .add(keychainData) - .then(function () { + .then(async function () { // Add the backup keychain if (params.backupXpubProvider) { // If requested, use a KRS or backup key provider @@ -388,7 +388,7 @@ Wallets.prototype.createWalletWithKeychains = function (params, callback) { backupKeychain = { xpub: params.backupXpub }; } else { // no provided xpub, so default to creating one here - backupKeychain = self.bitgo.keychains().create(); + backupKeychain = await self.bitgo.keychains().create(); } return self.bitgo.keychains().add(backupKeychain); diff --git a/modules/sdk-coin-ada/src/ada.ts b/modules/sdk-coin-ada/src/ada.ts index 280cec81b2..bc2fb8c8a5 100644 --- a/modules/sdk-coin-ada/src/ada.ts +++ b/modules/sdk-coin-ada/src/ada.ts @@ -195,7 +195,7 @@ export class Ada extends BaseCoin { return transactionExplanation as unknown as ParsedTransaction; } - generateKeyPair(seed?: Buffer): KeyPair { + async generateKeyPair(seed?: Buffer): Promise { const keyPair = seed ? new AdaKeyPair({ seed }) : new AdaKeyPair(); const keys = keyPair.getKeys(); if (!keys.prv) { diff --git a/modules/sdk-coin-ada/test/unit/ada.ts b/modules/sdk-coin-ada/test/unit/ada.ts index 5c05995727..b90969549e 100644 --- a/modules/sdk-coin-ada/test/unit/ada.ts +++ b/modules/sdk-coin-ada/test/unit/ada.ts @@ -160,15 +160,15 @@ describe('ADA', function () { }); describe('Generate wallet key pair: ', () => { - it('should generate key pair', () => { - const kp = basecoin.generateKeyPair(); + it('should generate key pair', async () => { + const kp = await basecoin.generateKeyPair(); basecoin.isValidPub(kp.pub).should.equal(true); basecoin.isValidPrv(kp.prv).should.equal(true); }); - it('should generate key pair from seed', () => { + it('should generate key pair from seed', async () => { const seed = Buffer.from('9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60', 'hex'); - const kp = basecoin.generateKeyPair(seed); + const kp = await basecoin.generateKeyPair(seed); basecoin.isValidPub(kp.pub).should.equal(true); basecoin.isValidPrv(kp.prv).should.equal(true); }); diff --git a/modules/sdk-coin-algo/src/algo.ts b/modules/sdk-coin-algo/src/algo.ts index 06c28268dc..a3ca57abfc 100644 --- a/modules/sdk-coin-algo/src/algo.ts +++ b/modules/sdk-coin-algo/src/algo.ts @@ -1,7 +1,6 @@ /** * @prettier */ -import * as utxolib from '@bitgo/utxo-lib'; import * as _ from 'lodash'; import { SeedValidator } from './seedValidator'; import { coins, CoinFamily } from '@bitgo/statics'; @@ -10,7 +9,6 @@ import { AddressCoinSpecific, BaseCoin, BitGoBase, - Ed25519KeyDeriver, InvalidAddressError, InvalidKey, KeyIndices, @@ -26,6 +24,7 @@ import { UnexpectedAddressError, VerifyAddressOptions, VerifyTransactionOptions, + EddsaKeyDeriver, } from '@bitgo/sdk-core'; import stellar from 'stellar-sdk'; @@ -175,7 +174,11 @@ export class Algo extends BaseCoin { * @param seed * @returns {Object} object with generated pub, prv */ - generateKeyPair(seed?: Buffer): KeyPair { + async generateKeyPair(seed?: Buffer, rootKey?: boolean): Promise { + if (rootKey) { + const keypair = await EddsaKeyDeriver.createRootKeys(seed); + return keypair; + } const keyPair = seed ? new AlgoLib.KeyPair({ seed }) : new AlgoLib.KeyPair(); const keys = keyPair.getKeys(); if (!keys.prv) { @@ -505,20 +508,8 @@ export class Algo extends BaseCoin { } /** @inheritDoc */ - deriveKeyWithSeed({ key, seed }: { key: string; seed: string }): { derivationPath: string; key: string } { - const derivationPathInput = utxolib.crypto.hash256(Buffer.from(seed, 'utf8')).toString('hex'); - const derivationPathParts = [ - 999999, - parseInt(derivationPathInput.slice(0, 7), 16), - parseInt(derivationPathInput.slice(7, 14), 16), - ]; - const derivationPath = 'm/' + derivationPathParts.map((part) => `${part}'`).join('/'); - const derivedKey = Ed25519KeyDeriver.derivePath(derivationPath, key).key; - const keypair = new AlgoLib.KeyPair({ seed: derivedKey }); - return { - key: keypair.getAddress(), - derivationPath, - }; + async deriveKeyWithSeed({ key, seed }: { key: string; seed: string }): Promise { + return EddsaKeyDeriver.deriveKeyWithSeed(key, seed); } decodeTx(txn: Buffer): unknown { diff --git a/modules/sdk-coin-algo/test/unit/algo.ts b/modules/sdk-coin-algo/test/unit/algo.ts index da0307c1a1..009a79ce7f 100644 --- a/modules/sdk-coin-algo/test/unit/algo.ts +++ b/modules/sdk-coin-algo/test/unit/algo.ts @@ -608,32 +608,18 @@ describe('ALGO:', function () { }); describe('Generate wallet key pair: ', () => { - it('should generate key pair', () => { - const kp = basecoin.generateKeyPair(); + it('should generate key pair', async () => { + const kp = await basecoin.generateKeyPair(); basecoin.isValidPub(kp.pub).should.equal(true); basecoin.isValidPrv(kp.prv).should.equal(true); }); - it('should generate key pair from seed', () => { + it('should generate key pair from seed', async () => { const seed = Buffer.from('9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60', 'hex'); - const kp = basecoin.generateKeyPair(seed); + const kp = await basecoin.generateKeyPair(seed); basecoin.isValidPub(kp.pub).should.equal(true); basecoin.isValidPrv(kp.prv).should.equal(true); }); - - it('should deterministically derive keypair with seed', () => { - const derivedKeypair = basecoin.deriveKeyWithSeed({ - key: 'UBI2KNGT742KGIPHMZDJHHSADIT56HRDPVOOCCRYIETD4BAJLCBMQNSCNE', - seed: 'cold derivation seed', - }); - console.log(JSON.stringify(derivedKeypair)); - - basecoin.isValidPub(derivedKeypair.key).should.be.true(); - derivedKeypair.should.deepEqual({ - key: 'NAYUBR4HQKJBBTNNKXQIY7GMHUCHVAUH5DQ4ZVHVL67CUQLGHRWDKQAHYU', - derivationPath: "m/999999'/25725073'/5121434'", - }); - }); }); describe('Enable, disable and transfer Token ', () => { diff --git a/modules/sdk-coin-avaxc/src/avaxc.ts b/modules/sdk-coin-avaxc/src/avaxc.ts index 8a0d012fa7..6601624306 100644 --- a/modules/sdk-coin-avaxc/src/avaxc.ts +++ b/modules/sdk-coin-avaxc/src/avaxc.ts @@ -126,7 +126,7 @@ export class AvaxC extends BaseCoin { return false; } - generateKeyPair(seed?: Buffer): KeyPair { + async generateKeyPair(seed?: Buffer): Promise { const avaxKeyPair = seed ? new AvaxcKeyPair({ seed }) : new AvaxcKeyPair(); const extendedKeys = avaxKeyPair.getExtendedKeys(); return { diff --git a/modules/sdk-coin-avaxc/test/unit/avaxc.ts b/modules/sdk-coin-avaxc/test/unit/avaxc.ts index 6a06801e73..d7eae0642f 100644 --- a/modules/sdk-coin-avaxc/test/unit/avaxc.ts +++ b/modules/sdk-coin-avaxc/test/unit/avaxc.ts @@ -93,22 +93,22 @@ describe('Avalanche C-Chain', function () { }); describe('KeyPair', () => { - it('should generate tavax keyPair without aguments', () => { - const kp = tavaxCoin.generateKeyPair(); + it('should generate tavax keyPair without aguments', async () => { + const kp = await tavaxCoin.generateKeyPair(); kp.should.have.property('prv'); kp.should.have.property('pub'); }); - it('should generate avax keyPair without aguments', () => { - const kp = avaxCoin.generateKeyPair(); + it('should generate avax keyPair without aguments', async () => { + const kp = await avaxCoin.generateKeyPair(); kp.should.have.property('prv'); kp.should.have.property('pub'); }); - it('should generate avax keyPair from seed', () => { + it('should generate avax keyPair from seed', async () => { const seed = '4b3b89f6ca897cb729d2146913877f71'; - const tAvaxKeyPair = tavaxCoin.generateKeyPair(Buffer.from(seed, 'hex')); - const avaxKeyPair = avaxCoin.generateKeyPair(Buffer.from(seed, 'hex')); + const tAvaxKeyPair = await tavaxCoin.generateKeyPair(Buffer.from(seed, 'hex')); + const avaxKeyPair = await avaxCoin.generateKeyPair(Buffer.from(seed, 'hex')); tAvaxKeyPair.should.have.property('prv'); tAvaxKeyPair.should.have.property('pub'); tAvaxKeyPair.prv.should.equals( diff --git a/modules/sdk-coin-avaxp/src/avaxp.ts b/modules/sdk-coin-avaxp/src/avaxp.ts index 5ea1564daa..482cedf962 100644 --- a/modules/sdk-coin-avaxp/src/avaxp.ts +++ b/modules/sdk-coin-avaxp/src/avaxp.ts @@ -257,7 +257,7 @@ export class AvaxP extends BaseCoin { * @param {Buffer} seed - Seed from which the new keypair should be generated, otherwise a random seed is used * @returns {Object} object with generated pub and prv */ - generateKeyPair(seed?: Buffer): KeyPair { + async generateKeyPair(seed?: Buffer): Promise { const keyPair = seed ? new AvaxpLib.KeyPair({ seed }) : new AvaxpLib.KeyPair(); const keys = keyPair.getKeys(); diff --git a/modules/sdk-coin-avaxp/test/unit/avaxp.ts b/modules/sdk-coin-avaxp/test/unit/avaxp.ts index cbe2facb3b..1f7554bd92 100644 --- a/modules/sdk-coin-avaxp/test/unit/avaxp.ts +++ b/modules/sdk-coin-avaxp/test/unit/avaxp.ts @@ -87,30 +87,30 @@ describe('Avaxp', function () { }); describe('Keypairs:', () => { - it('should generate a keypair from random seed', function () { - const keyPair = basecoin.generateKeyPair(); + it('should generate a keypair from random seed', async function () { + const keyPair = await basecoin.generateKeyPair(); keyPair.should.have.property('pub'); keyPair.should.have.property('prv'); }); - it('should generate a keypair from a seed', function () { + it('should generate a keypair from a seed', async function () { const seedText = testData.SEED_ACCOUNT.seed; const seed = Buffer.from(seedText, 'hex'); - const keyPair = basecoin.generateKeyPair(seed); + const keyPair = await basecoin.generateKeyPair(seed); keyPair.pub.should.equal(testData.SEED_ACCOUNT.publicKey); keyPair.prv.should.equal(testData.SEED_ACCOUNT.privateKey); }); - it('should validate a public key', function () { - const keyPair = basecoin.generateKeyPair(); + it('should validate a public key', async function () { + const keyPair = await basecoin.generateKeyPair(); keyPair.should.have.property('pub'); keyPair.should.have.property('prv'); basecoin.isValidPub(keyPair.pub).should.equal(true); }); - it('should validate a private key', function () { - const keyPair = basecoin.generateKeyPair(); + it('should validate a private key', async function () { + const keyPair = await basecoin.generateKeyPair(); keyPair.should.have.property('pub'); keyPair.should.have.property('prv'); diff --git a/modules/sdk-coin-btc/src/inscriptionBuilder.ts b/modules/sdk-coin-btc/src/inscriptionBuilder.ts index 44fbbfa46f..a5940b2a80 100644 --- a/modules/sdk-coin-btc/src/inscriptionBuilder.ts +++ b/modules/sdk-coin-btc/src/inscriptionBuilder.ts @@ -40,7 +40,7 @@ export class InscriptionBuilder implements IInscriptionBuilder { const user = await this.wallet.baseCoin.keychains().get({ id: this.wallet.keyIds()[KeyIndices.USER] }); assert(user.pub); - const derived = this.coin.deriveKeyWithSeed({ key: user.pub, seed: inscriptionData.toString() }); + const derived = await this.coin.deriveKeyWithSeed({ key: user.pub, seed: inscriptionData.toString() }); const compressedPublicKey = xpubToCompressedPub(derived.key); const xOnlyPublicKey = utxolib.bitgo.outputScripts.toXOnlyPublicKey(Buffer.from(compressedPublicKey, 'hex')); @@ -220,7 +220,7 @@ export class InscriptionBuilder implements IInscriptionBuilder { }, })) as HalfSignedUtxoTransaction; - const derived = this.coin.deriveKeyWithSeed({ key: xprv, seed: inscriptionData.toString() }); + const derived = await this.coin.deriveKeyWithSeed({ key: xprv, seed: inscriptionData.toString() }); const prv = xprvToRawPrv(derived.key); const fullySignedRevealTransaction = await inscriptions.signRevealTransaction( @@ -250,7 +250,7 @@ export class InscriptionBuilder implements IInscriptionBuilder { txPrebuild: PrebuildTransactionResult ): Promise { const userKeychain = await this.wallet.baseCoin.keychains().get({ id: this.wallet.keyIds()[KeyIndices.USER] }); - const prv = this.wallet.getUserPrv({ keychain: userKeychain, walletPassphrase }); + const prv = await this.wallet.getUserPrv({ keychain: userKeychain, walletPassphrase }); const halfSigned = (await this.wallet.signTransaction({ prv, txPrebuild })) as HalfSignedUtxoTransaction; return this.wallet.submitTransaction({ halfSigned }); diff --git a/modules/sdk-coin-cspr/src/cspr.ts b/modules/sdk-coin-cspr/src/cspr.ts index b41027b363..76cd5d77c6 100644 --- a/modules/sdk-coin-cspr/src/cspr.ts +++ b/modules/sdk-coin-cspr/src/cspr.ts @@ -130,7 +130,7 @@ export class Cspr extends BaseCoin { * @param {Buffer} seed - Seed from which the new keypair should be generated, otherwise a random seed is used * @returns {Object} object with generated xpub and xprv */ - generateKeyPair(seed?: Buffer): KeyPair { + async generateKeyPair(seed?: Buffer): Promise { const keyPair = seed ? new CsprLib.KeyPair({ seed }) : new CsprLib.KeyPair(); const keys = keyPair.getExtendedKeys(); diff --git a/modules/sdk-coin-cspr/test/unit/cspr.ts b/modules/sdk-coin-cspr/test/unit/cspr.ts index 5f5724ade9..004cbef809 100644 --- a/modules/sdk-coin-cspr/test/unit/cspr.ts +++ b/modules/sdk-coin-cspr/test/unit/cspr.ts @@ -44,8 +44,8 @@ describe('Casper', function () { }); describe('Keypairs:', () => { - it('should generate a keypair from random seed', function () { - const keyPair = basecoin.generateKeyPair(); + it('should generate a keypair from random seed', async function () { + const keyPair = await basecoin.generateKeyPair(); keyPair.should.have.property('pub'); keyPair.should.have.property('prv'); }); @@ -63,16 +63,16 @@ describe('Casper', function () { ); }); - it('should validate a public key', function () { - const keyPair = basecoin.generateKeyPair(); + it('should validate a public key', async function () { + const keyPair = await basecoin.generateKeyPair(); keyPair.should.have.property('pub'); keyPair.should.have.property('prv'); basecoin.isValidPub(keyPair.pub).should.equal(true); }); - it('should validate a private key', function () { - const keyPair = basecoin.generateKeyPair(); + it('should validate a private key', async function () { + const keyPair = await basecoin.generateKeyPair(); keyPair.should.have.property('pub'); keyPair.should.have.property('prv'); diff --git a/modules/sdk-coin-dot/src/dot.ts b/modules/sdk-coin-dot/src/dot.ts index fe5487d040..e5a7e61549 100644 --- a/modules/sdk-coin-dot/src/dot.ts +++ b/modules/sdk-coin-dot/src/dot.ts @@ -132,7 +132,7 @@ export class Dot extends BaseCoin { * @param seed * @returns {Object} object with generated pub, prv */ - generateKeyPair(seed?: Buffer): KeyPair { + async generateKeyPair(seed?: Buffer): Promise { const keyPair = seed ? dotUtils.keyPairFromSeed(new Uint8Array(seed)) : new DotKeyPair(); const keys = keyPair.getKeys(); if (!keys.prv) { diff --git a/modules/sdk-coin-dot/test/unit/dot.ts b/modules/sdk-coin-dot/test/unit/dot.ts index 4f17606cdd..dcb51d9425 100644 --- a/modules/sdk-coin-dot/test/unit/dot.ts +++ b/modules/sdk-coin-dot/test/unit/dot.ts @@ -100,15 +100,15 @@ describe('DOT:', function () { }); describe('Generate wallet key pair: ', () => { - it('should generate key pair', () => { - const kp = basecoin.generateKeyPair(); + it('should generate key pair', async () => { + const kp = await basecoin.generateKeyPair(); basecoin.isValidPub(kp.pub).should.equal(true); basecoin.isValidPrv(kp.prv).should.equal(true); }); - it('should generate key pair from seed', () => { + it('should generate key pair from seed', async () => { const seed = Buffer.from('9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60', 'hex'); - const kp = basecoin.generateKeyPair(seed); + const kp = await basecoin.generateKeyPair(seed); basecoin.isValidPub(kp.pub).should.equal(true); basecoin.isValidPrv(kp.prv).should.equal(true); }); diff --git a/modules/sdk-coin-dot/test/unit/keypair.ts b/modules/sdk-coin-dot/test/unit/keypair.ts index 3620661cd0..e783dceab0 100644 --- a/modules/sdk-coin-dot/test/unit/keypair.ts +++ b/modules/sdk-coin-dot/test/unit/keypair.ts @@ -42,23 +42,6 @@ describe('Dot KeyPair', () => { const keyPair = new KeyPair({ pub: bs58Account.publicKey }); should.equal(keyPair.getKeys().pub, publicKeyHexString); }); - - it('should be able to derive keypair with hardened derivation', () => { - // using ed25519 (polkadot.js uses sr25519) - const keyPair = new KeyPair({ - prv: account1.secretKey, - }); - const derivationIndex = 0; - const derived = keyPair.deriveHardened(`m/0'/0'/0'/${derivationIndex}'`); - const derivedKeyPair = new KeyPair({ - prv: derived.prv || '', - }); - should.exists(derivedKeyPair.getAddress(DotAddressFormat.substrate)); - should.exists(derivedKeyPair.getKeys().prv); - should.exists(derivedKeyPair.getKeys().pub); - should.equal(derivedKeyPair.getKeys().prv?.length, 64); - should.equal(derivedKeyPair.getKeys().pub?.length, 64); - }); }); describe('KeyPair validation', () => { diff --git a/modules/sdk-coin-eos/src/eos.ts b/modules/sdk-coin-eos/src/eos.ts index 64fb633390..9fc72c0226 100644 --- a/modules/sdk-coin-eos/src/eos.ts +++ b/modules/sdk-coin-eos/src/eos.ts @@ -249,7 +249,7 @@ export class Eos extends BaseCoin { * * @param seed - Seed from which the new keypair should be generated, otherwise a random seed is used */ - generateKeyPair(seed?: Buffer): KeyPair { + async generateKeyPair(seed?: Buffer): Promise { 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 diff --git a/modules/sdk-coin-eos/test/unit/eos.ts b/modules/sdk-coin-eos/test/unit/eos.ts index 59592cbe11..83f02f7b21 100644 --- a/modules/sdk-coin-eos/test/unit/eos.ts +++ b/modules/sdk-coin-eos/test/unit/eos.ts @@ -88,14 +88,14 @@ describe('EOS:', function () { basecoin.isValidMemoId(EosInputs.string257CharsLong).should.equal(false); }); - it('should validate pub key', () => { - const { pub } = basecoin.keychains().create(); + it('should validate pub key', async () => { + const { pub } = await basecoin.keychains().create(); basecoin.isValidPub(pub).should.equal(true); }); describe('Keypairs:', () => { - it('should generate a keypair from random seed', function () { - const keyPair = basecoin.generateKeyPair(); + it('should generate a keypair from random seed', async function () { + const keyPair = await basecoin.generateKeyPair(); keyPair.should.have.property('pub'); keyPair.should.have.property('prv'); @@ -103,9 +103,9 @@ describe('EOS:', function () { basecoin.isValidPrv(keyPair.prv).should.equal(true); }); - it('should generate a keypair from seed', function () { + it('should generate a keypair from seed', async function () { const seed = Buffer.from('c3b09c24731be2851b641d9d5b3f60fa129695c24071768d15654bea207b7bb6', 'hex'); - const keyPair = basecoin.generateKeyPair(seed); + const keyPair = await basecoin.generateKeyPair(seed); keyPair.pub.should.equal( 'xpub661MyMwAqRbcF2SUqUMiqxWGwaVX6sH4okTtX8jxJ1A14wfL8W7jZEoNE537JqSESXFpTcXCZahPz7RKQLpAEGsVp233dc5CffLSecpU13X' @@ -212,7 +212,7 @@ describe('EOS:', function () { }; const seed = Buffer.from('c3b09c24731be2851b624d9d5b3f60fa129695c24071768d15654bea207b7bb6', 'hex'); - const keyPair = basecoin.generateKeyPair(seed); + const keyPair = await basecoin.generateKeyPair(seed); const { halfSigned } = await basecoin.signTransaction({ txPrebuild: tx, prv: keyPair.prv }); const signature = halfSigned.transaction.signatures[0]; @@ -357,7 +357,7 @@ describe('EOS:', function () { }, }; const seed = Buffer.from('c3b09c24731be2851b624d9d5b3f60fa129695c24071768d15654bea207b7bb6', 'hex'); - const keyPair = basecoin.generateKeyPair(seed); + const keyPair = await basecoin.generateKeyPair(seed); const txParams = { txPrebuild, prv: keyPair.prv, diff --git a/modules/sdk-coin-eos/test/unit/eosToken.ts b/modules/sdk-coin-eos/test/unit/eosToken.ts index d7d7631ba6..8646b26581 100644 --- a/modules/sdk-coin-eos/test/unit/eosToken.ts +++ b/modules/sdk-coin-eos/test/unit/eosToken.ts @@ -41,7 +41,7 @@ describe('EOS Token:', function () { let newTxPrebuild; let newTxParams; - before(function () { + before(async function () { const walletData = { id: '5a78dd561c6258a907f1eeaee132f796', users: [ @@ -126,7 +126,7 @@ describe('EOS Token:', function () { }, }; const seed = Buffer.from('c3b09c24731be2851b624d9d5b3f60fa129695c24071768d15654bea207b7bb6', 'hex'); - const keyPair = baseCoin.generateKeyPair(seed); + const keyPair = await baseCoin.generateKeyPair(seed); const txParams = { txPrebuild, prv: keyPair.prv, diff --git a/modules/sdk-coin-eth2/src/eth2.ts b/modules/sdk-coin-eth2/src/eth2.ts index 33aac3b967..5d9bf9e85d 100644 --- a/modules/sdk-coin-eth2/src/eth2.ts +++ b/modules/sdk-coin-eth2/src/eth2.ts @@ -299,7 +299,7 @@ export class Eth2 extends BaseCoin { * @param seed - byte array to generate BLS key pair from * @returns {Object} object with generated pub and prv */ - generateKeyPair(seed?: Buffer): IBlsKeyPair { + async generateKeyPair(seed?: Buffer): Promise { let keyPair = new Eth2KeyPair(); if (seed && Eth2KeyPair.isValidPrv(seed)) { const seedStr = Buffer.from(seed).toString('hex'); diff --git a/modules/sdk-coin-eth2/test/unit/eth2.ts b/modules/sdk-coin-eth2/test/unit/eth2.ts index ca1b826eda..20d4e35c27 100644 --- a/modules/sdk-coin-eth2/test/unit/eth2.ts +++ b/modules/sdk-coin-eth2/test/unit/eth2.ts @@ -36,16 +36,16 @@ describe('Ethereum 2.0', function () { localBasecoin.preCreateBitGo(params); }); - it('should generate keypair from prv', function () { + it('should generate keypair from prv', async function () { const prv = Buffer.from('4fd90ae1b8f724a4902615c09145ae134617c325b98c6970dcf62ab9cc5e12f3', 'hex'); const localBaseCoin = bitgo.coin('teth2'); - const keyPair = localBaseCoin.generateKeyPair(prv); + const keyPair = await localBaseCoin.generateKeyPair(prv); keyPair.prv.should.equal('4fd90ae1b8f724a4902615c09145ae134617c325b98c6970dcf62ab9cc5e12f3'); }); - it('should generate keypair without seed', function () { + it('should generate keypair without seed', async function () { const localBaseCoin = bitgo.coin('teth2') as Teth2; - const keyPair = localBaseCoin.generateKeyPair(); + const keyPair = await localBaseCoin.generateKeyPair(); keyPair.pub?.length.should.equal(96); localBaseCoin.isValidPub(keyPair.pub as string).should.be.true(); keyPair.secretShares?.every((secretShare) => secretShare.length.should.equal(64)); @@ -63,9 +63,9 @@ describe('Ethereum 2.0', function () { describe('Sign message:', () => { it('should sign and validate a string message', async function () { - const userKeyPair = basecoin.generateKeyPair(); - const backupKeyPair = basecoin.generateKeyPair(); - const walletKeyPair = basecoin.generateKeyPair(); + const userKeyPair = await basecoin.generateKeyPair(); + const backupKeyPair = await basecoin.generateKeyPair(); + const walletKeyPair = await basecoin.generateKeyPair(); const message = 'hello world'; const userKey = basecoin.aggregateShares({ @@ -92,9 +92,9 @@ describe('Ethereum 2.0', function () { }); it('should sign with child key and validate a string message', async function () { - const userKeyPair = basecoin.generateKeyPair(); - const backupKeyPair = basecoin.generateKeyPair(); - const walletKeyPair = basecoin.generateKeyPair(); + const userKeyPair = await basecoin.generateKeyPair(); + const backupKeyPair = await basecoin.generateKeyPair(); + const walletKeyPair = await basecoin.generateKeyPair(); const message = 'hello world'; const userKey = basecoin.aggregateShares({ @@ -129,10 +129,10 @@ describe('Ethereum 2.0', function () { }); it('should fail to validate a string message with wrong public key', async function () { - const userKeyPair = basecoin.generateKeyPair(); - const backupKeyPair = basecoin.generateKeyPair(); - const walletKeyPair = basecoin.generateKeyPair(); - const otherKeyPair = basecoin.generateKeyPair(); + const userKeyPair = await basecoin.generateKeyPair(); + const backupKeyPair = await basecoin.generateKeyPair(); + const walletKeyPair = await basecoin.generateKeyPair(); + const otherKeyPair = await basecoin.generateKeyPair(); const message = 'hello world'; const userKey = basecoin.aggregateShares({ diff --git a/modules/sdk-coin-ethw/src/ethw.ts b/modules/sdk-coin-ethw/src/ethw.ts index d012f669c9..d470716e24 100644 --- a/modules/sdk-coin-ethw/src/ethw.ts +++ b/modules/sdk-coin-ethw/src/ethw.ts @@ -43,7 +43,7 @@ export class Ethw extends Eth { parseTransaction(params: ParseTransactionOptions): Promise { throw new Error('Method not implemented.'); } - generateKeyPair(seed?: Buffer | undefined): KeyPair { + async generateKeyPair(seed?: Buffer): Promise { throw new Error('Method not implemented.'); } diff --git a/modules/sdk-coin-hbar/src/hbar.ts b/modules/sdk-coin-hbar/src/hbar.ts index a1df0cfeec..cb5ee2223d 100644 --- a/modules/sdk-coin-hbar/src/hbar.ts +++ b/modules/sdk-coin-hbar/src/hbar.ts @@ -20,6 +20,7 @@ import { TokenEnablementConfig, BaseBroadcastTransactionOptions, BaseBroadcastTransactionResult, + EddsaKeyDeriver, } from '@bitgo/sdk-core'; import { BigNumber } from 'bignumber.js'; import * as stellar from 'stellar-sdk'; @@ -180,7 +181,11 @@ export class Hbar extends BaseCoin { * @param seed * @returns {Object} object with generated pub, prv */ - generateKeyPair(seed?: Buffer): KeyPair { + async generateKeyPair(seed?: Buffer, rootKey?: boolean): Promise { + if (rootKey) { + const keypair = await EddsaKeyDeriver.createRootKeys(seed); + return keypair; + } const keyPair = seed ? new HbarKeyPair({ seed }) : new HbarKeyPair(); const keys = keyPair.getKeys(); @@ -592,4 +597,9 @@ export class Hbar extends BaseCoin { return { txId: transactionResponse.transactionId.toString(), status: transactionReceipt.status.toString() }; } + + /** @inheritDoc */ + async deriveKeyWithSeed({ key, seed }: { key: string; seed: string }): Promise<{ key: any; derivationPath: string }> { + return EddsaKeyDeriver.deriveKeyWithSeed(key, seed); + } } diff --git a/modules/sdk-coin-hbar/test/unit/hbar.ts b/modules/sdk-coin-hbar/test/unit/hbar.ts index 50cd821961..7afef50f48 100644 --- a/modules/sdk-coin-hbar/test/unit/hbar.ts +++ b/modules/sdk-coin-hbar/test/unit/hbar.ts @@ -195,18 +195,18 @@ describe('Hedera Hashgraph:', function () { }); describe('Keypairs:', () => { - it('should generate a keypair from random seed', function () { - const keyPair = basecoin.generateKeyPair(); + it('should generate a keypair from random seed', async function () { + const keyPair = await basecoin.generateKeyPair(); keyPair.should.have.property('pub'); keyPair.should.have.property('prv'); basecoin.isValidPub(keyPair.pub).should.equal(true); }); - it('should generate a keypair from a seed', function () { + it('should generate a keypair from a seed', async function () { const seedText = '80350b4208d381fbfe2276a326603049fe500731c46d3c9936b5ce036b51377f'; const seed = Buffer.from(seedText, 'hex'); - const keyPair = basecoin.generateKeyPair(seed); + const keyPair = await basecoin.generateKeyPair(seed); keyPair.prv.should.equal( '302e020100300506032b65700422042080350b4208d381fbfe2276a326603049fe500731c46d3c9936b5ce036b51377f' @@ -226,6 +226,32 @@ describe('Hedera Hashgraph:', function () { '302e020100300506032b6570042204205965b6bfe85e8d543c36bf1b39800d633948bfdf742160d522f2391c57b0b055' ); }); + + it('should generate rootKeys with seed', async function () { + const seedText = + '3ba996300549b5d303c411fb83fbd5440da67ef1d725d5dbf57974d9187b2c6a3c6de78fed110d6cc17b5d98cd10e6de299a67c24cd767e966ec061717f07c5e'; + const seed = Buffer.from(seedText, 'hex'); + const keyPair = await basecoin.generateKeyPair(seed, true); + + assert.equal( + keyPair.prv, + 'rprv50d51c4eba07fb365fe0f6522d6e16fb8958c6c39498f30e5d9e0e946e252d79:3c6de78fed110d6cc17b5d98cd10e6de299a67c24cd767e966ec061717f07c5e:dad7c8d66bd039ee3e1886a2eb060e4b3812b142722d5074ce8364971592f669' + ); + assert.equal( + keyPair.pub, + 'rpub136aff358cb5503b0617943ec322f54998fab5df37220474b66026d833310122:3c6de78fed110d6cc17b5d98cd10e6de299a67c24cd767e966ec061717f07c5e' + ); + }); + + it('should generate rootKeys without seed', async function () { + const keyPair = await basecoin.generateKeyPair(undefined, true); + assert.ok(keyPair.prv); + assert.ok(keyPair.prv.startsWith('rprv')); + assert.equal(keyPair.prv.length, 198); + assert.ok(keyPair.pub); + assert.ok(keyPair.pub.startsWith('rpub')); + assert.equal(keyPair.pub.length, 133); + }); }); describe('Verify Transaction:', () => { diff --git a/modules/sdk-coin-near/src/near.ts b/modules/sdk-coin-near/src/near.ts index 173249fa3e..46d55c2db3 100644 --- a/modules/sdk-coin-near/src/near.ts +++ b/modules/sdk-coin-near/src/near.ts @@ -187,7 +187,7 @@ export class Near extends BaseCoin { * @param seed * @returns {Object} object with generated pub, prv */ - generateKeyPair(seed?: Buffer): KeyPair { + async generateKeyPair(seed?: Buffer): Promise { const keyPair = seed ? new NearKeyPair({ seed }) : new NearKeyPair(); const keys = keyPair.getKeys(); if (!keys.prv) { diff --git a/modules/sdk-coin-near/test/unit/near.ts b/modules/sdk-coin-near/test/unit/near.ts index 185e3fefad..c24647ab70 100644 --- a/modules/sdk-coin-near/test/unit/near.ts +++ b/modules/sdk-coin-near/test/unit/near.ts @@ -127,15 +127,15 @@ describe('NEAR:', function () { }); describe('Generate wallet key pair: ', () => { - it('should generate key pair', () => { - const kp = basecoin.generateKeyPair(); + it('should generate key pair', async () => { + const kp = await basecoin.generateKeyPair(); basecoin.isValidPub(kp.pub).should.equal(true); basecoin.isValidPrv(kp.prv).should.equal(true); }); - it('should generate key pair from seed', () => { + it('should generate key pair from seed', async () => { const seed = Buffer.from('9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60', 'hex'); - const kp = basecoin.generateKeyPair(seed); + const kp = await basecoin.generateKeyPair(seed); basecoin.isValidPub(kp.pub).should.equal(true); basecoin.isValidPrv(kp.prv).should.equal(true); }); diff --git a/modules/sdk-coin-sol/src/sol.ts b/modules/sdk-coin-sol/src/sol.ts index b8b5e0c9ec..11e4f6f997 100644 --- a/modules/sdk-coin-sol/src/sol.ts +++ b/modules/sdk-coin-sol/src/sol.ts @@ -337,7 +337,7 @@ export class Sol extends BaseCoin { * @param {Buffer} seed - Seed from which the new SolKeyPair should be generated, otherwise a random seed is used * @returns {Object} object with generated pub and prv */ - generateKeyPair(seed?: Buffer | undefined): KeyPair { + async generateKeyPair(seed?: Buffer): Promise { const result = seed ? new SolKeyPair({ seed }).getKeys() : new SolKeyPair().getKeys(); return result as KeyPair; } diff --git a/modules/sdk-coin-sol/test/unit/keyPair.ts b/modules/sdk-coin-sol/test/unit/keyPair.ts index 612814db6c..5d3330c786 100644 --- a/modules/sdk-coin-sol/test/unit/keyPair.ts +++ b/modules/sdk-coin-sol/test/unit/keyPair.ts @@ -2,7 +2,7 @@ import assert from 'assert'; import { KeyPair } from '../../src'; import should from 'should'; import * as testData from '../resources/sol'; -import { isValidPublicKey, isValidAddress, isValidPrivateKey } from '../../src/lib/utils'; +import { isValidPublicKey, isValidAddress } from '../../src/lib/utils'; describe('Sol KeyPair', function () { const defaultSeed = { seed: testData.accountWithSeed.seed }; @@ -158,34 +158,4 @@ describe('Sol KeyPair', function () { keyPair.verifySignature(message, signature).should.equal(false); }); }); - - describe('deriveHardened', () => { - it('should derive child key pairs', () => { - const rootKeyPair = new KeyPair(); - for (let i = 0; i < 50; i++) { - const path = `m/0'/0'/0'/${i}'`; - const derived = new KeyPair(rootKeyPair.deriveHardened(path)); - - isValidPublicKey(derived.getKeys().pub).should.be.true(); - isValidAddress(derived.getAddress()).should.be.true(); - - const derivedPrv = derived.getKeys().prv; - should.exist(derivedPrv); - isValidPrivateKey(derivedPrv as string | Uint8Array).should.be.true(); - - const rederived = new KeyPair(rootKeyPair.deriveHardened(path)); - rederived.getKeys().should.deepEqual(derived.getKeys()); - } - }); - - it('should not be able to derive without private key', () => { - const rootKeyPair = new KeyPair({ pub: testData.accountWithSeed.publicKey }); - assert.throws(() => rootKeyPair.deriveHardened("m/0'/0'/0'/0'"), /need private key to derive hardened keypair/); - }); - - it('should throw error for non-hardened path', () => { - const rootKeyPair = new KeyPair(); - assert.throws(() => rootKeyPair.deriveHardened('m/0/0/0/0'), /Invalid derivation path/); - }); - }); }); diff --git a/modules/sdk-coin-sol/test/unit/sol.ts b/modules/sdk-coin-sol/test/unit/sol.ts index 5e8577b719..9d0dd5ca32 100644 --- a/modules/sdk-coin-sol/test/unit/sol.ts +++ b/modules/sdk-coin-sol/test/unit/sol.ts @@ -118,13 +118,13 @@ describe('SOL:', function () { const amount = '10000'; const validator = resources.validator; - before(function () { + before(async function () { bitgo = TestBitGo.decorate(BitGoAPI, { env: 'mock' }); bitgo.safeRegister('sol', Tsol.createInstance); bitgo.safeRegister('tsol', Tsol.createInstance); bitgo.initializeTestVars(); basecoin = bitgo.coin('tsol') as Tsol; - keyPair = basecoin.generateKeyPair(resources.accountWithSeed.seed); + keyPair = await basecoin.generateKeyPair(resources.accountWithSeed.seed); newTxPrebuild = () => { return _.cloneDeep(txPrebuild); }; @@ -1268,12 +1268,18 @@ describe('SOL:', function () { }); describe('Keypair:', () => { - it('should generate a keypair from random seed', function () { - should.throws(() => basecoin.generateKeyPair('placeholder' as any), 'generateKeyPair method not implemented'); - }); - - it('should generate a keypair from a seed', function () { - should.throws(() => basecoin.generateKeyPair('placeholder' as any), 'generateKeyPair method not implemented'); + it('should generate a keypair from random seed', async function () { + const seedText = + '80350b4208d381fbfe2276a326603049fe500731c46d3c9936b5ce036b51377f24bab7dd0c2af7f107416ef858ff79b0670c72406dad064e72bb17fc0a9038bb'; + const keyPair = await basecoin.generateKeyPair(Buffer.from(seedText, 'hex')); + keyPair.should.have.property('pub'); + keyPair.should.have.property('prv'); + }); + + it('should generate a keypair from a seed', async function () { + const keyPair = await basecoin.generateKeyPair(); + keyPair.should.have.property('pub'); + keyPair.should.have.property('prv'); }); }); diff --git a/modules/sdk-coin-stx/src/stx.ts b/modules/sdk-coin-stx/src/stx.ts index 8c8ce1c7f6..42ce5bc5d2 100644 --- a/modules/sdk-coin-stx/src/stx.ts +++ b/modules/sdk-coin-stx/src/stx.ts @@ -74,7 +74,7 @@ export class Stx extends BaseCoin { * @param {Buffer} seed - Seed from which the new keypair should be generated, otherwise a random seed is used * @returns {Object} object with generated pub and prv */ - generateKeyPair(seed?: Buffer): KeyPair { + async generateKeyPair(seed?: Buffer): Promise { const keyPair = seed ? new StxLib.KeyPair({ seed }) : new StxLib.KeyPair(); const keys = keyPair.getExtendedKeys(); diff --git a/modules/sdk-coin-stx/test/unit/stx.ts b/modules/sdk-coin-stx/test/unit/stx.ts index ae38089e8c..75fedc91df 100644 --- a/modules/sdk-coin-stx/test/unit/stx.ts +++ b/modules/sdk-coin-stx/test/unit/stx.ts @@ -190,17 +190,17 @@ describe('STX:', function () { }); describe('Keypairs:', () => { - it('should generate a keypair from random seed', function () { - const keyPair = basecoin.generateKeyPair(); + it('should generate a keypair from random seed', async function () { + const keyPair = await basecoin.generateKeyPair(); keyPair.should.have.property('pub'); keyPair.should.have.property('prv'); }); - it('should generate a keypair from a seed', function () { + it('should generate a keypair from a seed', async function () { const seedText = '80350b4208d381fbfe2276a326603049fe500731c46d3c9936b5ce036b51377f24bab7dd0c2af7f107416ef858ff79b0670c72406dad064e72bb17fc0a9038bb'; const seed = Buffer.from(seedText, 'hex'); - const keyPair = basecoin.generateKeyPair(seed); + const keyPair = await basecoin.generateKeyPair(seed); keyPair.pub.should.equal( 'xpub661MyMwAqRbcFAwqvSGbk35kJf7CQqdN1w4CMUBBTqH5e3ivjU6D8ugv9hRSgRbRenC4w3ahXdLVahwjgjXhSuQKMdNdn55Y9TNSagBktws' ); diff --git a/modules/sdk-coin-sui/src/sui.ts b/modules/sdk-coin-sui/src/sui.ts index 3495c26a03..c49f2b653e 100644 --- a/modules/sdk-coin-sui/src/sui.ts +++ b/modules/sdk-coin-sui/src/sui.ts @@ -198,7 +198,7 @@ export class Sui extends BaseCoin { }; } - generateKeyPair(seed?: Buffer): KeyPair { + async generateKeyPair(seed?: Buffer): Promise { const keyPair = seed ? new SuiKeyPair({ seed }) : new SuiKeyPair(); const keys = keyPair.getKeys(); if (!keys.prv) { diff --git a/modules/sdk-coin-ton/src/ton.ts b/modules/sdk-coin-ton/src/ton.ts index 141b5a413f..ae6856a30a 100644 --- a/modules/sdk-coin-ton/src/ton.ts +++ b/modules/sdk-coin-ton/src/ton.ts @@ -154,7 +154,7 @@ export class Ton extends BaseCoin { }; } - generateKeyPair(seed?: Buffer): KeyPair { + async generateKeyPair(seed?: Buffer): Promise { const keyPair = seed ? new TonKeyPair({ seed }) : new TonKeyPair(); const keys = keyPair.getKeys(); if (!keys.prv) { diff --git a/modules/sdk-coin-trx/src/trx.ts b/modules/sdk-coin-trx/src/trx.ts index a679d11293..efe5b697c2 100644 --- a/modules/sdk-coin-trx/src/trx.ts +++ b/modules/sdk-coin-trx/src/trx.ts @@ -210,7 +210,7 @@ export class Trx extends BaseCoin { * @param seed * @returns {Object} object with generated pub, prv */ - generateKeyPair(seed?: Buffer): KeyPair { + async generateKeyPair(seed?: Buffer): Promise { // TODO: move this and address creation logic to account-lib 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 diff --git a/modules/sdk-coin-trx/test/unit/trx.ts b/modules/sdk-coin-trx/test/unit/trx.ts index 7475bc18a8..2a36f9f030 100644 --- a/modules/sdk-coin-trx/test/unit/trx.ts +++ b/modules/sdk-coin-trx/test/unit/trx.ts @@ -166,18 +166,18 @@ describe('TRON:', function () { }); describe('Keypairs:', () => { - it('should generate a keypair from random seed', function () { - const keyPair = basecoin.generateKeyPair(); + it('should generate a keypair from random seed', async function () { + const keyPair = await basecoin.generateKeyPair(); keyPair.should.have.property('pub'); keyPair.should.have.property('prv'); basecoin.isValidPub(keyPair.pub).should.equal(true); }); - it('should generate a keypair from a seed', function () { + it('should generate a keypair from a seed', async function () { const seedText = '80350b4208d381fbfe2276a326603049fe500731c46d3c9936b5ce036b51377f24bab7dd0c2af7f107416ef858ff79b0670c72406dad064e72bb17fc0a9038bb'; const seed = Buffer.from(seedText, 'hex'); - const keyPair = basecoin.generateKeyPair(seed); + const keyPair = await basecoin.generateKeyPair(seed); keyPair.pub.should.equal( 'xpub661MyMwAqRbcFAwqvSGbk35kJf7CQqdN1w4CMUBBTqH5e3ivjU6D8ugv9hRSgRbRenC4w3ahXdLVahwjgjXhSuQKMdNdn55Y9TNSagBktws' ); diff --git a/modules/sdk-coin-xlm/src/xlm.ts b/modules/sdk-coin-xlm/src/xlm.ts index b2271a1d07..6e0a2afbad 100644 --- a/modules/sdk-coin-xlm/src/xlm.ts +++ b/modules/sdk-coin-xlm/src/xlm.ts @@ -1,6 +1,5 @@ import assert from 'assert'; import * as _ from 'lodash'; -import * as utxolib from '@bitgo/utxo-lib'; import * as querystring from 'querystring'; import * as url from 'url'; import * as request from 'superagent'; @@ -12,7 +11,6 @@ import { BitGoBase, checkKrsProvider, common, - Ed25519KeyDeriver, ExtraPrebuildParamsOptions, InvalidAddressError, InvalidMemoIdError, @@ -33,6 +31,7 @@ import { VerifyAddressOptions as BaseVerifyAddressOptions, VerifyTransactionOptions as BaseVerifyTransactionOptions, Wallet, + EddsaKeyDeriver, } from '@bitgo/sdk-core'; import { toBitgoRequest } from '@bitgo/sdk-api'; import { getStellarKeys } from './getStellarKeys'; @@ -214,7 +213,11 @@ export class Xlm extends BaseCoin { * @param seed * @returns generated pub and prv */ - generateKeyPair(seed: Buffer): KeyPair { + async generateKeyPair(seed?: Buffer, rootKey?: boolean): Promise { + if (rootKey) { + const keypair = await EddsaKeyDeriver.createRootKeys(seed); + return keypair; + } const pair = seed ? stellar.Keypair.fromRawEd25519Seed(seed) : stellar.Keypair.random(); return { pub: pair.publicKey(), @@ -782,7 +785,7 @@ export class Xlm extends BaseCoin { } seed = stellar.StrKey.decodeEd25519SecretSeed(rootPrv); } - const keyPair = this.generateKeyPair(seed); + const keyPair = await this.generateKeyPair(seed); // extend the wallet initialization params walletParams.rootPrivateKey = keyPair.prv; return walletParams; @@ -1112,29 +1115,8 @@ export class Xlm extends BaseCoin { return true; } - /** - * Derive a hardened child public key from a master key seed using an additional seed for randomness. - * - * Due to technical differences between keypairs on the ed25519 curve and the secp256k1 curve, - * only hardened private key derivation is supported. - * - * @param key seed for the master key. Note: Not the public key or encoded private key. This is the raw seed. - * @param entropySeed random seed which is hashed to generate the derivation path - */ - deriveKeyWithSeed({ key, seed }: { key: string; seed: string }): { derivationPath: string; key: string } { - const derivationPathInput = utxolib.crypto.hash256(Buffer.from(seed, 'utf8')).toString('hex'); - const derivationPathParts = [ - 999999, - parseInt(derivationPathInput.slice(0, 7), 16), - parseInt(derivationPathInput.slice(7, 14), 16), - ]; - const derivationPath = 'm/' + derivationPathParts.map((part) => `${part}'`).join('/'); - const derivedKey = Ed25519KeyDeriver.derivePath(derivationPath, key).key; - const keypair = stellar.Keypair.fromRawEd25519Seed(derivedKey); - return { - key: keypair.publicKey(), - derivationPath, - }; + async deriveKeyWithSeed({ key, seed }: { key: string; seed: string }): Promise<{ key: any; derivationPath: string }> { + return await EddsaKeyDeriver.deriveKeyWithSeed(key, seed); } /** diff --git a/modules/sdk-coin-xlm/test/unit/xlm.ts b/modules/sdk-coin-xlm/test/unit/xlm.ts index 436eabda56..942cfeb5f4 100644 --- a/modules/sdk-coin-xlm/test/unit/xlm.ts +++ b/modules/sdk-coin-xlm/test/unit/xlm.ts @@ -124,8 +124,8 @@ describe('XLM:', function () { }); }); - it('should validate pub key', () => { - const { pub } = basecoin.keychains().create(); + it('should validate pub key', async () => { + const { pub } = await basecoin.keychains().create(); basecoin.isValidPub(pub).should.equal(true); }); @@ -276,7 +276,7 @@ describe('XLM:', function () { }); it('should supplement wallet generation with provided private key', async function () { - const rootPrivateKey = basecoin.generateKeyPair().prv; + const rootPrivateKey = await basecoin.generateKeyPair().prv; const walletParams = await basecoin.supplementGenerateWallet({ rootPrivateKey }); walletParams.should.have.property('rootPrivateKey'); walletParams.rootPrivateKey.should.equal(rootPrivateKey); @@ -385,8 +385,8 @@ describe('XLM:', function () { validSignature.should.equal(true); }); - it('should fail to verify the wrong signature on a tx', function () { - const keyPair = basecoin.generateKeyPair(); + it('should fail to verify the wrong signature on a tx', async function () { + const keyPair = await basecoin.generateKeyPair(); const tx = new stellar.Transaction(halfSignedTransaction.halfSigned.txBase64, stellar.Networks.TESTNET); const validSignature = basecoin.verifySignature(keyPair.pub, tx.hash(), tx.signatures[0].signature()); validSignature.should.equal(false); @@ -863,8 +863,8 @@ describe('XLM:', function () { }); describe('Keypairs:', () => { - it('should generate a keypair from random seed', function () { - const keyPair = basecoin.generateKeyPair(); + it('should generate a keypair from random seed', async function () { + const keyPair = await basecoin.generateKeyPair(); keyPair.should.have.property('pub'); keyPair.should.have.property('prv'); @@ -875,9 +875,9 @@ describe('XLM:', function () { basecoin.isValidPrv(keyPair.prv).should.equal(true); }); - it('should generate a keypair from seed', function () { + it('should generate a keypair from seed', async function () { const seed = randomBytes(32); - const keyPair = basecoin.generateKeyPair(seed); + const keyPair = await basecoin.generateKeyPair(seed); keyPair.should.have.property('pub'); keyPair.should.have.property('prv'); @@ -891,20 +891,8 @@ describe('XLM:', function () { stellar.StrKey.encodeEd25519SecretSeed(seed).should.equal(secret); }); - it('should deterministically derive a child key from master seed and entropy seed', () => { - const seed = Buffer.alloc(32).fill(0).toString('hex'); - const masterSeed = '0x01020304050607080910111213141516171819202122232425262728293031'; - - const derivedKey = basecoin.deriveKeyWithSeed({ key: masterSeed, seed }); - - derivedKey.should.have.properties({ - key: 'GCJR3ORBWOKGFA3FTGYDDQVFEEMCYXFHY6KAUOTU4MQMFHK4LLSWWGLW', - derivationPath: "m/999999'/230673453'/206129755'", - }); - }); - - it('should validate pub key', () => { - const { pub } = basecoin.keychains().create(); + it('should validate pub key', async () => { + const { pub } = await basecoin.keychains().create(); basecoin.isValidPub(pub).should.equal(true); }); }); diff --git a/modules/sdk-coin-xrp/src/xrp.ts b/modules/sdk-coin-xrp/src/xrp.ts index 4860abeb1f..1ebbfea83c 100644 --- a/modules/sdk-coin-xrp/src/xrp.ts +++ b/modules/sdk-coin-xrp/src/xrp.ts @@ -621,7 +621,7 @@ export class Xrp extends BaseCoin { * Generate a new keypair for this coin. * @param seed Seed from which the new keypair should be generated, otherwise a random seed is used */ - public generateKeyPair(seed?: Buffer): KeyPair { + public async generateKeyPair(seed?: Buffer): Promise { 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 diff --git a/modules/sdk-coin-xrp/test/unit/xrp.ts b/modules/sdk-coin-xrp/test/unit/xrp.ts index e0b9d2caaf..4234b3cca0 100644 --- a/modules/sdk-coin-xrp/test/unit/xrp.ts +++ b/modules/sdk-coin-xrp/test/unit/xrp.ts @@ -193,8 +193,8 @@ describe('XRP:', function () { details.should.have.property('rootPrivateKey'); }); - it('should validate pub key', () => { - const { pub } = basecoin.keychains().create(); + it('should validate pub key', async () => { + const { pub } = await basecoin.keychains().create(); basecoin.isValidPub(pub).should.equal(true); }); }); diff --git a/modules/sdk-coin-xtz/src/xtz.ts b/modules/sdk-coin-xtz/src/xtz.ts index d1a737e89c..ac79028c14 100644 --- a/modules/sdk-coin-xtz/src/xtz.ts +++ b/modules/sdk-coin-xtz/src/xtz.ts @@ -81,7 +81,7 @@ export class Xtz extends BaseCoin { * @param seed * @returns {Object} object with generated xpub, xprv */ - generateKeyPair(seed?: Buffer): SdkCoreKeyPair { + async generateKeyPair(seed?: Buffer): Promise { const keyPair = seed ? new KeyPair({ seed }) : new KeyPair(); const keys = keyPair.getExtendedKeys(); diff --git a/modules/sdk-coin-xtz/test/unit/xtz.ts b/modules/sdk-coin-xtz/test/unit/xtz.ts index 974fe6a80f..f538bedee5 100644 --- a/modules/sdk-coin-xtz/test/unit/xtz.ts +++ b/modules/sdk-coin-xtz/test/unit/xtz.ts @@ -152,18 +152,18 @@ describe('Tezos:', function () { }); describe('Keypairs:', () => { - it('should generate a keypair from random seed', function () { - const keyPair = basecoin.generateKeyPair(); + it('should generate a keypair from random seed', async function () { + const keyPair = await basecoin.generateKeyPair(); keyPair.should.have.property('pub'); keyPair.should.have.property('prv'); basecoin.isValidPub(keyPair.pub).should.equal(true); }); - it('should generate a keypair from a seed', function () { + it('should generate a keypair from a seed', async function () { const seedText = '80350b4208d381fbfe2276a326603049fe500731c46d3c9936b5ce036b51377f24bab7dd0c2af7f107416ef858ff79b0670c72406dad064e72bb17fc0a9038bb'; const seed = Buffer.from(seedText, 'hex'); - const keyPair = basecoin.generateKeyPair(seed); + const keyPair = await basecoin.generateKeyPair(seed); keyPair.pub.should.equal( 'xpub661MyMwAqRbcFAwqvSGbk35kJf7CQqdN1w4CMUBBTqH5e3ivjU6D8ugv9hRSgRbRenC4w3ahXdLVahwjgjXhSuQKMdNdn55Y9TNSagBktws' ); @@ -175,7 +175,7 @@ describe('Tezos:', function () { describe('Sign message:', () => { it('should sign and validate a string message', async function () { - const keyPair = basecoin.generateKeyPair(); + const keyPair = await basecoin.generateKeyPair(); const message = 'hello world'; const signature = await basecoin.signMessage(keyPair, message); @@ -187,7 +187,7 @@ describe('Tezos:', function () { }); it('should fail to validate a string message with wrong public key', async function () { - const keyPair = basecoin.generateKeyPair(); + const keyPair = await basecoin.generateKeyPair(); const message = 'hello world'; const signature = await basecoin.signMessage(keyPair, message); diff --git a/modules/sdk-core/src/account-lib/baseCoin/ed25519KeyPair.ts b/modules/sdk-core/src/account-lib/baseCoin/ed25519KeyPair.ts index a62b397be0..8e9cf8ef6a 100644 --- a/modules/sdk-core/src/account-lib/baseCoin/ed25519KeyPair.ts +++ b/modules/sdk-core/src/account-lib/baseCoin/ed25519KeyPair.ts @@ -6,7 +6,6 @@ import { toHex, toUint8Array, } from '../util/crypto'; -import { Ed25519KeyDeriver } from '../util/ed25519KeyDeriver'; import { BaseKeyPair } from './baseKeyPair'; import { AddressFormat, DotAddressFormat } from './enum'; import { isPrivateKey, isPublicKey, isSeed, DefaultKeys, KeyPairOptions } from './iface'; @@ -122,21 +121,4 @@ export abstract class Ed25519KeyPair implements BaseKeyPair { const publicKey = toUint8Array(this.keyPair.pub); return nacl.sign.detached.verify(messageToVerify, signature, publicKey); } - - /** - * Derives a hardened child key pair using this key pair's secret key - * as the seed. - * - * @param path derivation path - */ - deriveHardened(path: string): DefaultKeys { - if (!this.keyPair?.prv) { - throw new Error('need private key to derive hardened keypair'); - } - - const seed = Ed25519KeyDeriver.derivePath(path, this.keyPair.prv).key; - const derivedKeyPair = nacl.sign.keyPair.fromSeed(seed); - - return this.getKeyPair(derivedKeyPair); - } } diff --git a/modules/sdk-core/src/account-lib/index.ts b/modules/sdk-core/src/account-lib/index.ts index a1cdc4feaa..f72e1a9e29 100644 --- a/modules/sdk-core/src/account-lib/index.ts +++ b/modules/sdk-core/src/account-lib/index.ts @@ -5,5 +5,7 @@ export * from './mpc'; export * from './util/crypto'; // Deprecated export * as acountLibCrypto from './util/crypto'; +// Deprecated export * from './util/ed25519KeyDeriver'; export * from './staking'; +export * from './util/eddsaKeyDeriver'; diff --git a/modules/sdk-core/src/account-lib/mpc/util.ts b/modules/sdk-core/src/account-lib/mpc/util.ts index ad5f2c522e..a9465276eb 100644 --- a/modules/sdk-core/src/account-lib/mpc/util.ts +++ b/modules/sdk-core/src/account-lib/mpc/util.ts @@ -6,6 +6,7 @@ import { bigIntToBufferBE, clamp, getPaillierPublicKey, + getDerivationPath, } from '@bitgo/sdk-lib-mpc'; /** @@ -19,4 +20,5 @@ export { bigIntToBufferBE, clamp, getPaillierPublicKey, + getDerivationPath, }; diff --git a/modules/sdk-core/src/account-lib/util/ed25519KeyDeriver.ts b/modules/sdk-core/src/account-lib/util/ed25519KeyDeriver.ts index acd98bf763..7ce712897b 100644 --- a/modules/sdk-core/src/account-lib/util/ed25519KeyDeriver.ts +++ b/modules/sdk-core/src/account-lib/util/ed25519KeyDeriver.ts @@ -14,6 +14,8 @@ export interface HdKeypair { * * https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0005.md * https://github.com/satoshilabs/slips/blob/master/slip-0010.md + * + * @deprecated */ export class Ed25519KeyDeriver { /** diff --git a/modules/sdk-core/src/account-lib/util/eddsaKeyDeriver.ts b/modules/sdk-core/src/account-lib/util/eddsaKeyDeriver.ts new file mode 100644 index 0000000000..69bdb537a0 --- /dev/null +++ b/modules/sdk-core/src/account-lib/util/eddsaKeyDeriver.ts @@ -0,0 +1,112 @@ +import { createHash } from 'crypto'; +import nacl from 'tweetnacl'; + +import { + Eddsa, + bigIntFromBufferLE, + bigIntToBufferLE, + clamp, + Ed25519BIP32, + bigIntFromBufferBE, + getDerivationPath, +} from '../mpc'; + +export type RootKeys = { + prv: string; + pub: string; +}; + +export class EddsaKeyDeriver { + static readonly ROOT_PUB_KEY_PREFIX = 'rpub'; + static readonly ROOT_PRV_KEY_PREFIX = 'rprv'; + + static async createRootKeys(seed?: Buffer): Promise { + if (seed && seed.length !== 64) { + throw new Error('Invalid seed length, requires 64 bytes Buffer'); + } + await Eddsa.initialize(); + const startingSeed = seed || Buffer.from(nacl.randomBytes(64)); + const hash = createHash('sha512').update(startingSeed.slice(0, 32)).digest(); + + const chaincode = startingSeed.slice(32).toString('hex'); + const prefix = hash.slice(32).toString('hex'); + + const sk = clamp(bigIntFromBufferLE(hash.slice(0, 32))); + const skString = bigIntToBufferLE(sk).toString('hex'); + const pkString = bigIntToBufferLE(Eddsa.curve.basePointMult(sk)).toString('hex'); + + return { + prv: this.formatRootPrvKey(skString, chaincode, prefix), + pub: this.formatRootPubKey(pkString, chaincode), + }; + } + + private static formatRootPubKey(pub: string, chaincode: string): string { + return this.ROOT_PUB_KEY_PREFIX + pub + ':' + chaincode; + } + + private static formatRootPrvKey(prv: string, chaincode: string, prefix: string): string { + return this.ROOT_PRV_KEY_PREFIX + prv + ':' + chaincode + ':' + prefix; + } + + private static parseRootPubKey(pub: string): { pub: string; chaincode: string } { + const parts = pub.replace(this.ROOT_PUB_KEY_PREFIX, '').split(':'); + if (parts.length !== 2) { + throw new Error('Invalid public key'); + } + return { + pub: parts[0], + chaincode: parts[1], + }; + } + + private static parseRootPrvKey(prv: string): { prv: string; chaincode: string; prefix: string } { + const parts = prv.replace(this.ROOT_PRV_KEY_PREFIX, '').split(':'); + if (parts.length !== 3) { + throw new Error('Invalid private key'); + } + return { + prv: parts[0], + chaincode: parts[1], + prefix: parts[2], + }; + } + + static async deriveKeyWithSeed(key: string, seed: string): Promise<{ key: string; derivationPath: string }> { + const hdTree = await Ed25519BIP32.initialize(); + const derivationPath = getDerivationPath(seed); + + if (key.startsWith(this.ROOT_PUB_KEY_PREFIX)) { + const { pub, chaincode } = this.parseRootPubKey(key); + + const publicKeychain = { + pk: bigIntFromBufferLE(Buffer.from(pub, 'hex')), + chaincode: bigIntFromBufferBE(Buffer.from(chaincode, 'hex')), + }; + + const derivedKeychain = hdTree.publicDerive(publicKeychain, derivationPath); + const derivedPub = bigIntToBufferLE(derivedKeychain.pk).toString('hex'); + + return { key: derivedPub, derivationPath }; + } else if (key.startsWith(EddsaKeyDeriver.ROOT_PRV_KEY_PREFIX)) { + await Eddsa.initialize(); + + const { prv, chaincode, prefix } = this.parseRootPrvKey(key); + const skBI = bigIntFromBufferLE(Buffer.from(prv, 'hex')); + + const privateKeychain = { + sk: skBI, + pk: Eddsa.curve.basePointMult(skBI), + chaincode: bigIntFromBufferBE(Buffer.from(chaincode, 'hex')), + prefix: bigIntFromBufferBE(Buffer.from(prefix, 'hex')), + }; + const derivedKeychain = hdTree.privateDerive(privateKeychain, derivationPath); + const derivedPrv = bigIntToBufferLE(derivedKeychain.sk).toString('hex'); + const derivedPub = bigIntToBufferLE(derivedKeychain.pk).toString('hex'); + + return { key: derivedPrv + derivedPub, derivationPath }; + } else { + throw new Error('Invalid key format'); + } + } +} diff --git a/modules/sdk-core/src/bitgo/baseCoin/baseCoin.ts b/modules/sdk-core/src/bitgo/baseCoin/baseCoin.ts index 3ad0ba52dc..29f5e5d19f 100644 --- a/modules/sdk-core/src/bitgo/baseCoin/baseCoin.ts +++ b/modules/sdk-core/src/bitgo/baseCoin/baseCoin.ts @@ -379,7 +379,13 @@ export abstract class BaseCoin implements IBaseCoin { * @param seed * @returns {{key: string, derivationPath: string}} */ - deriveKeyWithSeed({ key, seed }: { key: string; seed: string }): { key: string; derivationPath: string } { + async deriveKeyWithSeed({ + key, + seed, + }: { + key: string; + seed: string; + }): Promise<{ key: string; derivationPath: string }> { function sha256(input) { return crypto.createHash('sha256').update(input).digest(); } @@ -432,7 +438,7 @@ export abstract class BaseCoin implements IBaseCoin { * * @param seed */ - abstract generateKeyPair(seed?: Buffer): KeyPair; + abstract generateKeyPair(seed?: Buffer, rootKey?: boolean): Promise; /** * Return boolean indicating whether input is valid public key for the coin. diff --git a/modules/sdk-core/src/bitgo/baseCoin/iBaseCoin.ts b/modules/sdk-core/src/bitgo/baseCoin/iBaseCoin.ts index bb1eac3df7..a1cef68ff6 100644 --- a/modules/sdk-core/src/bitgo/baseCoin/iBaseCoin.ts +++ b/modules/sdk-core/src/bitgo/baseCoin/iBaseCoin.ts @@ -497,12 +497,12 @@ export interface IBaseCoin { ): Promise; newWalletObject(walletParams: any): IWallet; feeEstimate(params: FeeEstimateOptions): Promise; - deriveKeyWithSeed(params: DeriveKeyWithSeedOptions): { key: string; derivationPath: string }; + deriveKeyWithSeed(params: DeriveKeyWithSeedOptions): Promise<{ key: string; derivationPath: string }>; keyIdsForSigning(): number[]; preCreateBitGo(params: PrecreateBitGoOptions): void; initiateRecovery(params: InitiateRecoveryOptions): never; parseTransaction(params: ParseTransactionOptions): Promise; - generateKeyPair(seed?: Buffer): KeyPair; + generateKeyPair(seed?: Buffer, rootKey?: boolean): Promise; isValidPub(pub: string): boolean; isValidMofNSetup(params: ValidMofNOptions): boolean; isValidAddress(address: string): boolean; diff --git a/modules/sdk-core/src/bitgo/keychain/iKeychains.ts b/modules/sdk-core/src/bitgo/keychain/iKeychains.ts index bf2b5894bd..201f51def3 100644 --- a/modules/sdk-core/src/bitgo/keychain/iKeychains.ts +++ b/modules/sdk-core/src/bitgo/keychain/iKeychains.ts @@ -174,7 +174,7 @@ export interface IKeychains { list(params?: ListKeychainOptions): Promise; updatePassword(params: UpdatePasswordOptions): Promise; updateSingleKeychainPassword(params?: UpdateSingleKeychainPasswordOptions): Keychain; - create(params?: { seed?: Buffer }): KeyPair; + create(params?: { seed?: Buffer }): Promise; add(params?: AddKeychainOptions): Promise; createBitGo(params?: CreateBitGoOptions): Promise; createBackup(params?: CreateBackupOptions): Promise; diff --git a/modules/sdk-core/src/bitgo/keychain/keychains.ts b/modules/sdk-core/src/bitgo/keychain/keychains.ts index 8efaf76fa1..fc75834ac1 100644 --- a/modules/sdk-core/src/bitgo/keychain/keychains.ts +++ b/modules/sdk-core/src/bitgo/keychain/keychains.ts @@ -174,7 +174,7 @@ export class Keychains implements IKeychains { * Create a public/private key pair * @param params.seed */ - create(params: { seed?: Buffer } = {}): KeyPair { + async create(params: { seed?: Buffer } = {}): Promise { return this.baseCoin.generateKeyPair(params.seed); } diff --git a/modules/sdk-core/src/bitgo/utils/blsUtils.ts b/modules/sdk-core/src/bitgo/utils/blsUtils.ts index 14394f4941..3382c5831a 100644 --- a/modules/sdk-core/src/bitgo/utils/blsUtils.ts +++ b/modules/sdk-core/src/bitgo/utils/blsUtils.ts @@ -265,8 +265,8 @@ export class BlsUtils extends MpcUtils implements IBlsUtils { enterprise?: string; originalPasscodeEncryptionCode?: string; }): Promise { - const userKeyShare = this.baseCoin.generateKeyPair() as IBlsKeyPair; - const backupKeyShare = this.baseCoin.generateKeyPair() as IBlsKeyPair; + const userKeyShare = (await this.baseCoin.generateKeyPair()) as IBlsKeyPair; + const backupKeyShare = (await this.baseCoin.generateKeyPair()) as IBlsKeyPair; const randomHexString = randomBytes(12).toString('hex'); const randomHexString2 = randomBytes(12).toString('hex'); diff --git a/modules/sdk-core/src/bitgo/wallet/iWallet.ts b/modules/sdk-core/src/bitgo/wallet/iWallet.ts index a4ce4b1a0c..d9f7fe457d 100644 --- a/modules/sdk-core/src/bitgo/wallet/iWallet.ts +++ b/modules/sdk-core/src/bitgo/wallet/iWallet.ts @@ -735,7 +735,7 @@ export interface IWallet { removeUser(params?: RemoveUserOptions): Promise; prebuildTransaction(params?: PrebuildTransactionOptions): Promise; signTransaction(params?: WalletSignTransactionOptions): Promise; - getUserPrv(params?: GetUserPrvOptions): string; + getUserPrv(params?: GetUserPrvOptions): Promise; prebuildAndSignTransaction(params?: PrebuildAndSignTransactionOptions): Promise; accelerateTransaction(params?: AccelerateTransactionOptions): Promise; submitTransaction(params?: SubmitTransactionOptions): Promise; diff --git a/modules/sdk-core/src/bitgo/wallet/wallet.ts b/modules/sdk-core/src/bitgo/wallet/wallet.ts index 17ce9ed8b6..880a32998c 100644 --- a/modules/sdk-core/src/bitgo/wallet/wallet.ts +++ b/modules/sdk-core/src/bitgo/wallet/wallet.ts @@ -1705,7 +1705,11 @@ export class Wallet implements IWallet { }); if (this.multisigType() === 'tss') { - return this.signTransactionTss({ ...presign, prv: this.getUserPrv(presign as GetUserPrvOptions), apiVersion }); + return this.signTransactionTss({ + ...presign, + prv: await this.getUserPrv(presign as GetUserPrvOptions), + apiVersion, + }); } let { pubs } = params; @@ -1737,7 +1741,7 @@ export class Wallet implements IWallet { } return this.baseCoin.signTransaction({ ...signTransactionParams, - prv: this.getUserPrv(presign as GetUserPrvOptions), + prv: await this.getUserPrv(presign as GetUserPrvOptions), }); } @@ -1768,7 +1772,7 @@ export class Wallet implements IWallet { ...params, walletData: this._wallet, tssUtils: this.tssUtils, - prv: this.getUserPrv(userPrvOptions), + prv: await this.getUserPrv(userPrvOptions), keychain: keychains[0], backupKeychain: keychains.length > 1 ? keychains[1] : null, bitgoKeychain: keychains.length > 2 ? keychains[2] : null, @@ -1804,7 +1808,7 @@ export class Wallet implements IWallet { ...params, walletData: this._wallet, tssUtils: this.tssUtils, - prv: this.getUserPrv(userPrvOptions), + prv: await this.getUserPrv(userPrvOptions), keychain: keychains[0], backupKeychain: keychains.length > 1 ? keychains[1] : null, bitgoKeychain: keychains.length > 2 ? keychains[2] : null, @@ -1818,7 +1822,7 @@ export class Wallet implements IWallet { * @param [params.keychain / params.key] (object) or params.prv (string) * @param params.walletPassphrase (string) */ - getUserPrv(params: GetUserPrvOptions = {}): string { + async getUserPrv(params: GetUserPrvOptions = {}): Promise { const userKeychain = params.keychain || params.key; let userPrv = params.prv; if (userPrv && typeof userPrv !== 'string') { @@ -1839,7 +1843,7 @@ export class Wallet implements IWallet { if (userPrv && params.coldDerivationSeed) { // the derivation only makes sense when a key already exists - const derivation = this.baseCoin.deriveKeyWithSeed({ key: userPrv, seed: params.coldDerivationSeed }); + const derivation = await this.baseCoin.deriveKeyWithSeed({ key: userPrv, seed: params.coldDerivationSeed }); userPrv = derivation.key; } else if (!userPrv) { if (!userKeychain || typeof userKeychain !== 'object') { diff --git a/modules/sdk-core/src/bitgo/wallet/wallets.ts b/modules/sdk-core/src/bitgo/wallet/wallets.ts index e4b67ec5f1..1d2a41cee0 100644 --- a/modules/sdk-core/src/bitgo/wallet/wallets.ts +++ b/modules/sdk-core/src/bitgo/wallet/wallets.ts @@ -371,7 +371,7 @@ export class Wallets implements IWallets { userKeychainParams = userKeychain; if (params.coldDerivationSeed) { // the derivation only makes sense when a key already exists - const derivation = this.baseCoin.deriveKeyWithSeed({ + const derivation = await this.baseCoin.deriveKeyWithSeed({ key: params.userKey, seed: params.coldDerivationSeed, }); @@ -384,7 +384,7 @@ export class Wallets implements IWallets { throw new Error('cannot generate user keypair without passphrase'); } // Create the user key. - userKeychain = this.baseCoin.keychains().create(); + userKeychain = await this.baseCoin.keychains().create(); userKeychain.encryptedPrv = this.bitgo.encrypt({ password: passphrase, input: userKeychain.prv }); userKeychainParams = { pub: userKeychain.pub, diff --git a/modules/sdk-core/src/coins/fiateur.ts b/modules/sdk-core/src/coins/fiateur.ts index 55860d946b..c3e0ed616e 100644 --- a/modules/sdk-core/src/coins/fiateur.ts +++ b/modules/sdk-core/src/coins/fiateur.ts @@ -50,7 +50,7 @@ export class FiatEur extends BaseCoin { throw new MethodNotImplementedError(); } - generateKeyPair(seed?: Buffer): KeyPair { + async generateKeyPair(seed?: Buffer): Promise { throw new MethodNotImplementedError(); } diff --git a/modules/sdk-core/src/coins/fiatgbp.ts b/modules/sdk-core/src/coins/fiatgbp.ts index 0ee927cf05..f138b2cfa3 100644 --- a/modules/sdk-core/src/coins/fiatgbp.ts +++ b/modules/sdk-core/src/coins/fiatgbp.ts @@ -50,7 +50,7 @@ export class FiatGBP extends BaseCoin { throw new MethodNotImplementedError(); } - generateKeyPair(seed?: Buffer): KeyPair { + async generateKeyPair(seed?: Buffer): Promise { throw new MethodNotImplementedError(); } diff --git a/modules/sdk-core/src/coins/fiatusd.ts b/modules/sdk-core/src/coins/fiatusd.ts index b48a7fddf8..20945fcc58 100644 --- a/modules/sdk-core/src/coins/fiatusd.ts +++ b/modules/sdk-core/src/coins/fiatusd.ts @@ -50,7 +50,7 @@ export class FiatUsd extends BaseCoin { throw new MethodNotImplementedError(); } - generateKeyPair(seed?: Buffer): KeyPair { + async generateKeyPair(seed?: Buffer): Promise { throw new MethodNotImplementedError(); } diff --git a/modules/sdk-core/src/coins/ofc.ts b/modules/sdk-core/src/coins/ofc.ts index 80790566f8..c4c62a2d36 100644 --- a/modules/sdk-core/src/coins/ofc.ts +++ b/modules/sdk-core/src/coins/ofc.ts @@ -35,7 +35,7 @@ export class Ofc extends BaseCoin { * @param seed * @returns {Object} object with generated pub and prv */ - generateKeyPair(seed?: Buffer): KeyPair { + async generateKeyPair(seed?: Buffer): Promise { 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 diff --git a/modules/sdk-core/src/coins/susd.ts b/modules/sdk-core/src/coins/susd.ts index 2c8027a00d..9c75080878 100644 --- a/modules/sdk-core/src/coins/susd.ts +++ b/modules/sdk-core/src/coins/susd.ts @@ -50,7 +50,7 @@ export class Susd extends BaseCoin { throw new MethodNotImplementedError(); } - generateKeyPair(seed?: Buffer): KeyPair { + async generateKeyPair(seed?: Buffer): Promise { throw new MethodNotImplementedError(); } diff --git a/scripts/sdk-coin-generator/template/boilerplates/simple/.mainnet.ts b/scripts/sdk-coin-generator/template/boilerplates/simple/.mainnet.ts index 5a329fa7d9..1a3668d772 100644 --- a/scripts/sdk-coin-generator/template/boilerplates/simple/.mainnet.ts +++ b/scripts/sdk-coin-generator/template/boilerplates/simple/.mainnet.ts @@ -50,7 +50,7 @@ export class <%= constructor %> extends BaseCoin { throw new Error('Method not implemented.'); } - generateKeyPair(seed?: Buffer): KeyPair { + async generateKeyPair(seed?: Buffer): Promise { throw new Error('Method not implemented.'); }