Forked from bitcoinjs-message. Published to npm as @bitcoinerlab/btcmessage.
var tinysecp = require('tiny-secp256k1');
var MessageFactory = require('@bitcoinerlab/btcmessage').MessageFactory;
var toBase64 = require('uint8array-tools').toBase64;
var bitcoinMessage = MessageFactory(tinysecp);Breaking change in v4: this library is Uint8Array-first and does not return Buffer instances.
sign(message, privateKey, compressed[, network.messagePrefix, sigOptions])
- If you pass the sigOptions arg instead of messagePrefix it will dynamically replace.
- sigOptions contains two attributes
segwitTypeshould be one of'p2sh(p2wpkh)'or'p2wpkh'extraEntropywill be used to create non-deterministic signatures using the RFC6979 extra entropy parameter. R value reuse is not an issue.
Sign a Bitcoin message
var keyPair = ECPair.fromWIF(
'L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1',
);
var privateKey = keyPair.privateKey;
var message = 'This is an example of a signed message.';
var signature = bitcoinMessage.sign(message, privateKey, keyPair.compressed);
console.log(toBase64(signature));
// => 'H9L5yLFjti0QTHhPyFrZCT1V/MMnBtXKmoiKDZ78NDBjERki6ZTQZdSMCtkgoNmp17By9ItJr8o7ChX0XxY91nk='To produce non-deterministic signatures you can pass an extra option to sign()
var { randomBytes } = require('crypto');
var keyPair = ECPair.fromWIF(
'L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1',
);
var privateKey = keyPair.privateKey;
var message = 'This is an example of a signed message.';
var signature = bitcoinMessage.sign(message, privateKey, keyPair.compressed, {
extraEntropy: randomBytes(32),
});
console.log(toBase64(signature));
// => different (but valid) signature each timeSign a Bitcoin message (with segwit addresses)
// P2SH(P2WPKH) address 'p2sh(p2wpkh)'
var signature = bitcoinMessage.sign(message, privateKey, keyPair.compressed, {
segwitType: 'p2sh(p2wpkh)',
});
console.log(toBase64(signature));
// => 'I9L5yLFjti0QTHhPyFrZCT1V/MMnBtXKmoiKDZ78NDBjERki6ZTQZdSMCtkgoNmp17By9ItJr8o7ChX0XxY91nk='
// P2WPKH address 'p2wpkh'
var signature = bitcoinMessage.sign(message, privateKey, keyPair.compressed, {
segwitType: 'p2wpkh',
});
console.log(toBase64(signature));
// => 'J9L5yLFjti0QTHhPyFrZCT1V/MMnBtXKmoiKDZ78NDBjERki6ZTQZdSMCtkgoNmp17By9ItJr8o7ChX0XxY91nk='Sign a Bitcoin message using a Signer interface.
var keyPair = ECPair.fromWIF(
'L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1',
);
var privateKey = keyPair.privateKey;
var message = 'This is an example of a signed message.';
var secp256k1 = require('tiny-secp256k1');
// Notice we are using the privateKey var from the outer scope inside the sign function.
var signer = {
signRecoverable: (hash, extraData) =>
secp256k1.signRecoverable(hash, privateKey, extraData),
};
var signature = bitcoinMessage.sign(message, signer, keyPair.compressed);
console.log(toBase64(signature));
// => 'H9L5yLFjti0QTHhPyFrZCT1V/MMnBtXKmoiKDZ78NDBjERki6ZTQZdSMCtkgoNmp17By9ItJr8o7ChX0XxY91nk='signAsync(message, privateKey, compressed[, network.messagePrefix, sigOptions]) Same as sign, except returns a promise, and can accept a SignerAsync interface instead of privateKey
Sign a Bitcoin message asynchronously
var keyPair = ECPair.fromWIF(
'L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1',
);
var privateKey = keyPair.privateKey;
var message = 'This is an example of a signed message.';
bitcoinMessage
.signAsync(message, privateKey, keyPair.compressed)
.then(signature => {
console.log(toBase64(signature));
});
// => 'H9L5yLFjti0QTHhPyFrZCT1V/MMnBtXKmoiKDZ78NDBjERki6ZTQZdSMCtkgoNmp17By9ItJr8o7ChX0XxY91nk='Sign a Bitcoin message asynchronously using SignerAsync interface
var keyPair = ECPair.fromWIF(
'L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1',
);
var privateKey = keyPair.privateKey;
var message = 'This is an example of a signed message.';
var secp256k1 = require('tiny-secp256k1');
// Note that a Signer will also work
var signerAsync = {
signRecoverable: (hash, extraData) =>
Promise.resolve(secp256k1.signRecoverable(hash, privateKey, extraData)),
};
var signer = {
signRecoverable: (hash, extraData) =>
secp256k1.signRecoverable(hash, privateKey, extraData),
};
bitcoinMessage
.signAsync(message, signerAsync, keyPair.compressed)
.then(signature => {
console.log(toBase64(signature));
});
// => 'H9L5yLFjti0QTHhPyFrZCT1V/MMnBtXKmoiKDZ78NDBjERki6ZTQZdSMCtkgoNmp17By9ItJr8o7ChX0XxY91nk='
bitcoinMessage
.signAsync(message, signer, keyPair.compressed)
.then(signature => {
console.log(toBase64(signature));
});
// => 'H9L5yLFjti0QTHhPyFrZCT1V/MMnBtXKmoiKDZ78NDBjERki6ZTQZdSMCtkgoNmp17By9ItJr8o7ChX0XxY91nk='verify(message, address, signature[, network.messagePrefix, checkSegwitAlways])
Verify a Bitcoin message
var address = '1F3sAm6ZtwLAUnj7d38pGFxtP3RVEvtsbV';
console.log(bitcoinMessage.verify(message, address, signature));
// => true- For Signing: Use the non-segwit compressed signing parameters for both segwit types (p2sh-p2wpkh and p2wpkh)
- For Verifying: Pass the checkSegwitAlways argument as true. (messagePrefix should be set to null to default to Bitcoin messagePrefix)