Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,6 @@ COPY --from=builder /tmp/bitgo/modules/sdk-opensslbytes /var/modules/sdk-openssl
COPY --from=builder /tmp/bitgo/modules/secp256k1 /var/modules/secp256k1/
COPY --from=builder /tmp/bitgo/modules/sjcl /var/modules/sjcl/
COPY --from=builder /tmp/bitgo/modules/statics /var/modules/statics/
COPY --from=builder /tmp/bitgo/modules/utxo-core /var/modules/utxo-core/
COPY --from=builder /tmp/bitgo/modules/unspents /var/modules/unspents/
COPY --from=builder /tmp/bitgo/modules/utxo-lib /var/modules/utxo-lib/
COPY --from=builder /tmp/bitgo/modules/blake2b /var/modules/blake2b/
COPY --from=builder /tmp/bitgo/modules/blake2b-wasm /var/modules/blake2b-wasm/
Expand All @@ -55,6 +53,8 @@ COPY --from=builder /tmp/bitgo/modules/abstract-utxo /var/modules/abstract-utxo/
COPY --from=builder /tmp/bitgo/modules/blockapis /var/modules/blockapis/
COPY --from=builder /tmp/bitgo/modules/sdk-api /var/modules/sdk-api/
COPY --from=builder /tmp/bitgo/modules/sdk-hmac /var/modules/sdk-hmac/
COPY --from=builder /tmp/bitgo/modules/unspents /var/modules/unspents/
COPY --from=builder /tmp/bitgo/modules/utxo-core /var/modules/utxo-core/
COPY --from=builder /tmp/bitgo/modules/utxo-ord /var/modules/utxo-ord/
COPY --from=builder /tmp/bitgo/modules/account-lib /var/modules/account-lib/
COPY --from=builder /tmp/bitgo/modules/sdk-coin-ada /var/modules/sdk-coin-ada/
Expand Down Expand Up @@ -143,8 +143,6 @@ cd /var/modules/sdk-opensslbytes && yarn link && \
cd /var/modules/secp256k1 && yarn link && \
cd /var/modules/sjcl && yarn link && \
cd /var/modules/statics && yarn link && \
cd /var/modules/utxo-core && yarn link && \
cd /var/modules/unspents && yarn link && \
cd /var/modules/utxo-lib && yarn link && \
cd /var/modules/blake2b && yarn link && \
cd /var/modules/blake2b-wasm && yarn link && \
Expand All @@ -153,6 +151,8 @@ cd /var/modules/abstract-utxo && yarn link && \
cd /var/modules/blockapis && yarn link && \
cd /var/modules/sdk-api && yarn link && \
cd /var/modules/sdk-hmac && yarn link && \
cd /var/modules/unspents && yarn link && \
cd /var/modules/utxo-core && yarn link && \
cd /var/modules/utxo-ord && yarn link && \
cd /var/modules/account-lib && yarn link && \
cd /var/modules/sdk-coin-ada && yarn link && \
Expand Down Expand Up @@ -244,8 +244,6 @@ RUN cd /var/bitgo-express && \
yarn link @bitgo/secp256k1 && \
yarn link @bitgo/sjcl && \
yarn link @bitgo/statics && \
yarn link @bitgo/utxo-core && \
yarn link @bitgo/unspents && \
yarn link @bitgo/utxo-lib && \
yarn link @bitgo/blake2b && \
yarn link @bitgo/blake2b-wasm && \
Expand All @@ -254,6 +252,8 @@ RUN cd /var/bitgo-express && \
yarn link @bitgo/blockapis && \
yarn link @bitgo/sdk-api && \
yarn link @bitgo/sdk-hmac && \
yarn link @bitgo/unspents && \
yarn link @bitgo/utxo-core && \
yarn link @bitgo/utxo-ord && \
yarn link @bitgo/account-lib && \
yarn link @bitgo/sdk-coin-ada && \
Expand Down
1 change: 0 additions & 1 deletion modules/sdk-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@
"@bitgo/secp256k1": "^1.8.0",
"@bitgo/sjcl": "^1.0.1",
"@bitgo/statics": "^58.19.0",
"@bitgo/utxo-core": "^1.28.0",
"@bitgo/utxo-lib": "^11.19.0",
"@noble/curves": "1.8.1",
"@stablelib/hex": "^1.0.0",
Expand Down
2 changes: 1 addition & 1 deletion modules/sdk-core/src/bitgo/bip32util.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { bip32utils } from '@bitgo/utxo-core';
import { bip32utils } from '@bitgo/secp256k1';

export const signMessage = bip32utils.signMessage;
export const verifyMessage = bip32utils.verifyMessage;
2 changes: 2 additions & 0 deletions modules/secp256k1/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
"@brandonblack/musig": "^0.0.1-alpha.0",
"@noble/secp256k1": "1.6.3",
"bip32": "^3.0.1",
"bitcoinjs-message": "npm:@bitgo-forks/[email protected]",
"bs58check": "^2.1.2",
"create-hash": "^1.2.0",
"create-hmac": "^1.1.7",
"ecpair": "npm:@bitgo/[email protected]"
Expand Down
69 changes: 69 additions & 0 deletions modules/secp256k1/src/bip32utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { BIP32Interface } from 'bip32';
import * as bitcoinMessage from 'bitcoinjs-message';

const createHash = require('create-hash');
const bs58check = require('bs58check');

/**
* Computes hash160 (RIPEMD160(SHA256(data)))
*/
function hash160(data: Buffer): Buffer {
const sha256Hash = createHash('sha256').update(data).digest();
return createHash('ripemd160').update(sha256Hash).digest();
}

/**
* Encodes a hash with version byte in Base58Check format
*/
function toBase58Check(hash: Buffer, version: number): string {
const payload = Buffer.allocUnsafe(21);
payload.writeUInt8(version, 0);
hash.copy(payload, 1);
return bs58check.encode(payload);
}

// Bitcoin mainnet pubKeyHash version byte
const BITCOIN_PUBKEY_HASH_VERSION = 0x00;

/**
* bip32-aware wrapper around bitcoin-message package
* @see {bitcoinMessage.sign}
*/
export function signMessage(
message: string | Buffer,
privateKey: BIP32Interface | Buffer,
network: { messagePrefix: string }
): Buffer {
if (!Buffer.isBuffer(privateKey)) {
privateKey = privateKey.privateKey as Buffer;
if (!privateKey) {
throw new Error(`must provide privateKey`);
}
}
if (network === null || typeof network !== 'object' || typeof network.messagePrefix !== 'string') {
throw new Error(`invalid argument 'network'`);
}
const compressed = true;
return bitcoinMessage.sign(message, privateKey, compressed, network.messagePrefix);
}

/**
* bip32-aware wrapper around bitcoin-message package
* @see {bitcoinMessage.verify}
*/
export function verifyMessage(
message: string | Buffer,
publicKey: BIP32Interface | Buffer,
signature: Buffer,
network: { messagePrefix: string }
): boolean {
if (!Buffer.isBuffer(publicKey)) {
publicKey = publicKey.publicKey;
}
if (network === null || typeof network !== 'object' || typeof network.messagePrefix !== 'string') {
throw new Error(`invalid argument 'network'`);
}

const address = toBase58Check(hash160(publicKey), BITCOIN_PUBKEY_HASH_VERSION);
return bitcoinMessage.verify(message, address, signature, network.messagePrefix);
}
3 changes: 3 additions & 0 deletions modules/secp256k1/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,8 @@ const ECPair: ECPairAPI = ECPairFactory(ecc);
const bip32: BIP32API = BIP32Factory(ecc);
const musig: MuSig = MuSigFactory(crypto);

import * as bip32utils from './bip32utils';

export {
ecc,
ECPair,
Expand All @@ -209,4 +211,5 @@ export {
BIP32Interface,
musig,
MuSig,
bip32utils,
};
57 changes: 57 additions & 0 deletions modules/secp256k1/test/bip32utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import * as crypto from 'crypto';
import * as assert from 'assert';

import { bip32, bip32utils } from '../src';

const { signMessage, verifyMessage } = bip32utils;

// Bitcoin mainnet message prefix - matches utxolib.networks.bitcoin.messagePrefix
const bitcoinNetwork = {
messagePrefix: '\x18Bitcoin Signed Message:\n',
};

describe('bip32utils', function () {
function getSeedBuffers(length: number) {
return Array.from({ length }).map((_, i) => crypto.createHash('sha256').update(`${i}`).digest());
}

it('signMessage/verifyMessage', function () {
const keys = getSeedBuffers(4).map((seed) => bip32.fromSeed(seed));
const messages = ['hello', 'goodbye', Buffer.from('\x01\x02\x03'), Buffer.from('')];
keys.forEach((key) => {
messages.forEach((message) => {
const signature = signMessage(message, key, bitcoinNetwork);

keys.forEach((otherKey) => {
messages.forEach((otherMessage) => {
const expectValid = message === otherMessage && key === otherKey;
assert.strictEqual(verifyMessage(otherMessage, otherKey, signature, bitcoinNetwork), expectValid);
assert.strictEqual(
verifyMessage(Buffer.from(otherMessage), otherKey, signature, bitcoinNetwork),
expectValid
);
});
});
});
});
});

it('signMessage throws on missing privateKey', function () {
const key = bip32.fromSeed(getSeedBuffers(1)[0]);
const neutered = key.neutered();
assert.throws(() => signMessage('hello', neutered, bitcoinNetwork), /must provide privateKey/);
});

it('signMessage throws on invalid network', function () {
const key = bip32.fromSeed(getSeedBuffers(1)[0]);
assert.throws(() => signMessage('hello', key, null as any), /invalid argument 'network'/);
assert.throws(() => signMessage('hello', key, {} as any), /invalid argument 'network'/);
});

it('verifyMessage throws on invalid network', function () {
const key = bip32.fromSeed(getSeedBuffers(1)[0]);
const signature = signMessage('hello', key, bitcoinNetwork);
assert.throws(() => verifyMessage('hello', key, signature, null as any), /invalid argument 'network'/);
assert.throws(() => verifyMessage('hello', key, signature, {} as any), /invalid argument 'network'/);
});
});
1 change: 0 additions & 1 deletion modules/utxo-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@
"@bitgo/utxo-lib": "^11.19.0",
"@bitgo/wasm-utxo": "1.19.0",
"bip174": "npm:@bitgo-forks/[email protected]",
"bitcoinjs-message": "npm:@bitgo-forks/[email protected]",
"fast-sha256": "^1.3.0"
},
"gitHead": "18e460ddf02de2dbf13c2aa243478188fb539f0c"
Expand Down
52 changes: 8 additions & 44 deletions modules/utxo-core/src/bip32utils.ts
Original file line number Diff line number Diff line change
@@ -1,49 +1,13 @@
import { BIP32Interface } from '@bitgo/secp256k1';
import * as utxolib from '@bitgo/utxo-lib';
import * as bitcoinMessage from 'bitcoinjs-message';
import { bip32utils } from '@bitgo/secp256k1';

/**
* bip32-aware wrapper around bitcoin-message package
* @see {bitcoinMessage.sign}
* @deprecated Use signMessage from @bitgo/secp256k1 instead
* @see {bip32utils.signMessage}
*/
export function signMessage(
message: string | Buffer,
privateKey: BIP32Interface | Buffer,
network: { messagePrefix: string }
): Buffer {
if (!Buffer.isBuffer(privateKey)) {
privateKey = privateKey.privateKey as Buffer;
if (!privateKey) {
throw new Error(`must provide privateKey`);
}
}
if (network === null || typeof network !== 'object' || typeof network.messagePrefix !== 'string') {
throw new Error(`invalid argument 'network'`);
}
const compressed = true;
return bitcoinMessage.sign(message, privateKey, compressed, network.messagePrefix);
}
export const signMessage = bip32utils.signMessage;

/**
* bip32-aware wrapper around bitcoin-message package
* @see {bitcoinMessage.verify}
* @deprecated Use verifyMessage from @bitgo/secp256k1 instead
* @see {bip32utils.verifyMessage}
*/
export function verifyMessage(
message: string | Buffer,
publicKey: BIP32Interface | Buffer,
signature: Buffer,
network: { messagePrefix: string }
): boolean {
if (!Buffer.isBuffer(publicKey)) {
publicKey = publicKey.publicKey;
}
if (network === null || typeof network !== 'object' || typeof network.messagePrefix !== 'string') {
throw new Error(`invalid argument 'network'`);
}

const address = utxolib.address.toBase58Check(
utxolib.crypto.hash160(publicKey),
utxolib.networks.bitcoin.pubKeyHash,
utxolib.networks.bitcoin
);
return bitcoinMessage.verify(message, address, signature, network.messagePrefix);
}
export const verifyMessage = bip32utils.verifyMessage;