Hi everyone,
I'd like to propose an alternative approach to quantum resistance
for Bitcoin that I believe is simpler than BIP-360 P2QRH.
**Q-Lock: Quantum-Resistant Spending Protocol**
SUMMARY:
- Keeps ECDSA unchanged (no new signature algorithms!)
- Adds hash-based secret layer on top
- Uses only SHA256 + Merkle trees (proven crypto)
- ~3 KB transactions (comparable to FALCON)
- Two-phase commit-reveal scheme
- Soft fork compatible
- BIP-32 HD wallets work normally
KEY INSIGHT:
Instead of replacing ECDSA with new post-quantum algorithms
(FALCON, SPHINCS+, Dilithium), Q-Lock adds a quantum-safe
secret layer. Attacker must break BOTH ECDSA AND know the
hash preimages - quantum computers can't reverse SHA256.
COMPARISON TO BIP-360:
- BIP-360: New lattice-based crypto, 1.3-50 KB sigs, breaks BIP-32
- Q-Lock: Proven SHA256 crypto, ~3 KB sigs, BIP-32 works
HOW IT WORKS:
1. Setup: Generate 64 random secrets, commit via Merkle root
2. Commit phase: Lock outputs WITHOUT exposing pubkey
3. Reveal phase: Expose pubkey + secrets at block-hash-determined positions
4. Quantum attacker sees pubkey too late - outputs already locked!
```
Q-Lock is a quantum-resistant spending protocol for Bitcoin
that adds a hash-based secret layer on top of existing ECDSA
signatures. It uses a two-phase commit-reveal scheme where
spending positions are determined by the block hash, making
it secure against quantum attackers who can break ECDSA.
Q-Lock does NOT replace ECDSA. It adds quantum protection
while preserving Bitcoin's existing cryptographic foundation.
Transaction size: ~3 KB
Requires: Soft fork (1-2 new opcodes)
```
-----
## MOTIVATION
```
THE QUANTUM THREAT:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Shor's algorithm can break ECDSA by extracting private keys
from public keys. When a Bitcoin transaction is broadcast,
the public key is exposed in the mempool. A quantum attacker
could:
1. See public key in mempool
2. Run Shor's algorithm
3. Extract private key
4. Create competing transaction
5. Steal funds
Current solutions like Lamport signatures:
- Replace ECDSA entirely (24 KB signatures!)
- Politically difficult (changing Bitcoin's core crypto)
- Unlikely to be adopted before emergency
Q-LOCK ADVANTAGES:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
- Keeps ECDSA unchanged ✓
- Small size (~3 KB vs 24 KB) ✓
- Soft fork deployment ✓
- Opt-in adoption ✓
- Quantum resistant ✓
```
-----
## SPECIFICATION
### 1. SETUP
```
USER GENERATES:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1. Standard ECDSA keypair:
- privkey (256 bits)
- pubkey = privkey × G
- pubkey_hash = HASH160(pubkey)
2. Secret array (64 secrets):
- secret[0] = random(256 bits)
- secret[1] = random(256 bits)
- ...
- secret[63] = random(256 bits)
3. Commitment array:
- commitment[i] = SHA256(secret[i])
4. Merkle tree from commitments:
- merkle_root = MerkleRoot(commitment[0..63])
STORED IN WALLET:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
- privkey (32 bytes)
- secret[0..63] (2048 bytes)
- merkle_tree (for generating proofs)
STORED ON CHAIN (UTXO):
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
- pubkey_hash (20 bytes)
- merkle_root (32 bytes)
- num_secrets (1 byte) = 64
Total UTXO: ~53 bytes
```
-----
### 2. ADDRESS FORMAT
```
Q-LOCK ADDRESS:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
witness version: 2 (new)
witness program: <pubkey_hash> || <merkle_root>
Bech32m encoding: bc1q...
Example: bc1qlock1abc123...
```
-----
### 3. LOCKING SCRIPT
```
scriptPubKey:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
OP_2 <pubkey_hash> <merkle_root> <num_secrets>
```
-----
### 4. SPENDING: PHASE 1 (COMMIT)
```
PURPOSE:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Lock the transaction outputs WITHOUT exposing public key.
Prevents quantum attacker from knowing which key to attack.
COMMIT TRANSACTION:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
inputs:
- txid: <utxo_txid>
- vout: <utxo_index>
outputs:
- value: <amount>
- scriptPubKey: <destination>
witness:
- intent_hash = SHA256(pubkey || merkle_root || outputs_hash || nonce)
- nonce (for uniqueness)
- phase_flag = 0x00 (commit)
WHAT'S EXPOSED:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✓ Which UTXO being spent
✓ Where funds are going
✓ Intent hash (proves knowledge)
✗ NO public key exposed!
✗ NO signature exposed!
✗ Quantum attacker can't run Shor's!
VALIDATION RULES:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1. Intent hash is 32 bytes
2. Phase flag is 0x00
3. Creates "pending" state
4. Must be completed by reveal within 144 blocks (~24 hours)
```
-----
### 5. SPENDING: PHASE 2 (REVEAL)
```
PURPOSE:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Complete the spend by revealing:
- ECDSA signature
- Public key
- Secrets at block-determined positions
POSITION CALCULATION:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
commit_block_hash = GetBlockHash(commit_block_height)
position_seed = SHA256(commit_block_hash || commit_txid)
For i = 0 to 31:
position[i] = position_seed[i*2 : i*2+2] mod 64
Result: 32 positions from 0-63
REVEAL TRANSACTION:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
inputs:
- txid: <commit_txid>
- vout: 0
witness:
- signature (ECDSA)
- pubkey (compressed, 33 bytes)
- commit_block_height (4 bytes)
- num_reveals = 32
- For each position:
- secret[position[i]] (32 bytes)
- merkle_proof[i] (6 × 32 = 192 bytes)
- phase_flag = 0x01 (reveal)
REVEAL SIZE:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
- Signature: ~72 bytes
- Pubkey: 33 bytes
- Block height: 4 bytes
- 32 secrets: 1024 bytes
- 32 merkle proofs: ~2048 bytes (optimized)
- Overhead: ~50 bytes
TOTAL: ~3200 bytes (~3 KB)
```
-----
### 6. VALIDATION RULES
```
COMMIT VALIDATION:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1. phase_flag == 0x00
2. intent_hash is valid 32-byte hash
3. Output creates pending Q-Lock state
4. Mark UTXO as "commit pending"
REVEAL VALIDATION:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1. phase_flag == 0x01
2. Referenced commit exists and is pending
3. Reveal within 144 blocks of commit
4. ECDSA signature valid for pubkey
5. HASH160(pubkey) == pubkey_hash in UTXO
6. Recompute: position_seed = SHA256(block_hash || commit_txid)
7. Extract 32 positions from position_seed
8. For each position i:
a. commitment = SHA256(revealed_secret[i])
b. Verify merkle_proof[i] proves commitment is in merkle_root
9. intent_hash matches SHA256(pubkey || merkle_root || outputs_hash || nonce)
10. All checks pass → spend complete!
```
-----
### 7. NEW OPCODES
```
OPTION A: Single Opcode
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
OP_QLOCK (0xXX)
Handles both commit and reveal based on phase_flag.
Stack input:
<phase_flag> <witness_data...> <pubkey_hash> <merkle_root>
If phase_flag == 0x00: Validate commit
If phase_flag == 0x01: Validate reveal
OPTION B: Two Opcodes
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
OP_QLOCK_COMMIT (0xXX)
- Validates commit phase
- Creates pending state
OP_QLOCK_REVEAL (0xXY)
- Validates reveal phase
- Completes spend
```
-----
## SECURITY ANALYSIS
```
ATTACK 1: QUANTUM BREAKS ECDSA
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Attacker sees pubkey in REVEAL phase.
Runs Shor's algorithm, gets privkey.
RESULT: Too late!
- Commit already confirmed
- Outputs already locked
- tx_id bound to YOUR outputs
- Attacker's tx would have different tx_id
- Different tx_id = different positions
- Attacker doesn't have secrets at those positions!
ATTACK FAILS ✓
ATTACK 2: QUANTUM FRONT-RUNNING
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Attacker tries to attack during COMMIT phase.
RESULT: Can't!
- Public key not exposed in commit!
- Only intent_hash visible
- Can't run Shor's on a hash!
ATTACK FAILS ✓
ATTACK 3: GROVER'S ON SECRETS
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Attacker tries Grover's algorithm on SHA256.
RESULT: Impractical!
- SHA256: 2^256 → 2^128 with Grover
- 2^128 still astronomically large
- Would take longer than age of universe
ATTACK FAILS ✓
ATTACK 4: PREDICT BLOCK HASH
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Attacker tries to predict future block hash.
RESULT: Impossible!
- Block hash depends on mining nonce
- Nonce found by brute force
- Unpredictable until block mined
ATTACK FAILS ✓
ATTACK 5: INTERCEPT REVEAL
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Attacker sees secrets in reveal broadcast.
RESULT: Useless!
- Commit already locked outputs
- Secrets bound to YOUR tx_id
- Can't redirect funds
ATTACK FAILS ✓
SECURITY PROPERTIES:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✓ Quantum resistant (hash-based secrets)
✓ Forward secure (one-time use)
✓ Output binding (tx_id commits to destination)
✓ Unpredictable positions (block hash randomness)
```
-----
## RATIONALE
```
WHY NOT PURE LAMPORT?
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
- 24 KB signatures (too big!)
- Replaces ECDSA (political nightmare!)
- Hard to deploy
Q-Lock: ~3 KB, keeps ECDSA, soft fork!
WHY TWO PHASES?
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
- Phase 1 hides pubkey (prevents Shor's attack)
- Phase 2 reveals after outputs locked
- Only way to prevent mempool quantum attack!
WHY 64 SECRETS, REVEAL 32?
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
- 64 secrets = 2^64 possible combinations
- Reveal 32 = attacker needs to guess which 32
- Probability of guessing: 1 / C(64,32) ≈ 1 / 10^18
- Astronomically unlikely!
WHY MERKLE TREE?
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
- 64 commitments = 2048 bytes on chain (too big!)
- Merkle root = 32 bytes on chain (small!)
- Proofs in witness (~2 KB, acceptable)
```
-----
## BACKWARDS COMPATIBILITY
```
SOFT FORK:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
- Old nodes see Q-Lock outputs as "anyone can spend"
- New nodes enforce Q-Lock rules
- No chain split
- Gradual adoption
EXISTING ADDRESSES:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
- bc1q... (SegWit) continues to work
- bc1p... (Taproot) continues to work
- bc1qlock... (Q-Lock) is new option
- Users migrate when ready
```
-----
## TEST VECTORS
```
TEST VECTOR 1: SETUP
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
privkey: 0x0123456789abcdef...
pubkey: 0x02abc123...
pubkey_hash: 0x89ab...
secret[0]: 0xaaaa...
secret[1]: 0xbbbb...
...
secret[63]: 0xffff...
commitment[0]: SHA256(secret[0]) = 0x1111...
commitment[1]: SHA256(secret[1]) = 0x2222...
...
merkle_root: 0x9876...
TEST VECTOR 2: POSITION CALCULATION
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
commit_block_hash: 0x00000000000000000002f4a1...
commit_txid: 0x7a3f2b1c...
position_seed = SHA256(commit_block_hash || commit_txid)
= 0xe9c2a1b3...
positions = [3, 7, 12, 19, 24, 31, 33, 41, ...]
```
Full technical specification available. Looking for feedback
before formal BIP submission.
Does this approach have merit as an alternative/complement to BIP-360?