Skip to content

Commit e1d7324

Browse files
Merge pull request #38 from BitGo/WP-eddsa-keygen-draft
Wp eddsa keygen draft
2 parents 0c38563 + 73808ab commit e1d7324

File tree

11 files changed

+2190
-2153
lines changed

11 files changed

+2190
-2153
lines changed

src/api/enclaved/eddsaFinalize.ts

Lines changed: 0 additions & 126 deletions
This file was deleted.

src/api/enclaved/eddsaInitialize.ts

Lines changed: 0 additions & 119 deletions
This file was deleted.

src/api/enclaved/mpcFinalize.ts

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
import debug from 'debug';
2+
import * as bitgoSdk from '@bitgo/sdk-core';
3+
4+
import {
5+
EnclavedApiSpecRouteRequest,
6+
MpcFinalizeRequestType,
7+
} from '../../enclavedBitgoExpress/routers/enclavedApiSpec';
8+
import { KmsClient } from '../../kms/kmsClient';
9+
import { gpgDecrypt, gpgEncrypt } from './utils';
10+
11+
const debugLogger = debug('bitgo:enclavedBitGoExpress:mpcFinalize');
12+
13+
export async function eddsaFinalize(req: EnclavedApiSpecRouteRequest<'v1.mpc.finalize', 'post'>) {
14+
// request parsing
15+
const {
16+
source,
17+
encryptedDataKey,
18+
encryptedData,
19+
counterPartyGpgPub,
20+
bitgoKeyChain,
21+
coin,
22+
}: MpcFinalizeRequestType = req.decoded;
23+
const counterPartyToSourceKeyShare = req.decoded.counterPartyKeyShare;
24+
25+
// setup clients
26+
const kms = new KmsClient(req.config);
27+
const MPC = await bitgoSdk.Eddsa.initialize();
28+
const eddsaUtils = new bitgoSdk.EddsaUtils(req.bitgo, req.bitgo.coin(coin));
29+
30+
// indexes
31+
const sourceIndex = source === 'user' ? 1 : 2;
32+
const counterPartyIndex = source === 'user' ? 2 : 1;
33+
const bitgoIndex = 3;
34+
35+
// Decrypt the encrypted payload using encryptedDataKey to retrieve the previous state of computation
36+
const decryptedDataKey = await kms.decryptDataKey(encryptedDataKey);
37+
const previousState = JSON.parse(
38+
req.bitgo.decrypt({
39+
input: encryptedData,
40+
password: decryptedDataKey,
41+
}),
42+
);
43+
debugLogger('Decrypted previous state:', previousState);
44+
const { sourceGpgPub, sourceGpgPrv, sourcePrivateShare } = previousState;
45+
let sourceToCounterPartyKeyShare = previousState.counterPartyKeyShare;
46+
47+
// decrypt bitgo private key share
48+
const bitgoToSourceKeyShare = bitgoKeyChain.keyShares.find(
49+
(keyShare: any) => keyShare.to === source,
50+
);
51+
if (!bitgoToSourceKeyShare) {
52+
throw new Error(`BitGo key share for source ${source} not found`);
53+
}
54+
const bitgoToSourcePrivateShare = await gpgDecrypt(
55+
bitgoToSourceKeyShare.privateShare,
56+
sourceGpgPrv,
57+
);
58+
59+
await eddsaUtils.verifyWalletSignatures(
60+
source === 'user' ? sourceGpgPub : counterPartyGpgPub,
61+
source === 'user' ? counterPartyGpgPub : sourceGpgPub,
62+
bitgoKeyChain,
63+
bitgoToSourcePrivateShare,
64+
sourceIndex,
65+
);
66+
67+
// construct yShare and key
68+
const bitgoToSourceYShare = {
69+
i: sourceIndex, // to whom
70+
j: bitgoIndex, // from whom
71+
y: bitgoToSourceKeyShare.publicShare.slice(0, 64),
72+
v: bitgoToSourceKeyShare.vssProof,
73+
u: bitgoToSourcePrivateShare.slice(0, 64),
74+
chaincode: bitgoToSourcePrivateShare.slice(64),
75+
};
76+
77+
// TOOD: clean up, probably doign unnecessary transformations
78+
const counterPartyToSourcePrivateShare = await gpgDecrypt(
79+
counterPartyToSourceKeyShare.privateShare,
80+
sourceGpgPrv,
81+
);
82+
const counterPartyToSourceYShare = {
83+
i: sourceIndex, // to whom
84+
j: counterPartyIndex, // from whom
85+
y: counterPartyToSourceKeyShare.publicShare.slice(0, 64),
86+
v: counterPartyToSourceKeyShare.vssProof,
87+
u: counterPartyToSourcePrivateShare.slice(0, 64),
88+
chaincode: counterPartyToSourcePrivateShare.slice(64),
89+
};
90+
91+
// Log the constructed keychain for verification
92+
debugLogger('Constructed keychain:', {
93+
sourcePrivateShare,
94+
bitgoToSourceKeyShare,
95+
counterPartyToSourceKeyShare,
96+
commonKeychain: bitgoKeyChain.commonKeychain,
97+
});
98+
try {
99+
const combinedKey = MPC.keyCombine(sourcePrivateShare, [
100+
bitgoToSourceYShare,
101+
counterPartyToSourceYShare,
102+
]);
103+
104+
// check common keyChain
105+
const commonKeychain = combinedKey.pShare.y + combinedKey.pShare.chaincode;
106+
if (commonKeychain !== bitgoKeyChain.commonKeychain) {
107+
throw new Error('Failed to create user keychain - commonKeychains do not match.');
108+
}
109+
110+
const sourceSigningMaterial: bitgoSdk.SigningMaterial = {
111+
uShare: sourcePrivateShare,
112+
bitgoYShare: bitgoToSourceYShare,
113+
backupYShare: counterPartyToSourceYShare,
114+
};
115+
116+
debugLogger(`Common keychain for ${source}:`, commonKeychain);
117+
await kms.postKey({
118+
pub: commonKeychain,
119+
prv: JSON.stringify(sourceSigningMaterial),
120+
source,
121+
coin,
122+
type: 'tss',
123+
});
124+
debugLogger(`Stored key ${source} - ${commonKeychain}`);
125+
126+
// if counterPartyGpgPub is provided, encrypt the private key share to be sent to the counter party
127+
if (sourceToCounterPartyKeyShare) {
128+
sourceToCounterPartyKeyShare = {
129+
...sourceToCounterPartyKeyShare,
130+
privateShare: counterPartyGpgPub
131+
? await gpgEncrypt(sourceToCounterPartyKeyShare.privateShare, counterPartyGpgPub)
132+
: sourceToCounterPartyKeyShare.privateShare,
133+
};
134+
}
135+
136+
return {
137+
combinedKey,
138+
counterpartyKeyShare: sourceToCounterPartyKeyShare,
139+
source,
140+
commonKeychain,
141+
};
142+
} catch (e) {
143+
debugLogger(`Error: ${JSON.stringify(e)}`);
144+
if (e instanceof Error) {
145+
debugLogger(`${e.name}: ${e.message}`);
146+
throw e;
147+
}
148+
throw new Error(`Unknown failure: Failed to generate or store key`);
149+
}
150+
}

0 commit comments

Comments
 (0)