{"id":15540,"library":"bip322-js","title":"BIP-322 JavaScript Library","description":"bip322-js is a TypeScript/JavaScript library providing utility functions for the BIP-322 signature scheme, enabling generic message signing and verification across various Bitcoin address types. It supports P2PKH, P2SH-P2WPKH, P2WPKH, and single-key-spend P2TR addresses on mainnet, testnet, and regtest. The current stable version is 3.0.0, released in April 2025. A key differentiator is its 'Loose BIP-137 Verification' by default, which allows backward compatibility with legacy BIP-137 signatures, even if they have non-standard header flags, by assuming ownership of the private key for all derivable addresses. It also provides functionalities to generate raw `toSpend` and `toSign` BIP-322 transactions.","status":"active","version":"3.0.0","language":"javascript","source_language":"en","source_url":"https://github.com/ACken2/bip322-js","tags":["javascript","bip322","bitcoinjs","typescript","no-WASM"],"install":[{"cmd":"npm install bip322-js","lang":"bash","label":"npm"},{"cmd":"yarn add bip322-js","lang":"bash","label":"yarn"},{"cmd":"pnpm add bip322-js","lang":"bash","label":"pnpm"}],"dependencies":[],"imports":[{"note":"ESM is preferred for modern JavaScript/TypeScript projects. CommonJS `require` is also supported.","wrong":"const Signer = require('bip322-js').Signer","symbol":"Signer","correct":"import { Signer } from 'bip322-js'"},{"note":"ESM is preferred for modern JavaScript/TypeScript projects. CommonJS `require` is also supported.","wrong":"const Verifier = require('bip322-js').Verifier","symbol":"Verifier","correct":"import { Verifier } from 'bip322-js'"},{"note":"Used for generating raw BIP-322 transactions. ESM is preferred for modern JavaScript/TypeScript projects.","wrong":"const BIP322 = require('bip322-js').BIP322","symbol":"BIP322","correct":"import { BIP322 } from 'bip322-js'"}],"quickstart":{"code":"import { Signer, Verifier } from 'bip322-js';\n\nconst privateKey = 'L3VFeEujGtevx9w18HD1fhRbCH67Az2dpCymeRE1SoPK6XQtaN2k'; // Example private key (do not use in production)\nconst address = 'bc1q9vza2e8x573nczrlzms0wvx3gsqjx7vavgkx0l'; // P2WPKH address\nconst message = 'Hello World';\n\nasync function runBip322Example() {\n  try {\n    // Sign the message\n    const signature = Signer.sign(privateKey, address, message);\n    console.log('Generated Signature:', signature);\n\n    // Verify the signature\n    const isValid = Verifier.verifySignature(address, message, signature);\n    console.log('Is signature valid (strict verification disabled by default)?', isValid);\n\n    // Verify with strict BIP-137 verification (if applicable for BIP-137 signatures)\n    const isStrictlyValid = Verifier.verifySignature(address, message, signature, true);\n    console.log('Is signature valid (strict verification enabled)?', isStrictlyValid);\n\n  } catch (error) {\n    console.error('An error occurred:', error);\n  }\n}\n\nrunBip322Example();","lang":"typescript","description":"Demonstrates how to sign a message using a private key for a P2WPKH address and then verify the generated signature, including an example of toggling strict BIP-137 verification."},"warnings":[{"fix":"Ensure your code expects a `string` (Base64-encoded) return type from `Signer.sign` for all address types. If you need a Buffer, decode the Base64 string.","message":"The `Signer.sign` function now consistently returns a Base64-encoded string for all address types. Previously, for P2PKH addresses, it incorrectly returned a raw Buffer. Code expecting a Buffer for P2PKH signatures must be updated.","severity":"breaking","affected_versions":">=3.0.0"},{"fix":"Remove the `network` argument from `Signer.sign` calls. The library will infer the network (mainnet, testnet, regtest) from the address string.","message":"The `network` argument in `Signer.sign` was removed. The network is now automatically inferred from the provided address.","severity":"breaking","affected_versions":">=2.0.0"},{"fix":"Update imports and calls to `Key.compressPublicKey` and `Key.uncompressPublicKey` respectively.","message":"The utility functions `Address.compressPublicKey` and `Address.uncompressPublicKey` have been moved.","severity":"breaking","affected_versions":">=2.0.0"},{"fix":"Do not rely on byte-for-byte comparison of Taproot BIP-322 signatures. Instead, use `Verifier.verifySignature()` to validate signatures, which correctly handles non-deterministic outputs.","message":"Updating `@bitcoinerlab/secp256k1` to v1.2.0 for BIP-322 Schnorr signatures means `signSchnorr` now uses secure internal randomness (auxRand) by default. This makes BIP-322 signatures for Taproot addresses non-deterministic.","severity":"breaking","affected_versions":">=3.0.0"},{"fix":"To enforce strict BIP-137 verification, pass `true` as the fourth argument to `Verifier.verifySignature(address, message, signature, true)`.","message":"By default, the library uses 'Loose BIP-137 Verification,' meaning it will attempt to verify BIP-137 signatures even if they have an incorrect header flag, assuming the signature is valid for any address derivable from the public key. This behavior can lead to unexpected valid verifications if strict adherence to BIP-137 header flags is required.","severity":"gotcha","affected_versions":">=1.1.0"},{"fix":"Be aware of this behavior when interacting with systems that enforce strict adherence to BIP-137 and BIP-322 specifications regarding taproot addresses. For strict verification, consider using the `useStrictVerification` flag where applicable or ensuring a clear understanding of the expected signature scheme.","message":"The library's 'Loose BIP-137 Verification' also allows BIP-137 signatures to be used for taproot addresses, which is technically out-of-spec for both BIP-137 and BIP-322 specifications. This might lead to compatibility issues with other stricter implementations.","severity":"gotcha","affected_versions":">=1.1.0"}],"env_vars":null,"last_verified":"2026-04-21T00:00:00.000Z","next_check":"2026-07-20T00:00:00.000Z","problems":[{"fix":"Remove the `network` argument. The function now infers the network directly from the provided Bitcoin address. E.g., `Signer.sign(privateKey, address, message)`.","cause":"Attempting to pass the `network` argument to `Signer.sign` in versions 2.0.0 or higher.","error":"TypeError: Signer.sign() missing 4th argument 'network'"},{"fix":"These functions have been moved to the `Key` class. Use `Key.compressPublicKey` or `Key.uncompressPublicKey` instead.","cause":"Using `Address.compressPublicKey` or `Address.uncompressPublicKey` directly from the `Address` class in versions 2.0.0 or higher.","error":"TypeError: Cannot read properties of undefined (reading 'compressPublicKey')"},{"fix":"Update your code to expect a `string` (Base64-encoded) return from `Signer.sign` for all address types. If a Buffer is needed, decode the Base64 string, e.g., `Buffer.from(signature, 'base64')`.","cause":"Your code is expecting `Signer.sign` to return a Buffer for P2PKH addresses, but it now returns a Base64 string.","error":"Error: Invalid signature format: expected Base64 string"},{"fix":"This is expected behavior and does not indicate an invalid signature. Instead of byte-for-byte comparison, always use `Verifier.verifySignature()` to validate the signature.","cause":"Due to an update in the underlying secp256k1 library, BIP-322 Schnorr signatures for Taproot addresses are now non-deterministic.","error":"Signatures for Taproot addresses are inconsistent across runs/machines"}],"ecosystem":"npm"}