UNPKG

2.51 kBPlain TextView Raw
1/**
2 * @prettier
3 *
4 * Utility methods for Ellipic-Curve Diffie-Hellman (ECDH) shared secret generation
5 *
6 * > Elliptic-curve Diffie–Hellman (ECDH) is a key agreement protocol that allows two parties, each having an
7 * > elliptic-curve public–private key pair, to establish a shared secret over an insecure channel.
8 * > This shared secret may be directly used as a key, or to derive another key. The key, or the derived key, can then
9 * > be used to encrypt subsequent communications using a symmetric-key cipher. It is a variant of the Diffie–Hellman
10 * > protocol using elliptic-curve cryptography.
11 *
12 * https://en.wikipedia.org/wiki/Elliptic-curve_Diffie%E2%80%93Hellman
13 */
14
15import * as assert from 'assert';
16import * as bip32 from 'bip32';
17import * as secp256k1 from 'secp256k1';
18import * as utxolib from '@bitgo/utxo-lib';
19
20/**
21 * Calculate the Elliptic Curve Diffie Hellman
22 * @param privateKey HDNode of private key
23 * @param publicKey [neutered] HDNode of public key
24 * @returns Buffer public key buffer that can be used as shared secret (see note)
25 */
26export function getSharedSecret(
27 privateKey: bip32.BIP32Interface | utxolib.ECPair.ECPairInterface | Buffer,
28 publicKey: bip32.BIP32Interface | Buffer
29): Buffer {
30 function isBIP32Interface(k: any): k is bip32.BIP32Interface {
31 return k.constructor.name === 'BIP32';
32 }
33 function isECPairInterface(k: any): k is utxolib.ECPair.ECPairInterface {
34 return k.constructor.name === 'ECPair';
35 }
36 if (isBIP32Interface(privateKey)) {
37 if (!privateKey.privateKey) {
38 throw new Error(`privateNode must be private key`);
39 }
40 privateKey = privateKey.privateKey;
41 } else if (isECPairInterface(privateKey)) {
42 if (privateKey.privateKey === undefined || !Buffer.isBuffer(privateKey.privateKey)) {
43 throw new Error(`unexpected ECPair`);
44 }
45 privateKey = privateKey.privateKey;
46 }
47
48 if (!Buffer.isBuffer(publicKey)) {
49 publicKey = publicKey.publicKey;
50 }
51
52 if (!Buffer.isBuffer(privateKey) || !Buffer.isBuffer(publicKey)) {
53 throw new Error(`invalid state`);
54 }
55
56 assert.strictEqual(privateKey.length, 32);
57 assert.strictEqual(publicKey.length, 33);
58
59 // FIXME(BG-34386): we should use `secp256k1.ecdh()` in the future
60 // see discussion here https://github.com/bitcoin-core/secp256k1/issues/352
61 const buffer = Buffer.from(secp256k1.publicKeyTweakMul(publicKey, privateKey))
62 // remove leading parity bit
63 .slice(1);
64 assert.strictEqual(buffer.length, 32);
65 return buffer;
66}