Q-Lock: Quantum-Resistant Spending via ECDSA + Hash-Based Secrets

51 views
Skip to first unread message

Amarildo

unread,
Dec 10, 2025, 1:12:32 PM (6 days ago) Dec 10
to Bitcoin Development Mailing List
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?
Reply all
Reply to author
Forward
0 new messages