Q-Lock: Quantum-Resistant Spending via ECDSA + Hash-Based Secrets
3 messages, 28 Nov 2025 to 24 May 2026. Started by Amarildo.
Amarildo (2), Alex
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?
You should re-read BIP360 (it has changed a lot) and look at SHRINCS.
1. BIP360 does not introduce any new PQ algos. All it does is add a new Taproot address that disables the (implied) key spend path. That's all it does. That's a requirement either way. You cannot skip this BIP. It's a base requirement to any PQ solution. Without it, you have an open goal. 2. SHRINCS is better and simpler than your proposal. It only requires 1 OP code and has 324 byte signatures. It also collapses the security assumptions to solely hashes, which reduces attack surfaces.
Again, please re-read the latest BIP360 to see why it is a base requirement to all PQ solutions. onsdag 10 december 2025 kl. 19:12:32 UTC+1 skrev Amarildo:
Quoted text (514 lines)
> 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? >
You missed the point. The 2-transaction design is intentional — it’s the only approach that prevents pubkey mempool exposure entirely. SHRINCS doesn’t solve this at all. Q-Lock also supports 1tx fast mode for users who want SHRINCS-level performance. Show me where SHRINCS closes the mempool attack window On Monday, March 9, 2026 at 9:16:32 PM UTC+2 Alex wrote:
Quoted text (530 lines)
> You should re-read BIP360 (it has changed a lot) and look at SHRINCS. > > 1. BIP360 does not introduce any new PQ algos. All it does is add a new > Taproot address that disables the (implied) key spend path. That's all it > does. That's a requirement either way. You cannot skip this BIP. It's a > base requirement to any PQ solution. Without it, you have an open goal. > 2. SHRINCS is better and simpler than your proposal. It only requires 1 OP > code and has 324 byte signatures. It also collapses the security > assumptions to solely hashes, which reduces attack surfaces. > > Again, please re-read the latest BIP360 to see why it is a base > requirement to all PQ solutions. > onsdag 10 december 2025 kl. 19:12:32 UTC+1 skrev Amarildo: > >> 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? >> >