Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
libbitcoinpqc-bindings
Language bindings (Rust, Python, Node.js, WASM) for the libbitcoinpqc C library. BIP 360 defines P2MR tapscript signature overloads; this library implements all three:
- secp256k1 Schnorr (BIP-340): Classical elliptic-curve signatures with x-only public keys.
- ML-DSA-44 (formerly CRYSTALS-Dilithium): A lattice-based scheme from the NIST PQC standardization.
- SLH-DSA-SHA2-128s (formerly SPHINCS+): A stateless hash-based scheme using SHA-256, aligned with Bitcoin's native hash primitive.
The two post-quantum algorithms (ML-DSA-44 and SLH-DSA-SHA2-128s) are FIPS-certified, which should help with future native hardware support.
P2MR (BIP 360)
P2MR (Pay-to-Merkle-Root) is the output and tapscript framework in BIP 360. This library supplies the signature primitives for its script-path spends — classical secp256k1 Schnorr plus optional post-quantum schemes. That is separate from broader Bitcoin post-quantum migration work; BIP 360 is specifically about P2MR tapscript overloads.
Features
- Clean, unified C API for all three signature algorithms
- Safe Rust bindings with memory safety and zero-copy operations
- NodeJS TypeScript bindings with full type safety
- Python bindings for easy integration
- WASM builds for browser and Node.js (
bitcoinpqc/wasm) - User-provided entropy (bring your own randomness)
- Key generation, signing, and verification functions
- Minimal dependencies
Key Characteristics
| Algorithm | Public Key Size | Secret Key Size | Signature Size | Security Level |
|---|---|---|---|---|
| SECP256K1_SCHNORR | 32 bytes | 32 bytes | 64 bytes | Classical |
| ML-DSA-44 | 1,312 bytes | 2,560 bytes | 2,420 bytes | NIST Level 2 |
| SLH-DSA-SHA2-128s | 32 bytes | 64 bytes | 7,856 bytes | NIST Level 1 |
See REPORT.md for performance and size comparison to secp256k1.
Breaking Changes (Phase 2)
Phase 2 renames SLH-DSA bindings from SHAKE-128s to SHA2-128s. Update identifiers as follows:
| Old identifier | New identifier |
|---|---|
SLH_DSA_128S (Rust) |
SLH_DSA_SHA2_128S |
SLH_DSA_SHAKE_128S (Python/Node.js/WASM) |
SLH_DSA_SHA2_128S |
- Enum wire value
2is unchanged. - Key sizes (32/64/7856 bytes) are unchanged.
- Enum wire values:
SECP256K1_SCHNORR=0,ML_DSA_44=1,SLH_DSA_SHA2_128S=2. RemovedFN_DSA_512. - Re-keying required: keys and signatures from SHAKE-128s are cryptographically incompatible with SHA2-128s. Generate new key pairs after upgrading.
Security Notes
- This library does not provide its own random number generation. It is essential that the user provide entropy from a cryptographically secure source. See docs/user_provided_entropy.md.
- Random data is required for key generation, but not for signing. All signatures are deterministic, based on the message and secret key.
- The implementations are based on reference code from the NIST PQC standardization process and are not production-hardened.
- Care should be taken to securely manage secret keys in applications.
BIP 360 / P2MR compliance
This library implements the three tapscript OP_CHECKSIG overloads specified in BIP 360 (P2MR), with the parameter sets named in the BIP.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Dependencies
The C library is included as a git submodule from libbitcoinpqc at libbitcoinpqc/, tracking branch 27-slh-dsa-sha-2-128s (see .gitmodules). To bump the pinned commit after upstream changes on that branch (or once merged to main):
&& && &&
&&
Build outputs belong in the parent build/ directory (make c-lib, make c-lib-test). Do not run cmake -B build or bare ctest inside libbitcoinpqc/ — that leaves libbitcoinpqc/build/ and libbitcoinpqc/Testing/ behind and makes git submodule status report untracked content. Run make clean (or make clean-submodule) to remove those artifacts.
Building
Prerequisites
- CMake 3.10 or higher
- C99 compiler
- Rust 1.50 or higher
Building
# Clone the repository (with submodules)
# Or, if already cloned without submodules:
# git submodule update --init --recursive
# Build the Rust bindings (automatically builds the C library from the submodule)
# Or use the Makefile
Fuzz Testing
This library includes fuzz testing targets using cargo-fuzz.
Prerequisites
# Install cargo-fuzz
Available Fuzz Targets
- keypair_generation - Tests key pair generation with different algorithms
- sign_verify - Tests signature creation and verification
- cross_algorithm - Tests verification with mismatched keys and signatures from different algorithms
Running Fuzz Tests
# Run a specific fuzz target
# Run a fuzz target for a specific amount of time (in seconds)
# Run a fuzz target with a specific number of iterations
See fuzz/README.md for more details on fuzz testing.
C API Usage
// Generate random data (from a secure source in production)
uint8_t random_data;
// Fill random_data with entropy...
// Generate a key pair
bitcoin_pqc_keypair_t keypair;
;
// Sign a message
const uint8_t message = "Message to sign";
bitcoin_pqc_signature_t signature;
;
// Verify the signature
bitcoin_pqc_error_t result = ;
// Clean up resources
;
;
Rust API Usage
Rust docs can be found on docs.rs.
use ;
use ;
// Generate random data for key generation
let mut random_data = vec!;
OsRng.fill_bytes;
// Generate a key pair
let keypair = generate_keypair.unwrap;
// Create a message to sign
let message = b"Message to sign";
// Sign the message deterministically
let signature = sign.unwrap;
// Verify the signature
verify.unwrap;
Python API Usage
Python bindings for all three algorithms.
Installation
# Install the Python package
Prerequisites
- Python 3.7 or higher
- The libbitcoinpqc C library must be built and installed
Example Usage
# Generate random data for key generation
=
# Generate a key pair
= # CRYSTALS-Dilithium
=
# Create a message to sign
= b
# Sign the message
=
# Verify the signature
=
# Should print True
# Verification with incorrect message will fail
= b
=
# Should print False
Python API Reference
The Python API mirrors the C API closely, with some Pythonic improvements:
-
Algorithm - Enum class for algorithm selection
SECP256K1_SCHNORRML_DSA_44(CRYSTALS-Dilithium)SLH_DSA_SHA2_128S(SPHINCS+)
-
KeyPair - Class to hold a public/secret key pair
algorithm- The algorithm usedpublic_key- The public key as bytessecret_key- The secret key as bytes
-
Signature - Class to hold a signature
algorithm- The algorithm usedsignature- The signature as bytes
-
Functions
public_key_size(algorithm)- Get the public key size for an algorithmsecret_key_size(algorithm)- Get the secret key size for an algorithmsignature_size(algorithm)- Get the signature size for an algorithmkeygen(algorithm, random_data)- Generate a key pair (32 bytes forSECP256K1_SCHNORR, 128 for PQC)sign(algorithm, secret_key, message)- Sign a messageverify(algorithm, public_key, message, signature)- Verify a signature
NodeJS TypeScript API Usage
NodeJS TypeScript bindings for all three algorithms in JavaScript/TypeScript projects.
Installation
# Install the Node.js package
Prerequisites
- Node.js 16 or higher
- The libbitcoinpqc C library must be built and installed
Example Usage
import { Algorithm, generateKeyPair, sign, verify } from 'bitcoinpqc';
import crypto from 'crypto';
// Generate random data for key generation
const randomData = crypto.randomBytes(128);
// Generate a key pair using ML-DSA-44 (CRYSTALS-Dilithium)
const keypair = generateKeyPair(Algorithm.ML_DSA_44, randomData);
// Create a message to sign
const message = Buffer.from('Message to sign');
// Sign the message deterministically
const signature = sign(keypair.secretKey, message);
// Verify the signature
verify(keypair.publicKey, message, signature);
// If verification fails, it will throw a PqcError
// You can also verify using the raw signature bytes
verify(keypair.publicKey, message, signature.bytes);
NodeJS TypeScript API Reference
The TypeScript API provides a clean, modern interface:
-
Algorithm - Enum for algorithm selection
SECP256K1_SCHNORRML_DSA_44(CRYSTALS-Dilithium)SLH_DSA_SHA2_128S(SPHINCS+)
-
Classes
PublicKey- Public key wrapperSecretKey- Secret key wrapper with secure handlingKeyPair- Container for public/secret key pairsSignature- Signature wrapper
-
Functions
publicKeySize(algorithm)- Get the public key size for an algorithmsecretKeySize(algorithm)- Get the secret key size for an algorithmsignatureSize(algorithm)- Get the signature size for an algorithmgenerateKeyPair(algorithm, randomData)- Generate a key pair (32 bytes of entropy forSECP256K1_SCHNORR, 128 bytes for PQC)sign(secretKey, message)- Sign a messageverify(publicKey, message, signature)- Verify a signature
For more details, see the NodeJS TypeScript bindings README.
WASM API Usage
Browser and Node.js WASM builds are published as bitcoinpqc/wasm. The Emscripten high-level API covers all three algorithms with the same entropy rules as the native bindings.
See wasm/README.md for the full API reference and browser testing notes.
Acknowledgments
- The original NIST PQC competition teams for their reference implementations
- The NIST PQC standardization process for advancing post-quantum cryptography
- The BIP 360 (P2MR) contributors
Test vectors
Algorithm golden vectors: tests/vectors/. BIP-360 P2MR construction: tests/vectors/p2mr/.