Skip to content

Commit 189a0fc

Browse files
Merge remote-tracking branch 'origin/WP-2860/add-examples-for-tss-recovery'
2 parents 4fcc613 + 15fe12b commit 189a0fc

File tree

5 files changed

+59
-0
lines changed

5 files changed

+59
-0
lines changed

examples/ts/tss-recovery/.nvmrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
20
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<Value from keycard>
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { ECDSAUtils } from '@bitgo/sdk-core';
2+
import * as crypto from 'crypto';
3+
import * as fs from 'fs';
4+
import * as secp256k1 from 'secp256k1';
5+
import assert = require('assert');
6+
import { bigIntFromBufferBE, bigIntToBufferBE, HDTree, Secp256k1Bip32HdTree } from '@bitgo/sdk-lib-mpc';
7+
8+
const sampleMessage = "Hello, World!";
9+
// Replace the following variables with your own values. Moreover, copy the encrypted user and backup keys from the key card into the userKey.txt and backupKey.txt files.
10+
const commonKeyChain = "<Public key from key card>";
11+
const walletPassphrase = "<Wallet passphrase>";
12+
13+
14+
async function testRecoveryMpcV2() {
15+
const userKey = fs.readFileSync('userKey.txt', 'utf8').replace(/(\r\n|\n|\r)/gm, "");
16+
const backupKey = fs.readFileSync('backupKey.txt', 'utf8').replace(/(\r\n|\n|\r)/gm, "");
17+
// Converting the user and backup keys on the keycard to key buffers that can be used in signing.
18+
const mpcv2KeyChain = await ECDSAUtils.getMpcV2RecoveryKeyShares(userKey, backupKey, walletPassphrase);
19+
assert(mpcv2KeyChain.commonKeyChain === commonKeyChain, "Common key chain on keys do not match the common key chain from keycard.");
20+
// Computing SHA256 hash of the message.
21+
const messageHash = crypto.createHash('sha256').update(Buffer.from(sampleMessage, 'utf8')).digest();
22+
// Signing the message hash using the MPCv2 recovery key shares.
23+
const signature = await ECDSAUtils.signRecoveryMpcV2(messageHash, mpcv2KeyChain.userKeyShare, mpcv2KeyChain.backupKeyShare, commonKeyChain);
24+
const hdTree: HDTree = new Secp256k1Bip32HdTree();
25+
// Deriving the public key at path m/0 from the common key chain.
26+
const derivedPub = hdTree.publicDerive(
27+
{
28+
pk: bigIntFromBufferBE(Buffer.from(commonKeyChain.slice(0, 66), 'hex')),
29+
chaincode: bigIntFromBufferBE(Buffer.from(commonKeyChain.slice(66), 'hex')),
30+
},
31+
'm/0'
32+
);
33+
// Verifying that the signature is valid.
34+
const isSignatureValid = secp256k1.ecdsaVerify(Buffer.concat([Buffer.from(signature.r, 'hex'), Buffer.from(signature.s, 'hex')]), messageHash, bigIntToBufferBE(derivedPub.pk));
35+
assert(isSignatureValid, "Signature is not valid.");
36+
}
37+
38+
testRecoveryMpcV2().catch((e) => console.error(e));
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"name": "tss-recovery",
3+
"version": "1.0.0",
4+
"description": "TSS User <> Backup keycard signing",
5+
"scripts": {
6+
"test:ecdsa": "ts-node mpcv2-recovery.ts",
7+
"test:eddsa": "ts-node TBD"
8+
},
9+
"dependencies": {
10+
"@bitgo/sdk-core": "28.10.0",
11+
"@bitgo/sdk-lib-mpc": "10.0.0",
12+
"secp256k1": "5.0.0"
13+
},
14+
"devDependencies": {
15+
"ts-node": "10.9.1",
16+
"typescript": "5.1.6"
17+
}
18+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<Value from keycard>

0 commit comments

Comments
 (0)