adimiuprix / taproot-php
Bitcoin Taproot implementation for PHP using secp256k1
Requires
- php: >=8.5
- ext-gmp: *
- fenguoz/bip39-mnemonic-php: ^1.0
- kornrunner/secp256k1: ^0.4.0
Requires (Dev)
- phpunit/phpunit: ^11.0
Suggests
- ext-bcmath: For better performance with large numbers
This package is auto-updated.
Last update: 2026-08-17 12:50:34 UTC
README
Bitcoin Taproot implementation for PHP using secp256k1 extension.
Features
- Secp256k1 Integration: Native PHP extension wrapper for cryptographic operations
- Schnorr Signatures: BIP340 Schnorr signature implementation
- Taproot Addresses: Generate and validate P2TR (Pay-to-Taproot) addresses
- Script Trees: Build and manage Taproot script trees (MAST)
- Key Tweaking: Support for key aggregation and tweaking
Requirements
- PHP >= 8.5
- GMP extension
- kornrunner/secp256k1 library
- fenguoz/bip39-mnemonic-php library
Installation
Install via Composer:
composer require bitroot/taproot-php
Or add to your composer.json:
{
"require": {
"bitroot/taproot-php": "^1.0"
}
}
Then run:
composer install
Quick Start
See example.php for a complete single-file demonstration:
php example.php
Or try this quick snippet:
<?php require_once 'vendor/autoload.php'; use Bitroot\Bitcoin\Secp256k1; use Bitroot\Bitcoin\Taproot; use Bitroot\Bitcoin\Address; // Generate key pair $secp = new Secp256k1(); $privateKey = $secp->generatePrivateKey(); $publicKey = $secp->getXOnlyPublicKey($privateKey); // Create Taproot address $taproot = new Taproot(); $output = $taproot->createKeyPathSpend($publicKey); $address = Address::fromTaprootOutput($output); echo "Your Taproot Address: " . $address; // Output: bc1p...
Usage
1. BIP39 Mnemonic Seed Phrases
Generate and use mnemonic seed phrases (BIP39):
use Bitroot\Bitcoin\Mnemonic; $mnemonic = new Mnemonic('en'); // English language // Generate 24-word mnemonic (256-bit entropy) $seedPhrase = $mnemonic->generate(256); echo $seedPhrase; // abandon abandon abandon ... art // Generate with specific word count $seedPhrase12 = $mnemonic->generateWithWordCount(12); $seedPhrase24 = $mnemonic->generateWithWordCount(24); // Validate mnemonic $isValid = $mnemonic->validate($seedPhrase); // Derive master private key $masterKey = $mnemonic->toMasterKey($seedPhrase); // With optional passphrase for additional security $masterKey = $mnemonic->toMasterKey($seedPhrase, 'my-passphrase'); // Convert to/from entropy $entropy = $mnemonic->toEntropy($seedPhrase); $seedPhrase = $mnemonic->fromEntropy($entropy);
2. Generate Private/Public Key Pair
use Bitroot\Bitcoin\Secp256k1; $secp = new Secp256k1(); // Generate new private key $privateKey = $secp->generatePrivateKey(); // Derive public key $publicKey = $secp->getPublicKey($privateKey); echo "Private Key: " . bin2hex($privateKey) . "\n"; echo "Public Key: " . bin2hex($publicKey) . "\n";
3. Schnorr Signatures (BIP340)
use Bitroot\Bitcoin\Schnorr; $schnorr = new Schnorr(); $privateKey = hex2bin('your_private_key_hex'); $message = hash('sha256', 'Hello Bitcoin', true); // Sign message $signature = $schnorr->sign($message, $privateKey); // Verify signature $publicKey = $secp->getPublicKey($privateKey); $isValid = $schnorr->verify($signature, $message, $publicKey); echo "Signature: " . bin2hex($signature) . "\n"; echo "Valid: " . ($isValid ? 'Yes' : 'No') . "\n";
4. Taproot Address Generation
use Bitroot\Bitcoin\Taproot; use Bitroot\Bitcoin\Address; $taproot = new Taproot(); // Key-path spending (simple P2TR) $internalKey = $secp->getPublicKey($privateKey); $taprootOutput = $taproot->createKeyPathSpend($internalKey); // Generate address (mainnet) $address = Address::fromTaprootOutput($taprootOutput, 'mainnet'); echo "Taproot Address: " . $address . "\n"; // bc1p... // Testnet $addressTestnet = Address::fromTaprootOutput($taprootOutput, 'testnet'); echo "Testnet Address: " . $addressTestnet . "\n"; // tb1p...
5. Script Tree (MAST)
use Bitroot\Bitcoin\Taproot; use Bitroot\Bitcoin\Script; $taproot = new Taproot(); // Create script leaves $script1 = Script::fromAsm('OP_CHECKSIG'); $script2 = Script::fromAsm('144 OP_CHECKSEQUENCEVERIFY OP_DROP OP_CHECKSIG'); // Build script tree $scriptTree = $taproot->buildScriptTree([ $script1, $script2 ]); // Create Taproot output with script tree $internalKey = $secp->getPublicKey($privateKey); $taprootOutput = $taproot->createScriptPathSpend($internalKey, $scriptTree); // Generate address $address = Address::fromTaprootOutput($taprootOutput); echo "Taproot Script Address: " . $address . "\n"; // Get control block for spending $controlBlock = $taproot->getControlBlock($scriptTree, 0); // For first script
6. Key Tweaking
use Bitroot\Bitcoin\Taproot; $taproot = new Taproot(); $internalKey = $secp->getPublicKey($privateKey); $tweak = hash('sha256', 'some_tweak_data', true); // Tweak public key $tweakedKey = $taproot->tweakPublicKey($internalKey, $tweak); echo "Original: " . bin2hex($internalKey) . "\n"; echo "Tweaked: " . bin2hex($tweakedKey) . "\n";
7. Complete Example from Mnemonic to Address
<?php require_once 'vendor/autoload.php'; use Bitroot\Bitcoin\Mnemonic; use Bitroot\Bitcoin\Secp256k1; use Bitroot\Bitcoin\Schnorr; use Bitroot\Bitcoin\Taproot; use Bitroot\Bitcoin\Address; // Step 1: Generate mnemonic $mnemonic = new Mnemonic('en'); $seedPhrase = $mnemonic->generate(256); // 24 words echo "Seed Phrase: " . $seedPhrase . "\n\n"; // Step 2: Derive master key $masterKey = $mnemonic->toMasterKey($seedPhrase); echo "Master Key: " . bin2hex($masterKey) . "\n\n"; // Step 3: Generate key pair $secp = new Secp256k1(); $publicKey = $secp->getXOnlyPublicKey($masterKey); echo "Public Key: " . bin2hex($publicKey) . "\n\n"; // Step 4: Create Taproot address $taproot = new Taproot(); $taprootOutput = $taproot->createKeyPathSpend($publicKey); $address = Address::fromTaprootOutput($taprootOutput, 'mainnet'); echo "Taproot Address: " . $address . "\n\n"; // Step 5: Sign message with Schnorr $schnorr = new Schnorr(); $message = hash('sha256', 'Hello Taproot!', true); $signature = $schnorr->sign($message, $masterKey); $isValid = $schnorr->verify($signature, $message, $publicKey); echo "Signature: " . bin2hex($signature) . "\n"; echo "Valid: " . ($isValid ? 'Yes' : 'No') . "\n";
Examples
Single comprehensive example demonstrating all features:
# Run the complete example composer run examples # or php examples/all-features.php
The example demonstrates:
- ✓ BIP39 Mnemonic (24 & 12 words)
- ✓ Key Generation (Private, Public, X-Only)
- ✓ Taproot Addresses (Mainnet & Testnet)
- ✓ Schnorr Signatures (BIP340)
- ✓ Script Trees (MAST) with multiple spending paths
- ✓ Control Blocks for script-path spending
- ✓ Wallet Recovery from mnemonic
Output: Clean, organized display with all features in ~150 lines of code.
API Reference
Mnemonic Class
generate(int $strength = 256): string- Generate mnemonic (128, 160, 192, 224, 256 bits)generateWithWordCount(int $wordCount): string- Generate with specific word count (12, 15, 18, 21, 24)validate(string $mnemonic): bool- Validate mnemonic phrasetoSeed(string $mnemonic, string $passphrase = ''): string- Convert to 64-byte seedtoMasterKey(string $mnemonic, string $passphrase = ''): string- Derive master private key (BIP32)fromEntropy(string $entropy): string- Create mnemonic from entropytoEntropy(string $mnemonic): string- Extract entropy from mnemonicgetWordCount(string $mnemonic): int- Count words in mnemonic
Secp256k1 Class
generatePrivateKey(): string- Generate random 32-byte private keygetPublicKey(string $privateKey, bool $compressed = true): string- Derive public key from private keygetXOnlyPublicKey(string $privateKey): string- Get 32-byte X-only public key for TaprootvalidatePrivateKey(string $privateKey): bool- Validate private keyvalidatePublicKey(string $publicKey): bool- Validate public keyprivateKeyTweakAdd(string $privateKey, string $tweak): string- Tweak private keypublicKeyTweakAdd(string $publicKey, string $tweak): string- Tweak public keysign(string $message, string $privateKey): string- Sign with ECDSAverify(string $signature, string $message, string $publicKey): bool- Verify ECDSA signature
Schnorr Class
sign(string $message, string $privateKey, ?string $auxRand = null): string- Sign message with Schnorrverify(string $signature, string $message, string $publicKey): bool- Verify Schnorr signature
Taproot Class
createKeyPathSpend(string $internalKey): array- Create key-path only Taproot outputcreateScriptPathSpend(string $internalKey, array $scriptTree): array- Create Taproot with script treebuildScriptTree(array $scripts): array- Build Merkle tree from scriptstweakPublicKey(string $publicKey, string $tweak): string- Tweak public keygetControlBlock(array $scriptTree, int $leafIndex): string- Get control block for script spending
Address Class
fromTaprootOutput(array $output, string $network = 'mainnet'): string- Generate Bech32m address from Taproot outputdecode(string $address): array- Decode Bech32m addressvalidate(string $address, ?string $network = null): bool- Validate Taproot address
Script Class
fromAsm(string $asm): string- Create script from ASM notationtoAsm(string $script): string- Convert script to ASM notationpushData(string $data): string- Push data to scriptencodeNumber(int $num): string- Encode number for script
Technical Details
This library implements:
- BIP39: Mnemonic code for generating deterministic keys
- BIP32: Hierarchical Deterministic Wallets (master key derivation)
- BIP340: Schnorr Signatures for secp256k1
- BIP341: Taproot: SegWit version 1 spending rules
- BIP342: Validation of Taproot Scripts
- Bech32m: Address encoding for Taproot
Testing
composer install ./vendor/bin/phpunit
Security
This library is intended for educational and development purposes. For production use:
- Always use hardware wallets for key management
- Never expose private keys
- Audit your code thoroughly
- Use testnet for testing
License
MIT License. See LICENSE file for details.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Dependencies
- kornrunner/secp256k1 - Pure PHP secp256k1 implementation
- fenguoz/bip39-mnemonic-php - BIP39 mnemonic implementation