BTQ Architecture
How BTQ Core is built: a Bitcoin fork with Dilithium signatures, 8MB blocks, 1-minute block times, and the OP_CHECKSIGDILITHIUM opcodes.
BTQ Architecture
BTQ is built on Bitcoin Core's architecture with modifications for quantum-resistant cryptography. This page provides a technical overview.
Codebase Foundation
BTQ is a fork of Bitcoin Core, inheriting:
- 1M+ lines of battle-tested C++ code
- 15+ years of security hardening
- Comprehensive test suite (unit, functional, fuzz)
- Cross-platform support (Linux, macOS, Windows)
What Changed
| Component | Bitcoin | BTQ | Change |
|---|---|---|---|
| Signatures | ECDSA | ECDSA + Dilithium | Added |
| Script trees | Taproot (v1) | Taproot (v1) + P2MR (v2) | Extended |
| Block size | 1MB/4MW | 8MB/8MW | Increased |
| Script opcodes | Standard | + OP_CHECKSIGDILITHIUM | Added |
| Addresses | bc1... | qbtc1..., D... | New prefixes |
| Network | Port 8333 | Port 9333 | Changed |
| Genesis | Bitcoin | BTQ-specific | New |
What Stayed the Same
- Consensus: Proof of Work (SHA-256)
- Block time: ~1 minute (changed from Bitcoin's ~10 minutes)
- Supply: 21 million maximum
- Halving: Every 2,100,000 blocks (~4 years)
- UTXO model: Transaction structure
- P2P protocol: Network communication
Network Parameters
Chain Identity
// BTQ Genesis Block
nTime = 1771804800;
nNonce = 184980;
hashGenesisBlock = 0x0000ca45ea08433961609b50cd0c3f76d14589f8f61973ebbc344c3a160f7cddNetwork Magic Bytes
pchMessageStart[0] = 0xf1;
pchMessageStart[1] = 0xb2;
pchMessageStart[2] = 0xa3;
pchMessageStart[3] = 0xd4;These bytes identify BTQ network traffic and prevent cross-chain confusion.
Ports
| Network | P2P Port | RPC Port | Onion Port |
|---|---|---|---|
| Mainnet | 9333 | 8332 | 8334 |
| Testnet | 19333 | 18332 | 18334 |
| Signet | 38333 | 38332 | 38334 |
| Regtest | 19444 | 18443 | 18445 |
- P2P: Port for peer-to-peer node communication
- RPC: Port for JSON-RPC API access (btq-cli, applications)
- Onion: Target port for incoming Tor connections
Consensus Rules
Block Parameters
// Maximum block sizes
static const unsigned int MAX_BLOCK_SERIALIZED_SIZE = 8000000; // 8MB
static const unsigned int MAX_BLOCK_WEIGHT = 8000000; // 8MW
static const unsigned int MAX_BLOCK_SIGOPS_COST = 80000; // 4x Bitcoin
// Transaction limits (increased for Dilithium)
static const unsigned int MAX_STANDARD_TX_WEIGHT = 400000;Why Larger Blocks?
Dilithium signatures are significantly larger:
| Component | ECDSA | Dilithium | Increase |
|---|---|---|---|
| Signature | ~71 bytes | 2,420 bytes | 34x |
| Public Key | 33 bytes | 1,312 bytes | 40x |
| Typical Tx | ~250 bytes | ~3,800 bytes | 15x |
Without larger blocks, Dilithium transactions would severely limit throughput.
Cryptographic Modules
Directory Structure
src/crypto/
├── dilithium/ # Dilithium reference implementation
│ ├── api.h
│ ├── params.h
│ ├── sign.c
│ ├── packing.c
│ ├── polyvec.c
│ └── ...
├── dilithium_key.h # C++ key wrapper
├── dilithium_key.cpp
├── dilithium_wrapper.h # C/C++ interface
├── dilithium_wrapper.c
├── sha256.cpp # Existing Bitcoin crypto
├── ripemd160.cpp
└── ...Key Classes
// Private key wrapper
class CDilithiumKey {
std::vector<unsigned char> keydata; // 2,560 bytes
void MakeNewKey(); // Generate keypair
bool Sign(const uint256& hash,
std::vector<unsigned char>& sig);
CDilithiumPubKey GetPubKey() const;
bool IsValid() const;
};
// Public key wrapper
class CDilithiumPubKey {
std::vector<unsigned char> keydata; // 1,312 bytes
bool Verify(const uint256& hash,
const std::vector<unsigned char>& sig);
CKeyID GetID() const; // RIPEMD160(SHA256(pubkey))
};Script System
New Opcodes
// Added for Dilithium verification
OP_CHECKSIGDILITHIUM // Verify Dilithium signature
OP_DILITHIUM_PUBKEY // Mark Dilithium scriptScript Patterns
P2DPK (Pay-to-Dilithium-Public-Key):
<1312-byte pubkey> OP_CHECKSIGDILITHIUMP2DWPKH (Pay-to-Dilithium-Witness-Public-Key-Hash):
scriptPubKey: OP_0 <20-byte hash>
witness: <2421-byte sig> <1312-byte pubkey>BIP360 P2MR (Pay-to-Merkle-Root, witness v2):
scriptPubKey: OP_2 <32-byte merkle_root>
witness: <stack args...> <leaf script> <control block>P2MR uses script-path spending only. There is no key-path spend and no internal key tweak.
For complete protocol semantics and wallet-lifecycle behavior, see:
Auto-Detection
The script interpreter automatically detects Dilithium vs ECDSA:
// In interpreter.cpp
bool is_dilithium = (pubkey.size() > 100); // 1312 vs 33
if (is_dilithium) {
// Use OP_CHECKSIGDILITHIUM
} else {
// Use OP_CHECKSIG (ECDSA)
}Wallet Architecture
Key Storage
// Wallet database records
DILITHIUM_KEY // Unencrypted Dilithium key
DILITHIUM_CRYPTED_KEY // Encrypted Dilithium keyStorage format:
Key: (DILITHIUM_KEY, KeyID)
Value: 2560-byte raw private key
Key: (DILITHIUM_CRYPTED_KEY, KeyID)
Value: AES-256-CBC encrypted keyKey Derivation
Key ID is computed consistently with Bitcoin:
CKeyID GetID() const {
uint256 hash;
SHA256(pubkey.data(), pubkey.size(), hash.data());
CKeyID id;
RIPEMD160(hash.data(), 32, id.data());
return id; // 20 bytes
}Address System
Base58 Prefixes
// Mainnet
base58Prefixes[PUBKEY_ADDRESS] = {75}; // B...
base58Prefixes[DILITHIUM_PUBKEY] = {76}; // D...
base58Prefixes[SCRIPT_ADDRESS] = {135}; // Q...
base58Prefixes[DILITHIUM_SCRIPT] = {136}; // R...
// Bech32 Human-Readable Part
bech32_hrp = "qbtc"; // qbtc1q...Address Derivation
┌─────────────────┐
│ Dilithium │
│ Public Key │
│ (1,312 bytes) │
└────────┬────────┘
│
▼
SHA-256 Hash
│
▼
RIPEMD-160 Hash
│
▼
┌─────────────────┐
│ Public Key Hash │
│ (20 bytes) │
└────────┬────────┘
│
┌────┴────┐
▼ ▼
Base58 Bech32m
X... qbtc1z...
(historical) (P2MR, current)RPC Interface
Dilithium-Specific Commands
// Address generation
"getnewdilithiumaddress"
-> Generate new Dilithium address
// Message signing
"signmessagewithdilithium"
-> Sign message with Dilithium key
"verifydilithiumsignature"
-> Verify Dilithium signature
// Transaction signing
"signtransactionwithdilithium"
-> Sign transaction with Dilithium
// Key management
"importdilithiumkey"
-> Import Dilithium private keyStandard Bitcoin RPCs
All standard Bitcoin RPCs work:
getblockchaininfo,getblock,getblockhashcreatewallet,loadwallet,unloadwalletgetnewaddress,getbalance,listunspentcreaterawtransaction,sendrawtransactiongetmempoolinfo,getrawmempool
Transaction Flow
Creation
1. Select UTXOs (listunspent)
2. Build transaction (createrawtransaction)
3. Sign with Dilithium (signtransactionwithdilithium)
4. Broadcast (sendrawtransaction)Validation
// For each input:
1. Check UTXO exists and is unspent
2. Determine signature type (size-based)
3. If Dilithium:
a. Extract 2421-byte signature from witness
b. Extract 1312-byte pubkey from witness
c. Compute sighash (BIP-143 style)
d. Verify: Dilithium2.Verify(pubkey, sighash, sig)
4. Check amounts (inputs >= outputs + fees)
5. Accept to mempoolP2P Network
Message Types
Standard Bitcoin messages with BTQ magic bytes:
| Message | Purpose |
|---|---|
version | Protocol negotiation |
verack | Version acknowledgment |
addr | Peer addresses |
inv | Inventory announcement |
getdata | Request data |
tx | Transaction |
block | Block |
ping/pong | Keepalive |
Transaction Propagation
┌──────────┐ inv(txid) ┌──────────┐
│ Node A │ ───────────────▶│ Node B │
│ │◀─────────────── │ │
│ │ getdata(txid) │ │
│ │ ───────────────▶│ │
│ │ tx(data) │ │
└──────────┘ └──────────┘Testing Infrastructure
Unit Tests
# Run all unit tests
make check
# Run specific Dilithium tests
./src/test/test_btq --run_test=dilithium_key_tests
./src/test/test_btq --run_test=dilithium_address_script_tests
./src/test/test_btq --run_test=dilithium_wallet_tests
./src/test/test_btq --run_test=dilithium_descriptor_testsFunctional Tests
# Run all functional tests
./test/functional/test_runner.py
# Run BTQ-specific tests
./test/functional/btq_regtest_mining.py
./test/functional/btq_chain_identity.pyTest Coverage
| Area | Tests |
|---|---|
| Key generation | Unit |
| Signature creation | Unit |
| Signature verification | Unit |
| Address encoding | Unit + Functional |
| Wallet operations | Unit + Functional |
| Transaction signing | Functional |
| Block validation | Functional |
Build System
Dependencies
# Core dependencies
build-essential, libtool, autotools-dev, automake
pkg-config, bsdmainutils, python3
# Crypto/network
libevent-dev, libboost-dev, libsqlite3-dev
# Optional
libqt5-dev (GUI), libdb-dev (legacy wallet)Build Commands
./autogen.sh
./configure [options]
make -j$(nproc)
make check # Run testsSecurity Model
Threat Mitigation
| Threat | Bitcoin | BTQ |
|---|---|---|
| Classical attacks | Secure | Secure |
| Quantum (signatures) | Vulnerable | Protected |
| Quantum (mining) | Weakened | Weakened |
| 51% attack | PoW cost | PoW cost |
| Double spend | Confirmations | Confirmations |
Defense in Depth
- Cryptographic: Dilithium + SHA-256
- Economic: Mining cost, fee market
- Network: Decentralized validation
- Protocol: Confirmation depth
Future Roadmap
Short Term
- Complete Phase 4 (block validation)
- Mainnet launch
- Wallet improvements
Medium Term
- Additional post-quantum algorithms (Falcon, SPHINCS+)
- Hybrid signatures (ECDSA + Dilithium)
- Performance optimizations
Long Term
- HD wallet derivation for Dilithium
- Hardware wallet support
- Layer 2 solutions