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.0 to 1.1.1

64

dist/helpers/Address.d.ts

@@ -60,3 +60,67 @@ /// <reference types="node" />

};
/**
* Validates a given Bitcoin address.
* This method checks if the provided Bitcoin address is valid by attempting to decode it
* for different Bitcoin networks: mainnet, testnet, and regtest. The method uses the
* bitcoinjs-lib's address module for decoding.
*
* The process is as follows:
* 1. Attempt to decode the address for the Bitcoin mainnet. If decoding succeeds,
* the method returns true, indicating the address is valid for mainnet.
* 2. If the first step fails, catch the resulting error and attempt to decode the
* address for the Bitcoin testnet. If decoding succeeds, the method returns true,
* indicating the address is valid for testnet.
* 3. If the second step fails, catch the resulting error and attempt to decode the
* address for the Bitcoin regtest network. If decoding succeeds, the method returns
* true, indicating the address is valid for regtest.
* 4. If all attempts fail, the method returns false, indicating the address is not valid
* for any of the checked networks.
*
* @param address The Bitcoin address to validate.
* @return boolean Returns true if the address is valid for any of the Bitcoin networks,
* otherwise returns false.
*/
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;

@@ -27,2 +27,3 @@ "use strict";

// Import dependency
const elliptic_1 = require("elliptic");
const bitcoin = __importStar(require("bitcoinjs-lib"));

@@ -218,4 +219,116 @@ /**

}
/**
* Validates a given Bitcoin address.
* This method checks if the provided Bitcoin address is valid by attempting to decode it
* for different Bitcoin networks: mainnet, testnet, and regtest. The method uses the
* bitcoinjs-lib's address module for decoding.
*
* The process is as follows:
* 1. Attempt to decode the address for the Bitcoin mainnet. If decoding succeeds,
* the method returns true, indicating the address is valid for mainnet.
* 2. If the first step fails, catch the resulting error and attempt to decode the
* address for the Bitcoin testnet. If decoding succeeds, the method returns true,
* indicating the address is valid for testnet.
* 3. If the second step fails, catch the resulting error and attempt to decode the
* address for the Bitcoin regtest network. If decoding succeeds, the method returns
* true, indicating the address is valid for regtest.
* 4. If all attempts fail, the method returns false, indicating the address is not valid
* for any of the checked networks.
*
* @param address The Bitcoin address to validate.
* @return boolean Returns true if the address is valid for any of the Bitcoin networks,
* otherwise returns false.
*/
static isValidBitcoinAddress(address) {
try {
// Attempt to decode the address using bitcoinjs-lib's address module at mainnet
bitcoin.address.toOutputScript(address, bitcoin.networks.bitcoin);
return true; // If decoding succeeds, the address is valid
}
catch (error) { }
try {
// Attempt to decode the address using bitcoinjs-lib's address module at testnet
bitcoin.address.toOutputScript(address, bitcoin.networks.testnet);
return true; // If decoding succeeds, the address is valid
}
catch (error) { }
try {
// Attempt to decode the address using bitcoinjs-lib's address module at regtest
bitcoin.address.toOutputScript(address, bitcoin.networks.regtest);
return true; // If decoding succeeds, the address is valid
}
catch (error) { }
return false; // Probably not a valid address
}
/**
* 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

@@ -26,2 +26,22 @@ /**

/**
* Wraps the Bitcoin message verification process to avoid throwing exceptions.
* This method attempts to verify a BIP-137 message using the provided address and
* signature. It encapsulates the verification process within a try-catch block,
* catching any errors that occur during verification and returning false instead
* of allowing the exception to propagate.
*
* The process is as follows:
* 1. The `bitcoinjs-message.verify` function is called with the message, address,
* and signature provided in Base64 encoding.
* 2. If the verification is successful, the method returns true.
* 3. If any error occurs during the verification, the method catches the error
* and returns false, signaling an unsuccessful verification.
*
* @param message The Bitcoin message to be verified.
* @param address The Bitcoin address to which the message is allegedly signed.
* @param signatureBase64 The Base64 encoded signature corresponding to the message.
* @return boolean Returns true if the message is successfully verified, otherwise false.
*/
private static bitcoinMessageVerifyWrap;
/**
* Compute the hash to be signed for a given P2WPKH BIP-322 toSign transaction.

@@ -28,0 +48,0 @@ * @param toSignTx PSBT instance of the toSign transaction

117

dist/Verifier.js

@@ -50,2 +50,6 @@ "use strict";

static verifySignature(signerAddress, message, signatureBase64) {
// Check whether the given signerAddress is valid
if (!helpers_1.Address.isValidBitcoinAddress(signerAddress)) {
throw new Error("Invalid Bitcoin address is provided.");
}
// Handle legacy BIP-137 signature

@@ -150,43 +154,92 @@ // For P2PKH address, assume the signature is also a legacy signature

static verifyBIP137Signature(signerAddress, message, signatureBase64) {
if (helpers_1.Address.isP2PKH(signerAddress)) {
return bitcoinMessage.verify(message, signerAddress, signatureBase64);
// Recover the public key associated with the signature
const publicKeySignedRaw = helpers_1.BIP137.derivePubKey(message, signatureBase64);
// Compress and uncompress the public key if necessary
let publicKeySignedUncompressed;
let publicKeySigned;
if (publicKeySignedRaw.byteLength === 65) {
publicKeySignedUncompressed = publicKeySignedRaw; // The key recovered is an uncompressed key
publicKeySigned = helpers_1.Address.compressPublicKey(publicKeySignedRaw);
}
else {
// Recover the public key associated with the signature
const publicKeySigned = helpers_1.BIP137.derivePubKey(message, signatureBase64);
// Set the equivalent legacy address to prepare for validation from bitcoinjs-message
const legacySigningAddress = helpers_1.Address.convertPubKeyIntoAddress(publicKeySigned, 'p2pkh').mainnet;
// Make sure that public key recovered corresponds to the claimed signing address
if (helpers_1.Address.isP2SH(signerAddress)) {
// Assume it is a P2SH-P2WPKH address, derive a P2SH-P2WPKH address based on the public key recovered
const p2shAddressDerived = helpers_1.Address.convertPubKeyIntoAddress(publicKeySigned, 'p2sh-p2wpkh');
// Assert that the derived address is identical to the claimed signing address
if (p2shAddressDerived.mainnet !== signerAddress && p2shAddressDerived.testnet !== signerAddress) {
return false; // Derived address did not match with the claimed signing address
}
publicKeySignedUncompressed = helpers_1.Address.uncompressPublicKey(publicKeySignedRaw);
publicKeySigned = publicKeySignedRaw; // The key recovered is a compressed key
}
// Obtain the equivalent signing address in all address types (except taproot) to prepare for validation from bitcoinjs-message
// Taproot address is not needed since technically BIP-137 signatures does not support taproot address
const p2pkhSigningAddressUncompressed = helpers_1.Address.convertPubKeyIntoAddress(publicKeySignedUncompressed, 'p2pkh').mainnet;
const p2pkhSigningAddressCompressed = helpers_1.Address.convertPubKeyIntoAddress(publicKeySigned, 'p2pkh').mainnet;
const p2shSigningAddress = helpers_1.Address.convertPubKeyIntoAddress(publicKeySigned, 'p2sh-p2wpkh').mainnet;
const p2wpkhSigningAddress = helpers_1.Address.convertPubKeyIntoAddress(publicKeySigned, 'p2wpkh').mainnet;
// Make sure that public key recovered corresponds to the claimed signing address
if (helpers_1.Address.isP2PKH(signerAddress)) {
// Derive P2PKH address from both the uncompressed raw public key, and the compressed public key
const p2pkhAddressDerivedUncompressed = helpers_1.Address.convertPubKeyIntoAddress(publicKeySignedUncompressed, 'p2pkh');
const p2pkhAddressDerivedCompressed = helpers_1.Address.convertPubKeyIntoAddress(publicKeySigned, 'p2pkh');
// Assert that the derived address is identical to the claimed signing address
if (p2pkhAddressDerivedUncompressed.mainnet !== signerAddress && p2pkhAddressDerivedUncompressed.testnet !== signerAddress &&
p2pkhAddressDerivedCompressed.mainnet !== signerAddress && p2pkhAddressDerivedCompressed.testnet !== signerAddress) {
return false; // Derived address did not match with the claimed signing address
}
else if (helpers_1.Address.isP2WPKH(signerAddress)) {
// Assume it is a P2WPKH address, derive a P2WPKH address based on the public key recovered
const p2wpkhAddressDerived = helpers_1.Address.convertPubKeyIntoAddress(publicKeySigned, 'p2wpkh');
// Assert that the derived address is identical to the claimed signing address
if (p2wpkhAddressDerived.mainnet !== signerAddress && p2wpkhAddressDerived.testnet !== signerAddress) {
return false; // Derived address did not match with the claimed signing address
}
}
else if (helpers_1.Address.isP2SH(signerAddress)) {
// Assume it is a P2SH-P2WPKH address, derive a P2SH-P2WPKH address based on the public key recovered
const p2shAddressDerived = helpers_1.Address.convertPubKeyIntoAddress(publicKeySigned, 'p2sh-p2wpkh');
// Assert that the derived address is identical to the claimed signing address
if (p2shAddressDerived.mainnet !== signerAddress && p2shAddressDerived.testnet !== signerAddress) {
return false; // Derived address did not match with the claimed signing address
}
else if (helpers_1.Address.isP2TR(signerAddress)) {
// Assume it is a P2TR address, derive a P2TR address based on the public key recovered
const p2trAddressDerived = helpers_1.Address.convertPubKeyIntoAddress(publicKeySigned, 'p2tr');
// Assert that the derived address is identical to the claimed signing address
if (p2trAddressDerived.mainnet !== signerAddress && p2trAddressDerived.testnet !== signerAddress) {
return false; // Derived address did not match with the claimed signing address
}
}
else if (helpers_1.Address.isP2WPKH(signerAddress)) {
// Assume it is a P2WPKH address, derive a P2WPKH address based on the public key recovered
const p2wpkhAddressDerived = helpers_1.Address.convertPubKeyIntoAddress(publicKeySigned, 'p2wpkh');
// Assert that the derived address is identical to the claimed signing address
if (p2wpkhAddressDerived.mainnet !== signerAddress && p2wpkhAddressDerived.testnet !== signerAddress) {
return false; // Derived address did not match with the claimed signing address
}
else {
return false; // Unsupported address type
}
else {
// Assume it is a P2TR address, derive a P2TR address based on the public key recovered
const p2trAddressDerived = helpers_1.Address.convertPubKeyIntoAddress(publicKeySigned, 'p2tr');
// Assert that the derived address is identical to the claimed signing address
if (p2trAddressDerived.mainnet !== signerAddress && p2trAddressDerived.testnet !== signerAddress) {
return false; // Derived address did not match with the claimed signing address
}
// Validate the signature using bitcoinjs-message if address assertion succeeded
return bitcoinMessage.verify(message, legacySigningAddress, signatureBase64);
}
// Validate the signature using bitcoinjs-message if address assertion succeeded
// Accept the signature if it originates from any address derivable from the public key
const validity = (this.bitcoinMessageVerifyWrap(message, p2pkhSigningAddressUncompressed, signatureBase64) ||
this.bitcoinMessageVerifyWrap(message, p2pkhSigningAddressCompressed, signatureBase64) ||
this.bitcoinMessageVerifyWrap(message, p2shSigningAddress, signatureBase64) ||
this.bitcoinMessageVerifyWrap(message, p2wpkhSigningAddress, signatureBase64));
return validity;
}
/**
* Wraps the Bitcoin message verification process to avoid throwing exceptions.
* This method attempts to verify a BIP-137 message using the provided address and
* signature. It encapsulates the verification process within a try-catch block,
* catching any errors that occur during verification and returning false instead
* of allowing the exception to propagate.
*
* The process is as follows:
* 1. The `bitcoinjs-message.verify` function is called with the message, address,
* and signature provided in Base64 encoding.
* 2. If the verification is successful, the method returns true.
* 3. If any error occurs during the verification, the method catches the error
* and returns false, signaling an unsuccessful verification.
*
* @param message The Bitcoin message to be verified.
* @param address The Bitcoin address to which the message is allegedly signed.
* @param signatureBase64 The Base64 encoded signature corresponding to the message.
* @return boolean Returns true if the message is successfully verified, otherwise false.
*/
static bitcoinMessageVerifyWrap(message, address, signatureBase64) {
try {
return bitcoinMessage.verify(message, address, signatureBase64);
}
catch (err) {
return false; // Instead of throwing, just return false
}
}
/**
* Compute the hash to be signed for a given P2WPKH BIP-322 toSign transaction.

@@ -193,0 +246,0 @@ * @param toSignTx PSBT instance of the toSign transaction

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

@@ -22,6 +22,10 @@ "main": "dist/index.js",

"author": "Ken Sze <acken2@outlook.com>",
"repository": "github:ACken2/bip322-js",
"repository": {
"type": "git",
"url": "git+https://github.com/ACken2/bip322-js.git"
},
"license": "MIT",
"devDependencies": {
"@types/chai": "^4.3.5",
"@types/elliptic": "^6.4.18",
"@types/mocha": "^10.0.1",

@@ -43,2 +47,3 @@ "@types/node": "^20.2.5",

"ecpair": "^2.1.0",
"elliptic": "^6.5.5",
"fast-sha256": "^1.3.0",

@@ -45,0 +50,0 @@ "secp256k1": "^5.0.0"

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