Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

bip322-js

Package Overview
Dependencies
Maintainers
1
Versions
5
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

bip322-js - npm Package Compare versions

Comparing version 1.1.1 to 2.0.0

dist/helpers/Key.d.ts

18

dist/BIP322.js

@@ -74,6 +74,6 @@ "use strict";

psbt.addInput({
hash: '0'.repeat(64),
index: 0xFFFFFFFF,
sequence: 0,
finalScriptSig: Buffer.from(scriptSig),
hash: '0'.repeat(64), // vin[0].prevout.hash = 0000...000
index: 0xFFFFFFFF, // vin[0].prevout.n = 0xFFFFFFFF
sequence: 0, // vin[0].nSequence = 0
finalScriptSig: Buffer.from(scriptSig), // vin[0].scriptSig = OP_0 PUSH32[ message_hash ]
witnessScript: Buffer.from([]) // vin[0].scriptWitness = []

@@ -83,3 +83,3 @@ });

psbt.addOutput({
value: 0,
value: 0, // vout[0].nValue = 0
script: scriptPublicKey // vout[0].scriptPubKey = message_challenge

@@ -106,5 +106,5 @@ });

psbt.addInput({
hash: toSpendTxId,
index: 0,
sequence: 0,
hash: toSpendTxId, // vin[0].prevout.hash = to_spend.txid
index: 0, // vin[0].prevout.n = 0
sequence: 0, // vin[0].nSequence = 0
witnessUtxo: {

@@ -129,3 +129,3 @@ script: witnessScript,

psbt.addOutput({
value: 0,
value: 0, // vout[0].nValue = 0
script: Buffer.from([0x6a]) // vout[0].scriptPubKey = OP_RETURN

@@ -132,0 +132,0 @@ });

/// <reference types="node" />
import * as bitcoin from 'bitcoinjs-lib';
/**

@@ -43,2 +44,13 @@ * Class that implement address-related utility functions.

/**
* Determine network type by checking addresses prefixes
* Reference: https://en.bitcoin.it/wiki/List_of_address_prefixes
*
* Adopted from https://github.com/ACken2/bip322-js/pull/6 by Czino
*
* @param address Bitcoin address
* @returns Network type
* @throws If the address type is not recognized
*/
static getNetworkFromAddess(address: string): bitcoin.networks.Network;
/**
* Convert a given Bitcoin address into its corresponding script public key.

@@ -60,2 +72,3 @@ * Reference: https://github.com/buidl-bitcoin/buidl-python/blob/d79e9808e8ca60975d315be41293cb40d968626d/buidl/script.py#L607

testnet: string;
regtest: string;
};

@@ -85,44 +98,3 @@ /**

static isValidBitcoinAddress(address: string): boolean;
/**
* Compresses an uncompressed public key using the elliptic curve secp256k1.
* This method takes a public key in its uncompressed form and returns a compressed
* representation of the public key. Elliptic curve public keys can be represented in
* a shorter form known as compressed format which saves space and still retains the
* full public key's capabilities. The method uses the elliptic library to convert the
* uncompressed public key into its compressed form.
*
* The steps involved in the process are:
* 1. Initialize a new elliptic curve instance for the secp256k1 curve.
* 2. Create a key pair object from the uncompressed public key buffer.
* 3. Extract the compressed public key from the key pair object.
* 4. Return the compressed public key as a Buffer object.
*
* @param uncompressedPublicKey A Buffer containing the uncompressed public key.
* @return Buffer Returns a Buffer containing the compressed public key.
* @throws Error Throws an error if the provided public key cannot be compressed,
* typically indicating that the key is not valid.
*/
static compressPublicKey(uncompressedPublicKey: Buffer): Buffer;
/**
* Uncompresses a given public key using the elliptic curve secp256k1.
* This method accepts a compressed public key and attempts to convert it into its
* uncompressed form. Public keys are often compressed to save space, but certain
* operations require the full uncompressed key. This method uses the elliptic
* library to perform the conversion.
*
* The function operates as follows:
* 1. Initialize a new elliptic curve instance using secp256k1.
* 2. Attempt to create a key pair from the compressed public key buffer.
* 3. Extract the uncompressed public key from the key pair object.
* 4. Return the uncompressed public key as a Buffer object.
* If the compressed public key provided is invalid and cannot be uncompressed,
* the method will throw an error with a descriptive message.
*
* @param compressedPublicKey A Buffer containing the compressed public key.
* @return Buffer The uncompressed public key as a Buffer.
* @throws Error Throws an error if the provided public key cannot be uncompressed,
* typically indicating that the key is not valid.
*/
static uncompressPublicKey(compressedPublicKey: Buffer): Buffer;
}
export default Address;

@@ -25,5 +25,8 @@ "use strict";

};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
// Import dependency
const elliptic_1 = require("elliptic");
const Key_1 = __importDefault(require("./Key"));
const bitcoin = __importStar(require("bitcoinjs-lib"));

@@ -69,3 +72,3 @@ /**

// Check if the provided address is a P2WPKH/P2WSH address
if (address.slice(0, 4) === 'bc1q' || address.slice(0, 4) === 'tb1q') {
if (/^(bc1q|tb1q|bcrt1q)/.test(address)) {
// Either a P2WPKH / P2WSH address

@@ -92,3 +95,3 @@ // Convert the address into a scriptPubKey

static isP2TR(address) {
if (address.slice(0, 4) === 'bc1p' || address.slice(0, 4) === 'tb1p') {
if (/^(bc1p|tb1p|bcrt1p)/.test(address)) {
return true; // P2TR address

@@ -131,2 +134,24 @@ }

/**
* Determine network type by checking addresses prefixes
* Reference: https://en.bitcoin.it/wiki/List_of_address_prefixes
*
* Adopted from https://github.com/ACken2/bip322-js/pull/6 by Czino
*
* @param address Bitcoin address
* @returns Network type
* @throws If the address type is not recognized
*/
static getNetworkFromAddess(address) {
if (/^(bc1q|bc1p|1|3)/.test(address)) {
return bitcoin.networks.bitcoin;
}
else if (/^(tb1q|tb1p|2|m|n)/.test(address)) {
return bitcoin.networks.testnet;
}
else if (/^(bcrt1q|bcrt1p)/.test(address)) {
return bitcoin.networks.regtest;
}
throw new Error("Unknown address type");
}
/**
* Convert a given Bitcoin address into its corresponding script public key.

@@ -143,3 +168,3 @@ * Reference: https://github.com/buidl-bitcoin/buidl-python/blob/d79e9808e8ca60975d315be41293cb40d968626d/buidl/script.py#L607

address: address,
network: (address[0] === '1') ? bitcoin.networks.bitcoin : bitcoin.networks.testnet
network: this.getNetworkFromAddess(address)
}).output;

@@ -151,28 +176,28 @@ }

address: address,
network: (address[0] === '3') ? bitcoin.networks.bitcoin : bitcoin.networks.testnet
network: this.getNetworkFromAddess(address)
}).output;
}
else if (address.slice(0, 4) === 'bc1q' || address.slice(0, 4) === 'tb1q') {
else if (/^(bc1q|tb1q|bcrt1q)/.test(address)) {
// P2WPKH or P2WSH address
if (address.length === 42) {
if (address.length === 42 || (address.includes('bcrt1q') && address.length === 44)) {
// P2WPKH address
return bitcoin.payments.p2wpkh({
address: address,
network: (address.slice(0, 4) === 'bc1q') ? bitcoin.networks.bitcoin : bitcoin.networks.testnet
network: this.getNetworkFromAddess(address)
}).output;
}
else if (address.length === 62) {
else if (address.length === 62 || (address.includes('bcrt1q') && address.length === 64)) {
// P2WSH address
return bitcoin.payments.p2wsh({
address: address,
network: (address.slice(0, 4) === 'bc1q') ? bitcoin.networks.bitcoin : bitcoin.networks.testnet
network: this.getNetworkFromAddess(address)
}).output;
}
}
else if (address.slice(0, 4) === 'bc1p' || address.slice(0, 4) === 'tb1p') {
if (address.length === 62) {
else if (/^(bc1p|tb1p|bcrt1p)/.test(address)) {
if (address.length === 62 || (address.includes('bcrt1p') && address.length === 64)) {
// P2TR address
return bitcoin.payments.p2tr({
address: address,
network: (address.slice(0, 4) === 'bc1p') ? bitcoin.networks.bitcoin : bitcoin.networks.testnet
network: this.getNetworkFromAddess(address)
}).output;

@@ -194,3 +219,4 @@ }

mainnet: bitcoin.payments.p2pkh({ pubkey: publicKey, network: bitcoin.networks.bitcoin }).address,
testnet: bitcoin.payments.p2pkh({ pubkey: publicKey, network: bitcoin.networks.testnet }).address
testnet: bitcoin.payments.p2pkh({ pubkey: publicKey, network: bitcoin.networks.testnet }).address,
regtest: bitcoin.payments.p2pkh({ pubkey: publicKey, network: bitcoin.networks.regtest }).address
};

@@ -207,2 +233,6 @@ case 'p2sh-p2wpkh':

network: bitcoin.networks.testnet
}).address,
regtest: bitcoin.payments.p2sh({
redeem: bitcoin.payments.p2wpkh({ pubkey: publicKey, network: bitcoin.networks.regtest }),
network: bitcoin.networks.regtest
}).address

@@ -213,10 +243,12 @@ };

mainnet: bitcoin.payments.p2wpkh({ pubkey: publicKey, network: bitcoin.networks.bitcoin }).address,
testnet: bitcoin.payments.p2wpkh({ pubkey: publicKey, network: bitcoin.networks.testnet }).address
testnet: bitcoin.payments.p2wpkh({ pubkey: publicKey, network: bitcoin.networks.testnet }).address,
regtest: bitcoin.payments.p2wpkh({ pubkey: publicKey, network: bitcoin.networks.regtest }).address
};
case 'p2tr':
// Convert full-length public key into internal public key if necessary
const internalPubkey = publicKey.byteLength === 33 ? publicKey.subarray(1, 33) : publicKey;
const internalPubkey = Key_1.default.toXOnly(publicKey);
return {
mainnet: bitcoin.payments.p2tr({ internalPubkey: internalPubkey, network: bitcoin.networks.bitcoin }).address,
testnet: bitcoin.payments.p2tr({ internalPubkey: internalPubkey, network: bitcoin.networks.testnet }).address
testnet: bitcoin.payments.p2tr({ internalPubkey: internalPubkey, network: bitcoin.networks.testnet }).address,
regtest: bitcoin.payments.p2tr({ internalPubkey: internalPubkey, network: bitcoin.networks.regtest }).address
};

@@ -270,73 +302,4 @@ default:

}
/**
* Compresses an uncompressed public key using the elliptic curve secp256k1.
* This method takes a public key in its uncompressed form and returns a compressed
* representation of the public key. Elliptic curve public keys can be represented in
* a shorter form known as compressed format which saves space and still retains the
* full public key's capabilities. The method uses the elliptic library to convert the
* uncompressed public key into its compressed form.
*
* The steps involved in the process are:
* 1. Initialize a new elliptic curve instance for the secp256k1 curve.
* 2. Create a key pair object from the uncompressed public key buffer.
* 3. Extract the compressed public key from the key pair object.
* 4. Return the compressed public key as a Buffer object.
*
* @param uncompressedPublicKey A Buffer containing the uncompressed public key.
* @return Buffer Returns a Buffer containing the compressed public key.
* @throws Error Throws an error if the provided public key cannot be compressed,
* typically indicating that the key is not valid.
*/
static compressPublicKey(uncompressedPublicKey) {
// Initialize elliptic curve
const ec = new elliptic_1.ec('secp256k1');
// Try to compress the provided public key
try {
// Create a key pair from the uncompressed public key buffer
const keyPair = ec.keyFromPublic(Buffer.from(uncompressedPublicKey));
// Get the compressed public key as a Buffer
const compressedPublicKey = Buffer.from(keyPair.getPublic(true, 'array'));
return compressedPublicKey;
}
catch (err) {
throw new Error('Fails to compress the provided public key. Please check if the provided key is a valid uncompressed public key.');
}
}
/**
* Uncompresses a given public key using the elliptic curve secp256k1.
* This method accepts a compressed public key and attempts to convert it into its
* uncompressed form. Public keys are often compressed to save space, but certain
* operations require the full uncompressed key. This method uses the elliptic
* library to perform the conversion.
*
* The function operates as follows:
* 1. Initialize a new elliptic curve instance using secp256k1.
* 2. Attempt to create a key pair from the compressed public key buffer.
* 3. Extract the uncompressed public key from the key pair object.
* 4. Return the uncompressed public key as a Buffer object.
* If the compressed public key provided is invalid and cannot be uncompressed,
* the method will throw an error with a descriptive message.
*
* @param compressedPublicKey A Buffer containing the compressed public key.
* @return Buffer The uncompressed public key as a Buffer.
* @throws Error Throws an error if the provided public key cannot be uncompressed,
* typically indicating that the key is not valid.
*/
static uncompressPublicKey(compressedPublicKey) {
// Initialize elliptic curve
const ec = new elliptic_1.ec('secp256k1');
// Try to uncompress the provided public key
try {
// Create a key pair from the compressed public key buffer
const keyPair = ec.keyFromPublic(Buffer.from(compressedPublicKey));
// Get the compressed public key as a Buffer
const uncompressedPublicKey = Buffer.from(keyPair.getPublic(false, 'array'));
return uncompressedPublicKey;
}
catch (err) {
throw new Error('Fails to uncompress the provided public key. Please check if the provided key is a valid compressed public key.');
}
}
}
exports.default = Address;
//# sourceMappingURL=Address.js.map
import Address from "./Address";
import BIP137 from "./BIP137";
import Key from "./Key";
import VarInt from "./VarInt";
import VarStr from "./VarStr";
import Witness from "./Witness";
export { Address, BIP137, VarInt, VarStr, Witness };
export { Address, BIP137, Key, VarInt, VarStr, Witness };

@@ -6,3 +6,3 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.Witness = exports.VarStr = exports.VarInt = exports.BIP137 = exports.Address = void 0;
exports.Witness = exports.VarStr = exports.VarInt = exports.Key = exports.BIP137 = exports.Address = void 0;
const Address_1 = __importDefault(require("./Address"));

@@ -12,2 +12,4 @@ exports.Address = Address_1.default;

exports.BIP137 = BIP137_1.default;
const Key_1 = __importDefault(require("./Key"));
exports.Key = Key_1.default;
const VarInt_1 = __importDefault(require("./VarInt"));

@@ -14,0 +16,0 @@ exports.VarInt = VarInt_1.default;

import BIP322 from "./BIP322";
import Signer from "./Signer";
import Verifier from "./Verifier";
import { Witness, Address, BIP137 } from "./helpers";
export { BIP322, Signer, Verifier, Witness, Address, BIP137 };
import { Address, BIP137, Key, Witness } from "./helpers";
export { BIP322, Signer, Verifier, Address, BIP137, Key, Witness };

@@ -29,3 +29,3 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.BIP137 = exports.Address = exports.Witness = exports.Verifier = exports.Signer = exports.BIP322 = void 0;
exports.Witness = exports.Key = exports.BIP137 = exports.Address = exports.Verifier = exports.Signer = exports.BIP322 = void 0;
// Import modules to be exported

@@ -39,5 +39,6 @@ const BIP322_1 = __importDefault(require("./BIP322"));

const helpers_1 = require("./helpers");
Object.defineProperty(exports, "Witness", { enumerable: true, get: function () { return helpers_1.Witness; } });
Object.defineProperty(exports, "Address", { enumerable: true, get: function () { return helpers_1.Address; } });
Object.defineProperty(exports, "BIP137", { enumerable: true, get: function () { return helpers_1.BIP137; } });
Object.defineProperty(exports, "Key", { enumerable: true, get: function () { return helpers_1.Key; } });
Object.defineProperty(exports, "Witness", { enumerable: true, get: function () { return helpers_1.Witness; } });
// Provide a ECC library to bitcoinjs-lib

@@ -44,0 +45,0 @@ const secp256k1_1 = __importDefault(require("@bitcoinerlab/secp256k1"));

/// <reference types="node" />
import * as bitcoin from 'bitcoinjs-lib';
/**

@@ -10,9 +9,10 @@ * Class that signs BIP-322 signature using a private key.

* Sign a BIP-322 signature from P2WPKH, P2SH-P2WPKH, and single-key-spend P2TR address and its corresponding private key.
* Network is automatically inferred from the given address.
*
* @param privateKey Private key used to sign the message
* @param address Address to be signing the message
* @param message message_challenge to be signed by the address
* @param network Network that the address is located, defaults to the Bitcoin mainnet
* @returns BIP-322 simple signature, encoded in base-64
*/
static sign(privateKey: string, address: string, message: string, network?: bitcoin.Network): string | Buffer;
static sign(privateKey: string, address: string, message: string): string | Buffer;
/**

@@ -19,0 +19,0 @@ * Check if a given public key is the public key for a claimed address.

@@ -43,12 +43,13 @@ "use strict";

* Sign a BIP-322 signature from P2WPKH, P2SH-P2WPKH, and single-key-spend P2TR address and its corresponding private key.
* Network is automatically inferred from the given address.
*
* @param privateKey Private key used to sign the message
* @param address Address to be signing the message
* @param message message_challenge to be signed by the address
* @param network Network that the address is located, defaults to the Bitcoin mainnet
* @returns BIP-322 simple signature, encoded in base-64
*/
static sign(privateKey, address, message, network = bitcoin.networks.bitcoin) {
static sign(privateKey, address, message) {
// Initialize private key used to sign the transaction
const ECPair = (0, ecpair_1.default)(secp256k1_1.default);
let signer = ECPair.fromWIF(privateKey, network);
let signer = ECPair.fromWIF(privateKey, [bitcoin.networks.bitcoin, bitcoin.networks.testnet, bitcoin.networks.regtest]);
// Check if the private key can sign message for the given address

@@ -75,3 +76,3 @@ if (!this.checkPubKeyCorrespondToAddress(signer.publicKey, address)) {

hash: bitcoin.crypto.hash160(signer.publicKey),
network: network
network: helpers_1.Address.getNetworkFromAddess(address)
}).output;

@@ -87,6 +88,6 @@ toSignTx = BIP322_1.default.buildToSignTx(toSpendTx.getId(), redeemScript, true);

// Extract the taproot internal public key
const internalPublicKey = signer.publicKey.subarray(1, 33);
const internalPublicKey = helpers_1.Key.toXOnly(signer.publicKey);
// Tweak the private key for signing, since the output and address uses tweaked key
// Reference: https://github.com/bitcoinjs/bitcoinjs-lib/blob/1a9119b53bcea4b83a6aa8b948f0e6370209b1b4/test/integration/taproot.spec.ts#L55
signer = signer.tweak(bitcoin.crypto.taggedHash('TapTweak', signer.publicKey.subarray(1, 33)));
signer = signer.tweak(bitcoin.crypto.taggedHash('TapTweak', internalPublicKey));
// Draft a toSign transaction that spends toSpend transaction

@@ -129,3 +130,4 @@ toSignTx = BIP322_1.default.buildToSignTx(toSpendTx.getId(), scriptPubKey, false, internalPublicKey);

// Check if the derived address correspond to the claimedAddress
return (derivedAddresses.mainnet === claimedAddress) || (derivedAddresses.testnet === claimedAddress);
return ((derivedAddresses.mainnet === claimedAddress) || (derivedAddresses.testnet === claimedAddress) ||
(derivedAddresses.regtest === claimedAddress));
}

@@ -132,0 +134,0 @@ }

@@ -11,6 +11,7 @@ /**

* @param signatureBase64 Signature produced by the signing address
* @param useStrictVerification If true, apply strict BIP-137 verification and enforce address flag verification; otherwise, address flag is ignored during verification
* @returns True if the provided signature is a valid BIP-322 signature for the given message and address, false if otherwise
* @throws If the provided signature fails basic validation, or if unsupported address and signature are provided
*/
static verifySignature(signerAddress: string, message: string, signatureBase64: string): boolean;
static verifySignature(signerAddress: string, message: string, signatureBase64: string, useStrictVerification?: boolean): boolean;
/**

@@ -22,2 +23,3 @@ * Verify a legacy BIP-137 signature.

* @param signatureBase64 Signature produced by the signing address
* @param useStrictVerification If true, apply strict BIP-137 verification and enforce address flag verification; otherwise, address flag is ignored during verification
* @returns True if the provided signature is a valid BIP-137 signature for the given message and address, false if otherwise

@@ -24,0 +26,0 @@ * @throws If the provided signature fails basic validation, or if unsupported address and signature are provided

@@ -31,5 +31,5 @@ "use strict";

const BIP322_1 = __importDefault(require("./BIP322"));
const helpers_1 = require("./helpers");
const bitcoin = __importStar(require("bitcoinjs-lib"));
const secp256k1_1 = __importDefault(require("@bitcoinerlab/secp256k1"));
const helpers_1 = require("./helpers");
const bitcoinMessage = __importStar(require("bitcoinjs-message"));

@@ -47,6 +47,7 @@ const bitcoinjs_1 = require("./bitcoinjs");

* @param signatureBase64 Signature produced by the signing address
* @param useStrictVerification If true, apply strict BIP-137 verification and enforce address flag verification; otherwise, address flag is ignored during verification
* @returns True if the provided signature is a valid BIP-322 signature for the given message and address, false if otherwise
* @throws If the provided signature fails basic validation, or if unsupported address and signature are provided
*/
static verifySignature(signerAddress, message, signatureBase64) {
static verifySignature(signerAddress, message, signatureBase64, useStrictVerification = false) {
// Check whether the given signerAddress is valid

@@ -59,3 +60,3 @@ if (!helpers_1.Address.isValidBitcoinAddress(signerAddress)) {

if (helpers_1.Address.isP2PKH(signerAddress) || helpers_1.BIP137.isBIP137Signature(signatureBase64)) {
return this.verifyBIP137Signature(signerAddress, message, signatureBase64);
return this.verifyBIP137Signature(signerAddress, message, signatureBase64, useStrictVerification);
}

@@ -152,6 +153,10 @@ // Convert address into corresponding script pubkey

* @param signatureBase64 Signature produced by the signing address
* @param useStrictVerification If true, apply strict BIP-137 verification and enforce address flag verification; otherwise, address flag is ignored during verification
* @returns True if the provided signature is a valid BIP-137 signature for the given message and address, false if otherwise
* @throws If the provided signature fails basic validation, or if unsupported address and signature are provided
*/
static verifyBIP137Signature(signerAddress, message, signatureBase64) {
static verifyBIP137Signature(signerAddress, message, signatureBase64, useStrictVerification) {
if (useStrictVerification) {
return this.bitcoinMessageVerifyWrap(message, signerAddress, signatureBase64);
}
// Recover the public key associated with the signature

@@ -164,6 +169,6 @@ const publicKeySignedRaw = helpers_1.BIP137.derivePubKey(message, signatureBase64);

publicKeySignedUncompressed = publicKeySignedRaw; // The key recovered is an uncompressed key
publicKeySigned = helpers_1.Address.compressPublicKey(publicKeySignedRaw);
publicKeySigned = helpers_1.Key.compressPublicKey(publicKeySignedRaw);
}
else {
publicKeySignedUncompressed = helpers_1.Address.uncompressPublicKey(publicKeySignedRaw);
publicKeySignedUncompressed = helpers_1.Key.uncompressPublicKey(publicKeySignedRaw);
publicKeySigned = publicKeySignedRaw; // The key recovered is a compressed key

@@ -184,3 +189,5 @@ }

if (p2pkhAddressDerivedUncompressed.mainnet !== signerAddress && p2pkhAddressDerivedUncompressed.testnet !== signerAddress &&
p2pkhAddressDerivedCompressed.mainnet !== signerAddress && p2pkhAddressDerivedCompressed.testnet !== signerAddress) {
p2pkhAddressDerivedUncompressed.regtest !== signerAddress &&
p2pkhAddressDerivedCompressed.mainnet !== signerAddress && p2pkhAddressDerivedCompressed.testnet !== signerAddress &&
p2pkhAddressDerivedCompressed.regtest !== signerAddress) {
return false; // Derived address did not match with the claimed signing address

@@ -193,3 +200,4 @@ }

// Assert that the derived address is identical to the claimed signing address
if (p2shAddressDerived.mainnet !== signerAddress && p2shAddressDerived.testnet !== signerAddress) {
if (p2shAddressDerived.mainnet !== signerAddress && p2shAddressDerived.testnet !== signerAddress &&
p2shAddressDerived.regtest !== signerAddress) {
return false; // Derived address did not match with the claimed signing address

@@ -202,3 +210,4 @@ }

// Assert that the derived address is identical to the claimed signing address
if (p2wpkhAddressDerived.mainnet !== signerAddress && p2wpkhAddressDerived.testnet !== signerAddress) {
if (p2wpkhAddressDerived.mainnet !== signerAddress && p2wpkhAddressDerived.testnet !== signerAddress &&
p2wpkhAddressDerived.regtest !== signerAddress) {
return false; // Derived address did not match with the claimed signing address

@@ -211,3 +220,4 @@ }

// Assert that the derived address is identical to the claimed signing address
if (p2trAddressDerived.mainnet !== signerAddress && p2trAddressDerived.testnet !== signerAddress) {
if (p2trAddressDerived.mainnet !== signerAddress && p2trAddressDerived.testnet !== signerAddress &&
p2trAddressDerived.regtest !== signerAddress) {
return false; // Derived address did not match with the claimed signing address

@@ -214,0 +224,0 @@ }

{
"name": "bip322-js",
"version": "1.1.1",
"version": "2.0.0",
"description": "A Javascript library that provides utility functions related to the BIP-322 signature scheme",

@@ -30,16 +30,16 @@ "main": "dist/index.js",

"@types/elliptic": "^6.4.18",
"@types/mocha": "^10.0.1",
"@types/node": "^20.2.5",
"@types/secp256k1": "^4.0.3",
"@types/mocha": "^10.0.6",
"@types/node": "^20.12.12",
"@types/secp256k1": "^4.0.6",
"chai": "^4.3.7",
"chai-bytes": "^0.1.2",
"mocha": "^10.2.0",
"mocha": "^10.4.0",
"nyc": "^15.1.0",
"ts-mocha": "^10.0.0",
"typedoc": "^0.24.8",
"typescript": "^5.1.3"
"typedoc": "^0.25.13",
"typescript": "^5.4.5"
},
"dependencies": {
"@bitcoinerlab/secp256k1": "^1.0.2",
"bitcoinjs-lib": "^6.1.1",
"@bitcoinerlab/secp256k1": "^1.1.1",
"bitcoinjs-lib": "^6.1.5",
"bitcoinjs-message": "^2.2.0",

@@ -46,0 +46,0 @@ "ecpair": "^2.1.0",

@@ -8,6 +8,2 @@ # BIP322-JS

## Limitations
Only P2PKH, P2SH-P2WPKH, P2WPKH, and single-key-spend P2TR are supported in this library.
## Documentation

@@ -19,6 +15,60 @@

1. Generate raw toSpend and toSign BIP-322 transactions
2. Sign a BIP-322 signature using a private key
3. Verify a simple BIP-322 signature
The following features are supported on mainnet, testnet, and regtest
for P2PKH, P2SH-P2WPKH, P2WPKH, and single-key-spend P2TR addresses:
1. Generate raw toSpend and toSign BIP-322 transactions.
2. Sign a BIP-322 signature using a private key.
3. Verify a legacy BIP-137 signature loosely (see below).
4. Verify a simple BIP-322 signature.
## Usage
Use the **Signer** class to sign a BIP-322 signature:
```js
Signer.sign(privateKey, address, message)
```
Use the **Verifier** class to verify a BIP-322 signature (which also validates a BIP-137 signature):
```js
Verifier.verifySignature(address, message, signature)
```
## Loose BIP-137 Verification
A BIP-322 signature is backward compatible with the legacy signature scheme (i.e., BIP-137 signature).
As a result, this library also recognizes valid BIP-137 signatures.
In a BIP-137 signature, a header flag indicates the type of Bitcoin address for which the signature is signed:
- 27-30: P2PKH uncompressed
- 31-34: P2PKH compressed
- 35-38: Segwit P2SH
- 39-42: Segwit Bech32
However, some wallets' implementations of the BIP-137 signature did not strictly follow this header flag specification,
and some may have signed signatures with the wrong header (e.g., using header 27 for a native segwit address).
It is trivial, however, to convert a BIP-137 signature with an incorrect header flag to one with the correct header
flag since the "address type" component in the header flag is not part of the actual signature.
As such, some BIP-137 signature verifiers online, such as [this one](https://www.verifybitcoinmessage.com/),
actively help to swap out any erroneous header flags.
This library defines this behavior as **"Loose BIP-137 Verification"**.
This behavior assumes that a signature proving ownership of the private key associated with public key $X$
is valid for all addresses $y_1$, $y_2$, ..., $y_n$ derivable from the same public key $X$.
This behavior is enabled by default in this library, but can be disabled by passing the
optional useStrictVerification flag in Verifier.verifySignature:
```js
Verifier.verifySignature(signerAddress, message, signatureBase64, true)
```
Consequently, this also allows BIP-137 signatures to be used for taproot addresses, which is technically out-of-spec
according to both BIP-137 and BIP-322 specifications, as implemented by some wallet implementations.
Please refer to [issue #1](https://github.com/ACken2/bip322-js/issues/1) for relevant discussions.
Note that this behavior does not exist in actual BIP-322 signature due to how BIP-322 signature is constructed.
## Example

@@ -32,10 +82,22 @@

const privateKey = 'L3VFeEujGtevx9w18HD1fhRbCH67Az2dpCymeRE1SoPK6XQtaN2k';
const address = 'bc1q9vza2e8x573nczrlzms0wvx3gsqjx7vavgkx0l';
const address = 'bc1q9vza2e8x573nczrlzms0wvx3gsqjx7vavgkx0l'; // P2WPKH address
const addressTestnet = 'tb1q9vza2e8x573nczrlzms0wvx3gsqjx7vaxwd45v'; // Equivalent testnet address
const addressRegtest = 'bcrt1q9vza2e8x573nczrlzms0wvx3gsqjx7vay85cr9'; // Equivalent regtest address
const taprootAddress = 'bc1ppv609nr0vr25u07u95waq5lucwfm6tde4nydujnu8npg4q75mr5sxq8lt3'; // P2TR address
const nestedSegwitAddress = '37qyp7jQAzqb2rCBpMvVtLDuuzKAUCVnJb'; // P2SH-P2WPKH address
const message = 'Hello World';
const signature = Signer.sign(privateKey, address, message);
console.log(signature);
const signatureTestnet = Signer.sign(privateKey, addressTestnet, message); // Wworks with testnet address
const signatureRegtest = Signer.sign(privateKey, addressRegtest, message); // And regtest address
const signatureP2TR = Signer.sign(privateKey, taprootAddress, message); // Also works with P2TR address
const signatureP2SH = Signer.sign(privateKey, nestedSegwitAddress, message); // And P2SH-P2WPKH address
console.log({ signature, signatureTestnet, signatureRegtest, signatureP2TR, signatureP2SH });
// Verifying a simple BIP-322 signature
const validity = Verifier.verifySignature(address, message, signature);
console.log(validity); // True
const validityTestnet = Verifier.verifySignature(addressTestnet, message, signatureTestnet); // Works with testnet address
const validityRegtest = Verifier.verifySignature(addressRegtest, message, signatureRegtest); // And regtest address
const validityP2TR = Verifier.verifySignature(taprootAddress, message, signatureP2TR); // Also works with P2TR address
const validityP2SH = Verifier.verifySignature(nestedSegwitAddress, message, signatureP2SH); // And P2SH-P2WPKH address
console.log({ validity, validityTestnet, validityRegtest, validityP2TR, validityP2SH }); // True

@@ -50,2 +112,12 @@ // You can also get the raw unsigned BIP-322 toSpend and toSign transaction directly

More working examples can be found within the unit test for BIP322, Signer, and Verifier.
More working examples can be found within the unit test for BIP322, Signer, and Verifier.
## Migration Guide from v1.X
There are only two non-backward-compatible changes in the API:
1. If you previously used `Address.compressPublicKey` or `Address.uncompressPublicKey`,
replace them with `Key.compressPublicKey` and `Key.uncompressPublicKey` respectively.
2. In v1.X, there was an option to pass the `network` parameter into `Signer.sign`: `Signer.sign(privateKey, address, message, network)`.
This option has been removed, as the network is now automatically inferred from the given address.

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc