Generate valid BIP-375 PSBTs for testing Silent Payment (BIP-352) verification in hardware wallets and coordinators.
FOR TESTING ONLY
These PSBTs reference non-existent inputs (randomly generated txids). They are designed purely for testing BIP-375 verification logic in hardware wallets. The Bitcoin network will reject any attempt to broadcast them since the inputs don't exist.
BIP-375 defines how to embed Silent Payment information into PSBTs, allowing hardware signers to verify that outputs are correctly derived for a given Silent Payment address.
This tool generates test PSBTs with:
PSBT_OUT_SP_V0_INFO(0x09) - Per-output B_scan and B_spend keysPSBT_GLOBAL_SP_ECDH_SHARE(0x07) - ECDH shared pointPSBT_GLOBAL_SP_DLEQ(0x08) - BIP-374 DLEQ proof
pip install -r requirements.txtpython gui.pyThe GUI provides:
- Generate SP addresses from any mnemonic (mainnet or testnet)
- Generate BIP-375 PSBTs with all required fields
- Animated UR QR codes for easy scanning
- Seed QR export for loading sender key into SeedSigner
- Camera scanning to verify signed PSBTs
- Transaction details display after verification
Workflow:
-
Recipient SP Address (left panel):
- Enter recipient mnemonic or use default
- Click "Generate SP Address" - QR code appears
-
Sender PSBT (right panel):
- Enter sender mnemonic (different from recipient)
- Click "Seed QR" to display the sender seed for SeedSigner
- Load the seed into SeedSigner via Scan > Scan a SeedQR
-
Generate and Sign:
- Set amount and click "Generate PSBT"
- Scan the animated PSBT QR with SeedSigner
- SeedSigner verifies BIP-375 and shows the SP address
- Approve and sign on SeedSigner
-
Verify Signature:
- Click "Use Camera to Verify Signed Transaction"
- Point webcam at SeedSigner's animated QR code
- Tool verifies signature and displays transaction details
# Generate PSBT for mainnet SP address
python generate_psbt.py --sp-address sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv --amount 100000
# Generate PSBT for testnet SP address with verbose output
python generate_psbt.py --sp-address tsp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgq8dv6yl92gtg66u5220sfrqlxrjkqlq4rk79d6y7vvgcf8p8hxq5k8kf6 --amount 50000 --verbose
# Save to file
python generate_psbt.py --sp-address sp1q... --amount 100000 --output test.psbt
# Use custom mnemonic for input key
python generate_psbt.py --sp-address sp1q... --amount 100000 --mnemonic "your twelve word mnemonic phrase here"from generate_psbt import create_bip375_psbt
psbt_base64, psbt_obj, output_xonly = create_bip375_psbt(
sp_address="sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv",
amount_sats=100000,
mnemonic="abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
)
print(f"PSBT: {psbt_base64}")
print(f"Derived output: {output_xonly.hex()}")| Option | Short | Description |
|---|---|---|
--sp-address |
-a |
Silent Payment address (required) |
--amount |
-n |
Amount in satoshis (default: 100000) |
--mnemonic |
-m |
BIP-39 mnemonic for input key |
--output |
-o |
Output file path |
--verbose |
-v |
Print additional info to stderr |
In a real Silent Payment workflow, your coordinator wallet (Sparrow, BlueWallet, etc.) would:
- Take the recipient's
sp1...address - Select UTXOs to spend from your wallet
- Derive the unique output address using BIP-352
- Build a PSBT with BIP-375 fields (including DLEQ proof) so your signing device can verify the output was derived correctly before signing
- Send the PSBT to your hardware signer for approval
This tool simulates step 4 - it generates the same BIP-375 PSBT that a coordinator wallet would create, allowing you to test hardware signer verification without needing a full wallet setup or real UTXOs.
PSBT generation steps:
- Parses SP address - Extracts B_scan and B_spend public keys
- Generates input key - Derives Taproot key from mnemonic at m/86'/0'/0'/0/0
- Computes SP output - Derives the unique Taproot output address per BIP-352
- Generates DLEQ proof - Creates BIP-374 proof that the ECDH was computed correctly
- Builds PSBT - Embeds BIP-375 fields so the signer can independently verify the output
The SP address is derived deterministically from the mnemonic at fixed BIP-352 paths:
m/352'/0'/0'/0'/0→ spend key (B_spend)m/352'/0'/0'/1'/0→ scan key (B_scan)
Same mnemonic + same network = same SP address every time.
This is intentional - a recipient's SP address is like their "permanent" receiving address. They share it publicly and can receive unlimited payments to it. The privacy magic happens on the sender's side.
Each time you click "Generate PSBT", you'll get a different PSBT even for the same SP address and amount. This is expected and happens because:
-
Random input txid - Each PSBT uses a newly generated random fake txid as its input. Since the Silent Payment output derivation depends on the input outpoints, different txids produce different SP outputs.
-
Random DLEQ nonce - The BIP-374 DLEQ proof uses a random nonce
kfor security. This makes each proof unique while still being valid.
This is the core privacy feature of Silent Payments: every payment to the same SP address produces a different on-chain output address. An observer cannot link multiple payments to the same recipient by looking at the blockchain.
The generated PSBTs can be used to test Silent Payment verification in:
- SeedSigner (with BIP-352/375 support)
- Other hardware signers implementing BIP-375
Required:
embit- Bitcoin library for PSBT/transaction handlingqrcode[pil]- QR code generationPillow- Image processingurtypes- Uniform Resources (UR) encoding for animated QR codes
Optional (for camera scanning):
opencv-python- Webcam capturepyzbar- QR code decoding
MIT